diff --git a/Makefile b/Makefile index 86e684f..c76bc16 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,5 @@ -OBJECTS=$(wildcard lib/*.js) - -all: dist/math-expressions.js - clean: - rm -f dist/math-expressions.js + rm -f build/math-expressions.js -dist/math-expressions.js: $(OBJECTS) - mkdir -p dist - node ./node_modules/amdee/bin/amdee --source lib/math-expressions.js --target dist/math-expressions.js - sed -i "s/define(\['require'\], function(require) {/var MathExpressions = (function() {/g" dist/math-expressions.js +all: + npm run build diff --git a/build/math-expressions.js b/build/math-expressions.js index 7b43aad..fb420f8 100644 --- a/build/math-expressions.js +++ b/build/math-expressions.js @@ -1,3509 +1,3632 @@ -const get_tree = function (expr_or_tree) { +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.MathExpression = factory()); +}(this, (function () { 'use strict'; - if (expr_or_tree === undefined || expr_or_tree === null) - return undefined; + const get_tree = function (expr_or_tree) { - var tree; - if (expr_or_tree.tree !== undefined) - tree = expr_or_tree.tree; - else - tree = expr_or_tree; + if (expr_or_tree === undefined || expr_or_tree === null) + return undefined; + + var tree; + if (expr_or_tree.tree !== undefined) + tree = expr_or_tree.tree; + else + tree = expr_or_tree; - return tree; -}; + return tree; + }; -function* subsets(arr, m) { - // returns an iterator over all subsets of array arr - // up to size m + function* subsets(arr, m) { + // returns an iterator over all subsets of array arr + // up to size m - var n = arr.length; + var n = arr.length; - if (m === undefined) - m = n; + if (m === undefined) + m = n; - if (m === 0) - return; + if (m === 0) + return; - for (let i = 0; i < n; i++) { - yield [arr[i]]; - } + for (let i = 0; i < n; i++) { + yield [arr[i]]; + } - if (m === 1) - return + if (m === 1) + return - for (let i = 0; i < n; i++) { - let sub = subsets(arr.slice(i + 1), m - 1); - for (let val of sub) { - yield [arr[i]].concat(val); + for (let i = 0; i < n; i++) { + let sub = subsets(arr.slice(i + 1), m - 1); + for (let val of sub) { + yield [arr[i]].concat(val); + } } } -} -var is_associative = { '+': true, '*': true, 'and': true, 'or': true, 'union': true, 'intersect': true }; + var is_associative = { '+': true, '*': true, 'and': true, 'or': true, 'union': true, 'intersect': true }; -function flatten(expr) { - // flatten tree with all associative operators + function flatten(expr) { + // flatten tree with all associative operators - var tree = get_tree(expr); + var tree = get_tree(expr); - if (!Array.isArray(tree)) - return tree; + if (!Array.isArray(tree)) + return tree; - var operator = tree[0]; - var operands = tree.slice(1); + var operator = tree[0]; + var operands = tree.slice(1); - operands = operands.map(function (v, i) { - return flatten(v); - }); + operands = operands.map(function (v, i) { + return flatten(v); + }); - if (is_associative[operator]) { - var result = []; + if (is_associative[operator]) { + var result = []; - for (var i = 0; i < operands.length; i++) { - if (Array.isArray(operands[i]) && (operands[i][0] === operator)) { - result = result.concat(operands[i].slice(1)); - } else { - result.push(operands[i]); + for (var i = 0; i < operands.length; i++) { + if (Array.isArray(operands[i]) && (operands[i][0] === operator)) { + result = result.concat(operands[i].slice(1)); + } else { + result.push(operands[i]); + } } + + operands = result; } - operands = result; + return [operator].concat(operands); } + const unflattenRight = function (expr) { + // unflatten tree with associate operators + // into a right heavy tree; - return [operator].concat(operands); -} -const unflattenRight = function (expr) { - // unflatten tree with associate operators - // into a right heavy tree; + var tree = get_tree(expr); - var tree = get_tree(expr); + if (!Array.isArray(tree)) + return tree; - if (!Array.isArray(tree)) - return tree; + var operator = tree[0]; + var operands = tree.slice(1); + + operands = operands.map(function (v, i) { + return unflattenRight(v); + }); - var operator = tree[0]; - var operands = tree.slice(1); + if (operands.length > 2 && is_associative[operator]) { + var result = [operator, operands[0], undefined]; + var next = result; - operands = operands.map(function (v, i) { - return unflattenRight(v); - }); + for (var i = 1; i < operands.length - 1; i++) { + next[2] = [operator, operands[i], undefined]; + next = next[2]; + } - if (operands.length > 2 && is_associative[operator]) { - var result = [operator, operands[0], undefined]; - var next = result; + next[2] = operands[operands.length - 1]; - for (var i = 1; i < operands.length - 1; i++) { - next[2] = [operator, operands[i], undefined]; - next = next[2]; + return result; } - next[2] = operands[operands.length - 1]; + return [operator].concat(operands); + }; - return result; - } + const unflattenLeft = function (expr) { + // unflatten tree with associate operator op + // into a left heavy tree; - return [operator].concat(operands); -}; + var tree = get_tree(expr); -const unflattenLeft = function (expr) { - // unflatten tree with associate operator op - // into a left heavy tree; + if (!Array.isArray(tree)) + return tree; - var tree = get_tree(expr); + var operator = tree[0]; + var operands = tree.slice(1); - if (!Array.isArray(tree)) - return tree; + operands = operands.map(function (v, i) { + return unflattenLeft(v); + }); - var operator = tree[0]; - var operands = tree.slice(1); + if (operands.length > 2 && is_associative[operator]) { + var result = [operator, undefined, operands[operands.length-1]]; + var next = result; - operands = operands.map(function (v, i) { - return unflattenLeft(v); - }); + for (var i = operands.length - 2; i > 0; i--) { + next[1] = [operator, undefined, operands[i]]; + next = next[1]; + } - if (operands.length > 2 && is_associative[operator]) { - var result = [operator, undefined, operands[operands.length-1]]; - var next = result; + next[1] = operands[0]; - for (var i = operands.length - 2; i > 0; i--) { - next[1] = [operator, undefined, operands[i]]; - next = next[1]; + return result; } - next[1] = operands[0]; - - return result; - } - - return [operator].concat(operands); -}; + return [operator].concat(operands); + }; -const allChildren = function (tree) { - // find all children of operator of tree as though it had been flattened + const allChildren = function (tree) { + // find all children of operator of tree as though it had been flattened - if (!Array.isArray(tree)) - return []; + if (!Array.isArray(tree)) + return []; - var operator = tree[0]; - var operands = tree.slice(1); + var operator = tree[0]; + var operands = tree.slice(1); - if (!is_associative[operator]) - return operands; + if (!is_associative[operator]) + return operands; - return operands.reduce(function (a, b) { - if (Array.isArray(b) && b[0] === operator) { - return a.concat(allChildren(b)); - } - else - return a.concat([b]); - }, []); + return operands.reduce(function (a, b) { + if (Array.isArray(b) && b[0] === operator) { + return a.concat(allChildren(b)); + } + else + return a.concat([b]); + }, []); -}; + }; -function remove_duplicate_negatives(tree) { - // remove pairs of consecutive minus signs + function remove_duplicate_negatives(tree) { + // remove pairs of consecutive minus signs - if (!Array.isArray(tree)) - return tree; + if (!Array.isArray(tree)) + return tree; - var operator = tree[0]; - var operands = tree.slice(1); + var operator = tree[0]; + var operands = tree.slice(1); - if (operator === '-' && operands[0][0] === '-') { - return remove_duplicate_negatives(operands[0][1]); - } + if (operator === '-' && operands[0][0] === '-') { + return remove_duplicate_negatives(operands[0][1]); + } - operands = operands.map(remove_duplicate_negatives); + operands = operands.map(remove_duplicate_negatives); - return [operator].concat(operands); + return [operator].concat(operands); -} + } -function normalize_negatives_in_factors(tree) { - // if any factors contain a negative, - // place negative outside factor - // - // run remove_duplicates_negatives before and after - // running this function to make sure all negatives are addressed + function normalize_negatives_in_factors(tree) { + // if any factors contain a negative, + // place negative outside factor + // + // run remove_duplicates_negatives before and after + // running this function to make sure all negatives are addressed - if (!Array.isArray(tree)) - return tree; + if (!Array.isArray(tree)) + return tree; - var operator = tree[0]; - var operands = tree.slice(1); + var operator = tree[0]; + var operands = tree.slice(1); - operands = operands.map(normalize_negatives_in_factors); + operands = operands.map(normalize_negatives_in_factors); - if (operator !== '*' && operator !== '/') - return [operator].concat(operands); + if (operator !== '*' && operator !== '/') + return [operator].concat(operands); - var sign = 1; - var operands_no_negatives = []; + var sign = 1; + var operands_no_negatives = []; - for (var i = 0; i < operands.length; i++) { - if (operands[i][0] === '-') { - sign *= -1; - operands_no_negatives.push(operands[i][1]); - } - else { - operands_no_negatives.push(operands[i]); + for (var i = 0; i < operands.length; i++) { + if (operands[i][0] === '-') { + sign *= -1; + operands_no_negatives.push(operands[i][1]); + } + else { + operands_no_negatives.push(operands[i]); + } } - } - var result = [operator].concat(operands_no_negatives); - if (sign === -1) - result = ['-', result]; + var result = [operator].concat(operands_no_negatives); + if (sign === -1) + result = ['-', result]; - return result; -} + return result; + } -function normalize_negatives(expr_or_tree) { - // Remove duplicate negatives and pull all negatives outside factors - var tree = get_tree(expr_or_tree); + function normalize_negatives(expr_or_tree) { + // Remove duplicate negatives and pull all negatives outside factors + var tree = get_tree(expr_or_tree); - tree = remove_duplicate_negatives(tree); - tree = normalize_negatives_in_factors(tree); - tree = remove_duplicate_negatives(tree); + tree = remove_duplicate_negatives(tree); + tree = normalize_negatives_in_factors(tree); + tree = remove_duplicate_negatives(tree); - return tree; -} + return tree; + } -function sort_key(tree, params={}) { - if (typeof tree === 'number') { - if (params.ignore_negatives) - return [0, 'number', Math.abs(tree)]; - return [0, 'number', tree]; - } - if (typeof tree === 'string') { - // if string is a constant, return number with value? - return [1, 'symbol', tree]; - } - if (typeof tree === 'boolean') { - return [1, 'boolean', tree]; - } + function sort_key(tree, params={}) { + if (typeof tree === 'number') { + if (params.ignore_negatives) + return [0, 'number', Math.abs(tree)]; + return [0, 'number', tree]; + } + if (typeof tree === 'string') { + // if string is a constant, return number with value? + return [1, 'symbol', tree]; + } + if (typeof tree === 'boolean') { + return [1, 'boolean', tree]; + } - if (!Array.isArray(tree)) - return [-1, 'unknown', tree]; + if (!Array.isArray(tree)) + return [-1, 'unknown', tree]; - var operator = tree[0]; - var operands = tree.slice(1); + var operator = tree[0]; + var operands = tree.slice(1); - if (operator === 'apply') { - var key = [2, 'function', operands[0]]; + if (operator === 'apply') { + var key = [2, 'function', operands[0]]; - var f_args = operands[1]; + var f_args = operands[1]; - var n_args = 1; + var n_args = 1; - var arg_keys = []; + var arg_keys = []; - if (Array.isArray(f_args)) { + if (Array.isArray(f_args)) { - f_args = f_args.slice(1); // remove vector operator + f_args = f_args.slice(1); // remove vector operator - n_args = f_args.length; + n_args = f_args.length; - arg_keys = f_args.map(x=>sort_key(x,params)); + arg_keys = f_args.map(x=>sort_key(x,params)); - } - else { - arg_keys = [sort_key(f_args,params)]; - } + } + else { + arg_keys = [sort_key(f_args,params)]; + } - key.push([n_args, arg_keys]); + key.push([n_args, arg_keys]); - return key; - } + return key; + } - var n_factors = operands.length; + var n_factors = operands.length; - var factor_keys = operands.map(sort_key, params); + var factor_keys = operands.map(sort_key, params); - if (operator === "*") { - return [4, 'product', n_factors, factor_keys]; - } + if (operator === "*") { + return [4, 'product', n_factors, factor_keys]; + } - if (operator === "/") { - return [4, 'quotient', n_factors, factor_keys]; - } + if (operator === "/") { + return [4, 'quotient', n_factors, factor_keys]; + } - if (operator === "+") { - return [5, 'sum', n_factors, factor_keys]; - } + if (operator === "+") { + return [5, 'sum', n_factors, factor_keys]; + } - if (operator === "-") { - if (params.ignore_negatives) - return factor_keys[0]; - return [6, 'minus', n_factors, factor_keys]; - } + if (operator === "-") { + if (params.ignore_negatives) + return factor_keys[0]; + return [6, 'minus', n_factors, factor_keys]; + } - return [7, operator, n_factors, factor_keys]; + return [7, operator, n_factors, factor_keys]; -} + } -function arrayCompare(a,b) { - if(Array.isArray(a)) { - if(Array.isArray(b)) { - let minLength = Math.min(a.length, b.length); - for(let i=0; i < minLength; i++) { - let comp = arrayCompare(a[i], b[i]); - if(comp !== 0) { - return comp; + function arrayCompare(a,b) { + if(Array.isArray(a)) { + if(Array.isArray(b)) { + let minLength = Math.min(a.length, b.length); + for(let i=0; i < minLength; i++) { + let comp = arrayCompare(a[i], b[i]); + if(comp !== 0) { + return comp; + } } - } - // shorter array comes first - return a.length < b.length ? -1 : (a.length > b.length ? 1: 0); + // shorter array comes first + return a.length < b.length ? -1 : (a.length > b.length ? 1: 0); - }else { - // non array comes before array - // a is the array - return 1; - } - } else { - if(Array.isArray(b)) { - // non-array comes before array - // b is the array - return -1; + }else { + // non array comes before array + // a is the array + return 1; + } } else { - // got to two scalar - return a < b ? -1 : (a > b ? 1: 0) + if(Array.isArray(b)) { + // non-array comes before array + // b is the array + return -1; + } else { + // got to two scalar + return a < b ? -1 : (a > b ? 1: 0) + } } } -} -function compare_function(a, b, params={}) { + function compare_function(a, b, params={}) { - var key_a = sort_key(a, params); - var key_b = sort_key(b, params); + var key_a = sort_key(a, params); + var key_b = sort_key(b, params); - return arrayCompare(key_a, key_b); -} + return arrayCompare(key_a, key_b); + } -function coeff_factors_from_term(term, string_factors) { - if(typeof term === "string") { - let ind = string_factors.indexOf(term); - if(ind === -1) { - string_factors.push(term); - ind = string_factors.length - 1; - } - let f = []; - f[ind] = 1; - return { factor_contains: f, coeff: 1} - } else if(Array.isArray(term)) { - let operator = term[0]; - let operands = term.slice(1); - if(operator === '*') { - let coeff = []; + function coeff_factors_from_term(term, string_factors) { + if(typeof term === "string") { + let ind = string_factors.indexOf(term); + if(ind === -1) { + string_factors.push(term); + ind = string_factors.length - 1; + } let f = []; - for(let factor of operands) { - if(typeof factor === "string") { - let ind = string_factors.indexOf(factor); - if(ind === -1) { - string_factors.push(factor); - ind = string_factors.length - 1; - } - if(f[ind] === undefined) { - f[ind] = 0; - } - f[ind]++; - continue; - } else if(Array.isArray(factor) && factor[0] === "^" || factor[0] === '-') { - let result = coeff_factors_from_term(factor, string_factors); - for(let ind in result.factor_contains) { + f[ind] = 1; + return { factor_contains: f, coeff: 1} + } else if(Array.isArray(term)) { + let operator = term[0]; + let operands = term.slice(1); + if(operator === '*') { + let coeff = []; + let f = []; + for(let factor of operands) { + if(typeof factor === "string") { + let ind = string_factors.indexOf(factor); + if(ind === -1) { + string_factors.push(factor); + ind = string_factors.length - 1; + } if(f[ind] === undefined) { f[ind] = 0; } - f[ind] += result.factor_contains[ind]; - } - if(result.coeff !== 1) { - coeff.push(result.coeff); + f[ind]++; + continue; + } else if(Array.isArray(factor) && factor[0] === "^" || factor[0] === '-') { + let result = coeff_factors_from_term(factor, string_factors); + for(let ind in result.factor_contains) { + if(f[ind] === undefined) { + f[ind] = 0; + } + f[ind] += result.factor_contains[ind]; + } + if(result.coeff !== 1) { + coeff.push(result.coeff); + } + continue; } - continue; + coeff.push(factor); } - coeff.push(factor); - } - if(coeff.length === 0) { - coeff = 1; - } else if(coeff.length === 1) { - coeff = coeff[0]; - } else { - coeff = ['*', ...coeff]; - } - return { factor_contains: f, coeff: coeff}; - } else if(operator === '^') { - let base = operands[0]; - let exponent = operands[1]; - let f=[]; - if(typeof base === "string" && Number.isFinite(exponent)) { - let ind = string_factors.indexOf(base); - if(ind === -1) { - string_factors.push(base); - ind = string_factors.length - 1; - } - f[ind] = exponent; - return {factor_contains: f, coeff: 1} - } - } else if(operator === '-') { - let result = coeff_factors_from_term(operands[0], string_factors); - let coeff = -1; - if(typeof result.coeff === "number") { - coeff *= result.coeff; - } else { - coeff = ['-', result.coeff]; + if(coeff.length === 0) { + coeff = 1; + } else if(coeff.length === 1) { + coeff = coeff[0]; + } else { + coeff = ['*', ...coeff]; + } + return { factor_contains: f, coeff: coeff}; + } else if(operator === '^') { + let base = operands[0]; + let exponent = operands[1]; + let f=[]; + if(typeof base === "string" && Number.isFinite(exponent)) { + let ind = string_factors.indexOf(base); + if(ind === -1) { + string_factors.push(base); + ind = string_factors.length - 1; + } + f[ind] = exponent; + return {factor_contains: f, coeff: 1} + } + } else if(operator === '-') { + let result = coeff_factors_from_term(operands[0], string_factors); + let coeff = -1; + if(typeof result.coeff === "number") { + coeff *= result.coeff; + } else { + coeff = ['-', result.coeff]; + } + return {factor_contains: result.factor_contains, coeff: coeff}; + } else if(operator === '/') { + let result = coeff_factors_from_term(operands[0], string_factors); + let coeff = ['/', result.coeff, operands[1]]; + return {factor_contains: result.factor_contains, coeff: coeff}; } - return {factor_contains: result.factor_contains, coeff: coeff}; - } else if(operator === '/') { - let result = coeff_factors_from_term(operands[0], string_factors); - let coeff = ['/', result.coeff, operands[1]]; - return {factor_contains: result.factor_contains, coeff: coeff}; } + + return {factor_contains: [], coeff: term} } - - return {factor_contains: [], coeff: term} -} -function default_order(expr_or_tree, params) { + function default_order(expr_or_tree, params) { - if (params === undefined) - params = {}; + if (params === undefined) + params = {}; - var tree = get_tree(expr_or_tree); + var tree = get_tree(expr_or_tree); - tree = flatten(tree); - tree = normalize_negatives(tree); + tree = flatten(tree); + tree = normalize_negatives(tree); - function sort_ast(subTree) { - if (!Array.isArray(subTree)) - return subTree; + function sort_ast(subTree) { + if (!Array.isArray(subTree)) + return subTree; - var operator = subTree[0]; - var operands = subTree.slice(1); + var operator = subTree[0]; + var operands = subTree.slice(1); - operands = operands.map(sort_ast); + operands = operands.map(sort_ast); - if (operator === "+" ) { + if (operator === "+" ) { - // kludge to get sort order closer to lexographic order + // kludge to get sort order closer to lexographic order - // TODO: clean this up + // TODO: clean this up - // find all string factors - let string_factors = []; - let factors_by_term = []; - let coeffs_by_term = []; - for(let term of operands) { - let result = coeff_factors_from_term(term, string_factors); - factors_by_term.push(result.factor_contains); - coeffs_by_term.push(result.coeff); - } + // find all string factors + let string_factors = []; + let factors_by_term = []; + let coeffs_by_term = []; + for(let term of operands) { + let result = coeff_factors_from_term(term, string_factors); + factors_by_term.push(result.factor_contains); + coeffs_by_term.push(result.coeff); + } - // factors_by_term = factors_by_term.map(x => Array.from(x, item => item || 0)) + // factors_by_term = factors_by_term.map(x => Array.from(x, item => item || 0)) - let variableInfo = []; - for(let [ind, varname] of string_factors.entries()) { - let thisvar = {varname: varname, exponents_in_term: []}; - for(let j=0; j< factors_by_term.length; j++) { - thisvar.exponents_in_term.push(factors_by_term[j][ind] || 0); + let variableInfo = []; + for(let [ind, varname] of string_factors.entries()) { + let thisvar = {varname: varname, exponents_in_term: []}; + for(let j=0; j< factors_by_term.length; j++) { + thisvar.exponents_in_term.push(factors_by_term[j][ind] || 0); + } + variableInfo.push(thisvar); } - variableInfo.push(thisvar); - } - variableInfo.sort((a,b) => a.varname < b.varname ? -1 : 1); + variableInfo.sort((a,b) => a.varname < b.varname ? -1 : 1); - let sort_keys_by_term = []; + let sort_keys_by_term = []; - for(let i=0; i< coeffs_by_term.length; i++) { - let this_sort_key = variableInfo.reduce((a,c) => [...a, -c.exponents_in_term[i]],[]); - this_sort_key.push(sort_key(coeffs_by_term[i], params)); - sort_keys_by_term.push(this_sort_key); - } + for(let i=0; i< coeffs_by_term.length; i++) { + let this_sort_key = variableInfo.reduce((a,c) => [...a, -c.exponents_in_term[i]],[]); + this_sort_key.push(sort_key(coeffs_by_term[i], params)); + sort_keys_by_term.push(this_sort_key); + } - let terms_with_sort_key = []; + let terms_with_sort_key = []; - for(let [ind,term] of operands.entries()) { - terms_with_sort_key.push({ - term: term, - sort_key: sort_keys_by_term[ind], - }); - } + for(let [ind,term] of operands.entries()) { + terms_with_sort_key.push({ + term: term, + sort_key: sort_keys_by_term[ind], + }); + } - terms_with_sort_key.sort((a,b) => arrayCompare(a.sort_key, b.sort_key)); + terms_with_sort_key.sort((a,b) => arrayCompare(a.sort_key, b.sort_key)); - operands = terms_with_sort_key.map(x => x.term); + operands = terms_with_sort_key.map(x => x.term); - // sort all operands of these arguments in default order - // determined by compare function - // operands.sort((a, b) => compare_function(a, b, params)); - } - else if (operator === "*" || operator === "=" - || operator === "and" || operator === "or" || operator === "ne" - || operator === "union" || operator === "intersect") { + // sort all operands of these arguments in default order + // determined by compare function + // operands.sort((a, b) => compare_function(a, b, params)); + } + else if (operator === "*" || operator === "=" + || operator === "and" || operator === "or" || operator === "ne" + || operator === "union" || operator === "intersect") { - // TODO: determine if commutative + // TODO: determine if commutative - // sort all operands of these arguments in default order - // determined by compare function - operands.sort((a, b) => compare_function(a, b, params)); - } - else if (operator === ">" || operator === "ge") { - // turn all greater thans to less thans + // sort all operands of these arguments in default order + // determined by compare function + operands.sort((a, b) => compare_function(a, b, params)); + } + else if (operator === ">" || operator === "ge") { + // turn all greater thans to less thans - operands = operands.reverse(); - if (operator === ">") - operator = "<"; - else - operator = "le"; - } - else if (operator === "gts") { - // turn all greater thans to less thans - var args = operands[0]; - var strict = operands[1]; + operands = operands.reverse(); + if (operator === ">") + operator = "<"; + else + operator = "le"; + } + else if (operator === "gts") { + // turn all greater thans to less thans + var args = operands[0]; + var strict = operands[1]; - if (args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); + if (args[0] !== 'tuple' || strict[0] !== 'tuple') + // something wrong if args or strict are not tuples + throw new Error("Badly formed ast"); - args = ['tuple'].concat(args.slice(1).reverse()); - strict = ['tuple'].concat(strict.slice(1).reverse()); + args = ['tuple'].concat(args.slice(1).reverse()); + strict = ['tuple'].concat(strict.slice(1).reverse()); - operator = "lts"; - operands = [args, strict]; + operator = "lts"; + operands = [args, strict]; - } - else if (operator === 'ni' || operator === 'notni' - || operator === 'superset' || operator === 'notsuperset') { - // turn all containment operators to have larger set at right + } + else if (operator === 'ni' || operator === 'notni' + || operator === 'superset' || operator === 'notsuperset') { + // turn all containment operators to have larger set at right - operands = operands.reverse(); - if (operator === 'ni') - operator = 'in'; - else if (operator === 'notni') - operator = 'notin'; - else if (operator === 'superset') - operator = 'subset'; - else - operator = 'notsubset'; - } - else if (operator === '-') { - // when negating a product with a numerical first factor - // put negative sign in that first factor - if (operands[0][0] === '*') { - operands[0][1] = ['-', operands[0][1]]; - return operands[0]; + operands = operands.reverse(); + if (operator === 'ni') + operator = 'in'; + else if (operator === 'notni') + operator = 'notin'; + else if (operator === 'superset') + operator = 'subset'; + else + operator = 'notsubset'; } + else if (operator === '-') { + // when negating a product with a numerical first factor + // put negative sign in that first factor + if (operands[0][0] === '*') { + operands[0][1] = ['-', operands[0][1]]; + return operands[0]; + } + } + + return [operator].concat(operands); } - return [operator].concat(operands); + return normalize_negatives(sort_ast(tree)); } - return normalize_negatives(sort_ast(tree)); -} + var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; -var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - -function unwrapExports (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; -} + function unwrapExports (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; + } -function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; -} + function createCommonjsModule(fn, module) { + return module = { exports: {} }, fn(module, module.exports), module.exports; + } -/** - * Test whether a value is a BigNumber - * @param {*} x - * @return {boolean} - */ -var isBigNumber = function isBigNumber(x) { - return x && x.constructor.prototype.isBigNumber || false -}; + /** + * Test whether a value is a BigNumber + * @param {*} x + * @return {boolean} + */ + var isBigNumber = function isBigNumber(x) { + return x && x.constructor.prototype.isBigNumber || false + }; -var object = createCommonjsModule(function (module, exports) { + var object = createCommonjsModule(function (module, exports) { -/** - * 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; + /** + * 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; - } + // 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(); - } + // 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); - }); - } + // 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 (isBigNumber(x)) return x; // bignumbers are immutable - if (x instanceof RegExp) throw new TypeError('Cannot clone ' + x); // TODO: clone a RegExp + 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 (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); -}; + // 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 = {}; + /** + * 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]); + for (var key in object) { + if (exports.hasOwnProperty(object, key)) { + clone[key] = callback(object[key]); + } } - } - return clone; -}; + 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]; + /** + * 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; -}; + 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'); - } + /** + * 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 { + 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]; } - } else if (Array.isArray(b[prop])) { - throw new TypeError('Arrays are not supported by deepExtend'); - } else { - a[prop] = b[prop]; } } - } - return a; -}; + 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; - } + /** + * 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])) { + if (a.length != b.length) { 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 (i = 0, len = a.length; i < len; i++) { + if (!exports.deepEqual(a[i], b[i])) { + return false; + } } + return true; } - for (prop in b) { - //noinspection JSUnfilteredForInLoop - if (!exports.deepEqual(a[prop], b[prop])) { + else if (a instanceof Object) { + if (Array.isArray(b) || !(b instanceof Object)) { return false; } - } - return true; - } - else { - return (typeof a === typeof b) && (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 () {} }); + 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; } - } 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 ( 3) + ? param.slice(3) + : 'any'; - /** - * Parse a parameter, like "...number | boolean" - * @param {string} param - * @param {ConversionDef[]} conversions - * @return {Param} param - */ - function parseParam (param, conversions) { - var restParam = param.indexOf('...') === 0; - var types = (!restParam) - ? param - : (param.length > 3) - ? param.slice(3) - : 'any'; + var typeNames = types.split('|').map(trim) + .filter(notEmpty) + .filter(notIgnore); - var typeNames = types.split('|').map(trim) - .filter(notEmpty) - .filter(notIgnore); + var matchingConversions = filterConversions(conversions, typeNames); - var matchingConversions = filterConversions(conversions, typeNames); + var exactTypes = typeNames.map(function (typeName) { + var type = findTypeByName(typeName); - var exactTypes = typeNames.map(function (typeName) { - var type = findTypeByName(typeName); + return { + name: typeName, + typeIndex: findTypeIndex(type), + test: type.test, + conversion: null, + conversionIndex: -1 + }; + }); - return { - name: typeName, - typeIndex: findTypeIndex(type), - test: type.test, - conversion: null, - conversionIndex: -1 - }; - }); + var convertibleTypes = matchingConversions.map(function (conversion) { + var type = findTypeByName(conversion.from); - var convertibleTypes = matchingConversions.map(function (conversion) { - var type = findTypeByName(conversion.from); + return { + name: conversion.from, + typeIndex: findTypeIndex(type), + test: type.test, + conversion: conversion, + conversionIndex: conversions.indexOf(conversion) + }; + }); return { - name: conversion.from, - typeIndex: findTypeIndex(type), - test: type.test, - conversion: conversion, - conversionIndex: conversions.indexOf(conversion) + types: exactTypes.concat(convertibleTypes), + restParam: restParam }; - }); - - return { - types: exactTypes.concat(convertibleTypes), - restParam: restParam - }; - } + } - /** - * Parse a signature with comma separated parameters, - * like "number | boolean, ...string" - * @param {string} signature - * @param {function} fn - * @param {ConversionDef[]} conversions - * @return {Signature | null} signature - */ - function parseSignature (signature, fn, conversions) { - var params = []; + /** + * Parse a signature with comma separated parameters, + * like "number | boolean, ...string" + * @param {string} signature + * @param {function} fn + * @param {ConversionDef[]} conversions + * @return {Signature | null} signature + */ + function parseSignature (signature, fn, conversions) { + var params = []; + + if (signature.trim() !== '') { + params = signature + .split(',') + .map(trim) + .map(function (param, index, array) { + var parsedParam = parseParam(param, conversions); + + if (parsedParam.restParam && (index !== array.length - 1)) { + throw new SyntaxError('Unexpected rest parameter "' + param + '": ' + + 'only allowed for the last parameter'); + } - if (signature.trim() !== '') { - params = signature - .split(',') - .map(trim) - .map(function (param, index, array) { - var parsedParam = parseParam(param, conversions); + return parsedParam; + }); + } - if (parsedParam.restParam && (index !== array.length - 1)) { - throw new SyntaxError('Unexpected rest parameter "' + param + '": ' + - 'only allowed for the last parameter'); - } + if (params.some(isInvalidParam)) { + // invalid signature: at least one parameter has no types + // (they may have been filtered) + return null; + } - return parsedParam; - }); + return { + params: params, + fn: fn + }; } - if (params.some(isInvalidParam)) { - // invalid signature: at least one parameter has no types - // (they may have been filtered) - return null; + /** + * Test whether a set of params contains a restParam + * @param {Param[]} params + * @return {boolean} Returns true when the last parameter is a restParam + */ + function hasRestParam(params) { + var param = last(params); + return param ? param.restParam : false; } - return { - params: params, - fn: fn - }; - } - - /** - * Test whether a set of params contains a restParam - * @param {Param[]} params - * @return {boolean} Returns true when the last parameter is a restParam - */ - function hasRestParam(params) { - var param = last(params); - return param ? param.restParam : false; - } - - /** - * Test whether a parameter contains conversions - * @param {Param} param - * @return {boolean} Returns true when at least one of the parameters - * contains a conversion. - */ - function hasConversions(param) { - return param.types.some(function (type) { - return type.conversion != null; - }); - } - - /** - * Create a type test for a single parameter, which can have one or multiple - * types. - * @param {Param} param - * @return {function(x: *) : boolean} Returns a test function - */ - function compileTest(param) { - if (!param || param.types.length === 0) { - // nothing to do - return ok; - } - else if (param.types.length === 1) { - return findTypeByName(param.types[0].name).test; + /** + * Test whether a parameter contains conversions + * @param {Param} param + * @return {boolean} Returns true when at least one of the parameters + * contains a conversion. + */ + function hasConversions(param) { + return param.types.some(function (type) { + return type.conversion != null; + }); } - else if (param.types.length === 2) { - var test0 = findTypeByName(param.types[0].name).test; - var test1 = findTypeByName(param.types[1].name).test; - return function or(x) { - return test0(x) || test1(x); + + /** + * Create a type test for a single parameter, which can have one or multiple + * types. + * @param {Param} param + * @return {function(x: *) : boolean} Returns a test function + */ + function compileTest(param) { + if (!param || param.types.length === 0) { + // nothing to do + return ok; + } + else if (param.types.length === 1) { + return findTypeByName(param.types[0].name).test; + } + else if (param.types.length === 2) { + var test0 = findTypeByName(param.types[0].name).test; + var test1 = findTypeByName(param.types[1].name).test; + return function or(x) { + return test0(x) || test1(x); + } } - } - else { // param.types.length > 2 - var tests = param.types.map(function (type) { - return findTypeByName(type.name).test; - }); - return function or(x) { - for (var i = 0; i < tests.length; i++) { - if (tests[i](x)) { - return true; + else { // param.types.length > 2 + var tests = param.types.map(function (type) { + return findTypeByName(type.name).test; + }); + return function or(x) { + for (var i = 0; i < tests.length; i++) { + if (tests[i](x)) { + return true; + } } + return false; } - return false; } } - } - /** - * Create a test for all parameters of a signature - * @param {Param[]} params - * @return {function(args: Array<*>) : boolean} - */ - function compileTests(params) { - var tests, test0, test1; - - if (hasRestParam(params)) { - // variable arguments like '...number' - tests = initial(params).map(compileTest); - var varIndex = tests.length; - var lastTest = compileTest(last(params)); - var testRestParam = function (args) { - for (var i = varIndex; i < args.length; i++) { - if (!lastTest(args[i])) { - return false; + /** + * Create a test for all parameters of a signature + * @param {Param[]} params + * @return {function(args: Array<*>) : boolean} + */ + function compileTests(params) { + var tests, test0, test1; + + if (hasRestParam(params)) { + // variable arguments like '...number' + tests = initial(params).map(compileTest); + var varIndex = tests.length; + var lastTest = compileTest(last(params)); + var testRestParam = function (args) { + for (var i = varIndex; i < args.length; i++) { + if (!lastTest(args[i])) { + return false; + } } - } - return true; - }; + return true; + }; - return function testArgs(args) { - for (var i = 0; i < tests.length; i++) { - if (!tests[i](args[i])) { - return false; - } - } - return testRestParam(args) && (args.length >= varIndex + 1); - }; - } - else { - // no variable arguments - if (params.length === 0) { - return function testArgs(args) { - return args.length === 0; - }; - } - else if (params.length === 1) { - test0 = compileTest(params[0]); - return function testArgs(args) { - return test0(args[0]) && args.length === 1; - }; - } - else if (params.length === 2) { - test0 = compileTest(params[0]); - test1 = compileTest(params[1]); - return function testArgs(args) { - return test0(args[0]) && test1(args[1]) && args.length === 2; - }; - } - else { // arguments.length > 2 - tests = params.map(compileTest); return function testArgs(args) { for (var i = 0; i < tests.length; i++) { if (!tests[i](args[i])) { return false; } } - return args.length === tests.length; + return testRestParam(args) && (args.length >= varIndex + 1); }; } + else { + // no variable arguments + if (params.length === 0) { + return function testArgs(args) { + return args.length === 0; + }; + } + else if (params.length === 1) { + test0 = compileTest(params[0]); + return function testArgs(args) { + return test0(args[0]) && args.length === 1; + }; + } + else if (params.length === 2) { + test0 = compileTest(params[0]); + test1 = compileTest(params[1]); + return function testArgs(args) { + return test0(args[0]) && test1(args[1]) && args.length === 2; + }; + } + else { // arguments.length > 2 + tests = params.map(compileTest); + return function testArgs(args) { + for (var i = 0; i < tests.length; i++) { + if (!tests[i](args[i])) { + return false; + } + } + return args.length === tests.length; + }; + } + } } - } - - /** - * Find the parameter at a specific index of a signature. - * Handles rest parameters. - * @param {Signature} signature - * @param {number} index - * @return {Param | null} Returns the matching parameter when found, - * null otherwise. - */ - function getParamAtIndex(signature, index) { - return index < signature.params.length - ? signature.params[index] - : hasRestParam(signature.params) - ? last(signature.params) - : null - } - /** - * Get all type names of a parameter - * @param {Signature} signature - * @param {number} index - * @param {boolean} excludeConversions - * @return {string[]} Returns an array with type names - */ - function getExpectedTypeNames (signature, index, excludeConversions) { - var param = getParamAtIndex(signature, index); - var types = param - ? excludeConversions - ? param.types.filter(isExactType) - : param.types - : []; + /** + * Find the parameter at a specific index of a signature. + * Handles rest parameters. + * @param {Signature} signature + * @param {number} index + * @return {Param | null} Returns the matching parameter when found, + * null otherwise. + */ + function getParamAtIndex(signature, index) { + return index < signature.params.length + ? signature.params[index] + : hasRestParam(signature.params) + ? last(signature.params) + : null + } - return types.map(getTypeName); - } + /** + * Get all type names of a parameter + * @param {Signature} signature + * @param {number} index + * @param {boolean} excludeConversions + * @return {string[]} Returns an array with type names + */ + function getExpectedTypeNames (signature, index, excludeConversions) { + var param = getParamAtIndex(signature, index); + var types = param + ? excludeConversions + ? param.types.filter(isExactType) + : param.types + : []; - /** - * Returns the name of a type - * @param {Type} type - * @return {string} Returns the type name - */ - function getTypeName(type) { - return type.name; - } + return types.map(getTypeName); + } - /** - * Test whether a type is an exact type or conversion - * @param {Type} type - * @return {boolean} Returns true when - */ - function isExactType(type) { - return type.conversion === null || type.conversion === undefined; - } + /** + * Returns the name of a type + * @param {Type} type + * @return {string} Returns the type name + */ + function getTypeName(type) { + return type.name; + } - /** - * Helper function for creating error messages: create an array with - * all available types on a specific argument index. - * @param {Signature[]} signatures - * @param {number} index - * @return {string[]} Returns an array with available types - */ - function mergeExpectedParams(signatures, index) { - var typeNames = uniq(flatMap(signatures, function (signature) { - return getExpectedTypeNames(signature, index, false); - })); + /** + * Test whether a type is an exact type or conversion + * @param {Type} type + * @return {boolean} Returns true when + */ + function isExactType(type) { + return type.conversion === null || type.conversion === undefined; + } - return (typeNames.indexOf('any') !== -1) ? ['any'] : typeNames; - } + /** + * Helper function for creating error messages: create an array with + * all available types on a specific argument index. + * @param {Signature[]} signatures + * @param {number} index + * @return {string[]} Returns an array with available types + */ + function mergeExpectedParams(signatures, index) { + var typeNames = uniq(flatMap(signatures, function (signature) { + return getExpectedTypeNames(signature, index, false); + })); - /** - * Create - * @param {string} name The name of the function - * @param {array.<*>} args The actual arguments passed to the function - * @param {Signature[]} signatures A list with available signatures - * @return {TypeError} Returns a type error with additional data - * attached to it in the property `data` - */ - function createError(name, args, signatures) { - var err, expected; - var _name = name || 'unnamed'; + return (typeNames.indexOf('any') !== -1) ? ['any'] : typeNames; + } - // test for wrong type at some index - var matchingSignatures = signatures; - var index; - for (index = 0; index < args.length; index++) { - var nextMatchingDefs = matchingSignatures.filter(function (signature) { - var test = compileTest(getParamAtIndex(signature, index)); - return (index < signature.params.length || hasRestParam(signature.params)) && - test(args[index]); - }); + /** + * Create + * @param {string} name The name of the function + * @param {array.<*>} args The actual arguments passed to the function + * @param {Signature[]} signatures A list with available signatures + * @return {TypeError} Returns a type error with additional data + * attached to it in the property `data` + */ + function createError(name, args, signatures) { + var err, expected; + var _name = name || 'unnamed'; + + // test for wrong type at some index + var matchingSignatures = signatures; + var index; + for (index = 0; index < args.length; index++) { + var nextMatchingDefs = matchingSignatures.filter(function (signature) { + var test = compileTest(getParamAtIndex(signature, index)); + return (index < signature.params.length || hasRestParam(signature.params)) && + test(args[index]); + }); - if (nextMatchingDefs.length === 0) { - // no matching signatures anymore, throw error "wrong type" - expected = mergeExpectedParams(matchingSignatures, index); - if (expected.length > 0) { - var actualType = findTypeName(args[index]); - - err = new TypeError('Unexpected type of argument in function ' + _name + - ' (expected: ' + expected.join(' or ') + - ', actual: ' + actualType + ', index: ' + index + ')'); - err.data = { - category: 'wrongType', - fn: _name, - index: index, - actual: actualType, - expected: expected - }; - return err; + if (nextMatchingDefs.length === 0) { + // no matching signatures anymore, throw error "wrong type" + expected = mergeExpectedParams(matchingSignatures, index); + if (expected.length > 0) { + var actualType = findTypeName(args[index]); + + err = new TypeError('Unexpected type of argument in function ' + _name + + ' (expected: ' + expected.join(' or ') + + ', actual: ' + actualType + ', index: ' + index + ')'); + err.data = { + category: 'wrongType', + fn: _name, + index: index, + actual: actualType, + expected: expected + }; + return err; + } + } + else { + matchingSignatures = nextMatchingDefs; } } - else { - matchingSignatures = nextMatchingDefs; - } - } - // test for too few arguments - var lengths = matchingSignatures.map(function (signature) { - return hasRestParam(signature.params) ? Infinity : signature.params.length; - }); - if (args.length < Math.min.apply(null, lengths)) { - expected = mergeExpectedParams(matchingSignatures, index); - err = new TypeError('Too few arguments in function ' + _name + - ' (expected: ' + expected.join(' or ') + - ', index: ' + args.length + ')'); - err.data = { - category: 'tooFewArgs', - fn: _name, - index: args.length, - expected: expected - }; - return err; - } + // test for too few arguments + var lengths = matchingSignatures.map(function (signature) { + return hasRestParam(signature.params) ? Infinity : signature.params.length; + }); + if (args.length < Math.min.apply(null, lengths)) { + expected = mergeExpectedParams(matchingSignatures, index); + err = new TypeError('Too few arguments in function ' + _name + + ' (expected: ' + expected.join(' or ') + + ', index: ' + args.length + ')'); + err.data = { + category: 'tooFewArgs', + fn: _name, + index: args.length, + expected: expected + }; + return err; + } + + // test for too many arguments + var maxLength = Math.max.apply(null, lengths); + if (args.length > maxLength) { + err = new TypeError('Too many arguments in function ' + _name + + ' (expected: ' + maxLength + ', actual: ' + args.length + ')'); + err.data = { + category: 'tooManyArgs', + fn: _name, + index: args.length, + expectedLength: maxLength + }; + return err; + } - // test for too many arguments - var maxLength = Math.max.apply(null, lengths); - if (args.length > maxLength) { - err = new TypeError('Too many arguments in function ' + _name + - ' (expected: ' + maxLength + ', actual: ' + args.length + ')'); + err = new TypeError('Arguments of type "' + args.join(', ') + + '" do not match any of the defined signatures of function ' + _name + '.'); err.data = { - category: 'tooManyArgs', - fn: _name, - index: args.length, - expectedLength: maxLength + category: 'mismatch', + actual: args.map(findTypeName) }; return err; } - err = new TypeError('Arguments of type "' + args.join(', ') + - '" do not match any of the defined signatures of function ' + _name + '.'); - err.data = { - category: 'mismatch', - actual: args.map(findTypeName) - }; - return err; - } - - /** - * Find the lowest index of all exact types of a parameter (no conversions) - * @param {Param} param - * @return {number} Returns the index of the lowest type in typed.types - */ - function getLowestTypeIndex (param) { - var min = 999; + /** + * Find the lowest index of all exact types of a parameter (no conversions) + * @param {Param} param + * @return {number} Returns the index of the lowest type in typed.types + */ + function getLowestTypeIndex (param) { + var min = 999; - for (var i = 0; i < param.types.length; i++) { - if (isExactType(param.types[i])) { - min = Math.min(min, param.types[i].typeIndex); + for (var i = 0; i < param.types.length; i++) { + if (isExactType(param.types[i])) { + min = Math.min(min, param.types[i].typeIndex); + } } - } - - return min; - } - - /** - * Find the lowest index of the conversion of all types of the parameter - * having a conversion - * @param {Param} param - * @return {number} Returns the lowest index of the conversions of this type - */ - function getLowestConversionIndex (param) { - var min = 999; - for (var i = 0; i < param.types.length; i++) { - if (!isExactType(param.types[i])) { - min = Math.min(min, param.types[i].conversionIndex); - } + return min; } - return min; - } - - /** - * Compare two params - * @param {Param} param1 - * @param {Param} param2 - * @return {number} returns a negative number when param1 must get a lower - * index than param2, a positive number when the opposite, - * or zero when both are equal - */ - function compareParams (param1, param2) { - var c; - - // compare having a rest parameter or not - c = param1.restParam - param2.restParam; - if (c !== 0) { - return c; - } + /** + * Find the lowest index of the conversion of all types of the parameter + * having a conversion + * @param {Param} param + * @return {number} Returns the lowest index of the conversions of this type + */ + function getLowestConversionIndex (param) { + var min = 999; - // compare having conversions or not - c = hasConversions(param1) - hasConversions(param2); - if (c !== 0) { - return c; - } + for (var i = 0; i < param.types.length; i++) { + if (!isExactType(param.types[i])) { + min = Math.min(min, param.types[i].conversionIndex); + } + } - // compare the index of the types - c = getLowestTypeIndex(param1) - getLowestTypeIndex(param2); - if (c !== 0) { - return c; + return min; } - // compare the index of any conversion - return getLowestConversionIndex(param1) - getLowestConversionIndex(param2); - } - - /** - * Compare two signatures - * @param {Signature} signature1 - * @param {Signature} signature2 - * @return {number} returns a negative number when param1 must get a lower - * index than param2, a positive number when the opposite, - * or zero when both are equal - */ - function compareSignatures (signature1, signature2) { - var len = Math.min(signature1.params.length, signature2.params.length); - var i; - var c; + /** + * Compare two params + * @param {Param} param1 + * @param {Param} param2 + * @return {number} returns a negative number when param1 must get a lower + * index than param2, a positive number when the opposite, + * or zero when both are equal + */ + function compareParams (param1, param2) { + var c; - // compare whether the params have conversions at all or not - c = signature1.params.some(hasConversions) - signature2.params.some(hasConversions); - if (c !== 0) { - return c; - } + // compare having a rest parameter or not + c = param1.restParam - param2.restParam; + if (c !== 0) { + return c; + } - // next compare whether the params have conversions one by one - for (i = 0; i < len; i++) { - c = hasConversions(signature1.params[i]) - hasConversions(signature2.params[i]); + // compare having conversions or not + c = hasConversions(param1) - hasConversions(param2); if (c !== 0) { return c; } - } - // compare the types of the params one by one - for (i = 0; i < len; i++) { - c = compareParams(signature1.params[i], signature2.params[i]); + // compare the index of the types + c = getLowestTypeIndex(param1) - getLowestTypeIndex(param2); if (c !== 0) { return c; } - } - // compare the number of params - return signature1.params.length - signature2.params.length; - } + // compare the index of any conversion + return getLowestConversionIndex(param1) - getLowestConversionIndex(param2); + } - /** - * Get params containing all types that can be converted to the defined types. - * - * @param {ConversionDef[]} conversions - * @param {string[]} typeNames - * @return {ConversionDef[]} Returns the conversions that are available - * for every type (if any) - */ - function filterConversions(conversions, typeNames) { - var matches = {}; + /** + * Compare two signatures + * @param {Signature} signature1 + * @param {Signature} signature2 + * @return {number} returns a negative number when param1 must get a lower + * index than param2, a positive number when the opposite, + * or zero when both are equal + */ + function compareSignatures (signature1, signature2) { + var len = Math.min(signature1.params.length, signature2.params.length); + var i; + var c; - conversions.forEach(function (conversion) { - if (typeNames.indexOf(conversion.from) === -1 && - typeNames.indexOf(conversion.to) !== -1 && - !matches[conversion.from]) { - matches[conversion.from] = conversion; + // compare whether the params have conversions at all or not + c = signature1.params.some(hasConversions) - signature2.params.some(hasConversions); + if (c !== 0) { + return c; } - }); - return Object.keys(matches).map(function (from) { - return matches[from]; - }); - } - - /** - * Preprocess arguments before calling the original function: - * - if needed convert the parameters - * - in case of rest parameters, move the rest parameters into an Array - * @param {Param[]} params - * @param {function} fn - * @return {function} Returns a wrapped function - */ - function compileArgsPreprocessing(params, fn) { - var fnConvert = fn; + // next compare whether the params have conversions one by one + for (i = 0; i < len; i++) { + c = hasConversions(signature1.params[i]) - hasConversions(signature2.params[i]); + if (c !== 0) { + return c; + } + } - // TODO: can we make this wrapper function smarter/simpler? + // compare the types of the params one by one + for (i = 0; i < len; i++) { + c = compareParams(signature1.params[i], signature2.params[i]); + if (c !== 0) { + return c; + } + } - if (params.some(hasConversions)) { - var restParam = hasRestParam(params); - var compiledConversions = params.map(compileArgConversion); + // compare the number of params + return signature1.params.length - signature2.params.length; + } - fnConvert = function convertArgs() { - var args = []; - var last = restParam ? arguments.length - 1 : arguments.length; - for (var i = 0; i < last; i++) { - args[i] = compiledConversions[i](arguments[i]); - } - if (restParam) { - args[last] = arguments[last].map(compiledConversions[last]); + /** + * Get params containing all types that can be converted to the defined types. + * + * @param {ConversionDef[]} conversions + * @param {string[]} typeNames + * @return {ConversionDef[]} Returns the conversions that are available + * for every type (if any) + */ + function filterConversions(conversions, typeNames) { + var matches = {}; + + conversions.forEach(function (conversion) { + if (typeNames.indexOf(conversion.from) === -1 && + typeNames.indexOf(conversion.to) !== -1 && + !matches[conversion.from]) { + matches[conversion.from] = conversion; } + }); - return fn.apply(null, args); - }; + return Object.keys(matches).map(function (from) { + return matches[from]; + }); } - var fnPreprocess = fnConvert; - if (hasRestParam(params)) { - var offset = params.length - 1; + /** + * Preprocess arguments before calling the original function: + * - if needed convert the parameters + * - in case of rest parameters, move the rest parameters into an Array + * @param {Param[]} params + * @param {function} fn + * @return {function} Returns a wrapped function + */ + function compileArgsPreprocessing(params, fn) { + var fnConvert = fn; - fnPreprocess = function preprocessRestParams () { - return fnConvert.apply(null, - slice(arguments, 0, offset).concat([slice(arguments, offset)])); - }; - } + // TODO: can we make this wrapper function smarter/simpler? - return fnPreprocess; - } + if (params.some(hasConversions)) { + var restParam = hasRestParam(params); + var compiledConversions = params.map(compileArgConversion); - /** - * Compile conversion for a parameter to the right type - * @param {Param} param - * @return {function} Returns the wrapped function that will convert arguments - * - */ - function compileArgConversion(param) { - var test0, test1, conversion0, conversion1; - var tests = []; - var conversions = []; + fnConvert = function convertArgs() { + var args = []; + var last = restParam ? arguments.length - 1 : arguments.length; + for (var i = 0; i < last; i++) { + args[i] = compiledConversions[i](arguments[i]); + } + if (restParam) { + args[last] = arguments[last].map(compiledConversions[last]); + } - param.types.forEach(function (type) { - if (type.conversion) { - tests.push(findTypeByName(type.conversion.from).test); - conversions.push(type.conversion.convert); + return fn.apply(null, args); + }; } - }); - // create optimized conversion functions depending on the number of conversions - switch (conversions.length) { - case 0: - return function convertArg(arg) { - return arg; + var fnPreprocess = fnConvert; + if (hasRestParam(params)) { + var offset = params.length - 1; + + fnPreprocess = function preprocessRestParams () { + return fnConvert.apply(null, + slice(arguments, 0, offset).concat([slice(arguments, offset)])); + }; + } + + return fnPreprocess; + } + + /** + * Compile conversion for a parameter to the right type + * @param {Param} param + * @return {function} Returns the wrapped function that will convert arguments + * + */ + function compileArgConversion(param) { + var test0, test1, conversion0, conversion1; + var tests = []; + var conversions = []; + + param.types.forEach(function (type) { + if (type.conversion) { + tests.push(findTypeByName(type.conversion.from).test); + conversions.push(type.conversion.convert); } + }); - case 1: - test0 = tests[0]; - conversion0 = conversions[0]; - return function convertArg(arg) { - if (test0(arg)) { - return conversion0(arg) + // create optimized conversion functions depending on the number of conversions + switch (conversions.length) { + case 0: + return function convertArg(arg) { + return arg; } - return arg; - } - case 2: - test0 = tests[0]; - test1 = tests[1]; - conversion0 = conversions[0]; - conversion1 = conversions[1]; - return function convertArg(arg) { - if (test0(arg)) { - return conversion0(arg) + case 1: + test0 = tests[0]; + conversion0 = conversions[0]; + return function convertArg(arg) { + if (test0(arg)) { + return conversion0(arg) + } + return arg; } - if (test1(arg)) { - return conversion1(arg) + + case 2: + test0 = tests[0]; + test1 = tests[1]; + conversion0 = conversions[0]; + conversion1 = conversions[1]; + return function convertArg(arg) { + if (test0(arg)) { + return conversion0(arg) + } + if (test1(arg)) { + return conversion1(arg) + } + return arg; } - return arg; - } - default: - return function convertArg(arg) { - for (var i = 0; i < conversions.length; i++) { - if (tests[i](arg)) { - return conversions[i](arg); + default: + return function convertArg(arg) { + for (var i = 0; i < conversions.length; i++) { + if (tests[i](arg)) { + return conversions[i](arg); + } } + return arg; } - return arg; + } + } + + /** + * Convert an array with signatures into a map with signatures, + * where signatures with union types are split into separate signatures + * + * Throws an error when there are conflicting types + * + * @param {Signature[]} signatures + * @return {Object.} Returns a map with signatures + * as key and the original function + * of this signature as value. + */ + function createSignaturesMap(signatures) { + var signaturesMap = {}; + signatures.forEach(function (signature) { + if (!signature.params.some(hasConversions)) { + splitParams(signature.params, true).forEach(function (params) { + signaturesMap[stringifyParams(params)] = signature.fn; + }); } + }); + + return signaturesMap; } - } - /** - * Convert an array with signatures into a map with signatures, - * where signatures with union types are split into separate signatures - * - * Throws an error when there are conflicting types - * - * @param {Signature[]} signatures - * @return {Object.} Returns a map with signatures - * as key and the original function - * of this signature as value. - */ - function createSignaturesMap(signatures) { - var signaturesMap = {}; - signatures.forEach(function (signature) { - if (!signature.params.some(hasConversions)) { - splitParams(signature.params, true).forEach(function (params) { - signaturesMap[stringifyParams(params)] = signature.fn; - }); - } - }); + /** + * Split params with union types in to separate params. + * + * For example: + * + * splitParams([['Array', 'Object'], ['string', 'RegExp']) + * // returns: + * // [ + * // ['Array', 'string'], + * // ['Array', 'RegExp'], + * // ['Object', 'string'], + * // ['Object', 'RegExp'] + * // ] + * + * @param {Param[]} params + * @param {boolean} ignoreConversionTypes + * @return {Param[]} + */ + function splitParams(params, ignoreConversionTypes) { + function _splitParams(params, index, types) { + if (index < params.length) { + var param = params[index]; + var filteredTypes = ignoreConversionTypes + ? param.types.filter(isExactType) + : param.types; + var typeGroups; + + if (param.restParam) { + // split the types of a rest parameter in two: + // one with only exact types, and one with exact types and conversions + var exactTypes = filteredTypes.filter(isExactType); + typeGroups = exactTypes.length < filteredTypes.length + ? [exactTypes, filteredTypes] + : [filteredTypes]; - return signaturesMap; - } + } + else { + // split all the types of a regular parameter into one type per group + typeGroups = filteredTypes.map(function (type) { + return [type] + }); + } - /** - * Split params with union types in to separate params. - * - * For example: - * - * splitParams([['Array', 'Object'], ['string', 'RegExp']) - * // returns: - * // [ - * // ['Array', 'string'], - * // ['Array', 'RegExp'], - * // ['Object', 'string'], - * // ['Object', 'RegExp'] - * // ] - * - * @param {Param[]} params - * @param {boolean} ignoreConversionTypes - * @return {Param[]} - */ - function splitParams(params, ignoreConversionTypes) { - function _splitParams(params, index, types) { - if (index < params.length) { - var param = params[index]; - var filteredTypes = ignoreConversionTypes - ? param.types.filter(isExactType) - : param.types; - var typeGroups; - - if (param.restParam) { - // split the types of a rest parameter in two: - // one with only exact types, and one with exact types and conversions - var exactTypes = filteredTypes.filter(isExactType); - typeGroups = exactTypes.length < filteredTypes.length - ? [exactTypes, filteredTypes] - : [filteredTypes]; + // recurse over the groups with types + return flatMap(typeGroups, function (typeGroup) { + return _splitParams(params, index + 1, types.concat([typeGroup])); + }); } else { - // split all the types of a regular parameter into one type per group - typeGroups = filteredTypes.map(function (type) { - return [type] + // we've reached the end of the parameters. Now build a new Param + var splittedParams = types.map(function (type, typeIndex) { + return { + types: type, + restParam: (typeIndex === params.length - 1) && hasRestParam(params) + } }); - } - - // recurse over the groups with types - return flatMap(typeGroups, function (typeGroup) { - return _splitParams(params, index + 1, types.concat([typeGroup])); - }); + return [splittedParams]; + } } - else { - // we've reached the end of the parameters. Now build a new Param - var splittedParams = types.map(function (type, typeIndex) { - return { - types: type, - restParam: (typeIndex === params.length - 1) && hasRestParam(params) - } - }); - return [splittedParams]; - } + return _splitParams(params, 0, []); } - return _splitParams(params, 0, []); - } + /** + * Test whether two signatures have a conflicting signature + * @param {Signature} signature1 + * @param {Signature} signature2 + * @return {boolean} Returns true when the signatures conflict, false otherwise. + */ + function hasConflictingParams(signature1, signature2) { + var ii = Math.max(signature1.params.length, signature2.params.length); - /** - * Test whether two signatures have a conflicting signature - * @param {Signature} signature1 - * @param {Signature} signature2 - * @return {boolean} Returns true when the signatures conflict, false otherwise. - */ - function hasConflictingParams(signature1, signature2) { - var ii = Math.max(signature1.params.length, signature2.params.length); + for (var i = 0; i < ii; i++) { + var typesNames1 = getExpectedTypeNames(signature1, i, true); + var typesNames2 = getExpectedTypeNames(signature2, i, true); - for (var i = 0; i < ii; i++) { - var typesNames1 = getExpectedTypeNames(signature1, i, true); - var typesNames2 = getExpectedTypeNames(signature2, i, true); + if (!hasOverlap(typesNames1, typesNames2)) { + return false; + } + } - if (!hasOverlap(typesNames1, typesNames2)) { - return false; - } - } - - var len1 = signature1.params.length; - var len2 = signature2.params.length; - var restParam1 = hasRestParam(signature1.params); - var restParam2 = hasRestParam(signature2.params); + var len1 = signature1.params.length; + var len2 = signature2.params.length; + var restParam1 = hasRestParam(signature1.params); + var restParam2 = hasRestParam(signature2.params); - return restParam1 - ? restParam2 ? (len1 === len2) : (len2 >= len1) - : restParam2 ? (len1 >= len2) : (len1 === len2) - } - - /** - * Create a typed function - * @param {String} name The name for the typed function - * @param {Object.} signaturesMap - * An object with one or - * multiple signatures as key, and the - * function corresponding to the - * signature as value. - * @return {function} Returns the created typed function. - */ - function createTypedFunction(name, signaturesMap) { - if (Object.keys(signaturesMap).length === 0) { - throw new SyntaxError('No signatures provided'); + return restParam1 + ? restParam2 ? (len1 === len2) : (len2 >= len1) + : restParam2 ? (len1 >= len2) : (len1 === len2) } - // parse the signatures, and check for conflicts - var parsedSignatures = []; - Object.keys(signaturesMap) - .map(function (signature) { - return parseSignature(signature, signaturesMap[signature], typed.conversions); - }) - .filter(notNull) - .forEach(function (parsedSignature) { - // check whether this parameter conflicts with already parsed signatures - var conflictingSignature = findInArray(parsedSignatures, function (s) { - return hasConflictingParams(s, parsedSignature) - }); - if (conflictingSignature) { - throw new TypeError('Conflicting signatures "' + - stringifyParams(conflictingSignature.params) + '" and "' + - stringifyParams(parsedSignature.params) + '".'); - } + /** + * Create a typed function + * @param {String} name The name for the typed function + * @param {Object.} signaturesMap + * An object with one or + * multiple signatures as key, and the + * function corresponding to the + * signature as value. + * @return {function} Returns the created typed function. + */ + function createTypedFunction(name, signaturesMap) { + if (Object.keys(signaturesMap).length === 0) { + throw new SyntaxError('No signatures provided'); + } + + // parse the signatures, and check for conflicts + var parsedSignatures = []; + Object.keys(signaturesMap) + .map(function (signature) { + return parseSignature(signature, signaturesMap[signature], typed.conversions); + }) + .filter(notNull) + .forEach(function (parsedSignature) { + // check whether this parameter conflicts with already parsed signatures + var conflictingSignature = findInArray(parsedSignatures, function (s) { + return hasConflictingParams(s, parsedSignature) + }); + if (conflictingSignature) { + throw new TypeError('Conflicting signatures "' + + stringifyParams(conflictingSignature.params) + '" and "' + + stringifyParams(parsedSignature.params) + '".'); + } - parsedSignatures.push(parsedSignature); - }); + parsedSignatures.push(parsedSignature); + }); - // split and filter the types of the signatures, and then order them - var signatures = flatMap(parsedSignatures, function (parsedSignature) { - var params = parsedSignature ? splitParams(parsedSignature.params, false) : []; + // split and filter the types of the signatures, and then order them + var signatures = flatMap(parsedSignatures, function (parsedSignature) { + var params = parsedSignature ? splitParams(parsedSignature.params, false) : []; - return params.map(function (params) { - return { - params: params, - fn: parsedSignature.fn - }; + return params.map(function (params) { + return { + params: params, + fn: parsedSignature.fn + }; + }); + }).filter(notNull); + + signatures.sort(compareSignatures); + + // we create a highly optimized checks for the first couple of signatures with max 2 arguments + var ok0 = signatures[0] && signatures[0].params.length <= 2 && !hasRestParam(signatures[0].params); + var ok1 = signatures[1] && signatures[1].params.length <= 2 && !hasRestParam(signatures[1].params); + var ok2 = signatures[2] && signatures[2].params.length <= 2 && !hasRestParam(signatures[2].params); + var ok3 = signatures[3] && signatures[3].params.length <= 2 && !hasRestParam(signatures[3].params); + var ok4 = signatures[4] && signatures[4].params.length <= 2 && !hasRestParam(signatures[4].params); + var ok5 = signatures[5] && signatures[5].params.length <= 2 && !hasRestParam(signatures[5].params); + var allOk = ok0 && ok1 && ok2 && ok3 && ok4 && ok5; + + // compile the tests + var tests = signatures.map(function (signature) { + return compileTests(signature.params); }); - }).filter(notNull); - - signatures.sort(compareSignatures); - - // we create a highly optimized checks for the first couple of signatures with max 2 arguments - var ok0 = signatures[0] && signatures[0].params.length <= 2 && !hasRestParam(signatures[0].params); - var ok1 = signatures[1] && signatures[1].params.length <= 2 && !hasRestParam(signatures[1].params); - var ok2 = signatures[2] && signatures[2].params.length <= 2 && !hasRestParam(signatures[2].params); - var ok3 = signatures[3] && signatures[3].params.length <= 2 && !hasRestParam(signatures[3].params); - var ok4 = signatures[4] && signatures[4].params.length <= 2 && !hasRestParam(signatures[4].params); - var ok5 = signatures[5] && signatures[5].params.length <= 2 && !hasRestParam(signatures[5].params); - var allOk = ok0 && ok1 && ok2 && ok3 && ok4 && ok5; - - // compile the tests - var tests = signatures.map(function (signature) { - return compileTests(signature.params); - }); - - var test00 = ok0 ? compileTest(signatures[0].params[0]) : notOk; - var test10 = ok1 ? compileTest(signatures[1].params[0]) : notOk; - var test20 = ok2 ? compileTest(signatures[2].params[0]) : notOk; - var test30 = ok3 ? compileTest(signatures[3].params[0]) : notOk; - var test40 = ok4 ? compileTest(signatures[4].params[0]) : notOk; - var test50 = ok5 ? compileTest(signatures[5].params[0]) : notOk; - - var test01 = ok0 ? compileTest(signatures[0].params[1]) : notOk; - var test11 = ok1 ? compileTest(signatures[1].params[1]) : notOk; - var test21 = ok2 ? compileTest(signatures[2].params[1]) : notOk; - var test31 = ok3 ? compileTest(signatures[3].params[1]) : notOk; - var test41 = ok4 ? compileTest(signatures[4].params[1]) : notOk; - var test51 = ok5 ? compileTest(signatures[5].params[1]) : notOk; - - // compile the functions - var fns = signatures.map(function(signature) { - return compileArgsPreprocessing(signature.params, signature.fn) - }); - var fn0 = ok0 ? fns[0] : undef; - var fn1 = ok1 ? fns[1] : undef; - var fn2 = ok2 ? fns[2] : undef; - var fn3 = ok3 ? fns[3] : undef; - var fn4 = ok4 ? fns[4] : undef; - var fn5 = ok5 ? fns[5] : undef; + var test00 = ok0 ? compileTest(signatures[0].params[0]) : notOk; + var test10 = ok1 ? compileTest(signatures[1].params[0]) : notOk; + var test20 = ok2 ? compileTest(signatures[2].params[0]) : notOk; + var test30 = ok3 ? compileTest(signatures[3].params[0]) : notOk; + var test40 = ok4 ? compileTest(signatures[4].params[0]) : notOk; + var test50 = ok5 ? compileTest(signatures[5].params[0]) : notOk; + + var test01 = ok0 ? compileTest(signatures[0].params[1]) : notOk; + var test11 = ok1 ? compileTest(signatures[1].params[1]) : notOk; + var test21 = ok2 ? compileTest(signatures[2].params[1]) : notOk; + var test31 = ok3 ? compileTest(signatures[3].params[1]) : notOk; + var test41 = ok4 ? compileTest(signatures[4].params[1]) : notOk; + var test51 = ok5 ? compileTest(signatures[5].params[1]) : notOk; + + // compile the functions + var fns = signatures.map(function(signature) { + return compileArgsPreprocessing(signature.params, signature.fn) + }); - var len0 = ok0 ? signatures[0].params.length : -1; - var len1 = ok1 ? signatures[1].params.length : -1; - var len2 = ok2 ? signatures[2].params.length : -1; - var len3 = ok3 ? signatures[3].params.length : -1; - var len4 = ok4 ? signatures[4].params.length : -1; - var len5 = ok5 ? signatures[5].params.length : -1; + var fn0 = ok0 ? fns[0] : undef; + var fn1 = ok1 ? fns[1] : undef; + var fn2 = ok2 ? fns[2] : undef; + var fn3 = ok3 ? fns[3] : undef; + var fn4 = ok4 ? fns[4] : undef; + var fn5 = ok5 ? fns[5] : undef; + + var len0 = ok0 ? signatures[0].params.length : -1; + var len1 = ok1 ? signatures[1].params.length : -1; + var len2 = ok2 ? signatures[2].params.length : -1; + var len3 = ok3 ? signatures[3].params.length : -1; + var len4 = ok4 ? signatures[4].params.length : -1; + var len5 = ok5 ? signatures[5].params.length : -1; + + // simple and generic, but also slow + var iStart = allOk ? 6 : 0; + var iEnd = signatures.length; + var generic = function generic() { + + for (var i = iStart; i < iEnd; i++) { + if (tests[i](arguments)) { + return fns[i].apply(null, arguments); + } + } - // simple and generic, but also slow - var iStart = allOk ? 6 : 0; - var iEnd = signatures.length; - var generic = function generic() { + throw createError(name, arguments, signatures); + }; - for (var i = iStart; i < iEnd; i++) { - if (tests[i](arguments)) { - return fns[i].apply(null, arguments); - } - } + // create the typed function + // fast, specialized version. Falls back to the slower, generic one if needed + var fn = function fn(arg0, arg1) { - throw createError(name, arguments, signatures); - }; + if (arguments.length === len0 && test00(arg0) && test01(arg1)) { return fn0.apply(null, arguments); } + if (arguments.length === len1 && test10(arg0) && test11(arg1)) { return fn1.apply(null, arguments); } + if (arguments.length === len2 && test20(arg0) && test21(arg1)) { return fn2.apply(null, arguments); } + if (arguments.length === len3 && test30(arg0) && test31(arg1)) { return fn3.apply(null, arguments); } + if (arguments.length === len4 && test40(arg0) && test41(arg1)) { return fn4.apply(null, arguments); } + if (arguments.length === len5 && test50(arg0) && test51(arg1)) { return fn5.apply(null, arguments); } - // create the typed function - // fast, specialized version. Falls back to the slower, generic one if needed - var fn = function fn(arg0, arg1) { + return generic.apply(null, arguments); + }; - if (arguments.length === len0 && test00(arg0) && test01(arg1)) { return fn0.apply(null, arguments); } - if (arguments.length === len1 && test10(arg0) && test11(arg1)) { return fn1.apply(null, arguments); } - if (arguments.length === len2 && test20(arg0) && test21(arg1)) { return fn2.apply(null, arguments); } - if (arguments.length === len3 && test30(arg0) && test31(arg1)) { return fn3.apply(null, arguments); } - if (arguments.length === len4 && test40(arg0) && test41(arg1)) { return fn4.apply(null, arguments); } - if (arguments.length === len5 && test50(arg0) && test51(arg1)) { return fn5.apply(null, arguments); } + // attach name the typed function + try { + Object.defineProperty(fn, 'name', {value: name}); + } + catch (err) { + // old browsers do not support Object.defineProperty and some don't support setting the name property + // the function name is not essential for the functioning, it's mostly useful for debugging, + // so it's fine to have unnamed functions. + } - return generic.apply(null, arguments); - }; + // attach signatures to the function + fn.signatures = createSignaturesMap(signatures); - // attach name the typed function - try { - Object.defineProperty(fn, 'name', {value: name}); - } - catch (err) { - // old browsers do not support Object.defineProperty and some don't support setting the name property - // the function name is not essential for the functioning, it's mostly useful for debugging, - // so it's fine to have unnamed functions. + return fn; } - // attach signatures to the function - fn.signatures = createSignaturesMap(signatures); + /** + * Test whether a type should be NOT be ignored + * @param {string} typeName + * @return {boolean} + */ + function notIgnore(typeName) { + return typed.ignore.indexOf(typeName) === -1; + } - return fn; - } + /** + * trim a string + * @param {string} str + * @return {string} + */ + function trim(str) { + return str.trim(); + } - /** - * Test whether a type should be NOT be ignored - * @param {string} typeName - * @return {boolean} - */ - function notIgnore(typeName) { - return typed.ignore.indexOf(typeName) === -1; - } + /** + * Test whether a string is not empty + * @param {string} str + * @return {boolean} + */ + function notEmpty(str) { + return !!str; + } - /** - * trim a string - * @param {string} str - * @return {string} - */ - function trim(str) { - return str.trim(); - } + /** + * test whether a value is not strict equal to null + * @param {*} value + * @return {boolean} + */ + function notNull(value) { + return value !== null; + } - /** - * Test whether a string is not empty - * @param {string} str - * @return {boolean} - */ - function notEmpty(str) { - return !!str; - } + /** + * Test whether a parameter has no types defined + * @param {Param} param + * @return {boolean} + */ + function isInvalidParam (param) { + return param.types.length === 0; + } - /** - * test whether a value is not strict equal to null - * @param {*} value - * @return {boolean} - */ - function notNull(value) { - return value !== null; - } + /** + * Return all but the last items of an array + * @param {Array} arr + * @return {Array} + */ + function initial(arr) { + return arr.slice(0, arr.length - 1); + } - /** - * Test whether a parameter has no types defined - * @param {Param} param - * @return {boolean} - */ - function isInvalidParam (param) { - return param.types.length === 0; - } + /** + * return the last item of an array + * @param {Array} arr + * @return {*} + */ + function last(arr) { + return arr[arr.length - 1]; + } - /** - * Return all but the last items of an array - * @param {Array} arr - * @return {Array} - */ - function initial(arr) { - return arr.slice(0, arr.length - 1); - } + /** + * Slice an array or function Arguments + * @param {Array | Arguments | IArguments} arr + * @param {number} start + * @param {number} [end] + * @return {Array} + */ + function slice(arr, start, end) { + return Array.prototype.slice.call(arr, start, end); + } - /** - * return the last item of an array - * @param {Array} arr - * @return {*} - */ - function last(arr) { - return arr[arr.length - 1]; - } + /** + * Test whether an array contains some item + * @param {Array} array + * @param {*} item + * @return {boolean} Returns true if array contains item, false if not. + */ + function contains(array, item) { + return array.indexOf(item) !== -1; + } - /** - * Slice an array or function Arguments - * @param {Array | Arguments | IArguments} arr - * @param {number} start - * @param {number} [end] - * @return {Array} - */ - function slice(arr, start, end) { - return Array.prototype.slice.call(arr, start, end); - } + /** + * Test whether two arrays have overlapping items + * @param {Array} array1 + * @param {Array} array2 + * @return {boolean} Returns true when at least one item exists in both arrays + */ + function hasOverlap(array1, array2) { + for (var i = 0; i < array1.length; i++) { + if (contains(array2, array1[i])) { + return true; + } + } - /** - * Test whether an array contains some item - * @param {Array} array - * @param {*} item - * @return {boolean} Returns true if array contains item, false if not. - */ - function contains(array, item) { - return array.indexOf(item) !== -1; - } + return false; + } - /** - * Test whether two arrays have overlapping items - * @param {Array} array1 - * @param {Array} array2 - * @return {boolean} Returns true when at least one item exists in both arrays - */ - function hasOverlap(array1, array2) { - for (var i = 0; i < array1.length; i++) { - if (contains(array2, array1[i])) { - return true; + /** + * Return the first item from an array for which test(arr[i]) returns true + * @param {Array} arr + * @param {function} test + * @return {* | undefined} Returns the first matching item + * or undefined when there is no match + */ + function findInArray(arr, test) { + for (var i = 0; i < arr.length; i++) { + if (test(arr[i])) { + return arr[i]; + } } + return undefined; } - return false; - } - - /** - * Return the first item from an array for which test(arr[i]) returns true - * @param {Array} arr - * @param {function} test - * @return {* | undefined} Returns the first matching item - * or undefined when there is no match - */ - function findInArray(arr, test) { - for (var i = 0; i < arr.length; i++) { - if (test(arr[i])) { - return arr[i]; + /** + * Filter unique items of an array with strings + * @param {string[]} arr + * @return {string[]} + */ + function uniq(arr) { + var entries = {}; + for (var i = 0; i < arr.length; i++) { + entries[arr[i]] = true; } + return Object.keys(entries); } - return undefined; - } - /** - * Filter unique items of an array with strings - * @param {string[]} arr - * @return {string[]} - */ - function uniq(arr) { - var entries = {}; - for (var i = 0; i < arr.length; i++) { - entries[arr[i]] = true; + /** + * Flat map the result invoking a callback for every item in an array. + * https://gist.github.com/samgiles/762ee337dff48623e729 + * @param {Array} arr + * @param {function} callback + * @return {Array} + */ + function flatMap(arr, callback) { + return Array.prototype.concat.apply([], arr.map(callback)); } - return Object.keys(entries); - } - - /** - * Flat map the result invoking a callback for every item in an array. - * https://gist.github.com/samgiles/762ee337dff48623e729 - * @param {Array} arr - * @param {function} callback - * @return {Array} - */ - function flatMap(arr, callback) { - return Array.prototype.concat.apply([], arr.map(callback)); - } - /** - * Retrieve the function name from a set of typed functions, - * and check whether the name of all functions match (if given) - * @param {function[]} fns - */ - function getName (fns) { - var name = ''; + /** + * Retrieve the function name from a set of typed functions, + * and check whether the name of all functions match (if given) + * @param {function[]} fns + */ + function getName (fns) { + var name = ''; - for (var i = 0; i < fns.length; i++) { - var fn = fns[i]; + for (var i = 0; i < fns.length; i++) { + var fn = fns[i]; - // check whether the names are the same when defined - if (fn.signatures && fn.name !== '') { - if (name === '') { - name = fn.name; - } - else if (name !== fn.name) { - var err = new Error('Function names do not match (expected: ' + name + ', actual: ' + fn.name + ')'); - err.data = { - actual: fn.name, - expected: name - }; - throw err; + // check whether the names are the same when defined + if (fn.signatures && fn.name !== '') { + if (name === '') { + name = fn.name; + } + else if (name !== fn.name) { + var err = new Error('Function names do not match (expected: ' + name + ', actual: ' + fn.name + ')'); + err.data = { + actual: fn.name, + expected: name + }; + throw err; + } } } - } - return name; - } + return name; + } - typed = createTypedFunction('typed', { - 'string, Object': createTypedFunction, - 'Object': function (signaturesMap) { - // find existing name - var fns = []; - for (var signature in signaturesMap) { - if (signaturesMap.hasOwnProperty(signature)) { - fns.push(signaturesMap[signature]); + typed = createTypedFunction('typed', { + 'string, Object': createTypedFunction, + 'Object': function (signaturesMap) { + // find existing name + var fns = []; + for (var signature in signaturesMap) { + if (signaturesMap.hasOwnProperty(signature)) { + fns.push(signaturesMap[signature]); + } } - } - var name = getName(fns); - return createTypedFunction(name, signaturesMap); - }, - '...Function': function (fns) { - var err; - var name = getName(fns); - var signaturesMap = {}; - - for (var i = 0; i < fns.length; i++) { - var fn = fns[i]; + var name = getName(fns); + return createTypedFunction(name, signaturesMap); + }, + '...Function': function (fns) { + var err; + var name = getName(fns); + var signaturesMap = {}; + + for (var i = 0; i < fns.length; i++) { + var fn = fns[i]; + + // test whether this is a typed-function + if (!(typeof fn.signatures === 'object')) { + err = new TypeError('Function is no typed-function (index: ' + i + ')'); + err.data = {index: i}; + throw err; + } - // test whether this is a typed-function - if (!(typeof fn.signatures === 'object')) { - err = new TypeError('Function is no typed-function (index: ' + i + ')'); - err.data = {index: i}; - throw err; - } - - // merge the signatures - for (var signature in fn.signatures) { - if (fn.signatures.hasOwnProperty(signature)) { - if (signaturesMap.hasOwnProperty(signature)) { - if (fn.signatures[signature] !== signaturesMap[signature]) { - err = new Error('Signature "' + signature + '" is defined twice'); - err.data = {signature: signature}; - throw err; + // merge the signatures + for (var signature in fn.signatures) { + if (fn.signatures.hasOwnProperty(signature)) { + if (signaturesMap.hasOwnProperty(signature)) { + if (fn.signatures[signature] !== signaturesMap[signature]) { + err = new Error('Signature "' + signature + '" is defined twice'); + err.data = {signature: signature}; + throw err; + } + // else: both signatures point to the same function, that's fine + } + else { + signaturesMap[signature] = fn.signatures[signature]; } - // else: both signatures point to the same function, that's fine - } - else { - signaturesMap[signature] = fn.signatures[signature]; } } } - } - - return createTypedFunction(name, signaturesMap); - } - }); - typed.create = create; - typed.types = _types; - typed.conversions = _conversions; - typed.ignore = _ignore; - typed.convert = convert; - typed.find = find; - - // add a type - typed.addType = function (type) { - if (!type || typeof type.name !== 'string' || typeof type.test !== 'function') { - throw new TypeError('Object with properties {name: string, test: function} expected'); - } + return createTypedFunction(name, signaturesMap); + } + }); - typed.types.push(type); - }; + typed.create = create; + typed.types = _types; + typed.conversions = _conversions; + typed.ignore = _ignore; + typed.convert = convert; + typed.find = find; - // add a conversion - typed.addConversion = function (conversion) { - if (!conversion - || typeof conversion.from !== 'string' - || typeof conversion.to !== 'string' - || typeof conversion.convert !== 'function') { - throw new TypeError('Object with properties {from: string, to: string, convert: function} expected'); - } + // add a type + typed.addType = function (type) { + if (!type || typeof type.name !== 'string' || typeof type.test !== 'function') { + throw new TypeError('Object with properties {name: string, test: function} expected'); + } - typed.conversions.push(conversion); - }; + typed.types.push(type); + }; - return typed; - } + // add a conversion + typed.addConversion = function (conversion) { + if (!conversion + || typeof conversion.from !== 'string' + || typeof conversion.to !== 'string' + || typeof conversion.convert !== 'function') { + throw new TypeError('Object with properties {from: string, to: string, convert: function} expected'); + } - return create(); -})); -}); - -var number = createCommonjsModule(function (module, exports) { - - - -/** - * @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) { - 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' 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 = undefined; - - if (options) { - // determine notation from options - if (options.notation) { - notation = options.notation; - } - - // determine precision from options - if (exports.isNumber(options)) { - precision = options; - } - else if (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); + typed.conversions.push(conversion); + }; - case 'engineering': - return exports.toEngineering(value, precision); + return typed; + } - 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 = object.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); - } + return create(); + })); + }); - 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)); + var number = createCommonjsModule(function (module, exports) { - 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; - }); + /** + * @typedef {{sign: '+' | '-' | '', coefficients: number[], exponent: number}} SplitValue + */ - 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); - }); + /** + * Test whether value is a number + * @param {*} value + * @return {boolean} isNumber + */ + exports.isNumber = function(value) { + return typeof value === 'number'; + }; - if (coefficients.length === 0) { - coefficients.push(0); - exponent++; - } + /** + * Check if a number is integer + * @param {number | boolean} value + * @return {boolean} isInteger + */ + exports.isInteger = function(value) { + return isFinite(value) + ? (value == Math.round(value)) + : false; + // Note: we use ==, not ===, as we can have Booleans as well + }; - return { - sign: sign, - coefficients: coefficients, - exponent: exponent + /** + * 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' 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); + } -/** - * Format a number in engineering notation. Like '1.23e+6', '2.3e+0', '3.500e-3' - * @param {number | string} value - * @param {number} [precision=0] Optional number of decimals after the - * decimal point. Zero by default. - */ -exports.toEngineering = function (value, precision) { - if (isNaN(value) || !isFinite(value)) { - return String(value); - } - - var rounded = exports.roundDigits(exports.splitNumber(value), precision); + // handle special cases + if (value === Infinity) { + return 'Infinity'; + } + else if (value === -Infinity) { + return '-Infinity'; + } + else if (isNaN(value)) { + return 'NaN'; + } - var e = rounded.exponent; - var c = rounded.coefficients; + // default values for options + var notation = 'auto'; + var precision = undefined; - // find nearest lower multiple of 3 for exponent - var newExp = e % 3 === 0 ? e : (e < 0 ? (e - 3) - (e % 3) : e - (e % 3)); + if (options) { + // determine notation from options + if (options.notation) { + notation = options.notation; + } - // concatenate coefficients with necessary zeros - var significandsDiff = e >= 0 ? e : Math.abs(newExp); + // determine precision from options + if (exports.isNumber(options)) { + precision = options; + } + else if (options.precision) { + precision = options.precision; + } + } - // add zeros if necessary (for ex: 1e+8) - if (c.length - 1 < significandsDiff) c = c.concat(zeros(significandsDiff - (c.length - 1))); + // handle the various notations + switch (notation) { + case 'fixed': + return exports.toFixed(value, precision); - // find difference in exponents - var expDiff = Math.abs(e - newExp); + case 'exponential': + return exports.toExponential(value, precision); - var decimalIdx = 1; + case 'engineering': + return exports.toEngineering(value, precision); - // push decimal index over by expDiff times - while (--expDiff >= 0) decimalIdx++; + 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 = object.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); + } - // if all coefficient values are zero after the decimal point, don't add a decimal value. - // otherwise concat with the rest of the coefficients - var decimals = c.slice(decimalIdx).join(''); - var decimalVal = decimals.match(/[1-9]/) ? ('.' + decimals) : ''; + 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)); - var str = c.slice(0, decimalIdx).join('') + - decimalVal + - 'e' + (e >= 0 ? '+' : '') + newExp.toString(); - return rounded.sign + str; -}; + return exports.toPrecision(value, precision, fixedOptions); + } -/** - * 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); - } + return exports + .toPrecision(value, precision, options && options) - 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 + // 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; + }); - // append zeros if needed - var pp = p + (precision || 0); - if (c.length < pp) { - c = c.concat(zeros(pp - c.length)); - } + default: + throw new Error('Unknown notation "' + notation + '". ' + + 'Choose "auto", "exponential", or "fixed".'); + } + }; - // 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)); + /** + * 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); } - // append trailing zeros - // TODO: simplify the next statement - c = c.concat(zeros(e - c.length + 1 + - (c.length < precision ? precision - c.length : 0))); + var sign = match[1]; + var digits = match[2]; + var exponent = parseFloat(match[4] || '0'); - // prepend zeros - c = zeros(-e).concat(c); + var dot = digits.indexOf('.'); + exponent += (dot !== -1) ? (dot - 1) : (digits.length - 1); - var dot = e > 0 ? e : 0; - if (dot < c.length - 1) { - c.splice(dot + 1, 0, '.'); - } + 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); + }); - 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]++; - } + if (coefficients.length === 0) { + coefficients.push(0); + exponent++; } - } - 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) { - return x == y; - } - - // use "==" operator, handles infinities - if (x == y) { - return true; - } + return { + sign: sign, + coefficients: coefficients, + exponent: exponent + }; + }; - // 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; + /** + * Format a number in engineering notation. Like '1.23e+6', '2.3e+0', '3.500e-3' + * @param {number | string} value + * @param {number} [precision=0] Optional number of decimals after the + * decimal point. Zero by default. + */ + exports.toEngineering = function (value, precision) { + if (isNaN(value) || !isFinite(value)) { + return String(value); } - 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; -}; -}); -var number_1 = number.isNumber; -var number_2 = number.isInteger; -var number_3 = number.sign; -var number_4 = number.format; -var number_5 = number.splitNumber; -var number_6 = number.toEngineering; -var number_7 = number.toFixed; -var number_8 = number.toExponential; -var number_9 = number.toPrecision; -var number_10 = number.roundDigits; -var number_11 = number.digits; -var number_12 = number.DBL_EPSILON; -var number_13 = number.nearlyEqual; - -/** - * Test whether a value is a Matrix - * @param {*} x - * @returns {boolean} returns true with input is a Matrix - * (like a DenseMatrix or SparseMatrix) - */ -var isMatrix = function isMatrix (x) { - return x && x.constructor.prototype.isMatrix || false; -}; - -var digits = number.digits; - - - -// returns a new instance of typed-function -var createTyped = function () { - // initially, return the original instance of typed-function - // consecutively, return a new instance from typed.create. - createTyped = typedFunction.create; - return typedFunction; -}; - -/** - * Factory function for creating a new typed instance - * @param {Object} type Object with data types like Complex and BigNumber - * @returns {Function} - */ -var create = function create(type) { - // TODO: typed-function must be able to silently ignore signatures with unknown data types - - // type checks for all known types - // - // note that: - // - // - check by duck-typing on a property like `isUnit`, instead of checking instanceof. - // instanceof cannot be used because that would not allow to pass data from - // one instance of math.js to another since each has it's own instance of Unit. - // - check the `isUnit` property via the constructor, so there will be no - // matches for "fake" instances like plain objects with a property `isUnit`. - // That is important for security reasons. - // - It must not be possible to override the type checks used internally, - // for security reasons, so these functions are not exposed in the expression - // parser. - type.isNumber = function (x) { return typeof x === 'number' }; - type.isComplex = function (x) { return type.Complex && x instanceof type.Complex || false }; - type.isBigNumber = isBigNumber; - type.isFraction = function (x) { return type.Fraction && x instanceof type.Fraction || false }; - type.isUnit = function (x) { return x && x.constructor.prototype.isUnit || false }; - type.isString = function (x) { return typeof x === 'string' }; - type.isArray = Array.isArray; - type.isMatrix = isMatrix; - type.isDenseMatrix = function (x) { return x && x.isDenseMatrix && x.constructor.prototype.isMatrix || false }; - type.isSparseMatrix = function (x) { return x && x.isSparseMatrix && x.constructor.prototype.isMatrix || false }; - type.isRange = function (x) { return x && x.constructor.prototype.isRange || false }; - type.isIndex = function (x) { return x && x.constructor.prototype.isIndex || false }; - type.isBoolean = function (x) { return typeof x === 'boolean' }; - type.isResultSet = function (x) { return x && x.constructor.prototype.isResultSet || false }; - type.isHelp = function (x) { return x && x.constructor.prototype.isHelp || false }; - type.isFunction = function (x) { return typeof x === 'function'}; - type.isDate = function (x) { return x instanceof Date }; - type.isRegExp = function (x) { return x instanceof RegExp }; - type.isObject = function (x) { - return typeof x === 'object' && - x.constructor === Object && - !type.isComplex(x) && - !type.isFraction(x) - }; - type.isNull = function (x) { return x === null }; - type.isUndefined = function (x) { return x === undefined }; - - type.isAccessorNode = function (x) { return x && x.isAccessorNode && x.constructor.prototype.isNode || false }; - type.isArrayNode = function (x) { return x && x.isArrayNode && x.constructor.prototype.isNode || false }; - type.isAssignmentNode = function (x) { return x && x.isAssignmentNode && x.constructor.prototype.isNode || false }; - type.isBlockNode = function (x) { return x && x.isBlockNode && x.constructor.prototype.isNode || false }; - type.isConditionalNode = function (x) { return x && x.isConditionalNode && x.constructor.prototype.isNode || false }; - type.isConstantNode = function (x) { return x && x.isConstantNode && x.constructor.prototype.isNode || false }; - type.isFunctionAssignmentNode = function (x) { return x && x.isFunctionAssignmentNode && x.constructor.prototype.isNode || false }; - type.isFunctionNode = function (x) { return x && x.isFunctionNode && x.constructor.prototype.isNode || false }; - type.isIndexNode = function (x) { return x && x.isIndexNode && x.constructor.prototype.isNode || false }; - type.isNode = function (x) { return x && x.isNode && x.constructor.prototype.isNode || false }; - type.isObjectNode = function (x) { return x && x.isObjectNode && x.constructor.prototype.isNode || false }; - type.isOperatorNode = function (x) { return x && x.isOperatorNode && x.constructor.prototype.isNode || false }; - type.isParenthesisNode = function (x) { return x && x.isParenthesisNode && x.constructor.prototype.isNode || false }; - type.isRangeNode = function (x) { return x && x.isRangeNode && x.constructor.prototype.isNode || false }; - type.isSymbolNode = function (x) { return x && x.isSymbolNode && x.constructor.prototype.isNode || false }; - - type.isChain = function (x) { return x && x.constructor.prototype.isChain || false }; - - // get a new instance of typed-function - var typed = createTyped(); - - // define all types. The order of the types determines in which order function - // arguments are type-checked (so for performance it's important to put the - // most used types first). - typed.types = [ - { name: 'number', test: type.isNumber }, - { name: 'Complex', test: type.isComplex }, - { name: 'BigNumber', test: type.isBigNumber }, - { name: 'Fraction', test: type.isFraction }, - { name: 'Unit', test: type.isUnit }, - { name: 'string', test: type.isString }, - { name: 'Array', test: type.isArray }, - { name: 'Matrix', test: type.isMatrix }, - { name: 'DenseMatrix', test: type.isDenseMatrix }, - { name: 'SparseMatrix', test: type.isSparseMatrix }, - { name: 'Range', test: type.isRange }, - { name: 'Index', test: type.isIndex }, - { name: 'boolean', test: type.isBoolean }, - { name: 'ResultSet', test: type.isResultSet }, - { name: 'Help', test: type.isHelp }, - { name: 'function', test: type.isFunction }, - { name: 'Date', test: type.isDate }, - { name: 'RegExp', test: type.isRegExp }, - { name: 'null', test: type.isNull }, - { name: 'undefined', test: type.isUndefined }, - - { name: 'OperatorNode', test: type.isOperatorNode }, - { name: 'ConstantNode', test: type.isConstantNode }, - { name: 'SymbolNode', test: type.isSymbolNode }, - { name: 'ParenthesisNode', test: type.isParenthesisNode }, - { name: 'FunctionNode', test: type.isFunctionNode }, - { name: 'FunctionAssignmentNode', test: type.isFunctionAssignmentNode }, - { name: 'ArrayNode', test: type.isArrayNode }, - { name: 'AssignmentNode', test: type.isAssignmentNode }, - { name: 'BlockNode', test: type.isBlockNode }, - { name: 'ConditionalNode', test: type.isConditionalNode }, - { name: 'IndexNode', test: type.isIndexNode }, - { name: 'RangeNode', test: type.isRangeNode }, - { name: 'Node', test: type.isNode }, - - { name: 'Object', test: type.isObject } // order 'Object' last, it's a tricky one - ]; + + var rounded = exports.roundDigits(exports.splitNumber(value), precision); - // TODO: add conversion from BigNumber to number? - typed.conversions = [ - { - from: 'number', - to: 'BigNumber', - convert: function (x) { - // note: conversion from number to BigNumber can fail if x has >15 digits - if (digits(x) > 15) { - throw new TypeError('Cannot implicitly convert a number with >15 significant digits to BigNumber ' + - '(value: ' + x + '). ' + - 'Use function bignumber(x) to convert to BigNumber.'); - } - return new type.BigNumber(x); - } - }, { - from: 'number', - to: 'Complex', - convert: function (x) { - return new type.Complex(x, 0); - } - }, { - from: 'number', - to: 'string', - convert: function (x) { - return x + ''; - } - }, { - from: 'BigNumber', - to: 'Complex', - convert: function (x) { - return new type.Complex(x.toNumber(), 0); - } - }, { - from: 'Fraction', - to: 'BigNumber', - convert: function (x) { - throw new TypeError('Cannot implicitly convert a Fraction to BigNumber or vice versa. ' + - 'Use function bignumber(x) to convert to BigNumber or fraction(x) to convert to Fraction.'); - } - }, { - from: 'Fraction', - to: 'Complex', - convert: function (x) { - return new type.Complex(x.valueOf(), 0); - } - }, { - from: 'number', - to: 'Fraction', - convert: function (x) { - var f = new type.Fraction(x); - if (f.valueOf() !== x) { - throw new TypeError('Cannot implicitly convert a number to a Fraction when there will be a loss of precision ' + - '(value: ' + x + '). ' + - 'Use function fraction(x) to convert to Fraction.'); - } - return new type.Fraction(x); - } - }, { - // FIXME: add conversion from Fraction to number, for example for `sqrt(fraction(1,3))` - // from: 'Fraction', - // to: 'number', - // convert: function (x) { - // return x.valueOf(); - // } - //}, { - from: 'string', - to: 'number', - convert: function (x) { - var n = Number(x); - if (isNaN(n)) { - throw new Error('Cannot convert "' + x + '" to a number'); - } - return n; - } - }, { - from: 'string', - to: 'BigNumber', - convert: function (x) { - try { - return new type.BigNumber(x); - } - catch (err) { - throw new Error('Cannot convert "' + x + '" to BigNumber'); - } - } - }, { - from: 'string', - to: 'Fraction', - convert: function (x) { - try { - return new type.Fraction(x); - } - catch (err) { - throw new Error('Cannot convert "' + x + '" to Fraction'); - } - } - }, { - from: 'string', - to: 'Complex', - convert: function (x) { - try { - return new type.Complex(x); - } - catch (err) { - throw new Error('Cannot convert "' + x + '" to Complex'); - } - } - }, { - from: 'boolean', - to: 'number', - convert: function (x) { - return +x; - } - }, { - from: 'boolean', - to: 'BigNumber', - convert: function (x) { - return new type.BigNumber(+x); - } - }, { - from: 'boolean', - to: 'Fraction', - convert: function (x) { - return new type.Fraction(+x); - } - }, { - from: 'boolean', - to: 'string', - convert: function (x) { - return +x; - } - }, { - from: 'Array', - to: 'Matrix', - convert: function (array) { - return new type.DenseMatrix(array); - } - }, { - from: 'Matrix', - to: 'Array', - convert: function (matrix) { - return matrix.valueOf(); - } - } - ]; + var e = rounded.exponent; + var c = rounded.coefficients; - return typed; -}; + // find nearest lower multiple of 3 for exponent + var newExp = e % 3 === 0 ? e : (e < 0 ? (e - 3) - (e % 3) : e - (e % 3)); -var typed = { - create: create -}; + // concatenate coefficients with necessary zeros + var significandsDiff = e >= 0 ? e : Math.abs(newExp); -function E () { - // Keep this empty so it's easier to inherit from - // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) -} + // add zeros if necessary (for ex: 1e+8) + if (c.length - 1 < significandsDiff) c = c.concat(zeros(significandsDiff - (c.length - 1))); -E.prototype = { - on: function (name, callback, ctx) { - var e = this.e || (this.e = {}); + // find difference in exponents + var expDiff = Math.abs(e - newExp); - (e[name] || (e[name] = [])).push({ - fn: callback, - ctx: ctx - }); + var decimalIdx = 1; - return this; - }, + // push decimal index over by expDiff times + while (--expDiff >= 0) decimalIdx++; - once: function (name, callback, ctx) { - var self = this; - function listener () { - self.off(name, listener); - callback.apply(ctx, arguments); - } - listener._ = callback; - return this.on(name, listener, ctx); - }, + // if all coefficient values are zero after the decimal point, don't add a decimal value. + // otherwise concat with the rest of the coefficients + var decimals = c.slice(decimalIdx).join(''); + var decimalVal = decimals.match(/[1-9]/) ? ('.' + decimals) : ''; - emit: function (name) { - var data = [].slice.call(arguments, 1); - var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); - var i = 0; - var len = evtArr.length; + var str = c.slice(0, decimalIdx).join('') + + decimalVal + + 'e' + (e >= 0 ? '+' : '') + newExp.toString(); + return rounded.sign + str; + }; - for (i; i < len; i++) { - evtArr[i].fn.apply(evtArr[i].ctx, data); + /** + * 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); } - return this; - }, - - off: function (name, callback) { - var e = this.e || (this.e = {}); - var evts = e[name]; - var liveEvents = []; + 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 - if (evts && callback) { - for (var i = 0, len = evts.length; i < len; i++) { - if (evts[i].fn !== callback && evts[i].fn._ !== callback) - liveEvents.push(evts[i]); - } + // append zeros if needed + var pp = p + (precision || 0); + if (c.length < pp) { + c = c.concat(zeros(pp - c.length)); } - // Remove event from queue to prevent memory leak - // Suggested by https://github.com/lazd - // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 - - (liveEvents.length) - ? e[name] = liveEvents - : delete e[name]; + // prepend zeros if needed + if (p < 0) { + c = zeros(-p + 1).concat(c); + p = 1; + } - return this; - } -}; + // insert a dot if needed + if (p < c.length) { + c.splice(p, 0, (p === 0) ? '0.' : '.'); + } -var tinyEmitter = E; + return rounded.sign + c.join(''); + }; -/** - * Extend given object with emitter functions `on`, `off`, `once`, `emit` - * @param {Object} obj - * @return {Object} obj - */ -var mixin = function (obj) { - // create event emitter - var emitter = new tinyEmitter(); + /** + * 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); + } - // bind methods to obj (we don't want to expose the emitter.e Array...) - obj.on = emitter.on.bind(emitter); - obj.off = emitter.off.bind(emitter); - obj.once = emitter.once.bind(emitter); - obj.emit = emitter.emit.bind(emitter); + // 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; - return obj; -}; + // append zeros if needed + if (c.length < precision) { + c = c.concat(zeros(precision - c.length)); + } -var emitter = { - mixin: mixin -}; + // 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; + }; -/** - * Create a syntax error with the message: - * 'Wrong number of arguments in function ( provided, - expected)' - * @param {string} fn Function name - * @param {number} count Actual argument count - * @param {number} min Minimum required argument count - * @param {number} [max] Maximum required argument count - * @extends Error - */ -function ArgumentsError(fn, count, min, max) { - if (!(this instanceof ArgumentsError)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + /** + * 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); + } - this.fn = fn; - this.count = count; - this.min = min; - this.max = max; + // 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; - this.message = 'Wrong number of arguments in function ' + fn + - ' (' + count + ' provided, ' + - min + ((max != undefined) ? ('-' + max) : '') + ' expected)'; + 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; - this.stack = (new Error()).stack; -} + // append trailing zeros + if (c.length < precision) { + c = c.concat(zeros(precision - c.length)); + } -ArgumentsError.prototype = new Error(); -ArgumentsError.prototype.constructor = Error; -ArgumentsError.prototype.name = 'ArgumentsError'; -ArgumentsError.prototype.isArgumentsError = true; + // append trailing zeros + // TODO: simplify the next statement + c = c.concat(zeros(e - c.length + 1 + + (c.length < precision ? precision - c.length : 0))); -var ArgumentsError_1 = ArgumentsError; + // prepend zeros + c = zeros(-e).concat(c); -var lazy = object.lazy; -var isFactory = object.isFactory; -var traverse = object.traverse; + var dot = e > 0 ? e : 0; + if (dot < c.length - 1) { + c.splice(dot + 1, 0, '.'); + } + return rounded.sign + c.join(''); + } + }; -function factory (type, config, load, typed, math) { /** - * Import functions from an object or a module - * - * Syntax: - * - * math.import(object) - * math.import(object, options) - * - * Where: - * - * - `object: Object` - * An object with functions to be imported. - * - `options: Object` An object with import options. Available options: - * - `override: boolean` - * If true, existing functions will be overwritten. False by default. - * - `silent: boolean` - * If true, the function will not throw errors on duplicates or invalid - * types. False by default. - * - `wrap: boolean` - * If true, the functions will be wrapped in a wrapper function - * which converts data types like Matrix to primitive data types like Array. - * The wrapper is needed when extending math.js with libraries which do not - * support these data type. False by default. - * - * Examples: - * - * // define new functions and variables - * math.import({ - * myvalue: 42, - * hello: function (name) { - * return 'hello, ' + name + '!'; - * } - * }); - * - * // use the imported function and variable - * math.myvalue * 2; // 84 - * math.hello('user'); // 'hello, user!' - * - * // import the npm module 'numbers' - * // (must be installed first with `npm install numbers`) - * math.import(require('numbers'), {wrap: true}); - * - * math.fibonacci(7); // returns 13 - * - * @param {Object | Array} object Object with functions to be imported. - * @param {Object} [options] Import options. + * 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 */ - function math_import(object$$1, options) { - var num = arguments.length; - if (num !== 1 && num !== 2) { - throw new ArgumentsError_1('import', num, 1, 2); - } + exports.roundDigits = function (split, precision) { + // create a clone + var rounded = { + sign: split.sign, + coefficients: split.coefficients, + exponent: split.exponent + }; + var c = rounded.coefficients; - if (!options) { - options = {}; + // prepend zeros if needed + while (precision <= 0) { + c.unshift(0); + rounded.exponent++; + precision++; } - if (isFactory(object$$1)) { - _importFactory(object$$1, options); - } - // TODO: allow a typed-function with name too - else if (Array.isArray(object$$1)) { - object$$1.forEach(function (entry) { - math_import(entry, options); - }); - } - else if (typeof object$$1 === 'object') { - // a map with functions - for (var name in object$$1) { - if (object$$1.hasOwnProperty(name)) { - var value = object$$1[name]; - if (isSupportedType(value)) { - _import(name, value, options); - } - else if (isFactory(object$$1)) { - _importFactory(object$$1, options); - } - else { - math_import(value, options); + 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]++; } } } - else { - if (!options.silent) { - throw new TypeError('Factory, Object, or Array expected'); - } + + 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; } /** - * Add a property to the math namespace and create a chain proxy for it. - * @param {string} name - * @param {*} value - * @param {Object} options See import for a description of the options - * @private + * 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 */ - function _import(name, value, options) { - // TODO: refactor this function, it's to complicated and contains duplicate code - if (options.wrap && typeof value === 'function') { - // create a wrapper around the function - value = _wrap(value); - } + exports.digits = function(value) { + return value + .toExponential() + .replace(/e.*$/, '') // remove exponential notation + .replace( /^0\.?0*|\./, '') // remove decimal point and leading zeros + .length + }; - if (isTypedFunction(math[name]) && isTypedFunction(value)) { - if (options.override) { - // give the typed function the right name - value = typed(name, value.signatures); - } - else { - // merge the existing and typed function - value = typed(math[name], value); - } + /** + * Minimum number added to one that makes the result different than one + */ + exports.DBL_EPSILON = Number.EPSILON || 2.2204460492503130808472633361816E-16; - math[name] = value; - _importTransform(name, value); - math.emit('import', name, function resolver() { - return value; - }); - return; + /** + * 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) { + return x == y; } - if (math[name] === undefined || options.override) { - math[name] = value; - _importTransform(name, value); - math.emit('import', name, function resolver() { - return value; - }); - return; + // use "==" operator, handles infinities + if (x == y) { + return true; } - if (!options.silent) { - throw new Error('Cannot import "' + name + '": already exists'); + // NaN + if (isNaN(x) || isNaN(y)) { + return false; } - } - function _importTransform (name, value) { - if (value && typeof value.transform === 'function') { - math.expression.transform[name] = value.transform; - if (allowedInExpressions(name)) { - math.expression.mathWithTransform[name] = value.transform; + // 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 { - // remove existing transform - delete math.expression.transform[name]; - if (allowedInExpressions(name)) { - math.expression.mathWithTransform[name] = value; + else { + // use relative error + return diff <= Math.max(Math.abs(x), Math.abs(y)) * epsilon; } } - } - /** - * Create a wrapper a round an function which converts the arguments - * to their primitive values (like convert a Matrix to Array) - * @param {Function} fn - * @return {Function} Returns the wrapped function - * @private + // Infinite and Number or negative Infinite and positive Infinite cases + return false; + }; + }); + var number_1 = number.isNumber; + var number_2 = number.isInteger; + var number_3 = number.sign; + var number_4 = number.format; + var number_5 = number.splitNumber; + var number_6 = number.toEngineering; + var number_7 = number.toFixed; + var number_8 = number.toExponential; + var number_9 = number.toPrecision; + var number_10 = number.roundDigits; + var number_11 = number.digits; + var number_12 = number.DBL_EPSILON; + var number_13 = number.nearlyEqual; + + /** + * Test whether a value is a Matrix + * @param {*} x + * @returns {boolean} returns true with input is a Matrix + * (like a DenseMatrix or SparseMatrix) */ - function _wrap (fn) { - var wrapper = function wrapper () { - var args = []; - for (var i = 0, len = arguments.length; i < len; i++) { - var arg = arguments[i]; - args[i] = arg && arg.valueOf(); - } - return fn.apply(math, args); - }; + var isMatrix = function isMatrix (x) { + return x && x.constructor.prototype.isMatrix || false; + }; - if (fn.transform) { - wrapper.transform = fn.transform; - } + var digits = number.digits; - return wrapper; - } + + + // returns a new instance of typed-function + var createTyped = function () { + // initially, return the original instance of typed-function + // consecutively, return a new instance from typed.create. + createTyped = typedFunction.create; + return typedFunction; + }; /** - * Import an instance of a factory into math.js - * @param {{factory: Function, name: string, path: string, math: boolean}} factory - * @param {Object} options See import for a description of the options - * @private + * Factory function for creating a new typed instance + * @param {Object} type Object with data types like Complex and BigNumber + * @returns {Function} */ - function _importFactory(factory, options) { - if (typeof factory.name === 'string') { - var name = factory.name; - var existingTransform = name in math.expression.transform; - var namespace = factory.path ? traverse(math, factory.path) : math; - var existing = namespace.hasOwnProperty(name) ? namespace[name] : undefined; + var create = function create(type) { + // TODO: typed-function must be able to silently ignore signatures with unknown data types - var resolver = function () { - var instance = load(factory); - if (instance && typeof instance.transform === 'function') { - throw new Error('Transforms cannot be attached to factory functions. ' + - 'Please create a separate function for it with exports.path="expression.transform"'); - } + // type checks for all known types + // + // note that: + // + // - check by duck-typing on a property like `isUnit`, instead of checking instanceof. + // instanceof cannot be used because that would not allow to pass data from + // one instance of math.js to another since each has it's own instance of Unit. + // - check the `isUnit` property via the constructor, so there will be no + // matches for "fake" instances like plain objects with a property `isUnit`. + // That is important for security reasons. + // - It must not be possible to override the type checks used internally, + // for security reasons, so these functions are not exposed in the expression + // parser. + type.isNumber = function (x) { return typeof x === 'number' }; + type.isComplex = function (x) { return type.Complex && x instanceof type.Complex || false }; + type.isBigNumber = isBigNumber; + type.isFraction = function (x) { return type.Fraction && x instanceof type.Fraction || false }; + type.isUnit = function (x) { return x && x.constructor.prototype.isUnit || false }; + type.isString = function (x) { return typeof x === 'string' }; + type.isArray = Array.isArray; + type.isMatrix = isMatrix; + type.isDenseMatrix = function (x) { return x && x.isDenseMatrix && x.constructor.prototype.isMatrix || false }; + type.isSparseMatrix = function (x) { return x && x.isSparseMatrix && x.constructor.prototype.isMatrix || false }; + type.isRange = function (x) { return x && x.constructor.prototype.isRange || false }; + type.isIndex = function (x) { return x && x.constructor.prototype.isIndex || false }; + type.isBoolean = function (x) { return typeof x === 'boolean' }; + type.isResultSet = function (x) { return x && x.constructor.prototype.isResultSet || false }; + type.isHelp = function (x) { return x && x.constructor.prototype.isHelp || false }; + type.isFunction = function (x) { return typeof x === 'function'}; + type.isDate = function (x) { return x instanceof Date }; + type.isRegExp = function (x) { return x instanceof RegExp }; + type.isObject = function (x) { + return typeof x === 'object' && + x.constructor === Object && + !type.isComplex(x) && + !type.isFraction(x) + }; + type.isNull = function (x) { return x === null }; + type.isUndefined = function (x) { return x === undefined }; + + type.isAccessorNode = function (x) { return x && x.isAccessorNode && x.constructor.prototype.isNode || false }; + type.isArrayNode = function (x) { return x && x.isArrayNode && x.constructor.prototype.isNode || false }; + type.isAssignmentNode = function (x) { return x && x.isAssignmentNode && x.constructor.prototype.isNode || false }; + type.isBlockNode = function (x) { return x && x.isBlockNode && x.constructor.prototype.isNode || false }; + type.isConditionalNode = function (x) { return x && x.isConditionalNode && x.constructor.prototype.isNode || false }; + type.isConstantNode = function (x) { return x && x.isConstantNode && x.constructor.prototype.isNode || false }; + type.isFunctionAssignmentNode = function (x) { return x && x.isFunctionAssignmentNode && x.constructor.prototype.isNode || false }; + type.isFunctionNode = function (x) { return x && x.isFunctionNode && x.constructor.prototype.isNode || false }; + type.isIndexNode = function (x) { return x && x.isIndexNode && x.constructor.prototype.isNode || false }; + type.isNode = function (x) { return x && x.isNode && x.constructor.prototype.isNode || false }; + type.isObjectNode = function (x) { return x && x.isObjectNode && x.constructor.prototype.isNode || false }; + type.isOperatorNode = function (x) { return x && x.isOperatorNode && x.constructor.prototype.isNode || false }; + type.isParenthesisNode = function (x) { return x && x.isParenthesisNode && x.constructor.prototype.isNode || false }; + type.isRangeNode = function (x) { return x && x.isRangeNode && x.constructor.prototype.isNode || false }; + type.isSymbolNode = function (x) { return x && x.isSymbolNode && x.constructor.prototype.isNode || false }; + + type.isChain = function (x) { return x && x.constructor.prototype.isChain || false }; + + // get a new instance of typed-function + var typed = createTyped(); + + // define all types. The order of the types determines in which order function + // arguments are type-checked (so for performance it's important to put the + // most used types first). + typed.types = [ + { name: 'number', test: type.isNumber }, + { name: 'Complex', test: type.isComplex }, + { name: 'BigNumber', test: type.isBigNumber }, + { name: 'Fraction', test: type.isFraction }, + { name: 'Unit', test: type.isUnit }, + { name: 'string', test: type.isString }, + { name: 'Array', test: type.isArray }, + { name: 'Matrix', test: type.isMatrix }, + { name: 'DenseMatrix', test: type.isDenseMatrix }, + { name: 'SparseMatrix', test: type.isSparseMatrix }, + { name: 'Range', test: type.isRange }, + { name: 'Index', test: type.isIndex }, + { name: 'boolean', test: type.isBoolean }, + { name: 'ResultSet', test: type.isResultSet }, + { name: 'Help', test: type.isHelp }, + { name: 'function', test: type.isFunction }, + { name: 'Date', test: type.isDate }, + { name: 'RegExp', test: type.isRegExp }, + { name: 'null', test: type.isNull }, + { name: 'undefined', test: type.isUndefined }, + + { name: 'OperatorNode', test: type.isOperatorNode }, + { name: 'ConstantNode', test: type.isConstantNode }, + { name: 'SymbolNode', test: type.isSymbolNode }, + { name: 'ParenthesisNode', test: type.isParenthesisNode }, + { name: 'FunctionNode', test: type.isFunctionNode }, + { name: 'FunctionAssignmentNode', test: type.isFunctionAssignmentNode }, + { name: 'ArrayNode', test: type.isArrayNode }, + { name: 'AssignmentNode', test: type.isAssignmentNode }, + { name: 'BlockNode', test: type.isBlockNode }, + { name: 'ConditionalNode', test: type.isConditionalNode }, + { name: 'IndexNode', test: type.isIndexNode }, + { name: 'RangeNode', test: type.isRangeNode }, + { name: 'Node', test: type.isNode }, + + { name: 'Object', test: type.isObject } // order 'Object' last, it's a tricky one + ]; - if (isTypedFunction(existing) && isTypedFunction(instance)) { - if (options.override) { - // replace the existing typed function (nothing to do) + // TODO: add conversion from BigNumber to number? + typed.conversions = [ + { + from: 'number', + to: 'BigNumber', + convert: function (x) { + // note: conversion from number to BigNumber can fail if x has >15 digits + if (digits(x) > 15) { + throw new TypeError('Cannot implicitly convert a number with >15 significant digits to BigNumber ' + + '(value: ' + x + '). ' + + 'Use function bignumber(x) to convert to BigNumber.'); } - else { - // merge the existing and new typed function - instance = typed(existing, instance); + return new type.BigNumber(x); + } + }, { + from: 'number', + to: 'Complex', + convert: function (x) { + return new type.Complex(x, 0); + } + }, { + from: 'number', + to: 'string', + convert: function (x) { + return x + ''; + } + }, { + from: 'BigNumber', + to: 'Complex', + convert: function (x) { + return new type.Complex(x.toNumber(), 0); + } + }, { + from: 'Fraction', + to: 'BigNumber', + convert: function (x) { + throw new TypeError('Cannot implicitly convert a Fraction to BigNumber or vice versa. ' + + 'Use function bignumber(x) to convert to BigNumber or fraction(x) to convert to Fraction.'); + } + }, { + from: 'Fraction', + to: 'Complex', + convert: function (x) { + return new type.Complex(x.valueOf(), 0); + } + }, { + from: 'number', + to: 'Fraction', + convert: function (x) { + var f = new type.Fraction(x); + if (f.valueOf() !== x) { + throw new TypeError('Cannot implicitly convert a number to a Fraction when there will be a loss of precision ' + + '(value: ' + x + '). ' + + 'Use function fraction(x) to convert to Fraction.'); } - - return instance; + return new type.Fraction(x); } - - if (existing === undefined || options.override) { - return instance; + }, { + // FIXME: add conversion from Fraction to number, for example for `sqrt(fraction(1,3))` + // from: 'Fraction', + // to: 'number', + // convert: function (x) { + // return x.valueOf(); + // } + //}, { + from: 'string', + to: 'number', + convert: function (x) { + var n = Number(x); + if (isNaN(n)) { + throw new Error('Cannot convert "' + x + '" to a number'); + } + return n; } - - if (!options.silent) { - throw new Error('Cannot import "' + name + '": already exists'); + }, { + from: 'string', + to: 'BigNumber', + convert: function (x) { + try { + return new type.BigNumber(x); + } + catch (err) { + throw new Error('Cannot convert "' + x + '" to BigNumber'); + } } - }; - - if (factory.lazy !== false) { - lazy(namespace, name, resolver); - - if (!existingTransform) { - if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) { - lazy(math.expression.mathWithTransform, name, resolver); + }, { + from: 'string', + to: 'Fraction', + convert: function (x) { + try { + return new type.Fraction(x); + } + catch (err) { + throw new Error('Cannot convert "' + x + '" to Fraction'); } } - } - else { - namespace[name] = resolver(); - - if (!existingTransform) { - if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) { - math.expression.mathWithTransform[name] = resolver(); + }, { + from: 'string', + to: 'Complex', + convert: function (x) { + try { + return new type.Complex(x); + } + catch (err) { + throw new Error('Cannot convert "' + x + '" to Complex'); } } + }, { + from: 'boolean', + to: 'number', + convert: function (x) { + return +x; + } + }, { + from: 'boolean', + to: 'BigNumber', + convert: function (x) { + return new type.BigNumber(+x); + } + }, { + from: 'boolean', + to: 'Fraction', + convert: function (x) { + return new type.Fraction(+x); + } + }, { + from: 'boolean', + to: 'string', + convert: function (x) { + return +x; + } + }, { + from: 'Array', + to: 'Matrix', + convert: function (array) { + return new type.DenseMatrix(array); + } + }, { + from: 'Matrix', + to: 'Array', + convert: function (matrix) { + return matrix.valueOf(); + } } + ]; - math.emit('import', name, resolver, factory.path); - } - else { - // unnamed factory. - // no lazy loading - load(factory); - } - } + return typed; + }; - /** - * Check whether given object is a type which can be imported - * @param {Function | number | string | boolean | null | Unit | Complex} object - * @return {boolean} - * @private - */ - function isSupportedType(object$$1) { - return typeof object$$1 === 'function' - || typeof object$$1 === 'number' - || typeof object$$1 === 'string' - || typeof object$$1 === 'boolean' - || object$$1 === null - || (object$$1 && type.isUnit(object$$1)) - || (object$$1 && type.isComplex(object$$1)) - || (object$$1 && type.isBigNumber(object$$1)) - || (object$$1 && type.isFraction(object$$1)) - || (object$$1 && type.isMatrix(object$$1)) - || (object$$1 && Array.isArray(object$$1)) - } + var typed = { + create: create + }; - /** - * Test whether a given thing is a typed-function - * @param {*} fn - * @return {boolean} Returns true when `fn` is a typed-function - */ - function isTypedFunction (fn) { - return typeof fn === 'function' && typeof fn.signatures === 'object'; + function E () { + // Keep this empty so it's easier to inherit from + // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) } - function allowedInExpressions (name) { - return !unsafe.hasOwnProperty(name); - } + E.prototype = { + on: function (name, callback, ctx) { + var e = this.e || (this.e = {}); - function factoryAllowedInExpressions (factory) { - return factory.path === undefined && !unsafe.hasOwnProperty(factory.name); - } + (e[name] || (e[name] = [])).push({ + fn: callback, + ctx: ctx + }); - // namespaces and functions not available in the parser for safety reasons - var unsafe = { - 'expression': true, - 'type': true, - 'docs': true, - 'error': true, - 'json': true, - 'chain': true // chain method not supported. Note that there is a unit chain too. - }; + return this; + }, - return math_import; -} + once: function (name, callback, ctx) { + var self = this; + function listener () { + self.off(name, listener); + callback.apply(ctx, arguments); + } + listener._ = callback; + return this.on(name, listener, ctx); + }, -var math = true; // request access to the math namespace as 5th argument of the factory function -var name = 'import'; -var factory_1 = factory; -var lazy_1 = true; + emit: function (name) { + var data = [].slice.call(arguments, 1); + var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); + var i = 0; + var len = evtArr.length; -var _import = { - math: math, - name: name, - factory: factory_1, - lazy: lazy_1 -}; + for (i; i < len; i++) { + evtArr[i].fn.apply(evtArr[i].ctx, data); + } -function factory$1 (type, config, load, typed, math) { - var MATRIX = ['Matrix', 'Array']; // valid values for option matrix - var NUMBER = ['number', 'BigNumber', 'Fraction']; // valid values for option number + return this; + }, - /** - * Set configuration options for math.js, and get current options. - * Will emit a 'config' event, with arguments (curr, prev, changes). - * - * Syntax: - * - * math.config(config: Object): Object - * - * Examples: - * - * math.config().number; // outputs 'number' - * math.eval('0.4'); // outputs number 0.4 - * math.config({number: 'Fraction'}); - * math.eval('0.4'); // outputs Fraction 2/5 - * + off: function (name, callback) { + var e = this.e || (this.e = {}); + var evts = e[name]; + var liveEvents = []; + + if (evts && callback) { + for (var i = 0, len = evts.length; i < len; i++) { + if (evts[i].fn !== callback && evts[i].fn._ !== callback) + liveEvents.push(evts[i]); + } + } + + // Remove event from queue to prevent memory leak + // Suggested by https://github.com/lazd + // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 + + (liveEvents.length) + ? e[name] = liveEvents + : delete e[name]; + + return this; + } + }; + + var tinyEmitter = E; + + /** + * Extend given object with emitter functions `on`, `off`, `once`, `emit` + * @param {Object} obj + * @return {Object} obj + */ + var mixin = function (obj) { + // create event emitter + var emitter = new tinyEmitter(); + + // bind methods to obj (we don't want to expose the emitter.e Array...) + obj.on = emitter.on.bind(emitter); + obj.off = emitter.off.bind(emitter); + obj.once = emitter.once.bind(emitter); + obj.emit = emitter.emit.bind(emitter); + + return obj; + }; + + var emitter = { + mixin: mixin + }; + + /** + * Create a syntax error with the message: + * 'Wrong number of arguments in function ( provided, - expected)' + * @param {string} fn Function name + * @param {number} count Actual argument count + * @param {number} min Minimum required argument count + * @param {number} [max] Maximum required argument count + * @extends Error + */ + function ArgumentsError(fn, count, min, max) { + if (!(this instanceof ArgumentsError)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } + + this.fn = fn; + this.count = count; + this.min = min; + this.max = max; + + this.message = 'Wrong number of arguments in function ' + fn + + ' (' + count + ' provided, ' + + min + ((max != undefined) ? ('-' + max) : '') + ' expected)'; + + this.stack = (new Error()).stack; + } + + ArgumentsError.prototype = new Error(); + ArgumentsError.prototype.constructor = Error; + ArgumentsError.prototype.name = 'ArgumentsError'; + ArgumentsError.prototype.isArgumentsError = true; + + var ArgumentsError_1 = ArgumentsError; + + var lazy = object.lazy; + var isFactory = object.isFactory; + var traverse = object.traverse; + + + function factory (type, config, load, typed, math) { + /** + * Import functions from an object or a module + * + * Syntax: + * + * math.import(object) + * math.import(object, options) + * + * Where: + * + * - `object: Object` + * An object with functions to be imported. + * - `options: Object` An object with import options. Available options: + * - `override: boolean` + * If true, existing functions will be overwritten. False by default. + * - `silent: boolean` + * If true, the function will not throw errors on duplicates or invalid + * types. False by default. + * - `wrap: boolean` + * If true, the functions will be wrapped in a wrapper function + * which converts data types like Matrix to primitive data types like Array. + * The wrapper is needed when extending math.js with libraries which do not + * support these data type. False by default. + * + * Examples: + * + * // define new functions and variables + * math.import({ + * myvalue: 42, + * hello: function (name) { + * return 'hello, ' + name + '!'; + * } + * }); + * + * // use the imported function and variable + * math.myvalue * 2; // 84 + * math.hello('user'); // 'hello, user!' + * + * // import the npm module 'numbers' + * // (must be installed first with `npm install numbers`) + * math.import(require('numbers'), {wrap: true}); + * + * math.fibonacci(7); // returns 13 + * + * @param {Object | Array} object Object with functions to be imported. + * @param {Object} [options] Import options. + */ + function math_import(object$$1, options) { + var num = arguments.length; + if (num !== 1 && num !== 2) { + throw new ArgumentsError_1('import', num, 1, 2); + } + + if (!options) { + options = {}; + } + + if (isFactory(object$$1)) { + _importFactory(object$$1, options); + } + // TODO: allow a typed-function with name too + else if (Array.isArray(object$$1)) { + object$$1.forEach(function (entry) { + math_import(entry, options); + }); + } + else if (typeof object$$1 === 'object') { + // a map with functions + for (var name in object$$1) { + if (object$$1.hasOwnProperty(name)) { + var value = object$$1[name]; + if (isSupportedType(value)) { + _import(name, value, options); + } + else if (isFactory(object$$1)) { + _importFactory(object$$1, options); + } + else { + math_import(value, options); + } + } + } + } + else { + if (!options.silent) { + throw new TypeError('Factory, Object, or Array expected'); + } + } + } + + /** + * Add a property to the math namespace and create a chain proxy for it. + * @param {string} name + * @param {*} value + * @param {Object} options See import for a description of the options + * @private + */ + function _import(name, value, options) { + // TODO: refactor this function, it's to complicated and contains duplicate code + if (options.wrap && typeof value === 'function') { + // create a wrapper around the function + value = _wrap(value); + } + + if (isTypedFunction(math[name]) && isTypedFunction(value)) { + if (options.override) { + // give the typed function the right name + value = typed(name, value.signatures); + } + else { + // merge the existing and typed function + value = typed(math[name], value); + } + + math[name] = value; + _importTransform(name, value); + math.emit('import', name, function resolver() { + return value; + }); + return; + } + + if (math[name] === undefined || options.override) { + math[name] = value; + _importTransform(name, value); + math.emit('import', name, function resolver() { + return value; + }); + return; + } + + if (!options.silent) { + throw new Error('Cannot import "' + name + '": already exists'); + } + } + + function _importTransform (name, value) { + if (value && typeof value.transform === 'function') { + math.expression.transform[name] = value.transform; + if (allowedInExpressions(name)) { + math.expression.mathWithTransform[name] = value.transform; + } + } + else { + // remove existing transform + delete math.expression.transform[name]; + if (allowedInExpressions(name)) { + math.expression.mathWithTransform[name] = value; + } + } + } + + /** + * Create a wrapper a round an function which converts the arguments + * to their primitive values (like convert a Matrix to Array) + * @param {Function} fn + * @return {Function} Returns the wrapped function + * @private + */ + function _wrap (fn) { + var wrapper = function wrapper () { + var args = []; + for (var i = 0, len = arguments.length; i < len; i++) { + var arg = arguments[i]; + args[i] = arg && arg.valueOf(); + } + return fn.apply(math, args); + }; + + if (fn.transform) { + wrapper.transform = fn.transform; + } + + return wrapper; + } + + /** + * Import an instance of a factory into math.js + * @param {{factory: Function, name: string, path: string, math: boolean}} factory + * @param {Object} options See import for a description of the options + * @private + */ + function _importFactory(factory, options) { + if (typeof factory.name === 'string') { + var name = factory.name; + var existingTransform = name in math.expression.transform; + var namespace = factory.path ? traverse(math, factory.path) : math; + var existing = namespace.hasOwnProperty(name) ? namespace[name] : undefined; + + var resolver = function () { + var instance = load(factory); + if (instance && typeof instance.transform === 'function') { + throw new Error('Transforms cannot be attached to factory functions. ' + + 'Please create a separate function for it with exports.path="expression.transform"'); + } + + if (isTypedFunction(existing) && isTypedFunction(instance)) { + if (options.override) { + // replace the existing typed function (nothing to do) + } + else { + // merge the existing and new typed function + instance = typed(existing, instance); + } + + return instance; + } + + if (existing === undefined || options.override) { + return instance; + } + + if (!options.silent) { + throw new Error('Cannot import "' + name + '": already exists'); + } + }; + + if (factory.lazy !== false) { + lazy(namespace, name, resolver); + + if (!existingTransform) { + if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) { + lazy(math.expression.mathWithTransform, name, resolver); + } + } + } + else { + namespace[name] = resolver(); + + if (!existingTransform) { + if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) { + math.expression.mathWithTransform[name] = resolver(); + } + } + } + + math.emit('import', name, resolver, factory.path); + } + else { + // unnamed factory. + // no lazy loading + load(factory); + } + } + + /** + * Check whether given object is a type which can be imported + * @param {Function | number | string | boolean | null | Unit | Complex} object + * @return {boolean} + * @private + */ + function isSupportedType(object$$1) { + return typeof object$$1 === 'function' + || typeof object$$1 === 'number' + || typeof object$$1 === 'string' + || typeof object$$1 === 'boolean' + || object$$1 === null + || (object$$1 && type.isUnit(object$$1)) + || (object$$1 && type.isComplex(object$$1)) + || (object$$1 && type.isBigNumber(object$$1)) + || (object$$1 && type.isFraction(object$$1)) + || (object$$1 && type.isMatrix(object$$1)) + || (object$$1 && Array.isArray(object$$1)) + } + + /** + * Test whether a given thing is a typed-function + * @param {*} fn + * @return {boolean} Returns true when `fn` is a typed-function + */ + function isTypedFunction (fn) { + return typeof fn === 'function' && typeof fn.signatures === 'object'; + } + + function allowedInExpressions (name) { + return !unsafe.hasOwnProperty(name); + } + + function factoryAllowedInExpressions (factory) { + return factory.path === undefined && !unsafe.hasOwnProperty(factory.name); + } + + // namespaces and functions not available in the parser for safety reasons + var unsafe = { + 'expression': true, + 'type': true, + 'docs': true, + 'error': true, + 'json': true, + 'chain': true // chain method not supported. Note that there is a unit chain too. + }; + + return math_import; + } + + var math = true; // request access to the math namespace as 5th argument of the factory function + var name = 'import'; + var factory_1 = factory; + var lazy_1 = true; + + var _import = { + math: math, + name: name, + factory: factory_1, + lazy: lazy_1 + }; + + function factory$1 (type, config, load, typed, math) { + var MATRIX = ['Matrix', 'Array']; // valid values for option matrix + var NUMBER = ['number', 'BigNumber', 'Fraction']; // valid values for option number + + /** + * Set configuration options for math.js, and get current options. + * Will emit a 'config' event, with arguments (curr, prev, changes). + * + * Syntax: + * + * math.config(config: Object): Object + * + * Examples: + * + * math.config().number; // outputs 'number' + * math.eval('0.4'); // outputs number 0.4 + * math.config({number: 'Fraction'}); + * math.eval('0.4'); // outputs Fraction 2/5 + * + * @param {Object} [options] Available options: + * {number} epsilon + * Minimum relative difference between two + * compared values, used by all comparison functions. + * {string} matrix + * A string 'Matrix' (default) or 'Array'. + * {string} number + * A string 'number' (default), 'BigNumber', or 'Fraction' + * {number} precision + * The number of significant digits for BigNumbers. + * Not applicable for Numbers. + * {string} parenthesis + * How to display parentheses in LaTeX and string + * output. + * {string} randomSeed + * Random seed for seeded pseudo random number generator. + * Set to null to randomly seed. + * @return {Object} Returns the current configuration + */ + function _config(options) { + if (options) { + var prev = object.map(config, object.clone); + + // validate some of the options + validateOption(options, 'matrix', MATRIX); + validateOption(options, 'number', NUMBER); + + // merge options + object.deepExtend(config, options); + + var curr = object.map(config, object.clone); + + var changes = object.map(options, object.clone); + + // emit 'config' event + math.emit('config', curr, prev, changes); + + return curr; + } + else { + return object.map(config, object.clone); + } + } + + // attach the valid options to the function so they can be extended + _config.MATRIX = MATRIX; + _config.NUMBER = NUMBER; + + return _config; + } + + /** + * Test whether an Array contains a specific item. + * @param {Array.} array + * @param {string} item + * @return {boolean} + */ + function contains (array, item) { + return array.indexOf(item) !== -1; + } + + /** + * Find a string in an array. Case insensitive search + * @param {Array.} array + * @param {string} item + * @return {number} Returns the index when found. Returns -1 when not found + */ + function findIndex (array, item) { + return array + .map(function (i) { + return i.toLowerCase(); + }) + .indexOf(item.toLowerCase()); + } + + /** + * Validate an option + * @param {Object} options Object with options + * @param {string} name Name of the option to validate + * @param {Array.} values Array with valid values for this option + */ + function validateOption(options, name, values) { + if (options[name] !== undefined && !contains(values, options[name])) { + var index = findIndex(values, options[name]); + if (index !== -1) { + // right value, wrong casing + // TODO: lower case values are deprecated since v3, remove this warning some day. + console.warn('Warning: Wrong casing for configuration option "' + name + '", should be "' + values[index] + '" instead of "' + options[name] + '".'); + + options[name] = values[index]; // change the option to the right casing + } + else { + // unknown value + console.warn('Warning: Unknown value "' + options[name] + '" for configuration option "' + name + '". Available options: ' + values.map(JSON.stringify).join(', ') + '.'); + } + } + } + + var name$1 = 'config'; + var math$1 = true; // request the math namespace as fifth argument + var factory_1$1 = factory$1; + + var config = { + name: name$1, + math: math$1, + factory: factory_1$1 + }; + + var isFactory$1 = object.isFactory; + + + + + + + /** + * Math.js core. Creates a new, empty math.js instance * @param {Object} [options] Available options: * {number} epsilon * Minimum relative difference between two @@ -3515,79787 +3638,81636 @@ function factory$1 (type, config, load, typed, math) { * {number} precision * The number of significant digits for BigNumbers. * Not applicable for Numbers. - * {string} parenthesis - * How to display parentheses in LaTeX and string - * output. + * {boolean} predictable + * Predictable output type of functions. When true, + * output type depends only on the input types. When + * false (default), output type can vary depending + * on input values. For example `math.sqrt(-4)` + * returns `complex('2i')` when predictable is false, and + * returns `NaN` when true. * {string} randomSeed * Random seed for seeded pseudo random number generator. * Set to null to randomly seed. - * @return {Object} Returns the current configuration - */ - function _config(options) { - if (options) { - var prev = object.map(config, object.clone); + * @returns {Object} Returns a bare-bone math.js instance containing + * functions: + * - `import` to add new functions + * - `config` to change configuration + * - `on`, `off`, `once`, `emit` for events + */ + var create$1 = function create (options) { + // 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.'); + } + + // cached factories and instances + var factories = []; + var instances = []; + + // create a namespace for the mathjs instance, and attach emitter functions + var math = emitter.mixin({}); + math.type = {}; + math.expression = { + transform: {}, + mathWithTransform: {} + }; - // validate some of the options - validateOption(options, 'matrix', MATRIX); - validateOption(options, 'number', NUMBER); + // create a new typed instance + math.typed = typed.create(math.type); - // merge options - object.deepExtend(config, options); + // create configuration options. These are private + var _config = { + // minimum relative difference between two compared values, + // used by all comparison functions + epsilon: 1e-12, - var curr = object.map(config, object.clone); + // type of default matrix output. Choose 'matrix' (default) or 'array' + matrix: 'Matrix', - var changes = object.map(options, object.clone); + // type of default number output. Choose 'number' (default) 'BigNumber', or 'Fraction + number: 'number', - // emit 'config' event - math.emit('config', curr, prev, changes); + // number of significant digits in BigNumbers + precision: 64, - return curr; - } - else { - return object.map(config, object.clone); - } - } - - // attach the valid options to the function so they can be extended - _config.MATRIX = MATRIX; - _config.NUMBER = NUMBER; - - return _config; -} - -/** - * Test whether an Array contains a specific item. - * @param {Array.} array - * @param {string} item - * @return {boolean} - */ -function contains (array, item) { - return array.indexOf(item) !== -1; -} - -/** - * Find a string in an array. Case insensitive search - * @param {Array.} array - * @param {string} item - * @return {number} Returns the index when found. Returns -1 when not found - */ -function findIndex (array, item) { - return array - .map(function (i) { - return i.toLowerCase(); - }) - .indexOf(item.toLowerCase()); -} - -/** - * Validate an option - * @param {Object} options Object with options - * @param {string} name Name of the option to validate - * @param {Array.} values Array with valid values for this option - */ -function validateOption(options, name, values) { - if (options[name] !== undefined && !contains(values, options[name])) { - var index = findIndex(values, options[name]); - if (index !== -1) { - // right value, wrong casing - // TODO: lower case values are deprecated since v3, remove this warning some day. - console.warn('Warning: Wrong casing for configuration option "' + name + '", should be "' + values[index] + '" instead of "' + options[name] + '".'); - - options[name] = values[index]; // change the option to the right casing - } - else { - // unknown value - console.warn('Warning: Unknown value "' + options[name] + '" for configuration option "' + name + '". Available options: ' + values.map(JSON.stringify).join(', ') + '.'); - } - } -} - -var name$1 = 'config'; -var math$1 = true; // request the math namespace as fifth argument -var factory_1$1 = factory$1; - -var config = { - name: name$1, - math: math$1, - factory: factory_1$1 -}; - -var isFactory$1 = object.isFactory; - - - - - - -/** - * Math.js core. Creates a new, empty math.js instance - * @param {Object} [options] Available options: - * {number} epsilon - * Minimum relative difference between two - * compared values, used by all comparison functions. - * {string} matrix - * A string 'Matrix' (default) or 'Array'. - * {string} number - * A string 'number' (default), 'BigNumber', or 'Fraction' - * {number} precision - * The number of significant digits for BigNumbers. - * Not applicable for Numbers. - * {boolean} predictable - * Predictable output type of functions. When true, - * output type depends only on the input types. When - * false (default), output type can vary depending - * on input values. For example `math.sqrt(-4)` - * returns `complex('2i')` when predictable is false, and - * returns `NaN` when true. - * {string} randomSeed - * Random seed for seeded pseudo random number generator. - * Set to null to randomly seed. - * @returns {Object} Returns a bare-bone math.js instance containing - * functions: - * - `import` to add new functions - * - `config` to change configuration - * - `on`, `off`, `once`, `emit` for events - */ -var create$1 = function create (options) { - // 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.'); - } - - // cached factories and instances - var factories = []; - var instances = []; - - // create a namespace for the mathjs instance, and attach emitter functions - var math = emitter.mixin({}); - math.type = {}; - math.expression = { - transform: {}, - mathWithTransform: {} - }; - - // create a new typed instance - math.typed = typed.create(math.type); - - // create configuration options. These are private - var _config = { - // minimum relative difference between two compared values, - // used by all comparison functions - epsilon: 1e-12, - - // type of default matrix output. Choose 'matrix' (default) or 'array' - matrix: 'Matrix', - - // type of default number output. Choose 'number' (default) 'BigNumber', or 'Fraction - number: 'number', - - // number of significant digits in BigNumbers - precision: 64, - - // predictable output type of functions. When true, output type depends only - // on the input types. When false (default), output type can vary depending - // on input values. For example `math.sqrt(-4)` returns `complex('2i')` when - // predictable is false, and returns `NaN` when true. - predictable: false, - - // random seed for seeded pseudo random number generation - // null = randomly seed - randomSeed: null - }; + // predictable output type of functions. When true, output type depends only + // on the input types. When false (default), output type can vary depending + // on input values. For example `math.sqrt(-4)` returns `complex('2i')` when + // predictable is false, and returns `NaN` when true. + predictable: false, - /** - * Load a function or data type from a factory. - * If the function or data type already exists, the existing instance is - * returned. - * @param {{type: string, name: string, factory: Function}} factory - * @returns {*} - */ - function load (factory) { - if (!isFactory$1(factory)) { - throw new Error('Factory object with properties `type`, `name`, and `factory` expected'); - } + // random seed for seeded pseudo random number generation + // null = randomly seed + randomSeed: null + }; + + /** + * Load a function or data type from a factory. + * If the function or data type already exists, the existing instance is + * returned. + * @param {{type: string, name: string, factory: Function}} factory + * @returns {*} + */ + function load (factory) { + if (!isFactory$1(factory)) { + throw new Error('Factory object with properties `type`, `name`, and `factory` expected'); + } + + var index = factories.indexOf(factory); + var instance; + if (index === -1) { + // doesn't yet exist + if (factory.math === true) { + // pass with math namespace + instance = factory.factory(math.type, _config, load, math.typed, math); + } + else { + instance = factory.factory(math.type, _config, load, math.typed); + } - var index = factories.indexOf(factory); - var instance; - if (index === -1) { - // doesn't yet exist - if (factory.math === true) { - // pass with math namespace - instance = factory.factory(math.type, _config, load, math.typed, math); + // append to the cache + factories.push(factory); + instances.push(instance); } else { - instance = factory.factory(math.type, _config, load, math.typed); + // already existing function, return the cached instance + instance = instances[index]; } - // append to the cache - factories.push(factory); - instances.push(instance); + return instance; } - else { - // already existing function, return the cached instance - instance = instances[index]; - } - - return instance; - } - // load the import and config functions - math['import'] = load(_import); - math['config'] = load(config); - math.expression.mathWithTransform['config'] = math['config']; + // load the import and config functions + math['import'] = load(_import); + math['config'] = load(config); + math.expression.mathWithTransform['config'] = math['config']; - // apply options - if (options) { - math.config(options); - } + // apply options + if (options) { + math.config(options); + } - return math; -}; + return math; + }; -var core = { - create: create$1 -}; + var core = { + create: create$1 + }; -var core$1 = core; + var core$1 = core; -var decimal = createCommonjsModule(function (module) { -(function (globalScope) { + var decimal = createCommonjsModule(function (module) { + (function (globalScope) { - /* - * decimal.js v9.0.1 - * An arbitrary-precision Decimal type for JavaScript. - * https://github.com/MikeMcl/decimal.js - * Copyright (c) 2017 Michael Mclaughlin - * MIT Licence - */ + /* + * decimal.js v9.0.1 + * An arbitrary-precision Decimal type for JavaScript. + * https://github.com/MikeMcl/decimal.js + * Copyright (c) 2017 Michael Mclaughlin + * MIT Licence + */ - // ----------------------------------- EDITABLE DEFAULTS ------------------------------------ // + // ----------------------------------- EDITABLE DEFAULTS ------------------------------------ // - // The maximum exponent magnitude. - // The limit on the value of `toExpNeg`, `toExpPos`, `minE` and `maxE`. - var EXP_LIMIT = 9e15, // 0 to 9e15 + // The maximum exponent magnitude. + // The limit on the value of `toExpNeg`, `toExpPos`, `minE` and `maxE`. + var EXP_LIMIT = 9e15, // 0 to 9e15 - // The limit on the value of `precision`, and on the value of the first argument to - // `toDecimalPlaces`, `toExponential`, `toFixed`, `toPrecision` and `toSignificantDigits`. - MAX_DIGITS = 1e9, // 0 to 1e9 + // The limit on the value of `precision`, and on the value of the first argument to + // `toDecimalPlaces`, `toExponential`, `toFixed`, `toPrecision` and `toSignificantDigits`. + MAX_DIGITS = 1e9, // 0 to 1e9 - // Base conversion alphabet. - NUMERALS = '0123456789abcdef', + // Base conversion alphabet. + NUMERALS = '0123456789abcdef', - // The natural logarithm of 10 (1025 digits). - LN10 = '2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058', + // The natural logarithm of 10 (1025 digits). + LN10 = '2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058', - // Pi (1025 digits). - PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789', + // Pi (1025 digits). + PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789', - // The initial configuration properties of the Decimal constructor. - DEFAULTS = { + // The initial configuration properties of the Decimal constructor. + DEFAULTS = { - // These values must be integers within the stated ranges (inclusive). - // Most of these values can be changed at run-time using the `Decimal.config` method. + // These values must be integers within the stated ranges (inclusive). + // Most of these values can be changed at run-time using the `Decimal.config` method. - // The maximum number of significant digits of the result of a calculation or base conversion. - // E.g. `Decimal.config({ precision: 20 });` - precision: 20, // 1 to MAX_DIGITS + // The maximum number of significant digits of the result of a calculation or base conversion. + // E.g. `Decimal.config({ precision: 20 });` + precision: 20, // 1 to MAX_DIGITS - // The rounding mode used when rounding to `precision`. - // - // ROUND_UP 0 Away from zero. - // ROUND_DOWN 1 Towards zero. - // ROUND_CEIL 2 Towards +Infinity. - // ROUND_FLOOR 3 Towards -Infinity. - // ROUND_HALF_UP 4 Towards nearest neighbour. If equidistant, up. - // ROUND_HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. - // ROUND_HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. - // ROUND_HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. - // ROUND_HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. - // - // E.g. - // `Decimal.rounding = 4;` - // `Decimal.rounding = Decimal.ROUND_HALF_UP;` - rounding: 4, // 0 to 8 - - // The modulo mode used when calculating the modulus: a mod n. - // The quotient (q = a / n) is calculated according to the corresponding rounding mode. - // The remainder (r) is calculated as: r = a - n * q. - // - // UP 0 The remainder is positive if the dividend is negative, else is negative. - // DOWN 1 The remainder has the same sign as the dividend (JavaScript %). - // FLOOR 3 The remainder has the same sign as the divisor (Python %). - // HALF_EVEN 6 The IEEE 754 remainder function. - // EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). Always positive. - // - // Truncated division (1), floored division (3), the IEEE 754 remainder (6), and Euclidian - // division (9) are commonly used for the modulus operation. The other rounding modes can also - // be used, but they may not give useful results. - modulo: 1, // 0 to 9 + // The rounding mode used when rounding to `precision`. + // + // ROUND_UP 0 Away from zero. + // ROUND_DOWN 1 Towards zero. + // ROUND_CEIL 2 Towards +Infinity. + // ROUND_FLOOR 3 Towards -Infinity. + // ROUND_HALF_UP 4 Towards nearest neighbour. If equidistant, up. + // ROUND_HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. + // ROUND_HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. + // ROUND_HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. + // ROUND_HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. + // + // E.g. + // `Decimal.rounding = 4;` + // `Decimal.rounding = Decimal.ROUND_HALF_UP;` + rounding: 4, // 0 to 8 - // The exponent value at and beneath which `toString` returns exponential notation. - // JavaScript numbers: -7 - toExpNeg: -7, // 0 to -EXP_LIMIT + // The modulo mode used when calculating the modulus: a mod n. + // The quotient (q = a / n) is calculated according to the corresponding rounding mode. + // The remainder (r) is calculated as: r = a - n * q. + // + // UP 0 The remainder is positive if the dividend is negative, else is negative. + // DOWN 1 The remainder has the same sign as the dividend (JavaScript %). + // FLOOR 3 The remainder has the same sign as the divisor (Python %). + // HALF_EVEN 6 The IEEE 754 remainder function. + // EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). Always positive. + // + // Truncated division (1), floored division (3), the IEEE 754 remainder (6), and Euclidian + // division (9) are commonly used for the modulus operation. The other rounding modes can also + // be used, but they may not give useful results. + modulo: 1, // 0 to 9 - // The exponent value at and above which `toString` returns exponential notation. - // JavaScript numbers: 21 - toExpPos: 21, // 0 to EXP_LIMIT + // The exponent value at and beneath which `toString` returns exponential notation. + // JavaScript numbers: -7 + toExpNeg: -7, // 0 to -EXP_LIMIT - // The minimum exponent value, beneath which underflow to zero occurs. - // JavaScript numbers: -324 (5e-324) - minE: -EXP_LIMIT, // -1 to -EXP_LIMIT + // The exponent value at and above which `toString` returns exponential notation. + // JavaScript numbers: 21 + toExpPos: 21, // 0 to EXP_LIMIT - // The maximum exponent value, above which overflow to Infinity occurs. - // JavaScript numbers: 308 (1.7976931348623157e+308) - maxE: EXP_LIMIT, // 1 to EXP_LIMIT + // The minimum exponent value, beneath which underflow to zero occurs. + // JavaScript numbers: -324 (5e-324) + minE: -EXP_LIMIT, // -1 to -EXP_LIMIT - // Whether to use cryptographically-secure random number generation, if available. - crypto: false // true/false - }, + // The maximum exponent value, above which overflow to Infinity occurs. + // JavaScript numbers: 308 (1.7976931348623157e+308) + maxE: EXP_LIMIT, // 1 to EXP_LIMIT + // Whether to use cryptographically-secure random number generation, if available. + crypto: false // true/false + }, - // ----------------------------------- END OF EDITABLE DEFAULTS ------------------------------- // + // ----------------------------------- END OF EDITABLE DEFAULTS ------------------------------- // - Decimal, inexact, noConflict, quadrant, - external = true, - decimalError = '[DecimalError] ', - invalidArgument = decimalError + 'Invalid argument: ', - precisionLimitExceeded = decimalError + 'Precision limit exceeded', - cryptoUnavailable = decimalError + 'crypto unavailable', + Decimal, inexact, noConflict, quadrant, + external = true, - mathfloor = Math.floor, - mathpow = Math.pow, + decimalError = '[DecimalError] ', + invalidArgument = decimalError + 'Invalid argument: ', + precisionLimitExceeded = decimalError + 'Precision limit exceeded', + cryptoUnavailable = decimalError + 'crypto unavailable', - isBinary = /^0b([01]+(\.[01]*)?|\.[01]+)(p[+-]?\d+)?$/i, - isHex = /^0x([0-9a-f]+(\.[0-9a-f]*)?|\.[0-9a-f]+)(p[+-]?\d+)?$/i, - isOctal = /^0o([0-7]+(\.[0-7]*)?|\.[0-7]+)(p[+-]?\d+)?$/i, - isDecimal = /^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i, + mathfloor = Math.floor, + mathpow = Math.pow, - BASE = 1e7, - LOG_BASE = 7, - MAX_SAFE_INTEGER = 9007199254740991, + isBinary = /^0b([01]+(\.[01]*)?|\.[01]+)(p[+-]?\d+)?$/i, + isHex = /^0x([0-9a-f]+(\.[0-9a-f]*)?|\.[0-9a-f]+)(p[+-]?\d+)?$/i, + isOctal = /^0o([0-7]+(\.[0-7]*)?|\.[0-7]+)(p[+-]?\d+)?$/i, + isDecimal = /^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i, - LN10_PRECISION = LN10.length - 1, - PI_PRECISION = PI.length - 1, + BASE = 1e7, + LOG_BASE = 7, + MAX_SAFE_INTEGER = 9007199254740991, - // Decimal.prototype object - P = { name: '[object Decimal]' }; + LN10_PRECISION = LN10.length - 1, + PI_PRECISION = PI.length - 1, + // Decimal.prototype object + P = { name: '[object Decimal]' }; - // Decimal prototype methods + // Decimal prototype methods - /* - * absoluteValue abs - * ceil - * comparedTo cmp - * cosine cos - * cubeRoot cbrt - * decimalPlaces dp - * dividedBy div - * dividedToIntegerBy divToInt - * equals eq - * floor - * greaterThan gt - * greaterThanOrEqualTo gte - * hyperbolicCosine cosh - * hyperbolicSine sinh - * hyperbolicTangent tanh - * inverseCosine acos - * inverseHyperbolicCosine acosh - * inverseHyperbolicSine asinh - * inverseHyperbolicTangent atanh - * inverseSine asin - * inverseTangent atan - * isFinite - * isInteger isInt - * isNaN - * isNegative isNeg - * isPositive isPos - * isZero - * lessThan lt - * lessThanOrEqualTo lte - * logarithm log - * [maximum] [max] - * [minimum] [min] - * minus sub - * modulo mod - * naturalExponential exp - * naturalLogarithm ln - * negated neg - * plus add - * precision sd - * round - * sine sin - * squareRoot sqrt - * tangent tan - * times mul - * toBinary - * toDecimalPlaces toDP - * toExponential - * toFixed - * toFraction - * toHexadecimal toHex - * toNearest - * toNumber - * toOctal - * toPower pow - * toPrecision - * toSignificantDigits toSD - * toString - * truncated trunc - * valueOf toJSON - */ + /* + * absoluteValue abs + * ceil + * comparedTo cmp + * cosine cos + * cubeRoot cbrt + * decimalPlaces dp + * dividedBy div + * dividedToIntegerBy divToInt + * equals eq + * floor + * greaterThan gt + * greaterThanOrEqualTo gte + * hyperbolicCosine cosh + * hyperbolicSine sinh + * hyperbolicTangent tanh + * inverseCosine acos + * inverseHyperbolicCosine acosh + * inverseHyperbolicSine asinh + * inverseHyperbolicTangent atanh + * inverseSine asin + * inverseTangent atan + * isFinite + * isInteger isInt + * isNaN + * isNegative isNeg + * isPositive isPos + * isZero + * lessThan lt + * lessThanOrEqualTo lte + * logarithm log + * [maximum] [max] + * [minimum] [min] + * minus sub + * modulo mod + * naturalExponential exp + * naturalLogarithm ln + * negated neg + * plus add + * precision sd + * round + * sine sin + * squareRoot sqrt + * tangent tan + * times mul + * toBinary + * toDecimalPlaces toDP + * toExponential + * toFixed + * toFraction + * toHexadecimal toHex + * toNearest + * toNumber + * toOctal + * toPower pow + * toPrecision + * toSignificantDigits toSD + * toString + * truncated trunc + * valueOf toJSON + */ - /* - * Return a new Decimal whose value is the absolute value of this Decimal. - * - */ - P.absoluteValue = P.abs = function () { - var x = new this.constructor(this); - if (x.s < 0) x.s = 1; - return finalise(x); - }; + /* + * Return a new Decimal whose value is the absolute value of this Decimal. + * + */ + P.absoluteValue = P.abs = function () { + var x = new this.constructor(this); + if (x.s < 0) x.s = 1; + return finalise(x); + }; - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a whole number in the - * direction of positive Infinity. - * - */ - P.ceil = function () { - return finalise(new this.constructor(this), this.e + 1, 2); - }; + /* + * Return a new Decimal whose value is the value of this Decimal rounded to a whole number in the + * direction of positive Infinity. + * + */ + P.ceil = function () { + return finalise(new this.constructor(this), this.e + 1, 2); + }; - /* - * Return - * 1 if the value of this Decimal is greater than the value of `y`, - * -1 if the value of this Decimal is less than the value of `y`, - * 0 if they have the same value, - * NaN if the value of either Decimal is NaN. - * - */ - P.comparedTo = P.cmp = function (y) { - var i, j, xdL, ydL, - x = this, - xd = x.d, - yd = (y = new x.constructor(y)).d, - xs = x.s, - ys = y.s; - - // Either NaN or ±Infinity? - if (!xd || !yd) { - return !xs || !ys ? NaN : xs !== ys ? xs : xd === yd ? 0 : !xd ^ xs < 0 ? 1 : -1; - } - // Either zero? - if (!xd[0] || !yd[0]) return xd[0] ? xs : yd[0] ? -ys : 0; + /* + * Return + * 1 if the value of this Decimal is greater than the value of `y`, + * -1 if the value of this Decimal is less than the value of `y`, + * 0 if they have the same value, + * NaN if the value of either Decimal is NaN. + * + */ + P.comparedTo = P.cmp = function (y) { + var i, j, xdL, ydL, + x = this, + xd = x.d, + yd = (y = new x.constructor(y)).d, + xs = x.s, + ys = y.s; - // Signs differ? - if (xs !== ys) return xs; + // Either NaN or ±Infinity? + if (!xd || !yd) { + return !xs || !ys ? NaN : xs !== ys ? xs : xd === yd ? 0 : !xd ^ xs < 0 ? 1 : -1; + } - // Compare exponents. - if (x.e !== y.e) return x.e > y.e ^ xs < 0 ? 1 : -1; + // Either zero? + if (!xd[0] || !yd[0]) return xd[0] ? xs : yd[0] ? -ys : 0; - xdL = xd.length; - ydL = yd.length; + // Signs differ? + if (xs !== ys) return xs; - // Compare digit by digit. - for (i = 0, j = xdL < ydL ? xdL : ydL; i < j; ++i) { - if (xd[i] !== yd[i]) return xd[i] > yd[i] ^ xs < 0 ? 1 : -1; - } + // Compare exponents. + if (x.e !== y.e) return x.e > y.e ^ xs < 0 ? 1 : -1; - // Compare lengths. - return xdL === ydL ? 0 : xdL > ydL ^ xs < 0 ? 1 : -1; - }; + xdL = xd.length; + ydL = yd.length; + // Compare digit by digit. + for (i = 0, j = xdL < ydL ? xdL : ydL; i < j; ++i) { + if (xd[i] !== yd[i]) return xd[i] > yd[i] ^ xs < 0 ? 1 : -1; + } - /* - * Return a new Decimal whose value is the cosine of the value in radians of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-1, 1] - * - * cos(0) = 1 - * cos(-0) = 1 - * cos(Infinity) = NaN - * cos(-Infinity) = NaN - * cos(NaN) = NaN - * - */ - P.cosine = P.cos = function () { - var pr, rm, - x = this, - Ctor = x.constructor; + // Compare lengths. + return xdL === ydL ? 0 : xdL > ydL ^ xs < 0 ? 1 : -1; + }; - if (!x.d) return new Ctor(NaN); - // cos(0) = cos(-0) = 1 - if (!x.d[0]) return new Ctor(1); + /* + * Return a new Decimal whose value is the cosine of the value in radians of this Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [-1, 1] + * + * cos(0) = 1 + * cos(-0) = 1 + * cos(Infinity) = NaN + * cos(-Infinity) = NaN + * cos(NaN) = NaN + * + */ + P.cosine = P.cos = function () { + var pr, rm, + x = this, + Ctor = x.constructor; + + if (!x.d) return new Ctor(NaN); - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(x.e, x.sd()) + LOG_BASE; - Ctor.rounding = 1; + // cos(0) = cos(-0) = 1 + if (!x.d[0]) return new Ctor(1); - x = cosine(Ctor, toLessThanHalfPi(Ctor, x)); + pr = Ctor.precision; + rm = Ctor.rounding; + Ctor.precision = pr + Math.max(x.e, x.sd()) + LOG_BASE; + Ctor.rounding = 1; - Ctor.precision = pr; - Ctor.rounding = rm; + x = cosine(Ctor, toLessThanHalfPi(Ctor, x)); - return finalise(quadrant == 2 || quadrant == 3 ? x.neg() : x, pr, rm, true); - }; + Ctor.precision = pr; + Ctor.rounding = rm; + return finalise(quadrant == 2 || quadrant == 3 ? x.neg() : x, pr, rm, true); + }; - /* - * - * Return a new Decimal whose value is the cube root of the value of this Decimal, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * cbrt(0) = 0 - * cbrt(-0) = -0 - * cbrt(1) = 1 - * cbrt(-1) = -1 - * cbrt(N) = N - * cbrt(-I) = -I - * cbrt(I) = I - * - * Math.cbrt(x) = (x < 0 ? -Math.pow(-x, 1/3) : Math.pow(x, 1/3)) - * - */ - P.cubeRoot = P.cbrt = function () { - var e, m, n, r, rep, s, sd, t, t3, t3plusx, - x = this, - Ctor = x.constructor; - if (!x.isFinite() || x.isZero()) return new Ctor(x); - external = false; + /* + * + * Return a new Decimal whose value is the cube root of the value of this Decimal, rounded to + * `precision` significant digits using rounding mode `rounding`. + * + * cbrt(0) = 0 + * cbrt(-0) = -0 + * cbrt(1) = 1 + * cbrt(-1) = -1 + * cbrt(N) = N + * cbrt(-I) = -I + * cbrt(I) = I + * + * Math.cbrt(x) = (x < 0 ? -Math.pow(-x, 1/3) : Math.pow(x, 1/3)) + * + */ + P.cubeRoot = P.cbrt = function () { + var e, m, n, r, rep, s, sd, t, t3, t3plusx, + x = this, + Ctor = x.constructor; + + if (!x.isFinite() || x.isZero()) return new Ctor(x); + external = false; - // Initial estimate. - s = x.s * Math.pow(x.s * x, 1 / 3); + // Initial estimate. + s = x.s * Math.pow(x.s * x, 1 / 3); - // Math.cbrt underflow/overflow? - // Pass x to Math.pow as integer, then adjust the exponent of the result. - if (!s || Math.abs(s) == 1 / 0) { - n = digitsToString(x.d); - e = x.e; + // Math.cbrt underflow/overflow? + // Pass x to Math.pow as integer, then adjust the exponent of the result. + if (!s || Math.abs(s) == 1 / 0) { + n = digitsToString(x.d); + e = x.e; - // Adjust n exponent so it is a multiple of 3 away from x exponent. - if (s = (e - n.length + 1) % 3) n += (s == 1 || s == -2 ? '0' : '00'); - s = Math.pow(n, 1 / 3); + // Adjust n exponent so it is a multiple of 3 away from x exponent. + if (s = (e - n.length + 1) % 3) n += (s == 1 || s == -2 ? '0' : '00'); + s = Math.pow(n, 1 / 3); - // Rarely, e may be one less than the result exponent value. - e = mathfloor((e + 1) / 3) - (e % 3 == (e < 0 ? -1 : 2)); + // Rarely, e may be one less than the result exponent value. + e = mathfloor((e + 1) / 3) - (e % 3 == (e < 0 ? -1 : 2)); - if (s == 1 / 0) { - n = '5e' + e; + if (s == 1 / 0) { + n = '5e' + e; + } else { + n = s.toExponential(); + n = n.slice(0, n.indexOf('e') + 1) + e; + } + + r = new Ctor(n); + r.s = x.s; } else { - n = s.toExponential(); - n = n.slice(0, n.indexOf('e') + 1) + e; + r = new Ctor(s.toString()); } - r = new Ctor(n); - r.s = x.s; - } else { - r = new Ctor(s.toString()); - } + sd = (e = Ctor.precision) + 3; - sd = (e = Ctor.precision) + 3; + // Halley's method. + // TODO? Compare Newton's method. + for (;;) { + t = r; + t3 = t.times(t).times(t); + t3plusx = t3.plus(x); + r = divide(t3plusx.plus(x).times(t), t3plusx.plus(t3), sd + 2, 1); - // Halley's method. - // TODO? Compare Newton's method. - for (;;) { - t = r; - t3 = t.times(t).times(t); - t3plusx = t3.plus(x); - r = divide(t3plusx.plus(x).times(t), t3plusx.plus(t3), sd + 2, 1); + // TODO? Replace with for-loop and checkRoundingDigits. + if (digitsToString(t.d).slice(0, sd) === (n = digitsToString(r.d)).slice(0, sd)) { + n = n.slice(sd - 3, sd + 1); - // TODO? Replace with for-loop and checkRoundingDigits. - if (digitsToString(t.d).slice(0, sd) === (n = digitsToString(r.d)).slice(0, sd)) { - n = n.slice(sd - 3, sd + 1); + // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or 4999 + // , i.e. approaching a rounding boundary, continue the iteration. + if (n == '9999' || !rep && n == '4999') { - // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or 4999 - // , i.e. approaching a rounding boundary, continue the iteration. - if (n == '9999' || !rep && n == '4999') { + // On the first iteration only, check to see if rounding up gives the exact result as the + // nines may infinitely repeat. + if (!rep) { + finalise(t, e + 1, 0); - // On the first iteration only, check to see if rounding up gives the exact result as the - // nines may infinitely repeat. - if (!rep) { - finalise(t, e + 1, 0); - - if (t.times(t).times(t).eq(x)) { - r = t; - break; + if (t.times(t).times(t).eq(x)) { + r = t; + break; + } } - } - sd += 4; - rep = 1; - } else { + sd += 4; + rep = 1; + } else { - // If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result. - // If not, then there are further digits and m will be truthy. - if (!+n || !+n.slice(1) && n.charAt(0) == '5') { + // If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result. + // If not, then there are further digits and m will be truthy. + if (!+n || !+n.slice(1) && n.charAt(0) == '5') { - // Truncate to the first rounding digit. - finalise(r, e + 1, 1); - m = !r.times(r).times(r).eq(x); - } + // Truncate to the first rounding digit. + finalise(r, e + 1, 1); + m = !r.times(r).times(r).eq(x); + } - break; + break; + } } } - } - - external = true; - - return finalise(r, e, Ctor.rounding, m); - }; - - - /* - * Return the number of decimal places of the value of this Decimal. - * - */ - P.decimalPlaces = P.dp = function () { - var w, - d = this.d, - n = NaN; - - if (d) { - w = d.length - 1; - n = (w - mathfloor(this.e / LOG_BASE)) * LOG_BASE; - - // Subtract the number of trailing zeros of the last word. - w = d[w]; - if (w) for (; w % 10 == 0; w /= 10) n--; - if (n < 0) n = 0; - } - - return n; - }; - - - /* - * n / 0 = I - * n / N = N - * n / I = 0 - * 0 / n = 0 - * 0 / 0 = N - * 0 / N = N - * 0 / I = 0 - * N / n = N - * N / 0 = N - * N / N = N - * N / I = N - * I / n = I - * I / 0 = I - * I / N = N - * I / I = N - * - * Return a new Decimal whose value is the value of this Decimal divided by `y`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - */ - P.dividedBy = P.div = function (y) { - return divide(this, new this.constructor(y)); - }; + external = true; - /* - * Return a new Decimal whose value is the integer part of dividing the value of this Decimal - * by the value of `y`, rounded to `precision` significant digits using rounding mode `rounding`. - * - */ - P.dividedToIntegerBy = P.divToInt = function (y) { - var x = this, - Ctor = x.constructor; - return finalise(divide(x, new Ctor(y), 0, 1, 1), Ctor.precision, Ctor.rounding); - }; + return finalise(r, e, Ctor.rounding, m); + }; - /* - * Return true if the value of this Decimal is equal to the value of `y`, otherwise return false. - * - */ - P.equals = P.eq = function (y) { - return this.cmp(y) === 0; - }; + /* + * Return the number of decimal places of the value of this Decimal. + * + */ + P.decimalPlaces = P.dp = function () { + var w, + d = this.d, + n = NaN; + + if (d) { + w = d.length - 1; + n = (w - mathfloor(this.e / LOG_BASE)) * LOG_BASE; + + // Subtract the number of trailing zeros of the last word. + w = d[w]; + if (w) for (; w % 10 == 0; w /= 10) n--; + if (n < 0) n = 0; + } + return n; + }; - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a whole number in the - * direction of negative Infinity. - * - */ - P.floor = function () { - return finalise(new this.constructor(this), this.e + 1, 3); - }; + /* + * n / 0 = I + * n / N = N + * n / I = 0 + * 0 / n = 0 + * 0 / 0 = N + * 0 / N = N + * 0 / I = 0 + * N / n = N + * N / 0 = N + * N / N = N + * N / I = N + * I / n = I + * I / 0 = I + * I / N = N + * I / I = N + * + * Return a new Decimal whose value is the value of this Decimal divided by `y`, rounded to + * `precision` significant digits using rounding mode `rounding`. + * + */ + P.dividedBy = P.div = function (y) { + return divide(this, new this.constructor(y)); + }; - /* - * Return true if the value of this Decimal is greater than the value of `y`, otherwise return - * false. - * - */ - P.greaterThan = P.gt = function (y) { - return this.cmp(y) > 0; - }; + /* + * Return a new Decimal whose value is the integer part of dividing the value of this Decimal + * by the value of `y`, rounded to `precision` significant digits using rounding mode `rounding`. + * + */ + P.dividedToIntegerBy = P.divToInt = function (y) { + var x = this, + Ctor = x.constructor; + return finalise(divide(x, new Ctor(y), 0, 1, 1), Ctor.precision, Ctor.rounding); + }; - /* - * Return true if the value of this Decimal is greater than or equal to the value of `y`, - * otherwise return false. - * - */ - P.greaterThanOrEqualTo = P.gte = function (y) { - var k = this.cmp(y); - return k == 1 || k === 0; - }; + /* + * Return true if the value of this Decimal is equal to the value of `y`, otherwise return false. + * + */ + P.equals = P.eq = function (y) { + return this.cmp(y) === 0; + }; - /* - * Return a new Decimal whose value is the hyperbolic cosine of the value in radians of this - * Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [1, Infinity] - * - * cosh(x) = 1 + x^2/2! + x^4/4! + x^6/6! + ... - * - * cosh(0) = 1 - * cosh(-0) = 1 - * cosh(Infinity) = Infinity - * cosh(-Infinity) = Infinity - * cosh(NaN) = NaN - * - * x time taken (ms) result - * 1000 9 9.8503555700852349694e+433 - * 10000 25 4.4034091128314607936e+4342 - * 100000 171 1.4033316802130615897e+43429 - * 1000000 3817 1.5166076984010437725e+434294 - * 10000000 abandoned after 2 minute wait - * - * TODO? Compare performance of cosh(x) = 0.5 * (exp(x) + exp(-x)) - * - */ - P.hyperbolicCosine = P.cosh = function () { - var k, n, pr, rm, len, - x = this, - Ctor = x.constructor, - one = new Ctor(1); - - if (!x.isFinite()) return new Ctor(x.s ? 1 / 0 : NaN); - if (x.isZero()) return one; - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(x.e, x.sd()) + 4; - Ctor.rounding = 1; - len = x.d.length; - - // Argument reduction: cos(4x) = 1 - 8cos^2(x) + 8cos^4(x) + 1 - // i.e. cos(x) = 1 - cos^2(x/4)(8 - 8cos^2(x/4)) - - // Estimate the optimum number of times to use the argument reduction. - // TODO? Estimation reused from cosine() and may not be optimal here. - if (len < 32) { - k = Math.ceil(len / 3); - n = Math.pow(4, -k).toString(); - } else { - k = 16; - n = '2.3283064365386962890625e-10'; - } - x = taylorSeries(Ctor, 1, x.times(n), new Ctor(1), true); + /* + * Return a new Decimal whose value is the value of this Decimal rounded to a whole number in the + * direction of negative Infinity. + * + */ + P.floor = function () { + return finalise(new this.constructor(this), this.e + 1, 3); + }; - // Reverse argument reduction - var cosh2_x, - i = k, - d8 = new Ctor(8); - for (; i--;) { - cosh2_x = x.times(x); - x = one.minus(cosh2_x.times(d8.minus(cosh2_x.times(d8)))); - } - return finalise(x, Ctor.precision = pr, Ctor.rounding = rm, true); - }; + /* + * Return true if the value of this Decimal is greater than the value of `y`, otherwise return + * false. + * + */ + P.greaterThan = P.gt = function (y) { + return this.cmp(y) > 0; + }; - /* - * Return a new Decimal whose value is the hyperbolic sine of the value in radians of this - * Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-Infinity, Infinity] - * - * sinh(x) = x + x^3/3! + x^5/5! + x^7/7! + ... - * - * sinh(0) = 0 - * sinh(-0) = -0 - * sinh(Infinity) = Infinity - * sinh(-Infinity) = -Infinity - * sinh(NaN) = NaN - * - * x time taken (ms) - * 10 2 ms - * 100 5 ms - * 1000 14 ms - * 10000 82 ms - * 100000 886 ms 1.4033316802130615897e+43429 - * 200000 2613 ms - * 300000 5407 ms - * 400000 8824 ms - * 500000 13026 ms 8.7080643612718084129e+217146 - * 1000000 48543 ms - * - * TODO? Compare performance of sinh(x) = 0.5 * (exp(x) - exp(-x)) - * - */ - P.hyperbolicSine = P.sinh = function () { - var k, pr, rm, len, - x = this, - Ctor = x.constructor; + /* + * Return true if the value of this Decimal is greater than or equal to the value of `y`, + * otherwise return false. + * + */ + P.greaterThanOrEqualTo = P.gte = function (y) { + var k = this.cmp(y); + return k == 1 || k === 0; + }; - if (!x.isFinite() || x.isZero()) return new Ctor(x); - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(x.e, x.sd()) + 4; - Ctor.rounding = 1; - len = x.d.length; + /* + * Return a new Decimal whose value is the hyperbolic cosine of the value in radians of this + * Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [1, Infinity] + * + * cosh(x) = 1 + x^2/2! + x^4/4! + x^6/6! + ... + * + * cosh(0) = 1 + * cosh(-0) = 1 + * cosh(Infinity) = Infinity + * cosh(-Infinity) = Infinity + * cosh(NaN) = NaN + * + * x time taken (ms) result + * 1000 9 9.8503555700852349694e+433 + * 10000 25 4.4034091128314607936e+4342 + * 100000 171 1.4033316802130615897e+43429 + * 1000000 3817 1.5166076984010437725e+434294 + * 10000000 abandoned after 2 minute wait + * + * TODO? Compare performance of cosh(x) = 0.5 * (exp(x) + exp(-x)) + * + */ + P.hyperbolicCosine = P.cosh = function () { + var k, n, pr, rm, len, + x = this, + Ctor = x.constructor, + one = new Ctor(1); - if (len < 3) { - x = taylorSeries(Ctor, 2, x, x, true); - } else { + if (!x.isFinite()) return new Ctor(x.s ? 1 / 0 : NaN); + if (x.isZero()) return one; - // Alternative argument reduction: sinh(3x) = sinh(x)(3 + 4sinh^2(x)) - // i.e. sinh(x) = sinh(x/3)(3 + 4sinh^2(x/3)) - // 3 multiplications and 1 addition + pr = Ctor.precision; + rm = Ctor.rounding; + Ctor.precision = pr + Math.max(x.e, x.sd()) + 4; + Ctor.rounding = 1; + len = x.d.length; - // Argument reduction: sinh(5x) = sinh(x)(5 + sinh^2(x)(20 + 16sinh^2(x))) - // i.e. sinh(x) = sinh(x/5)(5 + sinh^2(x/5)(20 + 16sinh^2(x/5))) - // 4 multiplications and 2 additions + // Argument reduction: cos(4x) = 1 - 8cos^2(x) + 8cos^4(x) + 1 + // i.e. cos(x) = 1 - cos^2(x/4)(8 - 8cos^2(x/4)) // Estimate the optimum number of times to use the argument reduction. - k = 1.4 * Math.sqrt(len); - k = k > 16 ? 16 : k | 0; - - x = x.times(Math.pow(5, -k)); + // TODO? Estimation reused from cosine() and may not be optimal here. + if (len < 32) { + k = Math.ceil(len / 3); + n = Math.pow(4, -k).toString(); + } else { + k = 16; + n = '2.3283064365386962890625e-10'; + } - x = taylorSeries(Ctor, 2, x, x, true); + x = taylorSeries(Ctor, 1, x.times(n), new Ctor(1), true); // Reverse argument reduction - var sinh2_x, - d5 = new Ctor(5), - d16 = new Ctor(16), - d20 = new Ctor(20); - for (; k--;) { - sinh2_x = x.times(x); - x = x.times(d5.plus(sinh2_x.times(d16.times(sinh2_x).plus(d20)))); + var cosh2_x, + i = k, + d8 = new Ctor(8); + for (; i--;) { + cosh2_x = x.times(x); + x = one.minus(cosh2_x.times(d8.minus(cosh2_x.times(d8)))); } - } - Ctor.precision = pr; - Ctor.rounding = rm; + return finalise(x, Ctor.precision = pr, Ctor.rounding = rm, true); + }; - return finalise(x, pr, rm, true); - }; + /* + * Return a new Decimal whose value is the hyperbolic sine of the value in radians of this + * Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [-Infinity, Infinity] + * + * sinh(x) = x + x^3/3! + x^5/5! + x^7/7! + ... + * + * sinh(0) = 0 + * sinh(-0) = -0 + * sinh(Infinity) = Infinity + * sinh(-Infinity) = -Infinity + * sinh(NaN) = NaN + * + * x time taken (ms) + * 10 2 ms + * 100 5 ms + * 1000 14 ms + * 10000 82 ms + * 100000 886 ms 1.4033316802130615897e+43429 + * 200000 2613 ms + * 300000 5407 ms + * 400000 8824 ms + * 500000 13026 ms 8.7080643612718084129e+217146 + * 1000000 48543 ms + * + * TODO? Compare performance of sinh(x) = 0.5 * (exp(x) - exp(-x)) + * + */ + P.hyperbolicSine = P.sinh = function () { + var k, pr, rm, len, + x = this, + Ctor = x.constructor; - /* - * Return a new Decimal whose value is the hyperbolic tangent of the value in radians of this - * Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-1, 1] - * - * tanh(x) = sinh(x) / cosh(x) - * - * tanh(0) = 0 - * tanh(-0) = -0 - * tanh(Infinity) = 1 - * tanh(-Infinity) = -1 - * tanh(NaN) = NaN - * - */ - P.hyperbolicTangent = P.tanh = function () { - var pr, rm, - x = this, - Ctor = x.constructor; + if (!x.isFinite() || x.isZero()) return new Ctor(x); - if (!x.isFinite()) return new Ctor(x.s); - if (x.isZero()) return new Ctor(x); + pr = Ctor.precision; + rm = Ctor.rounding; + Ctor.precision = pr + Math.max(x.e, x.sd()) + 4; + Ctor.rounding = 1; + len = x.d.length; - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + 7; - Ctor.rounding = 1; + if (len < 3) { + x = taylorSeries(Ctor, 2, x, x, true); + } else { - return divide(x.sinh(), x.cosh(), Ctor.precision = pr, Ctor.rounding = rm); - }; + // Alternative argument reduction: sinh(3x) = sinh(x)(3 + 4sinh^2(x)) + // i.e. sinh(x) = sinh(x/3)(3 + 4sinh^2(x/3)) + // 3 multiplications and 1 addition + // Argument reduction: sinh(5x) = sinh(x)(5 + sinh^2(x)(20 + 16sinh^2(x))) + // i.e. sinh(x) = sinh(x/5)(5 + sinh^2(x/5)(20 + 16sinh^2(x/5))) + // 4 multiplications and 2 additions - /* - * Return a new Decimal whose value is the arccosine (inverse cosine) in radians of the value of - * this Decimal. - * - * Domain: [-1, 1] - * Range: [0, pi] - * - * acos(x) = pi/2 - asin(x) - * - * acos(0) = pi/2 - * acos(-0) = pi/2 - * acos(1) = 0 - * acos(-1) = pi - * acos(1/2) = pi/3 - * acos(-1/2) = 2*pi/3 - * acos(|x| > 1) = NaN - * acos(NaN) = NaN - * - */ - P.inverseCosine = P.acos = function () { - var halfPi, - x = this, - Ctor = x.constructor, - k = x.abs().cmp(1), - pr = Ctor.precision, - rm = Ctor.rounding; + // Estimate the optimum number of times to use the argument reduction. + k = 1.4 * Math.sqrt(len); + k = k > 16 ? 16 : k | 0; - if (k !== -1) { - return k === 0 - // |x| is 1 - ? x.isNeg() ? getPi(Ctor, pr, rm) : new Ctor(0) - // |x| > 1 or x is NaN - : new Ctor(NaN); - } + x = x.times(Math.pow(5, -k)); - if (x.isZero()) return getPi(Ctor, pr + 4, rm).times(0.5); + x = taylorSeries(Ctor, 2, x, x, true); - // TODO? Special case acos(0.5) = pi/3 and acos(-0.5) = 2*pi/3 + // Reverse argument reduction + var sinh2_x, + d5 = new Ctor(5), + d16 = new Ctor(16), + d20 = new Ctor(20); + for (; k--;) { + sinh2_x = x.times(x); + x = x.times(d5.plus(sinh2_x.times(d16.times(sinh2_x).plus(d20)))); + } + } - Ctor.precision = pr + 6; - Ctor.rounding = 1; + Ctor.precision = pr; + Ctor.rounding = rm; - x = x.asin(); - halfPi = getPi(Ctor, pr + 4, rm).times(0.5); + return finalise(x, pr, rm, true); + }; - Ctor.precision = pr; - Ctor.rounding = rm; - return halfPi.minus(x); - }; + /* + * Return a new Decimal whose value is the hyperbolic tangent of the value in radians of this + * Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [-1, 1] + * + * tanh(x) = sinh(x) / cosh(x) + * + * tanh(0) = 0 + * tanh(-0) = -0 + * tanh(Infinity) = 1 + * tanh(-Infinity) = -1 + * tanh(NaN) = NaN + * + */ + P.hyperbolicTangent = P.tanh = function () { + var pr, rm, + x = this, + Ctor = x.constructor; + if (!x.isFinite()) return new Ctor(x.s); + if (x.isZero()) return new Ctor(x); - /* - * Return a new Decimal whose value is the inverse of the hyperbolic cosine in radians of the - * value of this Decimal. - * - * Domain: [1, Infinity] - * Range: [0, Infinity] - * - * acosh(x) = ln(x + sqrt(x^2 - 1)) - * - * acosh(x < 1) = NaN - * acosh(NaN) = NaN - * acosh(Infinity) = Infinity - * acosh(-Infinity) = NaN - * acosh(0) = NaN - * acosh(-0) = NaN - * acosh(1) = 0 - * acosh(-1) = NaN - * - */ - P.inverseHyperbolicCosine = P.acosh = function () { - var pr, rm, - x = this, - Ctor = x.constructor; + pr = Ctor.precision; + rm = Ctor.rounding; + Ctor.precision = pr + 7; + Ctor.rounding = 1; - if (x.lte(1)) return new Ctor(x.eq(1) ? 0 : NaN); - if (!x.isFinite()) return new Ctor(x); + return divide(x.sinh(), x.cosh(), Ctor.precision = pr, Ctor.rounding = rm); + }; - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(Math.abs(x.e), x.sd()) + 4; - Ctor.rounding = 1; - external = false; - x = x.times(x).minus(1).sqrt().plus(x); + /* + * Return a new Decimal whose value is the arccosine (inverse cosine) in radians of the value of + * this Decimal. + * + * Domain: [-1, 1] + * Range: [0, pi] + * + * acos(x) = pi/2 - asin(x) + * + * acos(0) = pi/2 + * acos(-0) = pi/2 + * acos(1) = 0 + * acos(-1) = pi + * acos(1/2) = pi/3 + * acos(-1/2) = 2*pi/3 + * acos(|x| > 1) = NaN + * acos(NaN) = NaN + * + */ + P.inverseCosine = P.acos = function () { + var halfPi, + x = this, + Ctor = x.constructor, + k = x.abs().cmp(1), + pr = Ctor.precision, + rm = Ctor.rounding; - external = true; - Ctor.precision = pr; - Ctor.rounding = rm; + if (k !== -1) { + return k === 0 + // |x| is 1 + ? x.isNeg() ? getPi(Ctor, pr, rm) : new Ctor(0) + // |x| > 1 or x is NaN + : new Ctor(NaN); + } - return x.ln(); - }; + if (x.isZero()) return getPi(Ctor, pr + 4, rm).times(0.5); + // TODO? Special case acos(0.5) = pi/3 and acos(-0.5) = 2*pi/3 - /* - * Return a new Decimal whose value is the inverse of the hyperbolic sine in radians of the value - * of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-Infinity, Infinity] - * - * asinh(x) = ln(x + sqrt(x^2 + 1)) - * - * asinh(NaN) = NaN - * asinh(Infinity) = Infinity - * asinh(-Infinity) = -Infinity - * asinh(0) = 0 - * asinh(-0) = -0 - * - */ - P.inverseHyperbolicSine = P.asinh = function () { - var pr, rm, - x = this, - Ctor = x.constructor; + Ctor.precision = pr + 6; + Ctor.rounding = 1; - if (!x.isFinite() || x.isZero()) return new Ctor(x); + x = x.asin(); + halfPi = getPi(Ctor, pr + 4, rm).times(0.5); - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + 2 * Math.max(Math.abs(x.e), x.sd()) + 6; - Ctor.rounding = 1; - external = false; + Ctor.precision = pr; + Ctor.rounding = rm; - x = x.times(x).plus(1).sqrt().plus(x); + return halfPi.minus(x); + }; - external = true; - Ctor.precision = pr; - Ctor.rounding = rm; - return x.ln(); - }; + /* + * Return a new Decimal whose value is the inverse of the hyperbolic cosine in radians of the + * value of this Decimal. + * + * Domain: [1, Infinity] + * Range: [0, Infinity] + * + * acosh(x) = ln(x + sqrt(x^2 - 1)) + * + * acosh(x < 1) = NaN + * acosh(NaN) = NaN + * acosh(Infinity) = Infinity + * acosh(-Infinity) = NaN + * acosh(0) = NaN + * acosh(-0) = NaN + * acosh(1) = 0 + * acosh(-1) = NaN + * + */ + P.inverseHyperbolicCosine = P.acosh = function () { + var pr, rm, + x = this, + Ctor = x.constructor; + if (x.lte(1)) return new Ctor(x.eq(1) ? 0 : NaN); + if (!x.isFinite()) return new Ctor(x); - /* - * Return a new Decimal whose value is the inverse of the hyperbolic tangent in radians of the - * value of this Decimal. - * - * Domain: [-1, 1] - * Range: [-Infinity, Infinity] - * - * atanh(x) = 0.5 * ln((1 + x) / (1 - x)) - * - * atanh(|x| > 1) = NaN - * atanh(NaN) = NaN - * atanh(Infinity) = NaN - * atanh(-Infinity) = NaN - * atanh(0) = 0 - * atanh(-0) = -0 - * atanh(1) = Infinity - * atanh(-1) = -Infinity - * - */ - P.inverseHyperbolicTangent = P.atanh = function () { - var pr, rm, wpr, xsd, - x = this, - Ctor = x.constructor; + pr = Ctor.precision; + rm = Ctor.rounding; + Ctor.precision = pr + Math.max(Math.abs(x.e), x.sd()) + 4; + Ctor.rounding = 1; + external = false; - if (!x.isFinite()) return new Ctor(NaN); - if (x.e >= 0) return new Ctor(x.abs().eq(1) ? x.s / 0 : x.isZero() ? x : NaN); + x = x.times(x).minus(1).sqrt().plus(x); - pr = Ctor.precision; - rm = Ctor.rounding; - xsd = x.sd(); + external = true; + Ctor.precision = pr; + Ctor.rounding = rm; - if (Math.max(xsd, pr) < 2 * -x.e - 1) return finalise(new Ctor(x), pr, rm, true); + return x.ln(); + }; - Ctor.precision = wpr = xsd - x.e; - x = divide(x.plus(1), new Ctor(1).minus(x), wpr + pr, 1); + /* + * Return a new Decimal whose value is the inverse of the hyperbolic sine in radians of the value + * of this Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [-Infinity, Infinity] + * + * asinh(x) = ln(x + sqrt(x^2 + 1)) + * + * asinh(NaN) = NaN + * asinh(Infinity) = Infinity + * asinh(-Infinity) = -Infinity + * asinh(0) = 0 + * asinh(-0) = -0 + * + */ + P.inverseHyperbolicSine = P.asinh = function () { + var pr, rm, + x = this, + Ctor = x.constructor; - Ctor.precision = pr + 4; - Ctor.rounding = 1; + if (!x.isFinite() || x.isZero()) return new Ctor(x); - x = x.ln(); + pr = Ctor.precision; + rm = Ctor.rounding; + Ctor.precision = pr + 2 * Math.max(Math.abs(x.e), x.sd()) + 6; + Ctor.rounding = 1; + external = false; - Ctor.precision = pr; - Ctor.rounding = rm; + x = x.times(x).plus(1).sqrt().plus(x); - return x.times(0.5); - }; + external = true; + Ctor.precision = pr; + Ctor.rounding = rm; + return x.ln(); + }; - /* - * Return a new Decimal whose value is the arcsine (inverse sine) in radians of the value of this - * Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-pi/2, pi/2] - * - * asin(x) = 2*atan(x/(1 + sqrt(1 - x^2))) - * - * asin(0) = 0 - * asin(-0) = -0 - * asin(1/2) = pi/6 - * asin(-1/2) = -pi/6 - * asin(1) = pi/2 - * asin(-1) = -pi/2 - * asin(|x| > 1) = NaN - * asin(NaN) = NaN - * - * TODO? Compare performance of Taylor series. - * - */ - P.inverseSine = P.asin = function () { - var halfPi, k, - pr, rm, - x = this, - Ctor = x.constructor; - if (x.isZero()) return new Ctor(x); + /* + * Return a new Decimal whose value is the inverse of the hyperbolic tangent in radians of the + * value of this Decimal. + * + * Domain: [-1, 1] + * Range: [-Infinity, Infinity] + * + * atanh(x) = 0.5 * ln((1 + x) / (1 - x)) + * + * atanh(|x| > 1) = NaN + * atanh(NaN) = NaN + * atanh(Infinity) = NaN + * atanh(-Infinity) = NaN + * atanh(0) = 0 + * atanh(-0) = -0 + * atanh(1) = Infinity + * atanh(-1) = -Infinity + * + */ + P.inverseHyperbolicTangent = P.atanh = function () { + var pr, rm, wpr, xsd, + x = this, + Ctor = x.constructor; - k = x.abs().cmp(1); - pr = Ctor.precision; - rm = Ctor.rounding; + if (!x.isFinite()) return new Ctor(NaN); + if (x.e >= 0) return new Ctor(x.abs().eq(1) ? x.s / 0 : x.isZero() ? x : NaN); - if (k !== -1) { + pr = Ctor.precision; + rm = Ctor.rounding; + xsd = x.sd(); - // |x| is 1 - if (k === 0) { - halfPi = getPi(Ctor, pr + 4, rm).times(0.5); - halfPi.s = x.s; - return halfPi; - } + if (Math.max(xsd, pr) < 2 * -x.e - 1) return finalise(new Ctor(x), pr, rm, true); - // |x| > 1 or x is NaN - return new Ctor(NaN); - } + Ctor.precision = wpr = xsd - x.e; - // TODO? Special case asin(1/2) = pi/6 and asin(-1/2) = -pi/6 + x = divide(x.plus(1), new Ctor(1).minus(x), wpr + pr, 1); - Ctor.precision = pr + 6; - Ctor.rounding = 1; + Ctor.precision = pr + 4; + Ctor.rounding = 1; - x = x.div(new Ctor(1).minus(x.times(x)).sqrt().plus(1)).atan(); + x = x.ln(); - Ctor.precision = pr; - Ctor.rounding = rm; + Ctor.precision = pr; + Ctor.rounding = rm; - return x.times(2); - }; + return x.times(0.5); + }; - /* - * Return a new Decimal whose value is the arctangent (inverse tangent) in radians of the value - * of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-pi/2, pi/2] - * - * atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... - * - * atan(0) = 0 - * atan(-0) = -0 - * atan(1) = pi/4 - * atan(-1) = -pi/4 - * atan(Infinity) = pi/2 - * atan(-Infinity) = -pi/2 - * atan(NaN) = NaN - * - */ - P.inverseTangent = P.atan = function () { - var i, j, k, n, px, t, r, wpr, x2, - x = this, - Ctor = x.constructor, - pr = Ctor.precision, - rm = Ctor.rounding; + /* + * Return a new Decimal whose value is the arcsine (inverse sine) in radians of the value of this + * Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [-pi/2, pi/2] + * + * asin(x) = 2*atan(x/(1 + sqrt(1 - x^2))) + * + * asin(0) = 0 + * asin(-0) = -0 + * asin(1/2) = pi/6 + * asin(-1/2) = -pi/6 + * asin(1) = pi/2 + * asin(-1) = -pi/2 + * asin(|x| > 1) = NaN + * asin(NaN) = NaN + * + * TODO? Compare performance of Taylor series. + * + */ + P.inverseSine = P.asin = function () { + var halfPi, k, + pr, rm, + x = this, + Ctor = x.constructor; - if (!x.isFinite()) { - if (!x.s) return new Ctor(NaN); - if (pr + 4 <= PI_PRECISION) { - r = getPi(Ctor, pr + 4, rm).times(0.5); - r.s = x.s; - return r; - } - } else if (x.isZero()) { - return new Ctor(x); - } else if (x.abs().eq(1) && pr + 4 <= PI_PRECISION) { - r = getPi(Ctor, pr + 4, rm).times(0.25); - r.s = x.s; - return r; - } + if (x.isZero()) return new Ctor(x); - Ctor.precision = wpr = pr + 10; - Ctor.rounding = 1; + k = x.abs().cmp(1); + pr = Ctor.precision; + rm = Ctor.rounding; - // TODO? if (x >= 1 && pr <= PI_PRECISION) atan(x) = halfPi * x.s - atan(1 / x); + if (k !== -1) { - // Argument reduction - // Ensure |x| < 0.42 - // atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2))) + // |x| is 1 + if (k === 0) { + halfPi = getPi(Ctor, pr + 4, rm).times(0.5); + halfPi.s = x.s; + return halfPi; + } - k = Math.min(28, wpr / LOG_BASE + 2 | 0); + // |x| > 1 or x is NaN + return new Ctor(NaN); + } - for (i = k; i; --i) x = x.div(x.times(x).plus(1).sqrt().plus(1)); + // TODO? Special case asin(1/2) = pi/6 and asin(-1/2) = -pi/6 - external = false; + Ctor.precision = pr + 6; + Ctor.rounding = 1; - j = Math.ceil(wpr / LOG_BASE); - n = 1; - x2 = x.times(x); - r = new Ctor(x); - px = x; + x = x.div(new Ctor(1).minus(x.times(x)).sqrt().plus(1)).atan(); - // atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... - for (; i !== -1;) { - px = px.times(x2); - t = r.minus(px.div(n += 2)); + Ctor.precision = pr; + Ctor.rounding = rm; - px = px.times(x2); - r = t.plus(px.div(n += 2)); + return x.times(2); + }; - if (r.d[j] !== void 0) for (i = j; r.d[i] === t.d[i] && i--;); - } - if (k) r = r.times(2 << (k - 1)); + /* + * Return a new Decimal whose value is the arctangent (inverse tangent) in radians of the value + * of this Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [-pi/2, pi/2] + * + * atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... + * + * atan(0) = 0 + * atan(-0) = -0 + * atan(1) = pi/4 + * atan(-1) = -pi/4 + * atan(Infinity) = pi/2 + * atan(-Infinity) = -pi/2 + * atan(NaN) = NaN + * + */ + P.inverseTangent = P.atan = function () { + var i, j, k, n, px, t, r, wpr, x2, + x = this, + Ctor = x.constructor, + pr = Ctor.precision, + rm = Ctor.rounding; - external = true; + if (!x.isFinite()) { + if (!x.s) return new Ctor(NaN); + if (pr + 4 <= PI_PRECISION) { + r = getPi(Ctor, pr + 4, rm).times(0.5); + r.s = x.s; + return r; + } + } else if (x.isZero()) { + return new Ctor(x); + } else if (x.abs().eq(1) && pr + 4 <= PI_PRECISION) { + r = getPi(Ctor, pr + 4, rm).times(0.25); + r.s = x.s; + return r; + } - return finalise(r, Ctor.precision = pr, Ctor.rounding = rm, true); - }; + Ctor.precision = wpr = pr + 10; + Ctor.rounding = 1; + // TODO? if (x >= 1 && pr <= PI_PRECISION) atan(x) = halfPi * x.s - atan(1 / x); - /* - * Return true if the value of this Decimal is a finite number, otherwise return false. - * - */ - P.isFinite = function () { - return !!this.d; - }; + // Argument reduction + // Ensure |x| < 0.42 + // atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2))) + k = Math.min(28, wpr / LOG_BASE + 2 | 0); - /* - * Return true if the value of this Decimal is an integer, otherwise return false. - * - */ - P.isInteger = P.isInt = function () { - return !!this.d && mathfloor(this.e / LOG_BASE) > this.d.length - 2; - }; + for (i = k; i; --i) x = x.div(x.times(x).plus(1).sqrt().plus(1)); + external = false; - /* - * Return true if the value of this Decimal is NaN, otherwise return false. - * - */ - P.isNaN = function () { - return !this.s; - }; + j = Math.ceil(wpr / LOG_BASE); + n = 1; + x2 = x.times(x); + r = new Ctor(x); + px = x; + // atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... + for (; i !== -1;) { + px = px.times(x2); + t = r.minus(px.div(n += 2)); - /* - * Return true if the value of this Decimal is negative, otherwise return false. - * - */ - P.isNegative = P.isNeg = function () { - return this.s < 0; - }; + px = px.times(x2); + r = t.plus(px.div(n += 2)); + if (r.d[j] !== void 0) for (i = j; r.d[i] === t.d[i] && i--;); + } - /* - * Return true if the value of this Decimal is positive, otherwise return false. - * - */ - P.isPositive = P.isPos = function () { - return this.s > 0; - }; + if (k) r = r.times(2 << (k - 1)); + external = true; - /* - * Return true if the value of this Decimal is 0 or -0, otherwise return false. - * - */ - P.isZero = function () { - return !!this.d && this.d[0] === 0; - }; + return finalise(r, Ctor.precision = pr, Ctor.rounding = rm, true); + }; - /* - * Return true if the value of this Decimal is less than `y`, otherwise return false. - * - */ - P.lessThan = P.lt = function (y) { - return this.cmp(y) < 0; - }; + /* + * Return true if the value of this Decimal is a finite number, otherwise return false. + * + */ + P.isFinite = function () { + return !!this.d; + }; - /* - * Return true if the value of this Decimal is less than or equal to `y`, otherwise return false. - * - */ - P.lessThanOrEqualTo = P.lte = function (y) { - return this.cmp(y) < 1; - }; + /* + * Return true if the value of this Decimal is an integer, otherwise return false. + * + */ + P.isInteger = P.isInt = function () { + return !!this.d && mathfloor(this.e / LOG_BASE) > this.d.length - 2; + }; - /* - * Return the logarithm of the value of this Decimal to the specified base, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * If no base is specified, return log[10](arg). - * - * log[base](arg) = ln(arg) / ln(base) - * - * The result will always be correctly rounded if the base of the log is 10, and 'almost always' - * otherwise: - * - * Depending on the rounding mode, the result may be incorrectly rounded if the first fifteen - * rounding digits are [49]99999999999999 or [50]00000000000000. In that case, the maximum error - * between the result and the correctly rounded result will be one ulp (unit in the last place). - * - * log[-b](a) = NaN - * log[0](a) = NaN - * log[1](a) = NaN - * log[NaN](a) = NaN - * log[Infinity](a) = NaN - * log[b](0) = -Infinity - * log[b](-0) = -Infinity - * log[b](-a) = NaN - * log[b](1) = 0 - * log[b](Infinity) = Infinity - * log[b](NaN) = NaN - * - * [base] {number|string|Decimal} The base of the logarithm. - * - */ - P.logarithm = P.log = function (base) { - var isBase10, d, denominator, k, inf, num, sd, r, - arg = this, - Ctor = arg.constructor, - pr = Ctor.precision, - rm = Ctor.rounding, - guard = 5; - - // Default base is 10. - if (base == null) { - base = new Ctor(10); - isBase10 = true; - } else { - base = new Ctor(base); - d = base.d; + /* + * Return true if the value of this Decimal is NaN, otherwise return false. + * + */ + P.isNaN = function () { + return !this.s; + }; - // Return NaN if base is negative, or non-finite, or is 0 or 1. - if (base.s < 0 || !d || !d[0] || base.eq(1)) return new Ctor(NaN); - isBase10 = base.eq(10); - } + /* + * Return true if the value of this Decimal is negative, otherwise return false. + * + */ + P.isNegative = P.isNeg = function () { + return this.s < 0; + }; - d = arg.d; - // Is arg negative, non-finite, 0 or 1? - if (arg.s < 0 || !d || !d[0] || arg.eq(1)) { - return new Ctor(d && !d[0] ? -1 / 0 : arg.s != 1 ? NaN : d ? 0 : 1 / 0); - } + /* + * Return true if the value of this Decimal is positive, otherwise return false. + * + */ + P.isPositive = P.isPos = function () { + return this.s > 0; + }; - // The result will have a non-terminating decimal expansion if base is 10 and arg is not an - // integer power of 10. - if (isBase10) { - if (d.length > 1) { - inf = true; - } else { - for (k = d[0]; k % 10 === 0;) k /= 10; - inf = k !== 1; - } - } - external = false; - sd = pr + guard; - num = naturalLogarithm(arg, sd); - denominator = isBase10 ? getLn10(Ctor, sd + 10) : naturalLogarithm(base, sd); - - // The result will have 5 rounding digits. - r = divide(num, denominator, sd, 1); - - // If at a rounding boundary, i.e. the result's rounding digits are [49]9999 or [50]0000, - // calculate 10 further digits. - // - // If the result is known to have an infinite decimal expansion, repeat this until it is clear - // that the result is above or below the boundary. Otherwise, if after calculating the 10 - // further digits, the last 14 are nines, round up and assume the result is exact. - // Also assume the result is exact if the last 14 are zero. - // - // Example of a result that will be incorrectly rounded: - // log[1048576](4503599627370502) = 2.60000000000000009610279511444746... - // The above result correctly rounded using ROUND_CEIL to 1 decimal place should be 2.7, but it - // will be given as 2.6 as there are 15 zeros immediately after the requested decimal place, so - // the exact result would be assumed to be 2.6, which rounded using ROUND_CEIL to 1 decimal - // place is still 2.6. - if (checkRoundingDigits(r.d, k = pr, rm)) { - - do { - sd += 10; - num = naturalLogarithm(arg, sd); - denominator = isBase10 ? getLn10(Ctor, sd + 10) : naturalLogarithm(base, sd); - r = divide(num, denominator, sd, 1); - - if (!inf) { - - // Check for 14 nines from the 2nd rounding digit, as the first may be 4. - if (+digitsToString(r.d).slice(k + 1, k + 15) + 1 == 1e14) { - r = finalise(r, pr + 1, 0); - } + /* + * Return true if the value of this Decimal is 0 or -0, otherwise return false. + * + */ + P.isZero = function () { + return !!this.d && this.d[0] === 0; + }; - break; - } - } while (checkRoundingDigits(r.d, k += 10, rm)); - } - external = true; + /* + * Return true if the value of this Decimal is less than `y`, otherwise return false. + * + */ + P.lessThan = P.lt = function (y) { + return this.cmp(y) < 0; + }; - return finalise(r, pr, rm); - }; + /* + * Return true if the value of this Decimal is less than or equal to `y`, otherwise return false. + * + */ + P.lessThanOrEqualTo = P.lte = function (y) { + return this.cmp(y) < 1; + }; - /* - * Return a new Decimal whose value is the maximum of the arguments and the value of this Decimal. - * - * arguments {number|string|Decimal} - * - P.max = function () { - Array.prototype.push.call(arguments, this); - return maxOrMin(this.constructor, arguments, 'lt'); - }; - */ + /* + * Return the logarithm of the value of this Decimal to the specified base, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * If no base is specified, return log[10](arg). + * + * log[base](arg) = ln(arg) / ln(base) + * + * The result will always be correctly rounded if the base of the log is 10, and 'almost always' + * otherwise: + * + * Depending on the rounding mode, the result may be incorrectly rounded if the first fifteen + * rounding digits are [49]99999999999999 or [50]00000000000000. In that case, the maximum error + * between the result and the correctly rounded result will be one ulp (unit in the last place). + * + * log[-b](a) = NaN + * log[0](a) = NaN + * log[1](a) = NaN + * log[NaN](a) = NaN + * log[Infinity](a) = NaN + * log[b](0) = -Infinity + * log[b](-0) = -Infinity + * log[b](-a) = NaN + * log[b](1) = 0 + * log[b](Infinity) = Infinity + * log[b](NaN) = NaN + * + * [base] {number|string|Decimal} The base of the logarithm. + * + */ + P.logarithm = P.log = function (base) { + var isBase10, d, denominator, k, inf, num, sd, r, + arg = this, + Ctor = arg.constructor, + pr = Ctor.precision, + rm = Ctor.rounding, + guard = 5; + + // Default base is 10. + if (base == null) { + base = new Ctor(10); + isBase10 = true; + } else { + base = new Ctor(base); + d = base.d; - /* - * Return a new Decimal whose value is the minimum of the arguments and the value of this Decimal. - * - * arguments {number|string|Decimal} - * - P.min = function () { - Array.prototype.push.call(arguments, this); - return maxOrMin(this.constructor, arguments, 'gt'); - }; - */ + // Return NaN if base is negative, or non-finite, or is 0 or 1. + if (base.s < 0 || !d || !d[0] || base.eq(1)) return new Ctor(NaN); + isBase10 = base.eq(10); + } - /* - * n - 0 = n - * n - N = N - * n - I = -I - * 0 - n = -n - * 0 - 0 = 0 - * 0 - N = N - * 0 - I = -I - * N - n = N - * N - 0 = N - * N - N = N - * N - I = N - * I - n = I - * I - 0 = I - * I - N = N - * I - I = N - * - * Return a new Decimal whose value is the value of this Decimal minus `y`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - */ - P.minus = P.sub = function (y) { - var d, e, i, j, k, len, pr, rm, xd, xe, xLTy, yd, - x = this, - Ctor = x.constructor; + d = arg.d; - y = new Ctor(y); + // Is arg negative, non-finite, 0 or 1? + if (arg.s < 0 || !d || !d[0] || arg.eq(1)) { + return new Ctor(d && !d[0] ? -1 / 0 : arg.s != 1 ? NaN : d ? 0 : 1 / 0); + } - // If either is not finite... - if (!x.d || !y.d) { + // The result will have a non-terminating decimal expansion if base is 10 and arg is not an + // integer power of 10. + if (isBase10) { + if (d.length > 1) { + inf = true; + } else { + for (k = d[0]; k % 10 === 0;) k /= 10; + inf = k !== 1; + } + } - // Return NaN if either is NaN. - if (!x.s || !y.s) y = new Ctor(NaN); + external = false; + sd = pr + guard; + num = naturalLogarithm(arg, sd); + denominator = isBase10 ? getLn10(Ctor, sd + 10) : naturalLogarithm(base, sd); - // Return y negated if x is finite and y is ±Infinity. - else if (x.d) y.s = -y.s; + // The result will have 5 rounding digits. + r = divide(num, denominator, sd, 1); - // Return x if y is finite and x is ±Infinity. - // Return x if both are ±Infinity with different signs. - // Return NaN if both are ±Infinity with the same sign. - else y = new Ctor(y.d || x.s !== y.s ? x : NaN); + // If at a rounding boundary, i.e. the result's rounding digits are [49]9999 or [50]0000, + // calculate 10 further digits. + // + // If the result is known to have an infinite decimal expansion, repeat this until it is clear + // that the result is above or below the boundary. Otherwise, if after calculating the 10 + // further digits, the last 14 are nines, round up and assume the result is exact. + // Also assume the result is exact if the last 14 are zero. + // + // Example of a result that will be incorrectly rounded: + // log[1048576](4503599627370502) = 2.60000000000000009610279511444746... + // The above result correctly rounded using ROUND_CEIL to 1 decimal place should be 2.7, but it + // will be given as 2.6 as there are 15 zeros immediately after the requested decimal place, so + // the exact result would be assumed to be 2.6, which rounded using ROUND_CEIL to 1 decimal + // place is still 2.6. + if (checkRoundingDigits(r.d, k = pr, rm)) { + + do { + sd += 10; + num = naturalLogarithm(arg, sd); + denominator = isBase10 ? getLn10(Ctor, sd + 10) : naturalLogarithm(base, sd); + r = divide(num, denominator, sd, 1); + + if (!inf) { + + // Check for 14 nines from the 2nd rounding digit, as the first may be 4. + if (+digitsToString(r.d).slice(k + 1, k + 15) + 1 == 1e14) { + r = finalise(r, pr + 1, 0); + } - return y; - } + break; + } + } while (checkRoundingDigits(r.d, k += 10, rm)); + } - // If signs differ... - if (x.s != y.s) { - y.s = -y.s; - return x.plus(y); - } + external = true; - xd = x.d; - yd = y.d; - pr = Ctor.precision; - rm = Ctor.rounding; + return finalise(r, pr, rm); + }; - // If either is zero... - if (!xd[0] || !yd[0]) { - // Return y negated if x is zero and y is non-zero. - if (yd[0]) y.s = -y.s; + /* + * Return a new Decimal whose value is the maximum of the arguments and the value of this Decimal. + * + * arguments {number|string|Decimal} + * + P.max = function () { + Array.prototype.push.call(arguments, this); + return maxOrMin(this.constructor, arguments, 'lt'); + }; + */ - // Return x if y is zero and x is non-zero. - else if (xd[0]) y = new Ctor(x); - // Return zero if both are zero. - // From IEEE 754 (2008) 6.3: 0 - 0 = -0 - -0 = -0 when rounding to -Infinity. - else return new Ctor(rm === 3 ? -0 : 0); + /* + * Return a new Decimal whose value is the minimum of the arguments and the value of this Decimal. + * + * arguments {number|string|Decimal} + * + P.min = function () { + Array.prototype.push.call(arguments, this); + return maxOrMin(this.constructor, arguments, 'gt'); + }; + */ - return external ? finalise(y, pr, rm) : y; - } - // x and y are finite, non-zero numbers with the same sign. + /* + * n - 0 = n + * n - N = N + * n - I = -I + * 0 - n = -n + * 0 - 0 = 0 + * 0 - N = N + * 0 - I = -I + * N - n = N + * N - 0 = N + * N - N = N + * N - I = N + * I - n = I + * I - 0 = I + * I - N = N + * I - I = N + * + * Return a new Decimal whose value is the value of this Decimal minus `y`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + */ + P.minus = P.sub = function (y) { + var d, e, i, j, k, len, pr, rm, xd, xe, xLTy, yd, + x = this, + Ctor = x.constructor; - // Calculate base 1e7 exponents. - e = mathfloor(y.e / LOG_BASE); - xe = mathfloor(x.e / LOG_BASE); + y = new Ctor(y); - xd = xd.slice(); - k = xe - e; + // If either is not finite... + if (!x.d || !y.d) { - // If base 1e7 exponents differ... - if (k) { - xLTy = k < 0; + // Return NaN if either is NaN. + if (!x.s || !y.s) y = new Ctor(NaN); - if (xLTy) { - d = xd; - k = -k; - len = yd.length; - } else { - d = yd; - e = xe; - len = xd.length; - } + // Return y negated if x is finite and y is ±Infinity. + else if (x.d) y.s = -y.s; - // Numbers with massively different exponents would result in a very high number of - // zeros needing to be prepended, but this can be avoided while still ensuring correct - // rounding by limiting the number of zeros to `Math.ceil(pr / LOG_BASE) + 2`. - i = Math.max(Math.ceil(pr / LOG_BASE), len) + 2; + // Return x if y is finite and x is ±Infinity. + // Return x if both are ±Infinity with different signs. + // Return NaN if both are ±Infinity with the same sign. + else y = new Ctor(y.d || x.s !== y.s ? x : NaN); - if (k > i) { - k = i; - d.length = 1; + return y; } - // Prepend zeros to equalise exponents. - d.reverse(); - for (i = k; i--;) d.push(0); - d.reverse(); - - // Base 1e7 exponents equal. - } else { - - // Check digits to determine which is the bigger number. - - i = xd.length; - len = yd.length; - xLTy = i < len; - if (xLTy) len = i; - - for (i = 0; i < len; i++) { - if (xd[i] != yd[i]) { - xLTy = xd[i] < yd[i]; - break; - } + // If signs differ... + if (x.s != y.s) { + y.s = -y.s; + return x.plus(y); } - k = 0; - } + xd = x.d; + yd = y.d; + pr = Ctor.precision; + rm = Ctor.rounding; - if (xLTy) { - d = xd; - xd = yd; - yd = d; - y.s = -y.s; - } + // If either is zero... + if (!xd[0] || !yd[0]) { - len = xd.length; + // Return y negated if x is zero and y is non-zero. + if (yd[0]) y.s = -y.s; - // Append zeros to `xd` if shorter. - // Don't add zeros to `yd` if shorter as subtraction only needs to start at `yd` length. - for (i = yd.length - len; i > 0; --i) xd[len++] = 0; + // Return x if y is zero and x is non-zero. + else if (xd[0]) y = new Ctor(x); - // Subtract yd from xd. - for (i = yd.length; i > k;) { + // Return zero if both are zero. + // From IEEE 754 (2008) 6.3: 0 - 0 = -0 - -0 = -0 when rounding to -Infinity. + else return new Ctor(rm === 3 ? -0 : 0); - if (xd[--i] < yd[i]) { - for (j = i; j && xd[--j] === 0;) xd[j] = BASE - 1; - --xd[j]; - xd[i] += BASE; + return external ? finalise(y, pr, rm) : y; } - xd[i] -= yd[i]; - } + // x and y are finite, non-zero numbers with the same sign. - // Remove trailing zeros. - for (; xd[--len] === 0;) xd.pop(); + // Calculate base 1e7 exponents. + e = mathfloor(y.e / LOG_BASE); + xe = mathfloor(x.e / LOG_BASE); - // Remove leading zeros and adjust exponent accordingly. - for (; xd[0] === 0; xd.shift()) --e; + xd = xd.slice(); + k = xe - e; - // Zero? - if (!xd[0]) return new Ctor(rm === 3 ? -0 : 0); + // If base 1e7 exponents differ... + if (k) { + xLTy = k < 0; - y.d = xd; - y.e = getBase10Exponent(xd, e); + if (xLTy) { + d = xd; + k = -k; + len = yd.length; + } else { + d = yd; + e = xe; + len = xd.length; + } - return external ? finalise(y, pr, rm) : y; - }; + // Numbers with massively different exponents would result in a very high number of + // zeros needing to be prepended, but this can be avoided while still ensuring correct + // rounding by limiting the number of zeros to `Math.ceil(pr / LOG_BASE) + 2`. + i = Math.max(Math.ceil(pr / LOG_BASE), len) + 2; + if (k > i) { + k = i; + d.length = 1; + } - /* - * n % 0 = N - * n % N = N - * n % I = n - * 0 % n = 0 - * -0 % n = -0 - * 0 % 0 = N - * 0 % N = N - * 0 % I = 0 - * N % n = N - * N % 0 = N - * N % N = N - * N % I = N - * I % n = N - * I % 0 = N - * I % N = N - * I % I = N - * - * Return a new Decimal whose value is the value of this Decimal modulo `y`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * The result depends on the modulo mode. - * - */ - P.modulo = P.mod = function (y) { - var q, - x = this, - Ctor = x.constructor; + // Prepend zeros to equalise exponents. + d.reverse(); + for (i = k; i--;) d.push(0); + d.reverse(); - y = new Ctor(y); + // Base 1e7 exponents equal. + } else { - // Return NaN if x is ±Infinity or NaN, or y is NaN or ±0. - if (!x.d || !y.s || y.d && !y.d[0]) return new Ctor(NaN); + // Check digits to determine which is the bigger number. - // Return x if y is ±Infinity or x is ±0. - if (!y.d || x.d && !x.d[0]) { - return finalise(new Ctor(x), Ctor.precision, Ctor.rounding); - } + i = xd.length; + len = yd.length; + xLTy = i < len; + if (xLTy) len = i; - // Prevent rounding of intermediate calculations. - external = false; + for (i = 0; i < len; i++) { + if (xd[i] != yd[i]) { + xLTy = xd[i] < yd[i]; + break; + } + } - if (Ctor.modulo == 9) { + k = 0; + } - // Euclidian division: q = sign(y) * floor(x / abs(y)) - // result = x - q * y where 0 <= result < abs(y) - q = divide(x, y.abs(), 0, 3, 1); - q.s *= y.s; - } else { - q = divide(x, y, 0, Ctor.modulo, 1); - } + if (xLTy) { + d = xd; + xd = yd; + yd = d; + y.s = -y.s; + } - q = q.times(y); + len = xd.length; - external = true; + // Append zeros to `xd` if shorter. + // Don't add zeros to `yd` if shorter as subtraction only needs to start at `yd` length. + for (i = yd.length - len; i > 0; --i) xd[len++] = 0; - return x.minus(q); - }; + // Subtract yd from xd. + for (i = yd.length; i > k;) { + if (xd[--i] < yd[i]) { + for (j = i; j && xd[--j] === 0;) xd[j] = BASE - 1; + --xd[j]; + xd[i] += BASE; + } - /* - * Return a new Decimal whose value is the natural exponential of the value of this Decimal, - * i.e. the base e raised to the power the value of this Decimal, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - */ - P.naturalExponential = P.exp = function () { - return naturalExponential(this); - }; + xd[i] -= yd[i]; + } + // Remove trailing zeros. + for (; xd[--len] === 0;) xd.pop(); - /* - * Return a new Decimal whose value is the natural logarithm of the value of this Decimal, - * rounded to `precision` significant digits using rounding mode `rounding`. - * - */ - P.naturalLogarithm = P.ln = function () { - return naturalLogarithm(this); - }; + // Remove leading zeros and adjust exponent accordingly. + for (; xd[0] === 0; xd.shift()) --e; + // Zero? + if (!xd[0]) return new Ctor(rm === 3 ? -0 : 0); - /* - * Return a new Decimal whose value is the value of this Decimal negated, i.e. as if multiplied by - * -1. - * - */ - P.negated = P.neg = function () { - var x = new this.constructor(this); - x.s = -x.s; - return finalise(x); - }; + y.d = xd; + y.e = getBase10Exponent(xd, e); + return external ? finalise(y, pr, rm) : y; + }; - /* - * n + 0 = n - * n + N = N - * n + I = I - * 0 + n = n - * 0 + 0 = 0 - * 0 + N = N - * 0 + I = I - * N + n = N - * N + 0 = N - * N + N = N - * N + I = N - * I + n = I - * I + 0 = I - * I + N = N - * I + I = I - * - * Return a new Decimal whose value is the value of this Decimal plus `y`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - */ - P.plus = P.add = function (y) { - var carry, d, e, i, k, len, pr, rm, xd, yd, - x = this, - Ctor = x.constructor; - y = new Ctor(y); + /* + * n % 0 = N + * n % N = N + * n % I = n + * 0 % n = 0 + * -0 % n = -0 + * 0 % 0 = N + * 0 % N = N + * 0 % I = 0 + * N % n = N + * N % 0 = N + * N % N = N + * N % I = N + * I % n = N + * I % 0 = N + * I % N = N + * I % I = N + * + * Return a new Decimal whose value is the value of this Decimal modulo `y`, rounded to + * `precision` significant digits using rounding mode `rounding`. + * + * The result depends on the modulo mode. + * + */ + P.modulo = P.mod = function (y) { + var q, + x = this, + Ctor = x.constructor; - // If either is not finite... - if (!x.d || !y.d) { + y = new Ctor(y); - // Return NaN if either is NaN. - if (!x.s || !y.s) y = new Ctor(NaN); + // Return NaN if x is ±Infinity or NaN, or y is NaN or ±0. + if (!x.d || !y.s || y.d && !y.d[0]) return new Ctor(NaN); - // Return x if y is finite and x is ±Infinity. - // Return x if both are ±Infinity with the same sign. - // Return NaN if both are ±Infinity with different signs. - // Return y if x is finite and y is ±Infinity. - else if (!x.d) y = new Ctor(y.d || x.s === y.s ? x : NaN); + // Return x if y is ±Infinity or x is ±0. + if (!y.d || x.d && !x.d[0]) { + return finalise(new Ctor(x), Ctor.precision, Ctor.rounding); + } - return y; - } + // Prevent rounding of intermediate calculations. + external = false; - // If signs differ... - if (x.s != y.s) { - y.s = -y.s; - return x.minus(y); - } + if (Ctor.modulo == 9) { - xd = x.d; - yd = y.d; - pr = Ctor.precision; - rm = Ctor.rounding; + // Euclidian division: q = sign(y) * floor(x / abs(y)) + // result = x - q * y where 0 <= result < abs(y) + q = divide(x, y.abs(), 0, 3, 1); + q.s *= y.s; + } else { + q = divide(x, y, 0, Ctor.modulo, 1); + } - // If either is zero... - if (!xd[0] || !yd[0]) { + q = q.times(y); - // Return x if y is zero. - // Return y if y is non-zero. - if (!yd[0]) y = new Ctor(x); + external = true; - return external ? finalise(y, pr, rm) : y; - } + return x.minus(q); + }; - // x and y are finite, non-zero numbers with the same sign. - // Calculate base 1e7 exponents. - k = mathfloor(x.e / LOG_BASE); - e = mathfloor(y.e / LOG_BASE); + /* + * Return a new Decimal whose value is the natural exponential of the value of this Decimal, + * i.e. the base e raised to the power the value of this Decimal, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + */ + P.naturalExponential = P.exp = function () { + return naturalExponential(this); + }; - xd = xd.slice(); - i = k - e; - // If base 1e7 exponents differ... - if (i) { - - if (i < 0) { - d = xd; - i = -i; - len = yd.length; - } else { - d = yd; - e = k; - len = xd.length; - } + /* + * Return a new Decimal whose value is the natural logarithm of the value of this Decimal, + * rounded to `precision` significant digits using rounding mode `rounding`. + * + */ + P.naturalLogarithm = P.ln = function () { + return naturalLogarithm(this); + }; - // Limit number of zeros prepended to max(ceil(pr / LOG_BASE), len) + 1. - k = Math.ceil(pr / LOG_BASE); - len = k > len ? k + 1 : len + 1; - if (i > len) { - i = len; - d.length = 1; - } + /* + * Return a new Decimal whose value is the value of this Decimal negated, i.e. as if multiplied by + * -1. + * + */ + P.negated = P.neg = function () { + var x = new this.constructor(this); + x.s = -x.s; + return finalise(x); + }; - // Prepend zeros to equalise exponents. Note: Faster to use reverse then do unshifts. - d.reverse(); - for (; i--;) d.push(0); - d.reverse(); - } - len = xd.length; - i = yd.length; + /* + * n + 0 = n + * n + N = N + * n + I = I + * 0 + n = n + * 0 + 0 = 0 + * 0 + N = N + * 0 + I = I + * N + n = N + * N + 0 = N + * N + N = N + * N + I = N + * I + n = I + * I + 0 = I + * I + N = N + * I + I = I + * + * Return a new Decimal whose value is the value of this Decimal plus `y`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + */ + P.plus = P.add = function (y) { + var carry, d, e, i, k, len, pr, rm, xd, yd, + x = this, + Ctor = x.constructor; - // If yd is longer than xd, swap xd and yd so xd points to the longer array. - if (len - i < 0) { - i = len; - d = yd; - yd = xd; - xd = d; - } + y = new Ctor(y); - // Only start adding at yd.length - 1 as the further digits of xd can be left as they are. - for (carry = 0; i;) { - carry = (xd[--i] = xd[i] + yd[i] + carry) / BASE | 0; - xd[i] %= BASE; - } + // If either is not finite... + if (!x.d || !y.d) { - if (carry) { - xd.unshift(carry); - ++e; - } + // Return NaN if either is NaN. + if (!x.s || !y.s) y = new Ctor(NaN); - // Remove trailing zeros. - // No need to check for zero, as +x + +y != 0 && -x + -y != 0 - for (len = xd.length; xd[--len] == 0;) xd.pop(); + // Return x if y is finite and x is ±Infinity. + // Return x if both are ±Infinity with the same sign. + // Return NaN if both are ±Infinity with different signs. + // Return y if x is finite and y is ±Infinity. + else if (!x.d) y = new Ctor(y.d || x.s === y.s ? x : NaN); - y.d = xd; - y.e = getBase10Exponent(xd, e); + return y; + } - return external ? finalise(y, pr, rm) : y; - }; + // If signs differ... + if (x.s != y.s) { + y.s = -y.s; + return x.minus(y); + } + xd = x.d; + yd = y.d; + pr = Ctor.precision; + rm = Ctor.rounding; - /* - * Return the number of significant digits of the value of this Decimal. - * - * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0. - * - */ - P.precision = P.sd = function (z) { - var k, - x = this; + // If either is zero... + if (!xd[0] || !yd[0]) { - if (z !== void 0 && z !== !!z && z !== 1 && z !== 0) throw Error(invalidArgument + z); + // Return x if y is zero. + // Return y if y is non-zero. + if (!yd[0]) y = new Ctor(x); - if (x.d) { - k = getPrecision(x.d); - if (z && x.e + 1 > k) k = x.e + 1; - } else { - k = NaN; - } + return external ? finalise(y, pr, rm) : y; + } - return k; - }; + // x and y are finite, non-zero numbers with the same sign. + // Calculate base 1e7 exponents. + k = mathfloor(x.e / LOG_BASE); + e = mathfloor(y.e / LOG_BASE); - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a whole number using - * rounding mode `rounding`. - * - */ - P.round = function () { - var x = this, - Ctor = x.constructor; + xd = xd.slice(); + i = k - e; - return finalise(new Ctor(x), x.e + 1, Ctor.rounding); - }; + // If base 1e7 exponents differ... + if (i) { + if (i < 0) { + d = xd; + i = -i; + len = yd.length; + } else { + d = yd; + e = k; + len = xd.length; + } - /* - * Return a new Decimal whose value is the sine of the value in radians of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-1, 1] - * - * sin(x) = x - x^3/3! + x^5/5! - ... - * - * sin(0) = 0 - * sin(-0) = -0 - * sin(Infinity) = NaN - * sin(-Infinity) = NaN - * sin(NaN) = NaN - * - */ - P.sine = P.sin = function () { - var pr, rm, - x = this, - Ctor = x.constructor; + // Limit number of zeros prepended to max(ceil(pr / LOG_BASE), len) + 1. + k = Math.ceil(pr / LOG_BASE); + len = k > len ? k + 1 : len + 1; - if (!x.isFinite()) return new Ctor(NaN); - if (x.isZero()) return new Ctor(x); + if (i > len) { + i = len; + d.length = 1; + } - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(x.e, x.sd()) + LOG_BASE; - Ctor.rounding = 1; + // Prepend zeros to equalise exponents. Note: Faster to use reverse then do unshifts. + d.reverse(); + for (; i--;) d.push(0); + d.reverse(); + } - x = sine(Ctor, toLessThanHalfPi(Ctor, x)); + len = xd.length; + i = yd.length; - Ctor.precision = pr; - Ctor.rounding = rm; + // If yd is longer than xd, swap xd and yd so xd points to the longer array. + if (len - i < 0) { + i = len; + d = yd; + yd = xd; + xd = d; + } - return finalise(quadrant > 2 ? x.neg() : x, pr, rm, true); - }; + // Only start adding at yd.length - 1 as the further digits of xd can be left as they are. + for (carry = 0; i;) { + carry = (xd[--i] = xd[i] + yd[i] + carry) / BASE | 0; + xd[i] %= BASE; + } + if (carry) { + xd.unshift(carry); + ++e; + } - /* - * Return a new Decimal whose value is the square root of this Decimal, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * sqrt(-n) = N - * sqrt(N) = N - * sqrt(-I) = N - * sqrt(I) = I - * sqrt(0) = 0 - * sqrt(-0) = -0 - * - */ - P.squareRoot = P.sqrt = function () { - var m, n, sd, r, rep, t, - x = this, - d = x.d, - e = x.e, - s = x.s, - Ctor = x.constructor; + // Remove trailing zeros. + // No need to check for zero, as +x + +y != 0 && -x + -y != 0 + for (len = xd.length; xd[--len] == 0;) xd.pop(); - // Negative/NaN/Infinity/zero? - if (s !== 1 || !d || !d[0]) { - return new Ctor(!s || s < 0 && (!d || d[0]) ? NaN : d ? x : 1 / 0); - } + y.d = xd; + y.e = getBase10Exponent(xd, e); - external = false; + return external ? finalise(y, pr, rm) : y; + }; - // Initial estimate. - s = Math.sqrt(+x); - // Math.sqrt underflow/overflow? - // Pass x to Math.sqrt as integer, then adjust the exponent of the result. - if (s == 0 || s == 1 / 0) { - n = digitsToString(d); + /* + * Return the number of significant digits of the value of this Decimal. + * + * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0. + * + */ + P.precision = P.sd = function (z) { + var k, + x = this; - if ((n.length + e) % 2 == 0) n += '0'; - s = Math.sqrt(n); - e = mathfloor((e + 1) / 2) - (e < 0 || e % 2); + if (z !== void 0 && z !== !!z && z !== 1 && z !== 0) throw Error(invalidArgument + z); - if (s == 1 / 0) { - n = '1e' + e; + if (x.d) { + k = getPrecision(x.d); + if (z && x.e + 1 > k) k = x.e + 1; } else { - n = s.toExponential(); - n = n.slice(0, n.indexOf('e') + 1) + e; + k = NaN; } - r = new Ctor(n); - } else { - r = new Ctor(s.toString()); - } + return k; + }; - sd = (e = Ctor.precision) + 3; - // Newton-Raphson iteration. - for (;;) { - t = r; - r = t.plus(divide(x, t, sd + 2, 1)).times(0.5); + /* + * Return a new Decimal whose value is the value of this Decimal rounded to a whole number using + * rounding mode `rounding`. + * + */ + P.round = function () { + var x = this, + Ctor = x.constructor; - // TODO? Replace with for-loop and checkRoundingDigits. - if (digitsToString(t.d).slice(0, sd) === (n = digitsToString(r.d)).slice(0, sd)) { - n = n.slice(sd - 3, sd + 1); + return finalise(new Ctor(x), x.e + 1, Ctor.rounding); + }; - // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or - // 4999, i.e. approaching a rounding boundary, continue the iteration. - if (n == '9999' || !rep && n == '4999') { - // On the first iteration only, check to see if rounding up gives the exact result as the - // nines may infinitely repeat. - if (!rep) { - finalise(t, e + 1, 0); + /* + * Return a new Decimal whose value is the sine of the value in radians of this Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [-1, 1] + * + * sin(x) = x - x^3/3! + x^5/5! - ... + * + * sin(0) = 0 + * sin(-0) = -0 + * sin(Infinity) = NaN + * sin(-Infinity) = NaN + * sin(NaN) = NaN + * + */ + P.sine = P.sin = function () { + var pr, rm, + x = this, + Ctor = x.constructor; - if (t.times(t).eq(x)) { - r = t; - break; - } - } + if (!x.isFinite()) return new Ctor(NaN); + if (x.isZero()) return new Ctor(x); - sd += 4; - rep = 1; - } else { + pr = Ctor.precision; + rm = Ctor.rounding; + Ctor.precision = pr + Math.max(x.e, x.sd()) + LOG_BASE; + Ctor.rounding = 1; - // If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result. - // If not, then there are further digits and m will be truthy. - if (!+n || !+n.slice(1) && n.charAt(0) == '5') { + x = sine(Ctor, toLessThanHalfPi(Ctor, x)); - // Truncate to the first rounding digit. - finalise(r, e + 1, 1); - m = !r.times(r).eq(x); - } + Ctor.precision = pr; + Ctor.rounding = rm; - break; - } - } - } + return finalise(quadrant > 2 ? x.neg() : x, pr, rm, true); + }; - external = true; - return finalise(r, e, Ctor.rounding, m); - }; + /* + * Return a new Decimal whose value is the square root of this Decimal, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * sqrt(-n) = N + * sqrt(N) = N + * sqrt(-I) = N + * sqrt(I) = I + * sqrt(0) = 0 + * sqrt(-0) = -0 + * + */ + P.squareRoot = P.sqrt = function () { + var m, n, sd, r, rep, t, + x = this, + d = x.d, + e = x.e, + s = x.s, + Ctor = x.constructor; + + // Negative/NaN/Infinity/zero? + if (s !== 1 || !d || !d[0]) { + return new Ctor(!s || s < 0 && (!d || d[0]) ? NaN : d ? x : 1 / 0); + } + external = false; - /* - * Return a new Decimal whose value is the tangent of the value in radians of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-Infinity, Infinity] - * - * tan(0) = 0 - * tan(-0) = -0 - * tan(Infinity) = NaN - * tan(-Infinity) = NaN - * tan(NaN) = NaN - * - */ - P.tangent = P.tan = function () { - var pr, rm, - x = this, - Ctor = x.constructor; + // Initial estimate. + s = Math.sqrt(+x); - if (!x.isFinite()) return new Ctor(NaN); - if (x.isZero()) return new Ctor(x); + // Math.sqrt underflow/overflow? + // Pass x to Math.sqrt as integer, then adjust the exponent of the result. + if (s == 0 || s == 1 / 0) { + n = digitsToString(d); - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + 10; - Ctor.rounding = 1; + if ((n.length + e) % 2 == 0) n += '0'; + s = Math.sqrt(n); + e = mathfloor((e + 1) / 2) - (e < 0 || e % 2); - x = x.sin(); - x.s = 1; - x = divide(x, new Ctor(1).minus(x.times(x)).sqrt(), pr + 10, 0); + if (s == 1 / 0) { + n = '1e' + e; + } else { + n = s.toExponential(); + n = n.slice(0, n.indexOf('e') + 1) + e; + } - Ctor.precision = pr; - Ctor.rounding = rm; + r = new Ctor(n); + } else { + r = new Ctor(s.toString()); + } - return finalise(quadrant == 2 || quadrant == 4 ? x.neg() : x, pr, rm, true); - }; + sd = (e = Ctor.precision) + 3; + // Newton-Raphson iteration. + for (;;) { + t = r; + r = t.plus(divide(x, t, sd + 2, 1)).times(0.5); - /* - * n * 0 = 0 - * n * N = N - * n * I = I - * 0 * n = 0 - * 0 * 0 = 0 - * 0 * N = N - * 0 * I = N - * N * n = N - * N * 0 = N - * N * N = N - * N * I = N - * I * n = I - * I * 0 = N - * I * N = N - * I * I = I - * - * Return a new Decimal whose value is this Decimal times `y`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - */ - P.times = P.mul = function (y) { - var carry, e, i, k, r, rL, t, xdL, ydL, - x = this, - Ctor = x.constructor, - xd = x.d, - yd = (y = new Ctor(y)).d; + // TODO? Replace with for-loop and checkRoundingDigits. + if (digitsToString(t.d).slice(0, sd) === (n = digitsToString(r.d)).slice(0, sd)) { + n = n.slice(sd - 3, sd + 1); - y.s *= x.s; + // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or + // 4999, i.e. approaching a rounding boundary, continue the iteration. + if (n == '9999' || !rep && n == '4999') { - // If either is NaN, ±Infinity or ±0... - if (!xd || !xd[0] || !yd || !yd[0]) { + // On the first iteration only, check to see if rounding up gives the exact result as the + // nines may infinitely repeat. + if (!rep) { + finalise(t, e + 1, 0); - return new Ctor(!y.s || xd && !xd[0] && !yd || yd && !yd[0] && !xd + if (t.times(t).eq(x)) { + r = t; + break; + } + } - // Return NaN if either is NaN. - // Return NaN if x is ±0 and y is ±Infinity, or y is ±0 and x is ±Infinity. - ? NaN + sd += 4; + rep = 1; + } else { - // Return ±Infinity if either is ±Infinity. - // Return ±0 if either is ±0. - : !xd || !yd ? y.s / 0 : y.s * 0); - } + // If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result. + // If not, then there are further digits and m will be truthy. + if (!+n || !+n.slice(1) && n.charAt(0) == '5') { - e = mathfloor(x.e / LOG_BASE) + mathfloor(y.e / LOG_BASE); - xdL = xd.length; - ydL = yd.length; - - // Ensure xd points to the longer array. - if (xdL < ydL) { - r = xd; - xd = yd; - yd = r; - rL = xdL; - xdL = ydL; - ydL = rL; - } + // Truncate to the first rounding digit. + finalise(r, e + 1, 1); + m = !r.times(r).eq(x); + } - // Initialise the result array with zeros. - r = []; - rL = xdL + ydL; - for (i = rL; i--;) r.push(0); - - // Multiply! - for (i = ydL; --i >= 0;) { - carry = 0; - for (k = xdL + i; k > i;) { - t = r[k] + yd[i] * xd[k - i - 1] + carry; - r[k--] = t % BASE | 0; - carry = t / BASE | 0; + break; + } + } } - r[k] = (r[k] + carry) % BASE | 0; - } + external = true; + + return finalise(r, e, Ctor.rounding, m); + }; + - // Remove trailing zeros. - for (; !r[--rL];) r.pop(); + /* + * Return a new Decimal whose value is the tangent of the value in radians of this Decimal. + * + * Domain: [-Infinity, Infinity] + * Range: [-Infinity, Infinity] + * + * tan(0) = 0 + * tan(-0) = -0 + * tan(Infinity) = NaN + * tan(-Infinity) = NaN + * tan(NaN) = NaN + * + */ + P.tangent = P.tan = function () { + var pr, rm, + x = this, + Ctor = x.constructor; - if (carry) ++e; - else r.shift(); + if (!x.isFinite()) return new Ctor(NaN); + if (x.isZero()) return new Ctor(x); - y.d = r; - y.e = getBase10Exponent(r, e); + pr = Ctor.precision; + rm = Ctor.rounding; + Ctor.precision = pr + 10; + Ctor.rounding = 1; - return external ? finalise(y, Ctor.precision, Ctor.rounding) : y; - }; + x = x.sin(); + x.s = 1; + x = divide(x, new Ctor(1).minus(x.times(x)).sqrt(), pr + 10, 0); + Ctor.precision = pr; + Ctor.rounding = rm; - /* - * Return a string representing the value of this Decimal in base 2, round to `sd` significant - * digits using rounding mode `rm`. - * - * If the optional `sd` argument is present then return binary exponential notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toBinary = function (sd, rm) { - return toStringBinary(this, 2, sd, rm); - }; + return finalise(quadrant == 2 || quadrant == 4 ? x.neg() : x, pr, rm, true); + }; - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `dp` - * decimal places using rounding mode `rm` or `rounding` if `rm` is omitted. - * - * If `dp` is omitted, return a new Decimal whose value is the value of this Decimal. - * - * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toDecimalPlaces = P.toDP = function (dp, rm) { - var x = this, - Ctor = x.constructor; + /* + * n * 0 = 0 + * n * N = N + * n * I = I + * 0 * n = 0 + * 0 * 0 = 0 + * 0 * N = N + * 0 * I = N + * N * n = N + * N * 0 = N + * N * N = N + * N * I = N + * I * n = I + * I * 0 = N + * I * N = N + * I * I = I + * + * Return a new Decimal whose value is this Decimal times `y`, rounded to `precision` significant + * digits using rounding mode `rounding`. + * + */ + P.times = P.mul = function (y) { + var carry, e, i, k, r, rL, t, xdL, ydL, + x = this, + Ctor = x.constructor, + xd = x.d, + yd = (y = new Ctor(y)).d; - x = new Ctor(x); - if (dp === void 0) return x; + y.s *= x.s; - checkInt32(dp, 0, MAX_DIGITS); + // If either is NaN, ±Infinity or ±0... + if (!xd || !xd[0] || !yd || !yd[0]) { - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); + return new Ctor(!y.s || xd && !xd[0] && !yd || yd && !yd[0] && !xd - return finalise(x, dp + x.e + 1, rm); - }; + // Return NaN if either is NaN. + // Return NaN if x is ±0 and y is ±Infinity, or y is ±0 and x is ±Infinity. + ? NaN + // Return ±Infinity if either is ±Infinity. + // Return ±0 if either is ±0. + : !xd || !yd ? y.s / 0 : y.s * 0); + } - /* - * Return a string representing the value of this Decimal in exponential notation rounded to - * `dp` fixed decimal places using rounding mode `rounding`. - * - * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toExponential = function (dp, rm) { - var str, - x = this, - Ctor = x.constructor; + e = mathfloor(x.e / LOG_BASE) + mathfloor(y.e / LOG_BASE); + xdL = xd.length; + ydL = yd.length; + + // Ensure xd points to the longer array. + if (xdL < ydL) { + r = xd; + xd = yd; + yd = r; + rL = xdL; + xdL = ydL; + ydL = rL; + } - if (dp === void 0) { - str = finiteToString(x, true); - } else { - checkInt32(dp, 0, MAX_DIGITS); + // Initialise the result array with zeros. + r = []; + rL = xdL + ydL; + for (i = rL; i--;) r.push(0); + + // Multiply! + for (i = ydL; --i >= 0;) { + carry = 0; + for (k = xdL + i; k > i;) { + t = r[k] + yd[i] * xd[k - i - 1] + carry; + r[k--] = t % BASE | 0; + carry = t / BASE | 0; + } - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); + r[k] = (r[k] + carry) % BASE | 0; + } - x = finalise(new Ctor(x), dp + 1, rm); - str = finiteToString(x, true, dp + 1); - } + // Remove trailing zeros. + for (; !r[--rL];) r.pop(); - return x.isNeg() && !x.isZero() ? '-' + str : str; - }; + if (carry) ++e; + else r.shift(); + y.d = r; + y.e = getBase10Exponent(r, e); - /* - * Return a string representing the value of this Decimal in normal (fixed-point) notation to - * `dp` fixed decimal places and rounded using rounding mode `rm` or `rounding` if `rm` is - * omitted. - * - * As with JavaScript numbers, (-0).toFixed(0) is '0', but e.g. (-0.00001).toFixed(0) is '-0'. - * - * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'. - * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'. - * (-0).toFixed(3) is '0.000'. - * (-0.5).toFixed(0) is '-0'. - * - */ - P.toFixed = function (dp, rm) { - var str, y, - x = this, - Ctor = x.constructor; + return external ? finalise(y, Ctor.precision, Ctor.rounding) : y; + }; - if (dp === void 0) { - str = finiteToString(x); - } else { - checkInt32(dp, 0, MAX_DIGITS); - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); + /* + * Return a string representing the value of this Decimal in base 2, round to `sd` significant + * digits using rounding mode `rm`. + * + * If the optional `sd` argument is present then return binary exponential notation. + * + * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + */ + P.toBinary = function (sd, rm) { + return toStringBinary(this, 2, sd, rm); + }; - y = finalise(new Ctor(x), dp + x.e + 1, rm); - str = finiteToString(y, false, dp + y.e + 1); - } - // To determine whether to add the minus sign look at the value before it was rounded, - // i.e. look at `x` rather than `y`. - return x.isNeg() && !x.isZero() ? '-' + str : str; - }; + /* + * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `dp` + * decimal places using rounding mode `rm` or `rounding` if `rm` is omitted. + * + * If `dp` is omitted, return a new Decimal whose value is the value of this Decimal. + * + * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + */ + P.toDecimalPlaces = P.toDP = function (dp, rm) { + var x = this, + Ctor = x.constructor; + x = new Ctor(x); + if (dp === void 0) return x; - /* - * Return an array representing the value of this Decimal as a simple fraction with an integer - * numerator and an integer denominator. - * - * The denominator will be a positive non-zero value less than or equal to the specified maximum - * denominator. If a maximum denominator is not specified, the denominator will be the lowest - * value necessary to represent the number exactly. - * - * [maxD] {number|string|Decimal} Maximum denominator. Integer >= 1 and < Infinity. - * - */ - P.toFraction = function (maxD) { - var d, d0, d1, d2, e, k, n, n0, n1, pr, q, r, - x = this, - xd = x.d, - Ctor = x.constructor; + checkInt32(dp, 0, MAX_DIGITS); - if (!xd) return new Ctor(x); + if (rm === void 0) rm = Ctor.rounding; + else checkInt32(rm, 0, 8); - n1 = d0 = new Ctor(1); - d1 = n0 = new Ctor(0); + return finalise(x, dp + x.e + 1, rm); + }; - d = new Ctor(d1); - e = d.e = getPrecision(xd) - x.e - 1; - k = e % LOG_BASE; - d.d[0] = mathpow(10, k < 0 ? LOG_BASE + k : k); - if (maxD == null) { + /* + * Return a string representing the value of this Decimal in exponential notation rounded to + * `dp` fixed decimal places using rounding mode `rounding`. + * + * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + */ + P.toExponential = function (dp, rm) { + var str, + x = this, + Ctor = x.constructor; - // d is 10**e, the minimum max-denominator needed. - maxD = e > 0 ? d : n1; - } else { - n = new Ctor(maxD); - if (!n.isInt() || n.lt(n1)) throw Error(invalidArgument + n); - maxD = n.gt(d) ? (e > 0 ? d : n1) : n; - } + if (dp === void 0) { + str = finiteToString(x, true); + } else { + checkInt32(dp, 0, MAX_DIGITS); - external = false; - n = new Ctor(digitsToString(xd)); - pr = Ctor.precision; - Ctor.precision = e = xd.length * LOG_BASE * 2; - - for (;;) { - q = divide(n, d, 0, 1, 1); - d2 = d0.plus(q.times(d1)); - if (d2.cmp(maxD) == 1) break; - d0 = d1; - d1 = d2; - d2 = n1; - n1 = n0.plus(q.times(d2)); - n0 = d2; - d2 = d; - d = n.minus(q.times(d2)); - n = d2; - } + if (rm === void 0) rm = Ctor.rounding; + else checkInt32(rm, 0, 8); - d2 = divide(maxD.minus(d0), d1, 0, 1, 1); - n0 = n0.plus(d2.times(n1)); - d0 = d0.plus(d2.times(d1)); - n0.s = n1.s = x.s; + x = finalise(new Ctor(x), dp + 1, rm); + str = finiteToString(x, true, dp + 1); + } - // Determine which fraction is closer to x, n0/d0 or n1/d1? - r = divide(n1, d1, e, 1).minus(x).abs().cmp(divide(n0, d0, e, 1).minus(x).abs()) < 1 - ? [n1, d1] : [n0, d0]; + return x.isNeg() && !x.isZero() ? '-' + str : str; + }; - Ctor.precision = pr; - external = true; - return r; - }; + /* + * Return a string representing the value of this Decimal in normal (fixed-point) notation to + * `dp` fixed decimal places and rounded using rounding mode `rm` or `rounding` if `rm` is + * omitted. + * + * As with JavaScript numbers, (-0).toFixed(0) is '0', but e.g. (-0.00001).toFixed(0) is '-0'. + * + * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'. + * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'. + * (-0).toFixed(3) is '0.000'. + * (-0.5).toFixed(0) is '-0'. + * + */ + P.toFixed = function (dp, rm) { + var str, y, + x = this, + Ctor = x.constructor; + if (dp === void 0) { + str = finiteToString(x); + } else { + checkInt32(dp, 0, MAX_DIGITS); - /* - * Return a string representing the value of this Decimal in base 16, round to `sd` significant - * digits using rounding mode `rm`. - * - * If the optional `sd` argument is present then return binary exponential notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toHexadecimal = P.toHex = function (sd, rm) { - return toStringBinary(this, 16, sd, rm); - }; + if (rm === void 0) rm = Ctor.rounding; + else checkInt32(rm, 0, 8); + y = finalise(new Ctor(x), dp + x.e + 1, rm); + str = finiteToString(y, false, dp + y.e + 1); + } + // To determine whether to add the minus sign look at the value before it was rounded, + // i.e. look at `x` rather than `y`. + return x.isNeg() && !x.isZero() ? '-' + str : str; + }; - /* - * Returns a new Decimal whose value is the nearest multiple of the magnitude of `y` to the value - * of this Decimal. - * - * If the value of this Decimal is equidistant from two multiples of `y`, the rounding mode `rm`, - * or `Decimal.rounding` if `rm` is omitted, determines the direction of the nearest multiple. - * - * In the context of this method, rounding mode 4 (ROUND_HALF_UP) is the same as rounding mode 0 - * (ROUND_UP), and so on. - * - * The return value will always have the same sign as this Decimal, unless either this Decimal - * or `y` is NaN, in which case the return value will be also be NaN. - * - * The return value is not affected by the value of `precision`. - * - * y {number|string|Decimal} The magnitude to round to a multiple of. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toNearest() rounding mode not an integer: {rm}' - * 'toNearest() rounding mode out of range: {rm}' - * - */ - P.toNearest = function (y, rm) { - var x = this, - Ctor = x.constructor; - x = new Ctor(x); + /* + * Return an array representing the value of this Decimal as a simple fraction with an integer + * numerator and an integer denominator. + * + * The denominator will be a positive non-zero value less than or equal to the specified maximum + * denominator. If a maximum denominator is not specified, the denominator will be the lowest + * value necessary to represent the number exactly. + * + * [maxD] {number|string|Decimal} Maximum denominator. Integer >= 1 and < Infinity. + * + */ + P.toFraction = function (maxD) { + var d, d0, d1, d2, e, k, n, n0, n1, pr, q, r, + x = this, + xd = x.d, + Ctor = x.constructor; - if (y == null) { + if (!xd) return new Ctor(x); - // If x is not finite, return x. - if (!x.d) return x; + n1 = d0 = new Ctor(1); + d1 = n0 = new Ctor(0); - y = new Ctor(1); - rm = Ctor.rounding; - } else { - y = new Ctor(y); - if (rm !== void 0) checkInt32(rm, 0, 8); + d = new Ctor(d1); + e = d.e = getPrecision(xd) - x.e - 1; + k = e % LOG_BASE; + d.d[0] = mathpow(10, k < 0 ? LOG_BASE + k : k); - // If x is not finite, return x if y is not NaN, else NaN. - if (!x.d) return y.s ? x : y; + if (maxD == null) { - // If y is not finite, return Infinity with the sign of x if y is Infinity, else NaN. - if (!y.d) { - if (y.s) y.s = x.s; - return y; + // d is 10**e, the minimum max-denominator needed. + maxD = e > 0 ? d : n1; + } else { + n = new Ctor(maxD); + if (!n.isInt() || n.lt(n1)) throw Error(invalidArgument + n); + maxD = n.gt(d) ? (e > 0 ? d : n1) : n; } - } - // If y is not zero, calculate the nearest multiple of y to x. - if (y.d[0]) { external = false; - if (rm < 4) rm = [4, 5, 7, 8][rm]; - x = divide(x, y, 0, rm, 1).times(y); - external = true; - finalise(x); + n = new Ctor(digitsToString(xd)); + pr = Ctor.precision; + Ctor.precision = e = xd.length * LOG_BASE * 2; + + for (;;) { + q = divide(n, d, 0, 1, 1); + d2 = d0.plus(q.times(d1)); + if (d2.cmp(maxD) == 1) break; + d0 = d1; + d1 = d2; + d2 = n1; + n1 = n0.plus(q.times(d2)); + n0 = d2; + d2 = d; + d = n.minus(q.times(d2)); + n = d2; + } - // If y is zero, return zero with the sign of x. - } else { - y.s = x.s; - x = y; - } + d2 = divide(maxD.minus(d0), d1, 0, 1, 1); + n0 = n0.plus(d2.times(n1)); + d0 = d0.plus(d2.times(d1)); + n0.s = n1.s = x.s; - return x; - }; + // Determine which fraction is closer to x, n0/d0 or n1/d1? + r = divide(n1, d1, e, 1).minus(x).abs().cmp(divide(n0, d0, e, 1).minus(x).abs()) < 1 + ? [n1, d1] : [n0, d0]; + Ctor.precision = pr; + external = true; - /* - * Return the value of this Decimal converted to a number primitive. - * Zero keeps its sign. - * - */ - P.toNumber = function () { - return +this; - }; + return r; + }; - /* - * Return a string representing the value of this Decimal in base 8, round to `sd` significant - * digits using rounding mode `rm`. - * - * If the optional `sd` argument is present then return binary exponential notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toOctal = function (sd, rm) { - return toStringBinary(this, 8, sd, rm); - }; + /* + * Return a string representing the value of this Decimal in base 16, round to `sd` significant + * digits using rounding mode `rm`. + * + * If the optional `sd` argument is present then return binary exponential notation. + * + * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + */ + P.toHexadecimal = P.toHex = function (sd, rm) { + return toStringBinary(this, 16, sd, rm); + }; - /* - * Return a new Decimal whose value is the value of this Decimal raised to the power `y`, rounded - * to `precision` significant digits using rounding mode `rounding`. - * - * ECMAScript compliant. - * - * pow(x, NaN) = NaN - * pow(x, ±0) = 1 - - * pow(NaN, non-zero) = NaN - * pow(abs(x) > 1, +Infinity) = +Infinity - * pow(abs(x) > 1, -Infinity) = +0 - * pow(abs(x) == 1, ±Infinity) = NaN - * pow(abs(x) < 1, +Infinity) = +0 - * pow(abs(x) < 1, -Infinity) = +Infinity - * pow(+Infinity, y > 0) = +Infinity - * pow(+Infinity, y < 0) = +0 - * pow(-Infinity, odd integer > 0) = -Infinity - * pow(-Infinity, even integer > 0) = +Infinity - * pow(-Infinity, odd integer < 0) = -0 - * pow(-Infinity, even integer < 0) = +0 - * pow(+0, y > 0) = +0 - * pow(+0, y < 0) = +Infinity - * pow(-0, odd integer > 0) = -0 - * pow(-0, even integer > 0) = +0 - * pow(-0, odd integer < 0) = -Infinity - * pow(-0, even integer < 0) = +Infinity - * pow(finite x < 0, finite non-integer) = NaN - * - * For non-integer or very large exponents pow(x, y) is calculated using - * - * x^y = exp(y*ln(x)) - * - * Assuming the first 15 rounding digits are each equally likely to be any digit 0-9, the - * probability of an incorrectly rounded result - * P([49]9{14} | [50]0{14}) = 2 * 0.2 * 10^-14 = 4e-15 = 1/2.5e+14 - * i.e. 1 in 250,000,000,000,000 - * - * If a result is incorrectly rounded the maximum error will be 1 ulp (unit in last place). - * - * y {number|string|Decimal} The power to which to raise this Decimal. - * - */ - P.toPower = P.pow = function (y) { - var e, k, pr, r, rm, s, - x = this, - Ctor = x.constructor, - yn = +(y = new Ctor(y)); - // Either ±Infinity, NaN or ±0? - if (!x.d || !y.d || !x.d[0] || !y.d[0]) return new Ctor(mathpow(+x, yn)); + /* + * Returns a new Decimal whose value is the nearest multiple of the magnitude of `y` to the value + * of this Decimal. + * + * If the value of this Decimal is equidistant from two multiples of `y`, the rounding mode `rm`, + * or `Decimal.rounding` if `rm` is omitted, determines the direction of the nearest multiple. + * + * In the context of this method, rounding mode 4 (ROUND_HALF_UP) is the same as rounding mode 0 + * (ROUND_UP), and so on. + * + * The return value will always have the same sign as this Decimal, unless either this Decimal + * or `y` is NaN, in which case the return value will be also be NaN. + * + * The return value is not affected by the value of `precision`. + * + * y {number|string|Decimal} The magnitude to round to a multiple of. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toNearest() rounding mode not an integer: {rm}' + * 'toNearest() rounding mode out of range: {rm}' + * + */ + P.toNearest = function (y, rm) { + var x = this, + Ctor = x.constructor; - x = new Ctor(x); + x = new Ctor(x); - if (x.eq(1)) return x; + if (y == null) { - pr = Ctor.precision; - rm = Ctor.rounding; + // If x is not finite, return x. + if (!x.d) return x; - if (y.eq(1)) return finalise(x, pr, rm); + y = new Ctor(1); + rm = Ctor.rounding; + } else { + y = new Ctor(y); + if (rm !== void 0) checkInt32(rm, 0, 8); - // y exponent - e = mathfloor(y.e / LOG_BASE); + // If x is not finite, return x if y is not NaN, else NaN. + if (!x.d) return y.s ? x : y; - // If y is a small integer use the 'exponentiation by squaring' algorithm. - if (e >= y.d.length - 1 && (k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) { - r = intPow(Ctor, x, k, pr); - return y.s < 0 ? new Ctor(1).div(r) : finalise(r, pr, rm); - } + // If y is not finite, return Infinity with the sign of x if y is Infinity, else NaN. + if (!y.d) { + if (y.s) y.s = x.s; + return y; + } + } - s = x.s; + // If y is not zero, calculate the nearest multiple of y to x. + if (y.d[0]) { + external = false; + if (rm < 4) rm = [4, 5, 7, 8][rm]; + x = divide(x, y, 0, rm, 1).times(y); + external = true; + finalise(x); - // if x is negative - if (s < 0) { + // If y is zero, return zero with the sign of x. + } else { + y.s = x.s; + x = y; + } - // if y is not an integer - if (e < y.d.length - 1) return new Ctor(NaN); + return x; + }; - // Result is positive if x is negative and the last digit of integer y is even. - if ((y.d[e] & 1) == 0) s = 1; - // if x.eq(-1) - if (x.e == 0 && x.d[0] == 1 && x.d.length == 1) { - x.s = s; - return x; - } - } + /* + * Return the value of this Decimal converted to a number primitive. + * Zero keeps its sign. + * + */ + P.toNumber = function () { + return +this; + }; - // Estimate result exponent. - // x^y = 10^e, where e = y * log10(x) - // log10(x) = log10(x_significand) + x_exponent - // log10(x_significand) = ln(x_significand) / ln(10) - k = mathpow(+x, yn); - e = k == 0 || !isFinite(k) - ? mathfloor(yn * (Math.log('0.' + digitsToString(x.d)) / Math.LN10 + x.e + 1)) - : new Ctor(k + '').e; - // Exponent estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1. + /* + * Return a string representing the value of this Decimal in base 8, round to `sd` significant + * digits using rounding mode `rm`. + * + * If the optional `sd` argument is present then return binary exponential notation. + * + * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + */ + P.toOctal = function (sd, rm) { + return toStringBinary(this, 8, sd, rm); + }; - // Overflow/underflow? - if (e > Ctor.maxE + 1 || e < Ctor.minE - 1) return new Ctor(e > 0 ? s / 0 : 0); - external = false; - Ctor.rounding = x.s = 1; + /* + * Return a new Decimal whose value is the value of this Decimal raised to the power `y`, rounded + * to `precision` significant digits using rounding mode `rounding`. + * + * ECMAScript compliant. + * + * pow(x, NaN) = NaN + * pow(x, ±0) = 1 + + * pow(NaN, non-zero) = NaN + * pow(abs(x) > 1, +Infinity) = +Infinity + * pow(abs(x) > 1, -Infinity) = +0 + * pow(abs(x) == 1, ±Infinity) = NaN + * pow(abs(x) < 1, +Infinity) = +0 + * pow(abs(x) < 1, -Infinity) = +Infinity + * pow(+Infinity, y > 0) = +Infinity + * pow(+Infinity, y < 0) = +0 + * pow(-Infinity, odd integer > 0) = -Infinity + * pow(-Infinity, even integer > 0) = +Infinity + * pow(-Infinity, odd integer < 0) = -0 + * pow(-Infinity, even integer < 0) = +0 + * pow(+0, y > 0) = +0 + * pow(+0, y < 0) = +Infinity + * pow(-0, odd integer > 0) = -0 + * pow(-0, even integer > 0) = +0 + * pow(-0, odd integer < 0) = -Infinity + * pow(-0, even integer < 0) = +Infinity + * pow(finite x < 0, finite non-integer) = NaN + * + * For non-integer or very large exponents pow(x, y) is calculated using + * + * x^y = exp(y*ln(x)) + * + * Assuming the first 15 rounding digits are each equally likely to be any digit 0-9, the + * probability of an incorrectly rounded result + * P([49]9{14} | [50]0{14}) = 2 * 0.2 * 10^-14 = 4e-15 = 1/2.5e+14 + * i.e. 1 in 250,000,000,000,000 + * + * If a result is incorrectly rounded the maximum error will be 1 ulp (unit in last place). + * + * y {number|string|Decimal} The power to which to raise this Decimal. + * + */ + P.toPower = P.pow = function (y) { + var e, k, pr, r, rm, s, + x = this, + Ctor = x.constructor, + yn = +(y = new Ctor(y)); - // Estimate the extra guard digits needed to ensure five correct rounding digits from - // naturalLogarithm(x). Example of failure without these extra digits (precision: 10): - // new Decimal(2.32456).pow('2087987436534566.46411') - // should be 1.162377823e+764914905173815, but is 1.162355823e+764914905173815 - k = Math.min(12, (e + '').length); + // Either ±Infinity, NaN or ±0? + if (!x.d || !y.d || !x.d[0] || !y.d[0]) return new Ctor(mathpow(+x, yn)); - // r = x^y = exp(y*ln(x)) - r = naturalExponential(y.times(naturalLogarithm(x, pr + k)), pr); + x = new Ctor(x); - // r may be Infinity, e.g. (0.9999999999999999).pow(-1e+40) - if (r.d) { + if (x.eq(1)) return x; - // Truncate to the required precision plus five rounding digits. - r = finalise(r, pr + 5, 1); + pr = Ctor.precision; + rm = Ctor.rounding; - // If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate - // the result. - if (checkRoundingDigits(r.d, pr, rm)) { - e = pr + 10; + if (y.eq(1)) return finalise(x, pr, rm); - // Truncate to the increased precision plus five rounding digits. - r = finalise(naturalExponential(y.times(naturalLogarithm(x, e + k)), e), e + 5, 1); + // y exponent + e = mathfloor(y.e / LOG_BASE); - // Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9). - if (+digitsToString(r.d).slice(pr + 1, pr + 15) + 1 == 1e14) { - r = finalise(r, pr + 1, 0); - } + // If y is a small integer use the 'exponentiation by squaring' algorithm. + if (e >= y.d.length - 1 && (k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) { + r = intPow(Ctor, x, k, pr); + return y.s < 0 ? new Ctor(1).div(r) : finalise(r, pr, rm); } - } - r.s = s; - external = true; - Ctor.rounding = rm; + s = x.s; - return finalise(r, pr, rm); - }; - - - /* - * Return a string representing the value of this Decimal rounded to `sd` significant digits - * using rounding mode `rounding`. - * - * Return exponential notation if `sd` is less than the number of digits necessary to represent - * the integer part of the value in normal notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toPrecision = function (sd, rm) { - var str, - x = this, - Ctor = x.constructor; + // if x is negative + if (s < 0) { - if (sd === void 0) { - str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); - } else { - checkInt32(sd, 1, MAX_DIGITS); + // if y is not an integer + if (e < y.d.length - 1) return new Ctor(NaN); - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); + // Result is positive if x is negative and the last digit of integer y is even. + if ((y.d[e] & 1) == 0) s = 1; - x = finalise(new Ctor(x), sd, rm); - str = finiteToString(x, sd <= x.e || x.e <= Ctor.toExpNeg, sd); - } + // if x.eq(-1) + if (x.e == 0 && x.d[0] == 1 && x.d.length == 1) { + x.s = s; + return x; + } + } - return x.isNeg() && !x.isZero() ? '-' + str : str; - }; + // Estimate result exponent. + // x^y = 10^e, where e = y * log10(x) + // log10(x) = log10(x_significand) + x_exponent + // log10(x_significand) = ln(x_significand) / ln(10) + k = mathpow(+x, yn); + e = k == 0 || !isFinite(k) + ? mathfloor(yn * (Math.log('0.' + digitsToString(x.d)) / Math.LN10 + x.e + 1)) + : new Ctor(k + '').e; + // Exponent estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1. - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `sd` - * significant digits using rounding mode `rm`, or to `precision` and `rounding` respectively if - * omitted. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toSD() digits out of range: {sd}' - * 'toSD() digits not an integer: {sd}' - * 'toSD() rounding mode not an integer: {rm}' - * 'toSD() rounding mode out of range: {rm}' - * - */ - P.toSignificantDigits = P.toSD = function (sd, rm) { - var x = this, - Ctor = x.constructor; + // Overflow/underflow? + if (e > Ctor.maxE + 1 || e < Ctor.minE - 1) return new Ctor(e > 0 ? s / 0 : 0); - if (sd === void 0) { - sd = Ctor.precision; - rm = Ctor.rounding; - } else { - checkInt32(sd, 1, MAX_DIGITS); + external = false; + Ctor.rounding = x.s = 1; - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); - } + // Estimate the extra guard digits needed to ensure five correct rounding digits from + // naturalLogarithm(x). Example of failure without these extra digits (precision: 10): + // new Decimal(2.32456).pow('2087987436534566.46411') + // should be 1.162377823e+764914905173815, but is 1.162355823e+764914905173815 + k = Math.min(12, (e + '').length); - return finalise(new Ctor(x), sd, rm); - }; + // r = x^y = exp(y*ln(x)) + r = naturalExponential(y.times(naturalLogarithm(x, pr + k)), pr); + // r may be Infinity, e.g. (0.9999999999999999).pow(-1e+40) + if (r.d) { - /* - * Return a string representing the value of this Decimal. - * - * Return exponential notation if this Decimal has a positive exponent equal to or greater than - * `toExpPos`, or a negative exponent equal to or less than `toExpNeg`. - * - */ - P.toString = function () { - var x = this, - Ctor = x.constructor, - str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); + // Truncate to the required precision plus five rounding digits. + r = finalise(r, pr + 5, 1); - return x.isNeg() && !x.isZero() ? '-' + str : str; - }; + // If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate + // the result. + if (checkRoundingDigits(r.d, pr, rm)) { + e = pr + 10; + // Truncate to the increased precision plus five rounding digits. + r = finalise(naturalExponential(y.times(naturalLogarithm(x, e + k)), e), e + 5, 1); - /* - * Return a new Decimal whose value is the value of this Decimal truncated to a whole number. - * - */ - P.truncated = P.trunc = function () { - return finalise(new this.constructor(this), this.e + 1, 1); - }; + // Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9). + if (+digitsToString(r.d).slice(pr + 1, pr + 15) + 1 == 1e14) { + r = finalise(r, pr + 1, 0); + } + } + } + r.s = s; + external = true; + Ctor.rounding = rm; - /* - * Return a string representing the value of this Decimal. - * Unlike `toString`, negative zero will include the minus sign. - * - */ - P.valueOf = P.toJSON = function () { - var x = this, - Ctor = x.constructor, - str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); + return finalise(r, pr, rm); + }; - return x.isNeg() ? '-' + str : str; - }; + /* + * Return a string representing the value of this Decimal rounded to `sd` significant digits + * using rounding mode `rounding`. + * + * Return exponential notation if `sd` is less than the number of digits necessary to represent + * the integer part of the value in normal notation. + * + * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + */ + P.toPrecision = function (sd, rm) { + var str, + x = this, + Ctor = x.constructor; - /* - // Add aliases to match BigDecimal method names. - // P.add = P.plus; - P.subtract = P.minus; - P.multiply = P.times; - P.divide = P.div; - P.remainder = P.mod; - P.compareTo = P.cmp; - P.negate = P.neg; - */ + if (sd === void 0) { + str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); + } else { + checkInt32(sd, 1, MAX_DIGITS); + if (rm === void 0) rm = Ctor.rounding; + else checkInt32(rm, 0, 8); - // Helper functions for Decimal.prototype (P) and/or Decimal methods, and their callers. + x = finalise(new Ctor(x), sd, rm); + str = finiteToString(x, sd <= x.e || x.e <= Ctor.toExpNeg, sd); + } + return x.isNeg() && !x.isZero() ? '-' + str : str; + }; - /* - * digitsToString P.cubeRoot, P.logarithm, P.squareRoot, P.toFraction, P.toPower, - * finiteToString, naturalExponential, naturalLogarithm - * checkInt32 P.toDecimalPlaces, P.toExponential, P.toFixed, P.toNearest, - * P.toPrecision, P.toSignificantDigits, toStringBinary, random - * checkRoundingDigits P.logarithm, P.toPower, naturalExponential, naturalLogarithm - * convertBase toStringBinary, parseOther - * cos P.cos - * divide P.atanh, P.cubeRoot, P.dividedBy, P.dividedToIntegerBy, - * P.logarithm, P.modulo, P.squareRoot, P.tan, P.tanh, P.toFraction, - * P.toNearest, toStringBinary, naturalExponential, naturalLogarithm, - * taylorSeries, atan2, parseOther - * finalise P.absoluteValue, P.atan, P.atanh, P.ceil, P.cos, P.cosh, - * P.cubeRoot, P.dividedToIntegerBy, P.floor, P.logarithm, P.minus, - * P.modulo, P.negated, P.plus, P.round, P.sin, P.sinh, P.squareRoot, - * P.tan, P.times, P.toDecimalPlaces, P.toExponential, P.toFixed, - * P.toNearest, P.toPower, P.toPrecision, P.toSignificantDigits, - * P.truncated, divide, getLn10, getPi, naturalExponential, - * naturalLogarithm, ceil, floor, round, trunc - * finiteToString P.toExponential, P.toFixed, P.toPrecision, P.toString, P.valueOf, - * toStringBinary - * getBase10Exponent P.minus, P.plus, P.times, parseOther - * getLn10 P.logarithm, naturalLogarithm - * getPi P.acos, P.asin, P.atan, toLessThanHalfPi, atan2 - * getPrecision P.precision, P.toFraction - * getZeroString digitsToString, finiteToString - * intPow P.toPower, parseOther - * isOdd toLessThanHalfPi - * maxOrMin max, min - * naturalExponential P.naturalExponential, P.toPower - * naturalLogarithm P.acosh, P.asinh, P.atanh, P.logarithm, P.naturalLogarithm, - * P.toPower, naturalExponential - * nonFiniteToString finiteToString, toStringBinary - * parseDecimal Decimal - * parseOther Decimal - * sin P.sin - * taylorSeries P.cosh, P.sinh, cos, sin - * toLessThanHalfPi P.cos, P.sin - * toStringBinary P.toBinary, P.toHexadecimal, P.toOctal - * truncate intPow - * - * Throws: P.logarithm, P.precision, P.toFraction, checkInt32, getLn10, getPi, - * naturalLogarithm, config, parseOther, random, Decimal - */ + /* + * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `sd` + * significant digits using rounding mode `rm`, or to `precision` and `rounding` respectively if + * omitted. + * + * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. + * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. + * + * 'toSD() digits out of range: {sd}' + * 'toSD() digits not an integer: {sd}' + * 'toSD() rounding mode not an integer: {rm}' + * 'toSD() rounding mode out of range: {rm}' + * + */ + P.toSignificantDigits = P.toSD = function (sd, rm) { + var x = this, + Ctor = x.constructor; - function digitsToString(d) { - var i, k, ws, - indexOfLastWord = d.length - 1, - str = '', - w = d[0]; + if (sd === void 0) { + sd = Ctor.precision; + rm = Ctor.rounding; + } else { + checkInt32(sd, 1, MAX_DIGITS); - if (indexOfLastWord > 0) { - str += w; - for (i = 1; i < indexOfLastWord; i++) { - ws = d[i] + ''; - k = LOG_BASE - ws.length; - if (k) str += getZeroString(k); - str += ws; + if (rm === void 0) rm = Ctor.rounding; + else checkInt32(rm, 0, 8); } - w = d[i]; - ws = w + ''; - k = LOG_BASE - ws.length; - if (k) str += getZeroString(k); - } else if (w === 0) { - return '0'; - } + return finalise(new Ctor(x), sd, rm); + }; - // Remove trailing zeros of last w. - for (; w % 10 === 0;) w /= 10; - return str + w; - } + /* + * Return a string representing the value of this Decimal. + * + * Return exponential notation if this Decimal has a positive exponent equal to or greater than + * `toExpPos`, or a negative exponent equal to or less than `toExpNeg`. + * + */ + P.toString = function () { + var x = this, + Ctor = x.constructor, + str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); + return x.isNeg() && !x.isZero() ? '-' + str : str; + }; - function checkInt32(i, min, max) { - if (i !== ~~i || i < min || i > max) { - throw Error(invalidArgument + i); - } - } + /* + * Return a new Decimal whose value is the value of this Decimal truncated to a whole number. + * + */ + P.truncated = P.trunc = function () { + return finalise(new this.constructor(this), this.e + 1, 1); + }; - /* - * Check 5 rounding digits if `repeating` is null, 4 otherwise. - * `repeating == null` if caller is `log` or `pow`, - * `repeating != null` if caller is `naturalLogarithm` or `naturalExponential`. - */ - function checkRoundingDigits(d, i, rm, repeating) { - var di, k, r, rd; - // Get the length of the first word of the array d. - for (k = d[0]; k >= 10; k /= 10) --i; + /* + * Return a string representing the value of this Decimal. + * Unlike `toString`, negative zero will include the minus sign. + * + */ + P.valueOf = P.toJSON = function () { + var x = this, + Ctor = x.constructor, + str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); - // Is the rounding digit in the first word of d? - if (--i < 0) { - i += LOG_BASE; - di = 0; - } else { - di = Math.ceil((i + 1) / LOG_BASE); - i %= LOG_BASE; - } + return x.isNeg() ? '-' + str : str; + }; - // i is the index (0 - 6) of the rounding digit. - // E.g. if within the word 3487563 the first rounding digit is 5, - // then i = 4, k = 1000, rd = 3487563 % 1000 = 563 - k = mathpow(10, LOG_BASE - i); - rd = d[di] % k | 0; - - if (repeating == null) { - if (i < 3) { - if (i == 0) rd = rd / 100 | 0; - else if (i == 1) rd = rd / 10 | 0; - r = rm < 4 && rd == 99999 || rm > 3 && rd == 49999 || rd == 50000 || rd == 0; - } else { - r = (rm < 4 && rd + 1 == k || rm > 3 && rd + 1 == k / 2) && - (d[di + 1] / k / 100 | 0) == mathpow(10, i - 2) - 1 || - (rd == k / 2 || rd == 0) && (d[di + 1] / k / 100 | 0) == 0; - } - } else { - if (i < 4) { - if (i == 0) rd = rd / 1000 | 0; - else if (i == 1) rd = rd / 100 | 0; - else if (i == 2) rd = rd / 10 | 0; - r = (repeating || rm < 4) && rd == 9999 || !repeating && rm > 3 && rd == 4999; - } else { - r = ((repeating || rm < 4) && rd + 1 == k || - (!repeating && rm > 3) && rd + 1 == k / 2) && - (d[di + 1] / k / 1000 | 0) == mathpow(10, i - 3) - 1; - } - } - return r; - } + /* + // Add aliases to match BigDecimal method names. + // P.add = P.plus; + P.subtract = P.minus; + P.multiply = P.times; + P.divide = P.div; + P.remainder = P.mod; + P.compareTo = P.cmp; + P.negate = P.neg; + */ - // Convert string of `baseIn` to an array of numbers of `baseOut`. - // Eg. convertBase('255', 10, 16) returns [15, 15]. - // Eg. convertBase('ff', 16, 10) returns [2, 5, 5]. - function convertBase(str, baseIn, baseOut) { - var j, - arr = [0], - arrL, - i = 0, - strL = str.length; - - for (; i < strL;) { - for (arrL = arr.length; arrL--;) arr[arrL] *= baseIn; - arr[0] += NUMERALS.indexOf(str.charAt(i++)); - for (j = 0; j < arr.length; j++) { - if (arr[j] > baseOut - 1) { - if (arr[j + 1] === void 0) arr[j + 1] = 0; - arr[j + 1] += arr[j] / baseOut | 0; - arr[j] %= baseOut; - } - } - } + // Helper functions for Decimal.prototype (P) and/or Decimal methods, and their callers. - return arr.reverse(); - } + /* + * digitsToString P.cubeRoot, P.logarithm, P.squareRoot, P.toFraction, P.toPower, + * finiteToString, naturalExponential, naturalLogarithm + * checkInt32 P.toDecimalPlaces, P.toExponential, P.toFixed, P.toNearest, + * P.toPrecision, P.toSignificantDigits, toStringBinary, random + * checkRoundingDigits P.logarithm, P.toPower, naturalExponential, naturalLogarithm + * convertBase toStringBinary, parseOther + * cos P.cos + * divide P.atanh, P.cubeRoot, P.dividedBy, P.dividedToIntegerBy, + * P.logarithm, P.modulo, P.squareRoot, P.tan, P.tanh, P.toFraction, + * P.toNearest, toStringBinary, naturalExponential, naturalLogarithm, + * taylorSeries, atan2, parseOther + * finalise P.absoluteValue, P.atan, P.atanh, P.ceil, P.cos, P.cosh, + * P.cubeRoot, P.dividedToIntegerBy, P.floor, P.logarithm, P.minus, + * P.modulo, P.negated, P.plus, P.round, P.sin, P.sinh, P.squareRoot, + * P.tan, P.times, P.toDecimalPlaces, P.toExponential, P.toFixed, + * P.toNearest, P.toPower, P.toPrecision, P.toSignificantDigits, + * P.truncated, divide, getLn10, getPi, naturalExponential, + * naturalLogarithm, ceil, floor, round, trunc + * finiteToString P.toExponential, P.toFixed, P.toPrecision, P.toString, P.valueOf, + * toStringBinary + * getBase10Exponent P.minus, P.plus, P.times, parseOther + * getLn10 P.logarithm, naturalLogarithm + * getPi P.acos, P.asin, P.atan, toLessThanHalfPi, atan2 + * getPrecision P.precision, P.toFraction + * getZeroString digitsToString, finiteToString + * intPow P.toPower, parseOther + * isOdd toLessThanHalfPi + * maxOrMin max, min + * naturalExponential P.naturalExponential, P.toPower + * naturalLogarithm P.acosh, P.asinh, P.atanh, P.logarithm, P.naturalLogarithm, + * P.toPower, naturalExponential + * nonFiniteToString finiteToString, toStringBinary + * parseDecimal Decimal + * parseOther Decimal + * sin P.sin + * taylorSeries P.cosh, P.sinh, cos, sin + * toLessThanHalfPi P.cos, P.sin + * toStringBinary P.toBinary, P.toHexadecimal, P.toOctal + * truncate intPow + * + * Throws: P.logarithm, P.precision, P.toFraction, checkInt32, getLn10, getPi, + * naturalLogarithm, config, parseOther, random, Decimal + */ - /* - * cos(x) = 1 - x^2/2! + x^4/4! - ... - * |x| < pi/2 - * - */ - function cosine(Ctor, x) { - var k, y, - len = x.d.length; - // Argument reduction: cos(4x) = 8*(cos^4(x) - cos^2(x)) + 1 - // i.e. cos(x) = 8*(cos^4(x/4) - cos^2(x/4)) + 1 + function digitsToString(d) { + var i, k, ws, + indexOfLastWord = d.length - 1, + str = '', + w = d[0]; - // Estimate the optimum number of times to use the argument reduction. - if (len < 32) { - k = Math.ceil(len / 3); - y = Math.pow(4, -k).toString(); - } else { - k = 16; - y = '2.3283064365386962890625e-10'; - } + if (indexOfLastWord > 0) { + str += w; + for (i = 1; i < indexOfLastWord; i++) { + ws = d[i] + ''; + k = LOG_BASE - ws.length; + if (k) str += getZeroString(k); + str += ws; + } - Ctor.precision += k; + w = d[i]; + ws = w + ''; + k = LOG_BASE - ws.length; + if (k) str += getZeroString(k); + } else if (w === 0) { + return '0'; + } - x = taylorSeries(Ctor, 1, x.times(y), new Ctor(1)); + // Remove trailing zeros of last w. + for (; w % 10 === 0;) w /= 10; - // Reverse argument reduction - for (var i = k; i--;) { - var cos2x = x.times(x); - x = cos2x.times(cos2x).minus(cos2x).times(8).plus(1); + return str + w; } - Ctor.precision -= k; - return x; - } - - - /* - * Perform division in the specified base. - */ - var divide = (function () { - - // Assumes non-zero x and k, and hence non-zero result. - function multiplyInteger(x, k, base) { - var temp, - carry = 0, - i = x.length; - - for (x = x.slice(); i--;) { - temp = x[i] * k + carry; - x[i] = temp % base | 0; - carry = temp / base | 0; + function checkInt32(i, min, max) { + if (i !== ~~i || i < min || i > max) { + throw Error(invalidArgument + i); } + } - if (carry) x.unshift(carry); - return x; - } + /* + * Check 5 rounding digits if `repeating` is null, 4 otherwise. + * `repeating == null` if caller is `log` or `pow`, + * `repeating != null` if caller is `naturalLogarithm` or `naturalExponential`. + */ + function checkRoundingDigits(d, i, rm, repeating) { + var di, k, r, rd; - function compare(a, b, aL, bL) { - var i, r; + // Get the length of the first word of the array d. + for (k = d[0]; k >= 10; k /= 10) --i; - if (aL != bL) { - r = aL > bL ? 1 : -1; + // Is the rounding digit in the first word of d? + if (--i < 0) { + i += LOG_BASE; + di = 0; } else { - for (i = r = 0; i < aL; i++) { - if (a[i] != b[i]) { - r = a[i] > b[i] ? 1 : -1; - break; - } + di = Math.ceil((i + 1) / LOG_BASE); + i %= LOG_BASE; + } + + // i is the index (0 - 6) of the rounding digit. + // E.g. if within the word 3487563 the first rounding digit is 5, + // then i = 4, k = 1000, rd = 3487563 % 1000 = 563 + k = mathpow(10, LOG_BASE - i); + rd = d[di] % k | 0; + + if (repeating == null) { + if (i < 3) { + if (i == 0) rd = rd / 100 | 0; + else if (i == 1) rd = rd / 10 | 0; + r = rm < 4 && rd == 99999 || rm > 3 && rd == 49999 || rd == 50000 || rd == 0; + } else { + r = (rm < 4 && rd + 1 == k || rm > 3 && rd + 1 == k / 2) && + (d[di + 1] / k / 100 | 0) == mathpow(10, i - 2) - 1 || + (rd == k / 2 || rd == 0) && (d[di + 1] / k / 100 | 0) == 0; + } + } else { + if (i < 4) { + if (i == 0) rd = rd / 1000 | 0; + else if (i == 1) rd = rd / 100 | 0; + else if (i == 2) rd = rd / 10 | 0; + r = (repeating || rm < 4) && rd == 9999 || !repeating && rm > 3 && rd == 4999; + } else { + r = ((repeating || rm < 4) && rd + 1 == k || + (!repeating && rm > 3) && rd + 1 == k / 2) && + (d[di + 1] / k / 1000 | 0) == mathpow(10, i - 3) - 1; } } return r; } - function subtract(a, b, aL, base) { - var i = 0; - // Subtract b from a. - for (; aL--;) { - a[aL] -= i; - i = a[aL] < b[aL] ? 1 : 0; - a[aL] = i * base + a[aL] - b[aL]; + // Convert string of `baseIn` to an array of numbers of `baseOut`. + // Eg. convertBase('255', 10, 16) returns [15, 15]. + // Eg. convertBase('ff', 16, 10) returns [2, 5, 5]. + function convertBase(str, baseIn, baseOut) { + var j, + arr = [0], + arrL, + i = 0, + strL = str.length; + + for (; i < strL;) { + for (arrL = arr.length; arrL--;) arr[arrL] *= baseIn; + arr[0] += NUMERALS.indexOf(str.charAt(i++)); + for (j = 0; j < arr.length; j++) { + if (arr[j] > baseOut - 1) { + if (arr[j + 1] === void 0) arr[j + 1] = 0; + arr[j + 1] += arr[j] / baseOut | 0; + arr[j] %= baseOut; + } + } } - // Remove leading zeros. - for (; !a[0] && a.length > 1;) a.shift(); + return arr.reverse(); } - return function (x, y, pr, rm, dp, base) { - var cmp, e, i, k, logBase, more, prod, prodL, q, qd, rem, remL, rem0, sd, t, xi, xL, yd0, - yL, yz, - Ctor = x.constructor, - sign = x.s == y.s ? 1 : -1, - xd = x.d, - yd = y.d; - - // Either NaN, Infinity or 0? - if (!xd || !xd[0] || !yd || !yd[0]) { - return new Ctor(// Return NaN if either NaN, or both Infinity or 0. - !x.s || !y.s || (xd ? yd && xd[0] == yd[0] : !yd) ? NaN : + /* + * cos(x) = 1 - x^2/2! + x^4/4! - ... + * |x| < pi/2 + * + */ + function cosine(Ctor, x) { + var k, y, + len = x.d.length; - // Return ±0 if x is 0 or y is ±Infinity, or return ±Infinity as y is 0. - xd && xd[0] == 0 || !yd ? sign * 0 : sign / 0); - } + // Argument reduction: cos(4x) = 8*(cos^4(x) - cos^2(x)) + 1 + // i.e. cos(x) = 8*(cos^4(x/4) - cos^2(x/4)) + 1 - if (base) { - logBase = 1; - e = x.e - y.e; + // Estimate the optimum number of times to use the argument reduction. + if (len < 32) { + k = Math.ceil(len / 3); + y = Math.pow(4, -k).toString(); } else { - base = BASE; - logBase = LOG_BASE; - e = mathfloor(x.e / logBase) - mathfloor(y.e / logBase); + k = 16; + y = '2.3283064365386962890625e-10'; } - yL = yd.length; - xL = xd.length; - q = new Ctor(sign); - qd = q.d = []; + Ctor.precision += k; - // Result exponent may be one less than e. - // The digit array of a Decimal from toStringBinary may have trailing zeros. - for (i = 0; yd[i] == (xd[i] || 0); i++); + x = taylorSeries(Ctor, 1, x.times(y), new Ctor(1)); - if (yd[i] > (xd[i] || 0)) e--; - - if (pr == null) { - sd = pr = Ctor.precision; - rm = Ctor.rounding; - } else if (dp) { - sd = pr + (x.e - y.e) + 1; - } else { - sd = pr; + // Reverse argument reduction + for (var i = k; i--;) { + var cos2x = x.times(x); + x = cos2x.times(cos2x).minus(cos2x).times(8).plus(1); } - if (sd < 0) { - qd.push(1); - more = true; - } else { + Ctor.precision -= k; - // Convert precision in number of base 10 digits to base 1e7 digits. - sd = sd / logBase + 2 | 0; - i = 0; + return x; + } - // divisor < 1e7 - if (yL == 1) { - k = 0; - yd = yd[0]; - sd++; - - // k is the carry. - for (; (i < xL || k) && sd--; i++) { - t = k * base + (xd[i] || 0); - qd[i] = t / yd | 0; - k = t % yd | 0; - } - more = k || i < xL; + /* + * Perform division in the specified base. + */ + var divide = (function () { + + // Assumes non-zero x and k, and hence non-zero result. + function multiplyInteger(x, k, base) { + var temp, + carry = 0, + i = x.length; + + for (x = x.slice(); i--;) { + temp = x[i] * k + carry; + x[i] = temp % base | 0; + carry = temp / base | 0; + } + + if (carry) x.unshift(carry); - // divisor >= 1e7 - } else { + return x; + } - // Normalise xd and yd so highest order digit of yd is >= base/2 - k = base / (yd[0] + 1) | 0; + function compare(a, b, aL, bL) { + var i, r; - if (k > 1) { - yd = multiplyInteger(yd, k, base); - xd = multiplyInteger(xd, k, base); - yL = yd.length; - xL = xd.length; + if (aL != bL) { + r = aL > bL ? 1 : -1; + } else { + for (i = r = 0; i < aL; i++) { + if (a[i] != b[i]) { + r = a[i] > b[i] ? 1 : -1; + break; + } } + } - xi = yL; - rem = xd.slice(0, yL); - remL = rem.length; + return r; + } - // Add zeros to make remainder as long as divisor. - for (; remL < yL;) rem[remL++] = 0; + function subtract(a, b, aL, base) { + var i = 0; - yz = yd.slice(); - yz.unshift(0); - yd0 = yd[0]; + // Subtract b from a. + for (; aL--;) { + a[aL] -= i; + i = a[aL] < b[aL] ? 1 : 0; + a[aL] = i * base + a[aL] - b[aL]; + } - if (yd[1] >= base / 2) ++yd0; + // Remove leading zeros. + for (; !a[0] && a.length > 1;) a.shift(); + } - do { - k = 0; + return function (x, y, pr, rm, dp, base) { + var cmp, e, i, k, logBase, more, prod, prodL, q, qd, rem, remL, rem0, sd, t, xi, xL, yd0, + yL, yz, + Ctor = x.constructor, + sign = x.s == y.s ? 1 : -1, + xd = x.d, + yd = y.d; - // Compare divisor and remainder. - cmp = compare(yd, rem, yL, remL); + // Either NaN, Infinity or 0? + if (!xd || !xd[0] || !yd || !yd[0]) { - // If divisor < remainder. - if (cmp < 0) { + return new Ctor(// Return NaN if either NaN, or both Infinity or 0. + !x.s || !y.s || (xd ? yd && xd[0] == yd[0] : !yd) ? NaN : - // Calculate trial digit, k. - rem0 = rem[0]; - if (yL != remL) rem0 = rem0 * base + (rem[1] || 0); + // Return ±0 if x is 0 or y is ±Infinity, or return ±Infinity as y is 0. + xd && xd[0] == 0 || !yd ? sign * 0 : sign / 0); + } - // k will be how many times the divisor goes into the current remainder. - k = rem0 / yd0 | 0; + if (base) { + logBase = 1; + e = x.e - y.e; + } else { + base = BASE; + logBase = LOG_BASE; + e = mathfloor(x.e / logBase) - mathfloor(y.e / logBase); + } - // Algorithm: - // 1. product = divisor * trial digit (k) - // 2. if product > remainder: product -= divisor, k-- - // 3. remainder -= product - // 4. if product was < remainder at 2: - // 5. compare new remainder and divisor - // 6. If remainder > divisor: remainder -= divisor, k++ + yL = yd.length; + xL = xd.length; + q = new Ctor(sign); + qd = q.d = []; - if (k > 1) { - if (k >= base) k = base - 1; + // Result exponent may be one less than e. + // The digit array of a Decimal from toStringBinary may have trailing zeros. + for (i = 0; yd[i] == (xd[i] || 0); i++); - // product = divisor * trial digit. - prod = multiplyInteger(yd, k, base); - prodL = prod.length; - remL = rem.length; + if (yd[i] > (xd[i] || 0)) e--; - // Compare product and remainder. - cmp = compare(prod, rem, prodL, remL); + if (pr == null) { + sd = pr = Ctor.precision; + rm = Ctor.rounding; + } else if (dp) { + sd = pr + (x.e - y.e) + 1; + } else { + sd = pr; + } - // product > remainder. - if (cmp == 1) { - k--; + if (sd < 0) { + qd.push(1); + more = true; + } else { - // Subtract divisor from product. - subtract(prod, yL < prodL ? yz : yd, prodL, base); - } - } else { + // Convert precision in number of base 10 digits to base 1e7 digits. + sd = sd / logBase + 2 | 0; + i = 0; - // cmp is -1. - // If k is 0, there is no need to compare yd and rem again below, so change cmp to 1 - // to avoid it. If k is 1 there is a need to compare yd and rem again below. - if (k == 0) cmp = k = 1; - prod = yd.slice(); - } + // divisor < 1e7 + if (yL == 1) { + k = 0; + yd = yd[0]; + sd++; + + // k is the carry. + for (; (i < xL || k) && sd--; i++) { + t = k * base + (xd[i] || 0); + qd[i] = t / yd | 0; + k = t % yd | 0; + } - prodL = prod.length; - if (prodL < remL) prod.unshift(0); + more = k || i < xL; - // Subtract product from remainder. - subtract(rem, prod, remL, base); + // divisor >= 1e7 + } else { - // If product was < previous remainder. - if (cmp == -1) { - remL = rem.length; + // Normalise xd and yd so highest order digit of yd is >= base/2 + k = base / (yd[0] + 1) | 0; - // Compare divisor and new remainder. - cmp = compare(yd, rem, yL, remL); + if (k > 1) { + yd = multiplyInteger(yd, k, base); + xd = multiplyInteger(xd, k, base); + yL = yd.length; + xL = xd.length; + } - // If divisor < new remainder, subtract divisor from remainder. - if (cmp < 1) { - k++; + xi = yL; + rem = xd.slice(0, yL); + remL = rem.length; - // Subtract divisor from remainder. - subtract(rem, yL < remL ? yz : yd, remL, base); - } - } + // Add zeros to make remainder as long as divisor. + for (; remL < yL;) rem[remL++] = 0; - remL = rem.length; - } else if (cmp === 0) { - k++; - rem = [0]; - } // if cmp === 1, k will be 0 + yz = yd.slice(); + yz.unshift(0); + yd0 = yd[0]; - // Add the next digit, k, to the result array. - qd[i++] = k; + if (yd[1] >= base / 2) ++yd0; - // Update the remainder. - if (cmp && rem[0]) { - rem[remL++] = xd[xi] || 0; - } else { - rem = [xd[xi]]; - remL = 1; - } + do { + k = 0; - } while ((xi++ < xL || rem[0] !== void 0) && sd--); + // Compare divisor and remainder. + cmp = compare(yd, rem, yL, remL); - more = rem[0] !== void 0; - } + // If divisor < remainder. + if (cmp < 0) { - // Leading zero? - if (!qd[0]) qd.shift(); - } + // Calculate trial digit, k. + rem0 = rem[0]; + if (yL != remL) rem0 = rem0 * base + (rem[1] || 0); - // logBase is 1 when divide is being used for base conversion. - if (logBase == 1) { - q.e = e; - inexact = more; - } else { + // k will be how many times the divisor goes into the current remainder. + k = rem0 / yd0 | 0; - // To calculate q.e, first get the number of digits of qd[0]. - for (i = 1, k = qd[0]; k >= 10; k /= 10) i++; - q.e = i + e * logBase - 1; + // Algorithm: + // 1. product = divisor * trial digit (k) + // 2. if product > remainder: product -= divisor, k-- + // 3. remainder -= product + // 4. if product was < remainder at 2: + // 5. compare new remainder and divisor + // 6. If remainder > divisor: remainder -= divisor, k++ - finalise(q, dp ? pr + q.e + 1 : pr, rm, more); - } + if (k > 1) { + if (k >= base) k = base - 1; - return q; - }; - })(); + // product = divisor * trial digit. + prod = multiplyInteger(yd, k, base); + prodL = prod.length; + remL = rem.length; + // Compare product and remainder. + cmp = compare(prod, rem, prodL, remL); - /* - * Round `x` to `sd` significant digits using rounding mode `rm`. - * Check for over/under-flow. - */ - function finalise(x, sd, rm, isTruncated) { - var digits, i, j, k, rd, roundUp, w, xd, xdi, - Ctor = x.constructor; + // product > remainder. + if (cmp == 1) { + k--; - // Don't round if sd is null or undefined. - out: if (sd != null) { - xd = x.d; + // Subtract divisor from product. + subtract(prod, yL < prodL ? yz : yd, prodL, base); + } + } else { - // Infinity/NaN. - if (!xd) return x; + // cmp is -1. + // If k is 0, there is no need to compare yd and rem again below, so change cmp to 1 + // to avoid it. If k is 1 there is a need to compare yd and rem again below. + if (k == 0) cmp = k = 1; + prod = yd.slice(); + } - // rd: the rounding digit, i.e. the digit after the digit that may be rounded up. - // w: the word of xd containing rd, a base 1e7 number. - // xdi: the index of w within xd. - // digits: the number of digits of w. - // i: what would be the index of rd within w if all the numbers were 7 digits long (i.e. if - // they had leading zeros) - // j: if > 0, the actual index of rd within w (if < 0, rd is a leading zero). + prodL = prod.length; + if (prodL < remL) prod.unshift(0); - // Get the length of the first word of the digits array xd. - for (digits = 1, k = xd[0]; k >= 10; k /= 10) digits++; - i = sd - digits; + // Subtract product from remainder. + subtract(rem, prod, remL, base); - // Is the rounding digit in the first word of xd? - if (i < 0) { - i += LOG_BASE; - j = sd; - w = xd[xdi = 0]; + // If product was < previous remainder. + if (cmp == -1) { + remL = rem.length; - // Get the rounding digit at index j of w. - rd = w / mathpow(10, digits - j - 1) % 10 | 0; - } else { - xdi = Math.ceil((i + 1) / LOG_BASE); - k = xd.length; - if (xdi >= k) { - if (isTruncated) { - - // Needed by `naturalExponential`, `naturalLogarithm` and `squareRoot`. - for (; k++ <= xdi;) xd.push(0); - w = rd = 0; - digits = 1; - i %= LOG_BASE; - j = i - LOG_BASE + 1; - } else { - break out; - } - } else { - w = k = xd[xdi]; + // Compare divisor and new remainder. + cmp = compare(yd, rem, yL, remL); - // Get the number of digits of w. - for (digits = 1; k >= 10; k /= 10) digits++; + // If divisor < new remainder, subtract divisor from remainder. + if (cmp < 1) { + k++; - // Get the index of rd within w. - i %= LOG_BASE; + // Subtract divisor from remainder. + subtract(rem, yL < remL ? yz : yd, remL, base); + } + } - // Get the index of rd within w, adjusted for leading zeros. - // The number of leading zeros of w is given by LOG_BASE - digits. - j = i - LOG_BASE + digits; + remL = rem.length; + } else if (cmp === 0) { + k++; + rem = [0]; + } // if cmp === 1, k will be 0 - // Get the rounding digit at index j of w. - rd = j < 0 ? 0 : w / mathpow(10, digits - j - 1) % 10 | 0; - } - } + // Add the next digit, k, to the result array. + qd[i++] = k; - // Are there any non-zero digits after the rounding digit? - isTruncated = isTruncated || sd < 0 || - xd[xdi + 1] !== void 0 || (j < 0 ? w : w % mathpow(10, digits - j - 1)); + // Update the remainder. + if (cmp && rem[0]) { + rem[remL++] = xd[xi] || 0; + } else { + rem = [xd[xi]]; + remL = 1; + } - // The expression `w % mathpow(10, digits - j - 1)` returns all the digits of w to the right - // of the digit at (left-to-right) index j, e.g. if w is 908714 and j is 2, the expression - // will give 714. + } while ((xi++ < xL || rem[0] !== void 0) && sd--); - roundUp = rm < 4 - ? (rd || isTruncated) && (rm == 0 || rm == (x.s < 0 ? 3 : 2)) - : rd > 5 || rd == 5 && (rm == 4 || isTruncated || rm == 6 && - - // Check whether the digit to the left of the rounding digit is odd. - ((i > 0 ? j > 0 ? w / mathpow(10, digits - j) : 0 : xd[xdi - 1]) % 10) & 1 || - rm == (x.s < 0 ? 8 : 7)); - - if (sd < 1 || !xd[0]) { - xd.length = 0; - if (roundUp) { + more = rem[0] !== void 0; + } - // Convert sd to decimal places. - sd -= x.e + 1; + // Leading zero? + if (!qd[0]) qd.shift(); + } - // 1, 0.1, 0.01, 0.001, 0.0001 etc. - xd[0] = mathpow(10, (LOG_BASE - sd % LOG_BASE) % LOG_BASE); - x.e = -sd || 0; + // logBase is 1 when divide is being used for base conversion. + if (logBase == 1) { + q.e = e; + inexact = more; } else { - // Zero. - xd[0] = x.e = 0; + // To calculate q.e, first get the number of digits of qd[0]. + for (i = 1, k = qd[0]; k >= 10; k /= 10) i++; + q.e = i + e * logBase - 1; + + finalise(q, dp ? pr + q.e + 1 : pr, rm, more); } - return x; - } + return q; + }; + })(); - // Remove excess digits. - if (i == 0) { - xd.length = xdi; - k = 1; - xdi--; - } else { - xd.length = xdi + 1; - k = mathpow(10, LOG_BASE - i); - // E.g. 56700 becomes 56000 if 7 is the rounding digit. - // j > 0 means i > number of leading zeros of w. - xd[xdi] = j > 0 ? (w / mathpow(10, digits - j) % mathpow(10, j) | 0) * k : 0; - } + /* + * Round `x` to `sd` significant digits using rounding mode `rm`. + * Check for over/under-flow. + */ + function finalise(x, sd, rm, isTruncated) { + var digits, i, j, k, rd, roundUp, w, xd, xdi, + Ctor = x.constructor; + + // Don't round if sd is null or undefined. + out: if (sd != null) { + xd = x.d; + + // Infinity/NaN. + if (!xd) return x; + + // rd: the rounding digit, i.e. the digit after the digit that may be rounded up. + // w: the word of xd containing rd, a base 1e7 number. + // xdi: the index of w within xd. + // digits: the number of digits of w. + // i: what would be the index of rd within w if all the numbers were 7 digits long (i.e. if + // they had leading zeros) + // j: if > 0, the actual index of rd within w (if < 0, rd is a leading zero). + + // Get the length of the first word of the digits array xd. + for (digits = 1, k = xd[0]; k >= 10; k /= 10) digits++; + i = sd - digits; + + // Is the rounding digit in the first word of xd? + if (i < 0) { + i += LOG_BASE; + j = sd; + w = xd[xdi = 0]; - if (roundUp) { - for (;;) { + // Get the rounding digit at index j of w. + rd = w / mathpow(10, digits - j - 1) % 10 | 0; + } else { + xdi = Math.ceil((i + 1) / LOG_BASE); + k = xd.length; + if (xdi >= k) { + if (isTruncated) { + + // Needed by `naturalExponential`, `naturalLogarithm` and `squareRoot`. + for (; k++ <= xdi;) xd.push(0); + w = rd = 0; + digits = 1; + i %= LOG_BASE; + j = i - LOG_BASE + 1; + } else { + break out; + } + } else { + w = k = xd[xdi]; - // Is the digit to be rounded up in the first word of xd? - if (xdi == 0) { + // Get the number of digits of w. + for (digits = 1; k >= 10; k /= 10) digits++; - // i will be the length of xd[0] before k is added. - for (i = 1, j = xd[0]; j >= 10; j /= 10) i++; - j = xd[0] += k; - for (k = 1; j >= 10; j /= 10) k++; + // Get the index of rd within w. + i %= LOG_BASE; - // if i != k the length has increased. - if (i != k) { - x.e++; - if (xd[0] == BASE) xd[0] = 1; - } + // Get the index of rd within w, adjusted for leading zeros. + // The number of leading zeros of w is given by LOG_BASE - digits. + j = i - LOG_BASE + digits; - break; - } else { - xd[xdi] += k; - if (xd[xdi] != BASE) break; - xd[xdi--] = 0; - k = 1; + // Get the rounding digit at index j of w. + rd = j < 0 ? 0 : w / mathpow(10, digits - j - 1) % 10 | 0; } } - } - // Remove trailing zeros. - for (i = xd.length; xd[--i] === 0;) xd.pop(); - } + // Are there any non-zero digits after the rounding digit? + isTruncated = isTruncated || sd < 0 || + xd[xdi + 1] !== void 0 || (j < 0 ? w : w % mathpow(10, digits - j - 1)); - if (external) { + // The expression `w % mathpow(10, digits - j - 1)` returns all the digits of w to the right + // of the digit at (left-to-right) index j, e.g. if w is 908714 and j is 2, the expression + // will give 714. - // Overflow? - if (x.e > Ctor.maxE) { + roundUp = rm < 4 + ? (rd || isTruncated) && (rm == 0 || rm == (x.s < 0 ? 3 : 2)) + : rd > 5 || rd == 5 && (rm == 4 || isTruncated || rm == 6 && - // Infinity. - x.d = null; - x.e = NaN; + // Check whether the digit to the left of the rounding digit is odd. + ((i > 0 ? j > 0 ? w / mathpow(10, digits - j) : 0 : xd[xdi - 1]) % 10) & 1 || + rm == (x.s < 0 ? 8 : 7)); - // Underflow? - } else if (x.e < Ctor.minE) { + if (sd < 1 || !xd[0]) { + xd.length = 0; + if (roundUp) { - // Zero. - x.e = 0; - x.d = [0]; - // Ctor.underflow = true; - } // else Ctor.underflow = false; - } + // Convert sd to decimal places. + sd -= x.e + 1; - return x; - } + // 1, 0.1, 0.01, 0.001, 0.0001 etc. + xd[0] = mathpow(10, (LOG_BASE - sd % LOG_BASE) % LOG_BASE); + x.e = -sd || 0; + } else { + // Zero. + xd[0] = x.e = 0; + } - function finiteToString(x, isExp, sd) { - if (!x.isFinite()) return nonFiniteToString(x); - var k, - e = x.e, - str = digitsToString(x.d), - len = str.length; + return x; + } - if (isExp) { - if (sd && (k = sd - len) > 0) { - str = str.charAt(0) + '.' + str.slice(1) + getZeroString(k); - } else if (len > 1) { - str = str.charAt(0) + '.' + str.slice(1); - } + // Remove excess digits. + if (i == 0) { + xd.length = xdi; + k = 1; + xdi--; + } else { + xd.length = xdi + 1; + k = mathpow(10, LOG_BASE - i); - str = str + (x.e < 0 ? 'e' : 'e+') + x.e; - } else if (e < 0) { - str = '0.' + getZeroString(-e - 1) + str; - if (sd && (k = sd - len) > 0) str += getZeroString(k); - } else if (e >= len) { - str += getZeroString(e + 1 - len); - if (sd && (k = sd - e - 1) > 0) str = str + '.' + getZeroString(k); - } else { - if ((k = e + 1) < len) str = str.slice(0, k) + '.' + str.slice(k); - if (sd && (k = sd - len) > 0) { - if (e + 1 === len) str += '.'; - str += getZeroString(k); - } - } + // E.g. 56700 becomes 56000 if 7 is the rounding digit. + // j > 0 means i > number of leading zeros of w. + xd[xdi] = j > 0 ? (w / mathpow(10, digits - j) % mathpow(10, j) | 0) * k : 0; + } - return str; - } + if (roundUp) { + for (;;) { + // Is the digit to be rounded up in the first word of xd? + if (xdi == 0) { - // Calculate the base 10 exponent from the base 1e7 exponent. - function getBase10Exponent(digits, e) { - var w = digits[0]; + // i will be the length of xd[0] before k is added. + for (i = 1, j = xd[0]; j >= 10; j /= 10) i++; + j = xd[0] += k; + for (k = 1; j >= 10; j /= 10) k++; - // Add the number of digits of the first word of the digits array. - for ( e *= LOG_BASE; w >= 10; w /= 10) e++; - return e; - } + // if i != k the length has increased. + if (i != k) { + x.e++; + if (xd[0] == BASE) xd[0] = 1; + } + break; + } else { + xd[xdi] += k; + if (xd[xdi] != BASE) break; + xd[xdi--] = 0; + k = 1; + } + } + } - function getLn10(Ctor, sd, pr) { - if (sd > LN10_PRECISION) { + // Remove trailing zeros. + for (i = xd.length; xd[--i] === 0;) xd.pop(); + } - // Reset global state in case the exception is caught. - external = true; - if (pr) Ctor.precision = pr; - throw Error(precisionLimitExceeded); - } - return finalise(new Ctor(LN10), sd, 1, true); - } + if (external) { + // Overflow? + if (x.e > Ctor.maxE) { - function getPi(Ctor, sd, rm) { - if (sd > PI_PRECISION) throw Error(precisionLimitExceeded); - return finalise(new Ctor(PI), sd, rm, true); - } + // Infinity. + x.d = null; + x.e = NaN; + // Underflow? + } else if (x.e < Ctor.minE) { - function getPrecision(digits) { - var w = digits.length - 1, - len = w * LOG_BASE + 1; + // Zero. + x.e = 0; + x.d = [0]; + // Ctor.underflow = true; + } // else Ctor.underflow = false; + } - w = digits[w]; + return x; + } - // If non-zero... - if (w) { - // Subtract the number of trailing zeros of the last word. - for (; w % 10 == 0; w /= 10) len--; + function finiteToString(x, isExp, sd) { + if (!x.isFinite()) return nonFiniteToString(x); + var k, + e = x.e, + str = digitsToString(x.d), + len = str.length; - // Add the number of digits of the first word. - for (w = digits[0]; w >= 10; w /= 10) len++; - } + if (isExp) { + if (sd && (k = sd - len) > 0) { + str = str.charAt(0) + '.' + str.slice(1) + getZeroString(k); + } else if (len > 1) { + str = str.charAt(0) + '.' + str.slice(1); + } - return len; - } + str = str + (x.e < 0 ? 'e' : 'e+') + x.e; + } else if (e < 0) { + str = '0.' + getZeroString(-e - 1) + str; + if (sd && (k = sd - len) > 0) str += getZeroString(k); + } else if (e >= len) { + str += getZeroString(e + 1 - len); + if (sd && (k = sd - e - 1) > 0) str = str + '.' + getZeroString(k); + } else { + if ((k = e + 1) < len) str = str.slice(0, k) + '.' + str.slice(k); + if (sd && (k = sd - len) > 0) { + if (e + 1 === len) str += '.'; + str += getZeroString(k); + } + } + return str; + } - function getZeroString(k) { - var zs = ''; - for (; k--;) zs += '0'; - return zs; - } + // Calculate the base 10 exponent from the base 1e7 exponent. + function getBase10Exponent(digits, e) { + var w = digits[0]; - /* - * Return a new Decimal whose value is the value of Decimal `x` to the power `n`, where `n` is an - * integer of type number. - * - * Implements 'exponentiation by squaring'. Called by `pow` and `parseOther`. - * - */ - function intPow(Ctor, x, n, pr) { - var isTruncated, - r = new Ctor(1), + // Add the number of digits of the first word of the digits array. + for ( e *= LOG_BASE; w >= 10; w /= 10) e++; + return e; + } - // Max n of 9007199254740991 takes 53 loop iterations. - // Maximum digits array length; leaves [28, 34] guard digits. - k = Math.ceil(pr / LOG_BASE + 4); - external = false; + function getLn10(Ctor, sd, pr) { + if (sd > LN10_PRECISION) { - for (;;) { - if (n % 2) { - r = r.times(x); - if (truncate(r.d, k)) isTruncated = true; + // Reset global state in case the exception is caught. + external = true; + if (pr) Ctor.precision = pr; + throw Error(precisionLimitExceeded); } + return finalise(new Ctor(LN10), sd, 1, true); + } - n = mathfloor(n / 2); - if (n === 0) { - - // To ensure correct rounding when r.d is truncated, increment the last word if it is zero. - n = r.d.length - 1; - if (isTruncated && r.d[n] === 0) ++r.d[n]; - break; - } - x = x.times(x); - truncate(x.d, k); + function getPi(Ctor, sd, rm) { + if (sd > PI_PRECISION) throw Error(precisionLimitExceeded); + return finalise(new Ctor(PI), sd, rm, true); } - external = true; - return r; - } + function getPrecision(digits) { + var w = digits.length - 1, + len = w * LOG_BASE + 1; + w = digits[w]; - function isOdd(n) { - return n.d[n.d.length - 1] & 1; - } + // If non-zero... + if (w) { + // Subtract the number of trailing zeros of the last word. + for (; w % 10 == 0; w /= 10) len--; - /* - * Handle `max` and `min`. `ltgt` is 'lt' or 'gt'. - */ - function maxOrMin(Ctor, args, ltgt) { - var y, - x = new Ctor(args[0]), - i = 0; - - for (; ++i < args.length;) { - y = new Ctor(args[i]); - if (!y.s) { - x = y; - break; - } else if (x[ltgt](y)) { - x = y; + // Add the number of digits of the first word. + for (w = digits[0]; w >= 10; w /= 10) len++; } - } - - return x; - } - - /* - * Return a new Decimal whose value is the natural exponential of `x` rounded to `sd` significant - * digits. - * - * Taylor/Maclaurin series. - * - * exp(x) = x^0/0! + x^1/1! + x^2/2! + x^3/3! + ... - * - * Argument reduction: - * Repeat x = x / 32, k += 5, until |x| < 0.1 - * exp(x) = exp(x / 2^k)^(2^k) - * - * Previously, the argument was initially reduced by - * exp(x) = exp(r) * 10^k where r = x - k * ln10, k = floor(x / ln10) - * to first put r in the range [0, ln10], before dividing by 32 until |x| < 0.1, but this was - * found to be slower than just dividing repeatedly by 32 as above. - * - * Max integer argument: exp('20723265836946413') = 6.3e+9000000000000000 - * Min integer argument: exp('-20723265836946411') = 1.2e-9000000000000000 - * (Math object integer min/max: Math.exp(709) = 8.2e+307, Math.exp(-745) = 5e-324) - * - * exp(Infinity) = Infinity - * exp(-Infinity) = 0 - * exp(NaN) = NaN - * exp(±0) = 1 - * - * exp(x) is non-terminating for any finite, non-zero x. - * - * The result will always be correctly rounded. - * - */ - function naturalExponential(x, sd) { - var denominator, guard, j, pow, sum, t, wpr, - rep = 0, - i = 0, - k = 0, - Ctor = x.constructor, - rm = Ctor.rounding, - pr = Ctor.precision; + return len; + } - // 0/NaN/Infinity? - if (!x.d || !x.d[0] || x.e > 17) { - return new Ctor(x.d - ? !x.d[0] ? 1 : x.s < 0 ? 0 : 1 / 0 - : x.s ? x.s < 0 ? 0 : x : 0 / 0); + function getZeroString(k) { + var zs = ''; + for (; k--;) zs += '0'; + return zs; } - if (sd == null) { - external = false; - wpr = pr; - } else { - wpr = sd; - } - t = new Ctor(0.03125); + /* + * Return a new Decimal whose value is the value of Decimal `x` to the power `n`, where `n` is an + * integer of type number. + * + * Implements 'exponentiation by squaring'. Called by `pow` and `parseOther`. + * + */ + function intPow(Ctor, x, n, pr) { + var isTruncated, + r = new Ctor(1), - // while abs(x) >= 0.1 - while (x.e > -2) { + // Max n of 9007199254740991 takes 53 loop iterations. + // Maximum digits array length; leaves [28, 34] guard digits. + k = Math.ceil(pr / LOG_BASE + 4); - // x = x / 2^5 - x = x.times(t); - k += 5; - } + external = false; - // Use 2 * log10(2^k) + 5 (empirically derived) to estimate the increase in precision - // necessary to ensure the first 4 rounding digits are correct. - guard = Math.log(mathpow(2, k)) / Math.LN10 * 2 + 5 | 0; - wpr += guard; - denominator = pow = sum = new Ctor(1); - Ctor.precision = wpr; - - for (;;) { - pow = finalise(pow.times(x), wpr, 1); - denominator = denominator.times(++i); - t = sum.plus(divide(pow, denominator, wpr, 1)); - - if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) { - j = k; - while (j--) sum = finalise(sum.times(sum), wpr, 1); - - // Check to see if the first 4 rounding digits are [49]999. - // If so, repeat the summation with a higher precision, otherwise - // e.g. with precision: 18, rounding: 1 - // exp(18.404272462595034083567793919843761) = 98372560.1229999999 (should be 98372560.123) - // `wpr - guard` is the index of first rounding digit. - if (sd == null) { - - if (rep < 3 && checkRoundingDigits(sum.d, wpr - guard, rm, rep)) { - Ctor.precision = wpr += 10; - denominator = pow = t = new Ctor(1); - i = 0; - rep++; - } else { - return finalise(sum, Ctor.precision = pr, rm, external = true); - } - } else { - Ctor.precision = pr; - return sum; + for (;;) { + if (n % 2) { + r = r.times(x); + if (truncate(r.d, k)) isTruncated = true; } - } - sum = t; - } - } + n = mathfloor(n / 2); + if (n === 0) { + // To ensure correct rounding when r.d is truncated, increment the last word if it is zero. + n = r.d.length - 1; + if (isTruncated && r.d[n] === 0) ++r.d[n]; + break; + } - /* - * Return a new Decimal whose value is the natural logarithm of `x` rounded to `sd` significant - * digits. - * - * ln(-n) = NaN - * ln(0) = -Infinity - * ln(-0) = -Infinity - * ln(1) = 0 - * ln(Infinity) = Infinity - * ln(-Infinity) = NaN - * ln(NaN) = NaN - * - * ln(n) (n != 1) is non-terminating. - * - */ - function naturalLogarithm(y, sd) { - var c, c0, denominator, e, numerator, rep, sum, t, wpr, x1, x2, - n = 1, - guard = 10, - x = y, - xd = x.d, - Ctor = x.constructor, - rm = Ctor.rounding, - pr = Ctor.precision; + x = x.times(x); + truncate(x.d, k); + } - // Is x negative or Infinity, NaN, 0 or 1? - if (x.s < 0 || !xd || !xd[0] || !x.e && xd[0] == 1 && xd.length == 1) { - return new Ctor(xd && !xd[0] ? -1 / 0 : x.s != 1 ? NaN : xd ? 0 : x); - } + external = true; - if (sd == null) { - external = false; - wpr = pr; - } else { - wpr = sd; + return r; } - Ctor.precision = wpr += guard; - c = digitsToString(xd); - c0 = c.charAt(0); - - if (Math.abs(e = x.e) < 1.5e15) { - - // Argument reduction. - // The series converges faster the closer the argument is to 1, so using - // ln(a^b) = b * ln(a), ln(a) = ln(a^b) / b - // multiply the argument by itself until the leading digits of the significand are 7, 8, 9, - // 10, 11, 12 or 13, recording the number of multiplications so the sum of the series can - // later be divided by this number, then separate out the power of 10 using - // ln(a*10^b) = ln(a) + b*ln(10). - - // max n is 21 (gives 0.9, 1.0 or 1.1) (9e15 / 21 = 4.2e14). - //while (c0 < 9 && c0 != 1 || c0 == 1 && c.charAt(1) > 1) { - // max n is 6 (gives 0.7 - 1.3) - while (c0 < 7 && c0 != 1 || c0 == 1 && c.charAt(1) > 3) { - x = x.times(y); - c = digitsToString(x.d); - c0 = c.charAt(0); - n++; - } - - e = x.e; - if (c0 > 1) { - x = new Ctor('0.' + c); - e++; - } else { - x = new Ctor(c0 + '.' + c.slice(1)); - } - } else { + function isOdd(n) { + return n.d[n.d.length - 1] & 1; + } - // The argument reduction method above may result in overflow if the argument y is a massive - // number with exponent >= 1500000000000000 (9e15 / 6 = 1.5e15), so instead recall this - // function using ln(x*10^e) = ln(x) + e*ln(10). - t = getLn10(Ctor, wpr + 2, pr).times(e + ''); - x = naturalLogarithm(new Ctor(c0 + '.' + c.slice(1)), wpr - guard).plus(t); - Ctor.precision = pr; - return sd == null ? finalise(x, pr, rm, external = true) : x; - } + /* + * Handle `max` and `min`. `ltgt` is 'lt' or 'gt'. + */ + function maxOrMin(Ctor, args, ltgt) { + var y, + x = new Ctor(args[0]), + i = 0; - // x1 is x reduced to a value near 1. - x1 = x; - - // Taylor series. - // ln(y) = ln((1 + x)/(1 - x)) = 2(x + x^3/3 + x^5/5 + x^7/7 + ...) - // where x = (y - 1)/(y + 1) (|x| < 1) - sum = numerator = x = divide(x.minus(1), x.plus(1), wpr, 1); - x2 = finalise(x.times(x), wpr, 1); - denominator = 3; - - for (;;) { - numerator = finalise(numerator.times(x2), wpr, 1); - t = sum.plus(divide(numerator, new Ctor(denominator), wpr, 1)); - - if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) { - sum = sum.times(2); - - // Reverse the argument reduction. Check that e is not 0 because, besides preventing an - // unnecessary calculation, -0 + 0 = +0 and to ensure correct rounding -0 needs to stay -0. - if (e !== 0) sum = sum.plus(getLn10(Ctor, wpr + 2, pr).times(e + '')); - sum = divide(sum, new Ctor(n), wpr, 1); - - // Is rm > 3 and the first 4 rounding digits 4999, or rm < 4 (or the summation has - // been repeated previously) and the first 4 rounding digits 9999? - // If so, restart the summation with a higher precision, otherwise - // e.g. with precision: 12, rounding: 1 - // ln(135520028.6126091714265381533) = 18.7246299999 when it should be 18.72463. - // `wpr - guard` is the index of first rounding digit. - if (sd == null) { - if (checkRoundingDigits(sum.d, wpr - guard, rm, rep)) { - Ctor.precision = wpr += guard; - t = numerator = x = divide(x1.minus(1), x1.plus(1), wpr, 1); - x2 = finalise(x.times(x), wpr, 1); - denominator = rep = 1; - } else { - return finalise(sum, Ctor.precision = pr, rm, external = true); - } - } else { - Ctor.precision = pr; - return sum; + for (; ++i < args.length;) { + y = new Ctor(args[i]); + if (!y.s) { + x = y; + break; + } else if (x[ltgt](y)) { + x = y; } } - sum = t; - denominator += 2; + return x; } - } - // ±Infinity, NaN. - function nonFiniteToString(x) { - // Unsigned. - return String(x.s * x.s / 0); - } + /* + * Return a new Decimal whose value is the natural exponential of `x` rounded to `sd` significant + * digits. + * + * Taylor/Maclaurin series. + * + * exp(x) = x^0/0! + x^1/1! + x^2/2! + x^3/3! + ... + * + * Argument reduction: + * Repeat x = x / 32, k += 5, until |x| < 0.1 + * exp(x) = exp(x / 2^k)^(2^k) + * + * Previously, the argument was initially reduced by + * exp(x) = exp(r) * 10^k where r = x - k * ln10, k = floor(x / ln10) + * to first put r in the range [0, ln10], before dividing by 32 until |x| < 0.1, but this was + * found to be slower than just dividing repeatedly by 32 as above. + * + * Max integer argument: exp('20723265836946413') = 6.3e+9000000000000000 + * Min integer argument: exp('-20723265836946411') = 1.2e-9000000000000000 + * (Math object integer min/max: Math.exp(709) = 8.2e+307, Math.exp(-745) = 5e-324) + * + * exp(Infinity) = Infinity + * exp(-Infinity) = 0 + * exp(NaN) = NaN + * exp(±0) = 1 + * + * exp(x) is non-terminating for any finite, non-zero x. + * + * The result will always be correctly rounded. + * + */ + function naturalExponential(x, sd) { + var denominator, guard, j, pow, sum, t, wpr, + rep = 0, + i = 0, + k = 0, + Ctor = x.constructor, + rm = Ctor.rounding, + pr = Ctor.precision; + // 0/NaN/Infinity? + if (!x.d || !x.d[0] || x.e > 17) { - /* - * Parse the value of a new Decimal `x` from string `str`. - */ - function parseDecimal(x, str) { - var e, i, len; + return new Ctor(x.d + ? !x.d[0] ? 1 : x.s < 0 ? 0 : 1 / 0 + : x.s ? x.s < 0 ? 0 : x : 0 / 0); + } - // Decimal point? - if ((e = str.indexOf('.')) > -1) str = str.replace('.', ''); + if (sd == null) { + external = false; + wpr = pr; + } else { + wpr = sd; + } - // Exponential form? - if ((i = str.search(/e/i)) > 0) { + t = new Ctor(0.03125); - // Determine exponent. - if (e < 0) e = i; - e += +str.slice(i + 1); - str = str.substring(0, i); - } else if (e < 0) { + // while abs(x) >= 0.1 + while (x.e > -2) { - // Integer. - e = str.length; - } + // x = x / 2^5 + x = x.times(t); + k += 5; + } - // Determine leading zeros. - for (i = 0; str.charCodeAt(i) === 48; i++); + // Use 2 * log10(2^k) + 5 (empirically derived) to estimate the increase in precision + // necessary to ensure the first 4 rounding digits are correct. + guard = Math.log(mathpow(2, k)) / Math.LN10 * 2 + 5 | 0; + wpr += guard; + denominator = pow = sum = new Ctor(1); + Ctor.precision = wpr; + + for (;;) { + pow = finalise(pow.times(x), wpr, 1); + denominator = denominator.times(++i); + t = sum.plus(divide(pow, denominator, wpr, 1)); + + if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) { + j = k; + while (j--) sum = finalise(sum.times(sum), wpr, 1); + + // Check to see if the first 4 rounding digits are [49]999. + // If so, repeat the summation with a higher precision, otherwise + // e.g. with precision: 18, rounding: 1 + // exp(18.404272462595034083567793919843761) = 98372560.1229999999 (should be 98372560.123) + // `wpr - guard` is the index of first rounding digit. + if (sd == null) { + + if (rep < 3 && checkRoundingDigits(sum.d, wpr - guard, rm, rep)) { + Ctor.precision = wpr += 10; + denominator = pow = t = new Ctor(1); + i = 0; + rep++; + } else { + return finalise(sum, Ctor.precision = pr, rm, external = true); + } + } else { + Ctor.precision = pr; + return sum; + } + } - // Determine trailing zeros. - for (len = str.length; str.charCodeAt(len - 1) === 48; --len); - str = str.slice(i, len); + sum = t; + } + } - if (str) { - len -= i; - x.e = e = e - i - 1; - x.d = []; - // Transform base + /* + * Return a new Decimal whose value is the natural logarithm of `x` rounded to `sd` significant + * digits. + * + * ln(-n) = NaN + * ln(0) = -Infinity + * ln(-0) = -Infinity + * ln(1) = 0 + * ln(Infinity) = Infinity + * ln(-Infinity) = NaN + * ln(NaN) = NaN + * + * ln(n) (n != 1) is non-terminating. + * + */ + function naturalLogarithm(y, sd) { + var c, c0, denominator, e, numerator, rep, sum, t, wpr, x1, x2, + n = 1, + guard = 10, + x = y, + xd = x.d, + Ctor = x.constructor, + rm = Ctor.rounding, + pr = Ctor.precision; - // e is the base 10 exponent. - // i is where to slice str to get the first word of the digits array. - i = (e + 1) % LOG_BASE; - if (e < 0) i += LOG_BASE; + // Is x negative or Infinity, NaN, 0 or 1? + if (x.s < 0 || !xd || !xd[0] || !x.e && xd[0] == 1 && xd.length == 1) { + return new Ctor(xd && !xd[0] ? -1 / 0 : x.s != 1 ? NaN : xd ? 0 : x); + } - if (i < len) { - if (i) x.d.push(+str.slice(0, i)); - for (len -= LOG_BASE; i < len;) x.d.push(+str.slice(i, i += LOG_BASE)); - str = str.slice(i); - i = LOG_BASE - str.length; + if (sd == null) { + external = false; + wpr = pr; } else { - i -= len; + wpr = sd; } - for (; i--;) str += '0'; - x.d.push(+str); + Ctor.precision = wpr += guard; + c = digitsToString(xd); + c0 = c.charAt(0); + + if (Math.abs(e = x.e) < 1.5e15) { + + // Argument reduction. + // The series converges faster the closer the argument is to 1, so using + // ln(a^b) = b * ln(a), ln(a) = ln(a^b) / b + // multiply the argument by itself until the leading digits of the significand are 7, 8, 9, + // 10, 11, 12 or 13, recording the number of multiplications so the sum of the series can + // later be divided by this number, then separate out the power of 10 using + // ln(a*10^b) = ln(a) + b*ln(10). + + // max n is 21 (gives 0.9, 1.0 or 1.1) (9e15 / 21 = 4.2e14). + //while (c0 < 9 && c0 != 1 || c0 == 1 && c.charAt(1) > 1) { + // max n is 6 (gives 0.7 - 1.3) + while (c0 < 7 && c0 != 1 || c0 == 1 && c.charAt(1) > 3) { + x = x.times(y); + c = digitsToString(x.d); + c0 = c.charAt(0); + n++; + } - if (external) { + e = x.e; - // Overflow? - if (x.e > x.constructor.maxE) { + if (c0 > 1) { + x = new Ctor('0.' + c); + e++; + } else { + x = new Ctor(c0 + '.' + c.slice(1)); + } + } else { - // Infinity. - x.d = null; - x.e = NaN; + // The argument reduction method above may result in overflow if the argument y is a massive + // number with exponent >= 1500000000000000 (9e15 / 6 = 1.5e15), so instead recall this + // function using ln(x*10^e) = ln(x) + e*ln(10). + t = getLn10(Ctor, wpr + 2, pr).times(e + ''); + x = naturalLogarithm(new Ctor(c0 + '.' + c.slice(1)), wpr - guard).plus(t); + Ctor.precision = pr; - // Underflow? - } else if (x.e < x.constructor.minE) { + return sd == null ? finalise(x, pr, rm, external = true) : x; + } - // Zero. - x.e = 0; - x.d = [0]; - // x.constructor.underflow = true; - } // else x.constructor.underflow = false; + // x1 is x reduced to a value near 1. + x1 = x; + + // Taylor series. + // ln(y) = ln((1 + x)/(1 - x)) = 2(x + x^3/3 + x^5/5 + x^7/7 + ...) + // where x = (y - 1)/(y + 1) (|x| < 1) + sum = numerator = x = divide(x.minus(1), x.plus(1), wpr, 1); + x2 = finalise(x.times(x), wpr, 1); + denominator = 3; + + for (;;) { + numerator = finalise(numerator.times(x2), wpr, 1); + t = sum.plus(divide(numerator, new Ctor(denominator), wpr, 1)); + + if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) { + sum = sum.times(2); + + // Reverse the argument reduction. Check that e is not 0 because, besides preventing an + // unnecessary calculation, -0 + 0 = +0 and to ensure correct rounding -0 needs to stay -0. + if (e !== 0) sum = sum.plus(getLn10(Ctor, wpr + 2, pr).times(e + '')); + sum = divide(sum, new Ctor(n), wpr, 1); + + // Is rm > 3 and the first 4 rounding digits 4999, or rm < 4 (or the summation has + // been repeated previously) and the first 4 rounding digits 9999? + // If so, restart the summation with a higher precision, otherwise + // e.g. with precision: 12, rounding: 1 + // ln(135520028.6126091714265381533) = 18.7246299999 when it should be 18.72463. + // `wpr - guard` is the index of first rounding digit. + if (sd == null) { + if (checkRoundingDigits(sum.d, wpr - guard, rm, rep)) { + Ctor.precision = wpr += guard; + t = numerator = x = divide(x1.minus(1), x1.plus(1), wpr, 1); + x2 = finalise(x.times(x), wpr, 1); + denominator = rep = 1; + } else { + return finalise(sum, Ctor.precision = pr, rm, external = true); + } + } else { + Ctor.precision = pr; + return sum; + } + } + + sum = t; + denominator += 2; } - } else { + } - // Zero. - x.e = 0; - x.d = [0]; + + // ±Infinity, NaN. + function nonFiniteToString(x) { + // Unsigned. + return String(x.s * x.s / 0); } - return x; - } + /* + * Parse the value of a new Decimal `x` from string `str`. + */ + function parseDecimal(x, str) { + var e, i, len; - /* - * Parse the value of a new Decimal `x` from a string `str`, which is not a decimal value. - */ - function parseOther(x, str) { - var base, Ctor, divisor, i, isFloat, len, p, xd, xe; + // Decimal point? + if ((e = str.indexOf('.')) > -1) str = str.replace('.', ''); - if (str === 'Infinity' || str === 'NaN') { - if (!+str) x.s = NaN; - x.e = NaN; - x.d = null; - return x; - } + // Exponential form? + if ((i = str.search(/e/i)) > 0) { - if (isHex.test(str)) { - base = 16; - str = str.toLowerCase(); - } else if (isBinary.test(str)) { - base = 2; - } else if (isOctal.test(str)) { - base = 8; - } else { - throw Error(invalidArgument + str); - } + // Determine exponent. + if (e < 0) e = i; + e += +str.slice(i + 1); + str = str.substring(0, i); + } else if (e < 0) { - // Is there a binary exponent part? - i = str.search(/p/i); + // Integer. + e = str.length; + } - if (i > 0) { - p = +str.slice(i + 1); - str = str.substring(2, i); - } else { - str = str.slice(2); - } + // Determine leading zeros. + for (i = 0; str.charCodeAt(i) === 48; i++); - // Convert `str` as an integer then divide the result by `base` raised to a power such that the - // fraction part will be restored. - i = str.indexOf('.'); - isFloat = i >= 0; - Ctor = x.constructor; + // Determine trailing zeros. + for (len = str.length; str.charCodeAt(len - 1) === 48; --len); + str = str.slice(i, len); - if (isFloat) { - str = str.replace('.', ''); - len = str.length; - i = len - i; + if (str) { + len -= i; + x.e = e = e - i - 1; + x.d = []; - // log[10](16) = 1.2041... , log[10](88) = 1.9444.... - divisor = intPow(Ctor, new Ctor(base), i, i * 2); - } + // Transform base - xd = convertBase(str, base, BASE); - xe = xd.length - 1; - - // Remove trailing zeros. - for (i = xe; xd[i] === 0; --i) xd.pop(); - if (i < 0) return new Ctor(x.s * 0); - x.e = getBase10Exponent(xd, xe); - x.d = xd; - external = false; - - // At what precision to perform the division to ensure exact conversion? - // maxDecimalIntegerPartDigitCount = ceil(log[10](b) * otherBaseIntegerPartDigitCount) - // log[10](2) = 0.30103, log[10](8) = 0.90309, log[10](16) = 1.20412 - // E.g. ceil(1.2 * 3) = 4, so up to 4 decimal digits are needed to represent 3 hex int digits. - // maxDecimalFractionPartDigitCount = {Hex:4|Oct:3|Bin:1} * otherBaseFractionPartDigitCount - // Therefore using 4 * the number of digits of str will always be enough. - if (isFloat) x = divide(x, divisor, len * 4); - - // Multiply by the binary exponent part if present. - if (p) x = x.times(Math.abs(p) < 54 ? Math.pow(2, p) : Decimal.pow(2, p)); - external = true; - - return x; - } + // e is the base 10 exponent. + // i is where to slice str to get the first word of the digits array. + i = (e + 1) % LOG_BASE; + if (e < 0) i += LOG_BASE; + if (i < len) { + if (i) x.d.push(+str.slice(0, i)); + for (len -= LOG_BASE; i < len;) x.d.push(+str.slice(i, i += LOG_BASE)); + str = str.slice(i); + i = LOG_BASE - str.length; + } else { + i -= len; + } - /* - * sin(x) = x - x^3/3! + x^5/5! - ... - * |x| < pi/2 - * - */ - function sine(Ctor, x) { - var k, - len = x.d.length; + for (; i--;) str += '0'; + x.d.push(+str); + + if (external) { + + // Overflow? + if (x.e > x.constructor.maxE) { - if (len < 3) return taylorSeries(Ctor, 2, x, x); + // Infinity. + x.d = null; + x.e = NaN; - // Argument reduction: sin(5x) = 16*sin^5(x) - 20*sin^3(x) + 5*sin(x) - // i.e. sin(x) = 16*sin^5(x/5) - 20*sin^3(x/5) + 5*sin(x/5) - // and sin(x) = sin(x/5)(5 + sin^2(x/5)(16sin^2(x/5) - 20)) + // Underflow? + } else if (x.e < x.constructor.minE) { - // Estimate the optimum number of times to use the argument reduction. - k = 1.4 * Math.sqrt(len); - k = k > 16 ? 16 : k | 0; + // Zero. + x.e = 0; + x.d = [0]; + // x.constructor.underflow = true; + } // else x.constructor.underflow = false; + } + } else { - // Max k before Math.pow precision loss is 22 - x = x.times(Math.pow(5, -k)); - x = taylorSeries(Ctor, 2, x, x); + // Zero. + x.e = 0; + x.d = [0]; + } - // Reverse argument reduction - var sin2_x, - d5 = new Ctor(5), - d16 = new Ctor(16), - d20 = new Ctor(20); - for (; k--;) { - sin2_x = x.times(x); - x = x.times(d5.plus(sin2_x.times(d16.times(sin2_x).minus(d20)))); + return x; } - return x; - } + /* + * Parse the value of a new Decimal `x` from a string `str`, which is not a decimal value. + */ + function parseOther(x, str) { + var base, Ctor, divisor, i, isFloat, len, p, xd, xe; - // Calculate Taylor series for `cos`, `cosh`, `sin` and `sinh`. - function taylorSeries(Ctor, n, x, y, isHyperbolic) { - var j, t, u, x2, - pr = Ctor.precision, - k = Math.ceil(pr / LOG_BASE); + if (str === 'Infinity' || str === 'NaN') { + if (!+str) x.s = NaN; + x.e = NaN; + x.d = null; + return x; + } - external = false; - x2 = x.times(x); - u = new Ctor(y); + if (isHex.test(str)) { + base = 16; + str = str.toLowerCase(); + } else if (isBinary.test(str)) { + base = 2; + } else if (isOctal.test(str)) { + base = 8; + } else { + throw Error(invalidArgument + str); + } - for (;;) { - t = divide(u.times(x2), new Ctor(n++ * n++), pr, 1); - u = isHyperbolic ? y.plus(t) : y.minus(t); - y = divide(t.times(x2), new Ctor(n++ * n++), pr, 1); - t = u.plus(y); + // Is there a binary exponent part? + i = str.search(/p/i); - if (t.d[k] !== void 0) { - for (j = k; t.d[j] === u.d[j] && j--;); - if (j == -1) break; + if (i > 0) { + p = +str.slice(i + 1); + str = str.substring(2, i); + } else { + str = str.slice(2); } - j = u; - u = y; - y = t; - t = j; - } + // Convert `str` as an integer then divide the result by `base` raised to a power such that the + // fraction part will be restored. + i = str.indexOf('.'); + isFloat = i >= 0; + Ctor = x.constructor; - external = true; - t.d.length = k + 1; + if (isFloat) { + str = str.replace('.', ''); + len = str.length; + i = len - i; - return t; - } + // log[10](16) = 1.2041... , log[10](88) = 1.9444.... + divisor = intPow(Ctor, new Ctor(base), i, i * 2); + } + xd = convertBase(str, base, BASE); + xe = xd.length - 1; - // Return the absolute value of `x` reduced to less than or equal to half pi. - function toLessThanHalfPi(Ctor, x) { - var t, - isNeg = x.s < 0, - pi = getPi(Ctor, Ctor.precision, 1), - halfPi = pi.times(0.5); + // Remove trailing zeros. + for (i = xe; xd[i] === 0; --i) xd.pop(); + if (i < 0) return new Ctor(x.s * 0); + x.e = getBase10Exponent(xd, xe); + x.d = xd; + external = false; - x = x.abs(); + // At what precision to perform the division to ensure exact conversion? + // maxDecimalIntegerPartDigitCount = ceil(log[10](b) * otherBaseIntegerPartDigitCount) + // log[10](2) = 0.30103, log[10](8) = 0.90309, log[10](16) = 1.20412 + // E.g. ceil(1.2 * 3) = 4, so up to 4 decimal digits are needed to represent 3 hex int digits. + // maxDecimalFractionPartDigitCount = {Hex:4|Oct:3|Bin:1} * otherBaseFractionPartDigitCount + // Therefore using 4 * the number of digits of str will always be enough. + if (isFloat) x = divide(x, divisor, len * 4); + + // Multiply by the binary exponent part if present. + if (p) x = x.times(Math.abs(p) < 54 ? Math.pow(2, p) : Decimal.pow(2, p)); + external = true; - if (x.lte(halfPi)) { - quadrant = isNeg ? 4 : 1; return x; } - t = x.divToInt(pi); - if (t.isZero()) { - quadrant = isNeg ? 3 : 2; - } else { - x = x.minus(t.times(pi)); + /* + * sin(x) = x - x^3/3! + x^5/5! - ... + * |x| < pi/2 + * + */ + function sine(Ctor, x) { + var k, + len = x.d.length; - // 0 <= x < pi - if (x.lte(halfPi)) { - quadrant = isOdd(t) ? (isNeg ? 2 : 3) : (isNeg ? 4 : 1); - return x; - } + if (len < 3) return taylorSeries(Ctor, 2, x, x); - quadrant = isOdd(t) ? (isNeg ? 1 : 4) : (isNeg ? 3 : 2); - } + // Argument reduction: sin(5x) = 16*sin^5(x) - 20*sin^3(x) + 5*sin(x) + // i.e. sin(x) = 16*sin^5(x/5) - 20*sin^3(x/5) + 5*sin(x/5) + // and sin(x) = sin(x/5)(5 + sin^2(x/5)(16sin^2(x/5) - 20)) - return x.minus(pi).abs(); - } + // Estimate the optimum number of times to use the argument reduction. + k = 1.4 * Math.sqrt(len); + k = k > 16 ? 16 : k | 0; + // Max k before Math.pow precision loss is 22 + x = x.times(Math.pow(5, -k)); + x = taylorSeries(Ctor, 2, x, x); - /* - * Return the value of Decimal `x` as a string in base `baseOut`. - * - * If the optional `sd` argument is present include a binary exponent suffix. - */ - function toStringBinary(x, baseOut, sd, rm) { - var base, e, i, k, len, roundUp, str, xd, y, - Ctor = x.constructor, - isExp = sd !== void 0; + // Reverse argument reduction + var sin2_x, + d5 = new Ctor(5), + d16 = new Ctor(16), + d20 = new Ctor(20); + for (; k--;) { + sin2_x = x.times(x); + x = x.times(d5.plus(sin2_x.times(d16.times(sin2_x).minus(d20)))); + } - if (isExp) { - checkInt32(sd, 1, MAX_DIGITS); - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); - } else { - sd = Ctor.precision; - rm = Ctor.rounding; + return x; } - if (!x.isFinite()) { - str = nonFiniteToString(x); - } else { - str = finiteToString(x); - i = str.indexOf('.'); - // Use exponential notation according to `toExpPos` and `toExpNeg`? No, but if required: - // maxBinaryExponent = floor((decimalExponent + 1) * log[2](10)) - // minBinaryExponent = floor(decimalExponent * log[2](10)) - // log[2](10) = 3.321928094887362347870319429489390175864 + // Calculate Taylor series for `cos`, `cosh`, `sin` and `sinh`. + function taylorSeries(Ctor, n, x, y, isHyperbolic) { + var j, t, u, x2, + pr = Ctor.precision, + k = Math.ceil(pr / LOG_BASE); - if (isExp) { - base = 2; - if (baseOut == 16) { - sd = sd * 4 - 3; - } else if (baseOut == 8) { - sd = sd * 3 - 2; + external = false; + x2 = x.times(x); + u = new Ctor(y); + + for (;;) { + t = divide(u.times(x2), new Ctor(n++ * n++), pr, 1); + u = isHyperbolic ? y.plus(t) : y.minus(t); + y = divide(t.times(x2), new Ctor(n++ * n++), pr, 1); + t = u.plus(y); + + if (t.d[k] !== void 0) { + for (j = k; t.d[j] === u.d[j] && j--;); + if (j == -1) break; } - } else { - base = baseOut; + + j = u; + u = y; + y = t; + t = j; } - // Convert the number as an integer then divide the result by its base raised to a power such - // that the fraction part will be restored. + external = true; + t.d.length = k + 1; - // Non-integer. - if (i >= 0) { - str = str.replace('.', ''); - y = new Ctor(1); - y.e = str.length - i; - y.d = convertBase(finiteToString(y), 10, base); - y.e = y.d.length; + return t; + } + + + // Return the absolute value of `x` reduced to less than or equal to half pi. + function toLessThanHalfPi(Ctor, x) { + var t, + isNeg = x.s < 0, + pi = getPi(Ctor, Ctor.precision, 1), + halfPi = pi.times(0.5); + + x = x.abs(); + + if (x.lte(halfPi)) { + quadrant = isNeg ? 4 : 1; + return x; } - xd = convertBase(str, 10, base); - e = len = xd.length; + t = x.divToInt(pi); - // Remove trailing zeros. - for (; xd[--len] == 0;) xd.pop(); + if (t.isZero()) { + quadrant = isNeg ? 3 : 2; + } else { + x = x.minus(t.times(pi)); + + // 0 <= x < pi + if (x.lte(halfPi)) { + quadrant = isOdd(t) ? (isNeg ? 2 : 3) : (isNeg ? 4 : 1); + return x; + } + + quadrant = isOdd(t) ? (isNeg ? 1 : 4) : (isNeg ? 3 : 2); + } + + return x.minus(pi).abs(); + } + + + /* + * Return the value of Decimal `x` as a string in base `baseOut`. + * + * If the optional `sd` argument is present include a binary exponent suffix. + */ + function toStringBinary(x, baseOut, sd, rm) { + var base, e, i, k, len, roundUp, str, xd, y, + Ctor = x.constructor, + isExp = sd !== void 0; - if (!xd[0]) { - str = isExp ? '0p+0' : '0'; + if (isExp) { + checkInt32(sd, 1, MAX_DIGITS); + if (rm === void 0) rm = Ctor.rounding; + else checkInt32(rm, 0, 8); } else { - if (i < 0) { - e--; + sd = Ctor.precision; + rm = Ctor.rounding; + } + + if (!x.isFinite()) { + str = nonFiniteToString(x); + } else { + str = finiteToString(x); + i = str.indexOf('.'); + + // Use exponential notation according to `toExpPos` and `toExpNeg`? No, but if required: + // maxBinaryExponent = floor((decimalExponent + 1) * log[2](10)) + // minBinaryExponent = floor(decimalExponent * log[2](10)) + // log[2](10) = 3.321928094887362347870319429489390175864 + + if (isExp) { + base = 2; + if (baseOut == 16) { + sd = sd * 4 - 3; + } else if (baseOut == 8) { + sd = sd * 3 - 2; + } } else { - x = new Ctor(x); - x.d = xd; - x.e = e; - x = divide(x, y, sd, rm, 0, base); - xd = x.d; - e = x.e; - roundUp = inexact; + base = baseOut; } - // The rounding digit, i.e. the digit after the digit that may be rounded up. - i = xd[sd]; - k = base / 2; - roundUp = roundUp || xd[sd + 1] !== void 0; + // Convert the number as an integer then divide the result by its base raised to a power such + // that the fraction part will be restored. - roundUp = rm < 4 - ? (i !== void 0 || roundUp) && (rm === 0 || rm === (x.s < 0 ? 3 : 2)) - : i > k || i === k && (rm === 4 || roundUp || rm === 6 && xd[sd - 1] & 1 || - rm === (x.s < 0 ? 8 : 7)); + // Non-integer. + if (i >= 0) { + str = str.replace('.', ''); + y = new Ctor(1); + y.e = str.length - i; + y.d = convertBase(finiteToString(y), 10, base); + y.e = y.d.length; + } - xd.length = sd; + xd = convertBase(str, 10, base); + e = len = xd.length; - if (roundUp) { + // Remove trailing zeros. + for (; xd[--len] == 0;) xd.pop(); - // Rounding up may mean the previous digit has to be rounded up and so on. - for (; ++xd[--sd] > base - 1;) { - xd[sd] = 0; - if (!sd) { - ++e; - xd.unshift(1); - } + if (!xd[0]) { + str = isExp ? '0p+0' : '0'; + } else { + if (i < 0) { + e--; + } else { + x = new Ctor(x); + x.d = xd; + x.e = e; + x = divide(x, y, sd, rm, 0, base); + xd = x.d; + e = x.e; + roundUp = inexact; } - } - // Determine trailing zeros. - for (len = xd.length; !xd[len - 1]; --len); + // The rounding digit, i.e. the digit after the digit that may be rounded up. + i = xd[sd]; + k = base / 2; + roundUp = roundUp || xd[sd + 1] !== void 0; - // E.g. [4, 11, 15] becomes 4bf. - for (i = 0, str = ''; i < len; i++) str += NUMERALS.charAt(xd[i]); + roundUp = rm < 4 + ? (i !== void 0 || roundUp) && (rm === 0 || rm === (x.s < 0 ? 3 : 2)) + : i > k || i === k && (rm === 4 || roundUp || rm === 6 && xd[sd - 1] & 1 || + rm === (x.s < 0 ? 8 : 7)); - // Add binary exponent suffix? - if (isExp) { - if (len > 1) { - if (baseOut == 16 || baseOut == 8) { - i = baseOut == 16 ? 4 : 3; - for (--len; len % i; len++) str += '0'; - xd = convertBase(str, base, baseOut); - for (len = xd.length; !xd[len - 1]; --len); - - // xd[0] will always be be 1 - for (i = 1, str = '1.'; i < len; i++) str += NUMERALS.charAt(xd[i]); - } else { - str = str.charAt(0) + '.' + str.slice(1); + xd.length = sd; + + if (roundUp) { + + // Rounding up may mean the previous digit has to be rounded up and so on. + for (; ++xd[--sd] > base - 1;) { + xd[sd] = 0; + if (!sd) { + ++e; + xd.unshift(1); + } } } - str = str + (e < 0 ? 'p' : 'p+') + e; - } else if (e < 0) { - for (; ++e;) str = '0' + str; - str = '0.' + str; - } else { - if (++e > len) for (e -= len; e-- ;) str += '0'; - else if (e < len) str = str.slice(0, e) + '.' + str.slice(e); + // Determine trailing zeros. + for (len = xd.length; !xd[len - 1]; --len); + + // E.g. [4, 11, 15] becomes 4bf. + for (i = 0, str = ''; i < len; i++) str += NUMERALS.charAt(xd[i]); + + // Add binary exponent suffix? + if (isExp) { + if (len > 1) { + if (baseOut == 16 || baseOut == 8) { + i = baseOut == 16 ? 4 : 3; + for (--len; len % i; len++) str += '0'; + xd = convertBase(str, base, baseOut); + for (len = xd.length; !xd[len - 1]; --len); + + // xd[0] will always be be 1 + for (i = 1, str = '1.'; i < len; i++) str += NUMERALS.charAt(xd[i]); + } else { + str = str.charAt(0) + '.' + str.slice(1); + } + } + + str = str + (e < 0 ? 'p' : 'p+') + e; + } else if (e < 0) { + for (; ++e;) str = '0' + str; + str = '0.' + str; + } else { + if (++e > len) for (e -= len; e-- ;) str += '0'; + else if (e < len) str = str.slice(0, e) + '.' + str.slice(e); + } } + + str = (baseOut == 16 ? '0x' : baseOut == 2 ? '0b' : baseOut == 8 ? '0o' : '') + str; } - str = (baseOut == 16 ? '0x' : baseOut == 2 ? '0b' : baseOut == 8 ? '0o' : '') + str; + return x.s < 0 ? '-' + str : str; } - return x.s < 0 ? '-' + str : str; - } - - // Does not strip trailing zeros. - function truncate(arr, len) { - if (arr.length > len) { - arr.length = len; - return true; + // Does not strip trailing zeros. + function truncate(arr, len) { + if (arr.length > len) { + arr.length = len; + return true; + } } - } - // Decimal methods + // Decimal methods - /* - * abs - * acos - * acosh - * add - * asin - * asinh - * atan - * atanh - * atan2 - * cbrt - * ceil - * clone - * config - * cos - * cosh - * div - * exp - * floor - * hypot - * ln - * log - * log2 - * log10 - * max - * min - * mod - * mul - * pow - * random - * round - * set - * sign - * sin - * sinh - * sqrt - * sub - * tan - * tanh - * trunc - */ + /* + * abs + * acos + * acosh + * add + * asin + * asinh + * atan + * atanh + * atan2 + * cbrt + * ceil + * clone + * config + * cos + * cosh + * div + * exp + * floor + * hypot + * ln + * log + * log2 + * log10 + * max + * min + * mod + * mul + * pow + * random + * round + * set + * sign + * sin + * sinh + * sqrt + * sub + * tan + * tanh + * trunc + */ - /* - * Return a new Decimal whose value is the absolute value of `x`. - * - * x {number|string|Decimal} - * - */ - function abs(x) { - return new this(x).abs(); - } + /* + * Return a new Decimal whose value is the absolute value of `x`. + * + * x {number|string|Decimal} + * + */ + function abs(x) { + return new this(x).abs(); + } - /* - * Return a new Decimal whose value is the arccosine in radians of `x`. - * - * x {number|string|Decimal} - * - */ - function acos(x) { - return new this(x).acos(); - } + /* + * Return a new Decimal whose value is the arccosine in radians of `x`. + * + * x {number|string|Decimal} + * + */ + function acos(x) { + return new this(x).acos(); + } - /* - * Return a new Decimal whose value is the inverse of the hyperbolic cosine of `x`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function acosh(x) { - return new this(x).acosh(); - } + /* + * Return a new Decimal whose value is the inverse of the hyperbolic cosine of `x`, rounded to + * `precision` significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function acosh(x) { + return new this(x).acosh(); + } - /* - * Return a new Decimal whose value is the sum of `x` and `y`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function add(x, y) { - return new this(x).plus(y); - } + /* + * Return a new Decimal whose value is the sum of `x` and `y`, rounded to `precision` significant + * digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * y {number|string|Decimal} + * + */ + function add(x, y) { + return new this(x).plus(y); + } - /* - * Return a new Decimal whose value is the arcsine in radians of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function asin(x) { - return new this(x).asin(); - } + /* + * Return a new Decimal whose value is the arcsine in radians of `x`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * + */ + function asin(x) { + return new this(x).asin(); + } - /* - * Return a new Decimal whose value is the inverse of the hyperbolic sine of `x`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function asinh(x) { - return new this(x).asinh(); - } + /* + * Return a new Decimal whose value is the inverse of the hyperbolic sine of `x`, rounded to + * `precision` significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function asinh(x) { + return new this(x).asinh(); + } - /* - * Return a new Decimal whose value is the arctangent in radians of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function atan(x) { - return new this(x).atan(); - } + /* + * Return a new Decimal whose value is the arctangent in radians of `x`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * + */ + function atan(x) { + return new this(x).atan(); + } - /* - * Return a new Decimal whose value is the inverse of the hyperbolic tangent of `x`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function atanh(x) { - return new this(x).atanh(); - } + /* + * Return a new Decimal whose value is the inverse of the hyperbolic tangent of `x`, rounded to + * `precision` significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function atanh(x) { + return new this(x).atanh(); + } - /* - * Return a new Decimal whose value is the arctangent in radians of `y/x` in the range -pi to pi - * (inclusive), rounded to `precision` significant digits using rounding mode `rounding`. - * - * Domain: [-Infinity, Infinity] - * Range: [-pi, pi] - * - * y {number|string|Decimal} The y-coordinate. - * x {number|string|Decimal} The x-coordinate. - * - * atan2(±0, -0) = ±pi - * atan2(±0, +0) = ±0 - * atan2(±0, -x) = ±pi for x > 0 - * atan2(±0, x) = ±0 for x > 0 - * atan2(-y, ±0) = -pi/2 for y > 0 - * atan2(y, ±0) = pi/2 for y > 0 - * atan2(±y, -Infinity) = ±pi for finite y > 0 - * atan2(±y, +Infinity) = ±0 for finite y > 0 - * atan2(±Infinity, x) = ±pi/2 for finite x - * atan2(±Infinity, -Infinity) = ±3*pi/4 - * atan2(±Infinity, +Infinity) = ±pi/4 - * atan2(NaN, x) = NaN - * atan2(y, NaN) = NaN - * - */ - function atan2(y, x) { - y = new this(y); - x = new this(x); - var r, - pr = this.precision, - rm = this.rounding, - wpr = pr + 4; - - // Either NaN - if (!y.s || !x.s) { - r = new this(NaN); - - // Both ±Infinity - } else if (!y.d && !x.d) { - r = getPi(this, wpr, 1).times(x.s > 0 ? 0.25 : 0.75); - r.s = y.s; - - // x is ±Infinity or y is ±0 - } else if (!x.d || y.isZero()) { - r = x.s < 0 ? getPi(this, pr, rm) : new this(0); - r.s = y.s; - - // y is ±Infinity or x is ±0 - } else if (!y.d || x.isZero()) { - r = getPi(this, wpr, 1).times(0.5); - r.s = y.s; - - // Both non-zero and finite - } else if (x.s < 0) { - this.precision = wpr; - this.rounding = 1; - r = this.atan(divide(y, x, wpr, 1)); - x = getPi(this, wpr, 1); - this.precision = pr; - this.rounding = rm; - r = y.s < 0 ? r.minus(x) : r.plus(x); - } else { - r = this.atan(divide(y, x, wpr, 1)); - } + /* + * Return a new Decimal whose value is the arctangent in radians of `y/x` in the range -pi to pi + * (inclusive), rounded to `precision` significant digits using rounding mode `rounding`. + * + * Domain: [-Infinity, Infinity] + * Range: [-pi, pi] + * + * y {number|string|Decimal} The y-coordinate. + * x {number|string|Decimal} The x-coordinate. + * + * atan2(±0, -0) = ±pi + * atan2(±0, +0) = ±0 + * atan2(±0, -x) = ±pi for x > 0 + * atan2(±0, x) = ±0 for x > 0 + * atan2(-y, ±0) = -pi/2 for y > 0 + * atan2(y, ±0) = pi/2 for y > 0 + * atan2(±y, -Infinity) = ±pi for finite y > 0 + * atan2(±y, +Infinity) = ±0 for finite y > 0 + * atan2(±Infinity, x) = ±pi/2 for finite x + * atan2(±Infinity, -Infinity) = ±3*pi/4 + * atan2(±Infinity, +Infinity) = ±pi/4 + * atan2(NaN, x) = NaN + * atan2(y, NaN) = NaN + * + */ + function atan2(y, x) { + y = new this(y); + x = new this(x); + var r, + pr = this.precision, + rm = this.rounding, + wpr = pr + 4; + + // Either NaN + if (!y.s || !x.s) { + r = new this(NaN); + + // Both ±Infinity + } else if (!y.d && !x.d) { + r = getPi(this, wpr, 1).times(x.s > 0 ? 0.25 : 0.75); + r.s = y.s; + + // x is ±Infinity or y is ±0 + } else if (!x.d || y.isZero()) { + r = x.s < 0 ? getPi(this, pr, rm) : new this(0); + r.s = y.s; + + // y is ±Infinity or x is ±0 + } else if (!y.d || x.isZero()) { + r = getPi(this, wpr, 1).times(0.5); + r.s = y.s; + + // Both non-zero and finite + } else if (x.s < 0) { + this.precision = wpr; + this.rounding = 1; + r = this.atan(divide(y, x, wpr, 1)); + x = getPi(this, wpr, 1); + this.precision = pr; + this.rounding = rm; + r = y.s < 0 ? r.minus(x) : r.plus(x); + } else { + r = this.atan(divide(y, x, wpr, 1)); + } - return r; - } + return r; + } - /* - * Return a new Decimal whose value is the cube root of `x`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function cbrt(x) { - return new this(x).cbrt(); - } + /* + * Return a new Decimal whose value is the cube root of `x`, rounded to `precision` significant + * digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * + */ + function cbrt(x) { + return new this(x).cbrt(); + } - /* - * Return a new Decimal whose value is `x` rounded to an integer using `ROUND_CEIL`. - * - * x {number|string|Decimal} - * - */ - function ceil(x) { - return finalise(x = new this(x), x.e + 1, 2); - } + /* + * Return a new Decimal whose value is `x` rounded to an integer using `ROUND_CEIL`. + * + * x {number|string|Decimal} + * + */ + function ceil(x) { + return finalise(x = new this(x), x.e + 1, 2); + } - /* - * Configure global settings for a Decimal constructor. - * - * `obj` is an object with one or more of the following properties, - * - * precision {number} - * rounding {number} - * toExpNeg {number} - * toExpPos {number} - * maxE {number} - * minE {number} - * modulo {number} - * crypto {boolean|number} - * defaults {true} - * - * E.g. Decimal.config({ precision: 20, rounding: 4 }) - * - */ - function config(obj) { - if (!obj || typeof obj !== 'object') throw Error(decimalError + 'Object expected'); - var i, p, v, - useDefaults = obj.defaults === true, - ps = [ - 'precision', 1, MAX_DIGITS, - 'rounding', 0, 8, - 'toExpNeg', -EXP_LIMIT, 0, - 'toExpPos', 0, EXP_LIMIT, - 'maxE', 0, EXP_LIMIT, - 'minE', -EXP_LIMIT, 0, - 'modulo', 0, 9 - ]; - - for (i = 0; i < ps.length; i += 3) { - if (p = ps[i], useDefaults) this[p] = DEFAULTS[p]; - if ((v = obj[p]) !== void 0) { - if (mathfloor(v) === v && v >= ps[i + 1] && v <= ps[i + 2]) this[p] = v; - else throw Error(invalidArgument + p + ': ' + v); + /* + * Configure global settings for a Decimal constructor. + * + * `obj` is an object with one or more of the following properties, + * + * precision {number} + * rounding {number} + * toExpNeg {number} + * toExpPos {number} + * maxE {number} + * minE {number} + * modulo {number} + * crypto {boolean|number} + * defaults {true} + * + * E.g. Decimal.config({ precision: 20, rounding: 4 }) + * + */ + function config(obj) { + if (!obj || typeof obj !== 'object') throw Error(decimalError + 'Object expected'); + var i, p, v, + useDefaults = obj.defaults === true, + ps = [ + 'precision', 1, MAX_DIGITS, + 'rounding', 0, 8, + 'toExpNeg', -EXP_LIMIT, 0, + 'toExpPos', 0, EXP_LIMIT, + 'maxE', 0, EXP_LIMIT, + 'minE', -EXP_LIMIT, 0, + 'modulo', 0, 9 + ]; + + for (i = 0; i < ps.length; i += 3) { + if (p = ps[i], useDefaults) this[p] = DEFAULTS[p]; + if ((v = obj[p]) !== void 0) { + if (mathfloor(v) === v && v >= ps[i + 1] && v <= ps[i + 2]) this[p] = v; + else throw Error(invalidArgument + p + ': ' + v); + } } - } - if (p = 'crypto', useDefaults) this[p] = DEFAULTS[p]; - if ((v = obj[p]) !== void 0) { - if (v === true || v === false || v === 0 || v === 1) { - if (v) { - if (typeof crypto != 'undefined' && crypto && - (crypto.getRandomValues || crypto.randomBytes)) { - this[p] = true; + if (p = 'crypto', useDefaults) this[p] = DEFAULTS[p]; + if ((v = obj[p]) !== void 0) { + if (v === true || v === false || v === 0 || v === 1) { + if (v) { + if (typeof crypto != 'undefined' && crypto && + (crypto.getRandomValues || crypto.randomBytes)) { + this[p] = true; + } else { + throw Error(cryptoUnavailable); + } } else { - throw Error(cryptoUnavailable); + this[p] = false; } } else { - this[p] = false; + throw Error(invalidArgument + p + ': ' + v); } - } else { - throw Error(invalidArgument + p + ': ' + v); } - } - - return this; - } + return this; + } - /* - * Return a new Decimal whose value is the cosine of `x`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function cos(x) { - return new this(x).cos(); - } + /* + * Return a new Decimal whose value is the cosine of `x`, rounded to `precision` significant + * digits using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function cos(x) { + return new this(x).cos(); + } - /* - * Return a new Decimal whose value is the hyperbolic cosine of `x`, rounded to precision - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function cosh(x) { - return new this(x).cosh(); - } + /* + * Return a new Decimal whose value is the hyperbolic cosine of `x`, rounded to precision + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function cosh(x) { + return new this(x).cosh(); + } - /* - * Create and return a Decimal constructor with the same configuration properties as this Decimal - * constructor. - * - */ - function clone(obj) { - var i, p, ps; /* - * The Decimal constructor and exported function. - * Return a new Decimal instance. - * - * v {number|string|Decimal} A numeric value. + * Create and return a Decimal constructor with the same configuration properties as this Decimal + * constructor. * */ - function Decimal(v) { - var e, i, t, - x = this; + function clone(obj) { + var i, p, ps; + + /* + * The Decimal constructor and exported function. + * Return a new Decimal instance. + * + * v {number|string|Decimal} A numeric value. + * + */ + function Decimal(v) { + var e, i, t, + x = this; + + // Decimal called without new. + if (!(x instanceof Decimal)) return new Decimal(v); + + // Retain a reference to this Decimal constructor, and shadow Decimal.prototype.constructor + // which points to Object. + x.constructor = Decimal; + + // Duplicate. + if (v instanceof Decimal) { + x.s = v.s; + x.e = v.e; + x.d = (v = v.d) ? v.slice() : v; + return; + } - // Decimal called without new. - if (!(x instanceof Decimal)) return new Decimal(v); + t = typeof v; - // Retain a reference to this Decimal constructor, and shadow Decimal.prototype.constructor - // which points to Object. - x.constructor = Decimal; + if (t === 'number') { + if (v === 0) { + x.s = 1 / v < 0 ? -1 : 1; + x.e = 0; + x.d = [0]; + return; + } - // Duplicate. - if (v instanceof Decimal) { - x.s = v.s; - x.e = v.e; - x.d = (v = v.d) ? v.slice() : v; - return; - } + if (v < 0) { + v = -v; + x.s = -1; + } else { + x.s = 1; + } - t = typeof v; + // Fast path for small integers. + if (v === ~~v && v < 1e7) { + for (e = 0, i = v; i >= 10; i /= 10) e++; + x.e = e; + x.d = [v]; + return; + + // Infinity, NaN. + } else if (v * 0 !== 0) { + if (!v) x.s = NaN; + x.e = NaN; + x.d = null; + return; + } - if (t === 'number') { - if (v === 0) { - x.s = 1 / v < 0 ? -1 : 1; - x.e = 0; - x.d = [0]; - return; + return parseDecimal(x, v.toString()); + + } else if (t !== 'string') { + throw Error(invalidArgument + v); } - if (v < 0) { - v = -v; + // Minus sign? + if (v.charCodeAt(0) === 45) { + v = v.slice(1); x.s = -1; } else { x.s = 1; } - // Fast path for small integers. - if (v === ~~v && v < 1e7) { - for (e = 0, i = v; i >= 10; i /= 10) e++; - x.e = e; - x.d = [v]; - return; + return isDecimal.test(v) ? parseDecimal(x, v) : parseOther(x, v); + } - // Infinity, NaN. - } else if (v * 0 !== 0) { - if (!v) x.s = NaN; - x.e = NaN; - x.d = null; - return; + Decimal.prototype = P; + + Decimal.ROUND_UP = 0; + Decimal.ROUND_DOWN = 1; + Decimal.ROUND_CEIL = 2; + Decimal.ROUND_FLOOR = 3; + Decimal.ROUND_HALF_UP = 4; + Decimal.ROUND_HALF_DOWN = 5; + Decimal.ROUND_HALF_EVEN = 6; + Decimal.ROUND_HALF_CEIL = 7; + Decimal.ROUND_HALF_FLOOR = 8; + Decimal.EUCLID = 9; + + Decimal.config = Decimal.set = config; + Decimal.clone = clone; + Decimal.isDecimal = isDecimalInstance; + + Decimal.abs = abs; + Decimal.acos = acos; + Decimal.acosh = acosh; // ES6 + Decimal.add = add; + Decimal.asin = asin; + Decimal.asinh = asinh; // ES6 + Decimal.atan = atan; + Decimal.atanh = atanh; // ES6 + Decimal.atan2 = atan2; + Decimal.cbrt = cbrt; // ES6 + Decimal.ceil = ceil; + Decimal.cos = cos; + Decimal.cosh = cosh; // ES6 + Decimal.div = div; + Decimal.exp = exp; + Decimal.floor = floor; + Decimal.hypot = hypot; // ES6 + Decimal.ln = ln; + Decimal.log = log; + Decimal.log10 = log10; // ES6 + Decimal.log2 = log2; // ES6 + Decimal.max = max; + Decimal.min = min; + Decimal.mod = mod; + Decimal.mul = mul; + Decimal.pow = pow; + Decimal.random = random; + Decimal.round = round; + Decimal.sign = sign; // ES6 + Decimal.sin = sin; + Decimal.sinh = sinh; // ES6 + Decimal.sqrt = sqrt; + Decimal.sub = sub; + Decimal.tan = tan; + Decimal.tanh = tanh; // ES6 + Decimal.trunc = trunc; // ES6 + + if (obj === void 0) obj = {}; + if (obj) { + if (obj.defaults !== true) { + ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'maxE', 'minE', 'modulo', 'crypto']; + for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p]; } + } - return parseDecimal(x, v.toString()); + Decimal.config(obj); - } else if (t !== 'string') { - throw Error(invalidArgument + v); - } + return Decimal; + } - // Minus sign? - if (v.charCodeAt(0) === 45) { - v = v.slice(1); - x.s = -1; - } else { - x.s = 1; - } - return isDecimal.test(v) ? parseDecimal(x, v) : parseOther(x, v); + /* + * Return a new Decimal whose value is `x` divided by `y`, rounded to `precision` significant + * digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * y {number|string|Decimal} + * + */ + function div(x, y) { + return new this(x).div(y); } - Decimal.prototype = P; - - Decimal.ROUND_UP = 0; - Decimal.ROUND_DOWN = 1; - Decimal.ROUND_CEIL = 2; - Decimal.ROUND_FLOOR = 3; - Decimal.ROUND_HALF_UP = 4; - Decimal.ROUND_HALF_DOWN = 5; - Decimal.ROUND_HALF_EVEN = 6; - Decimal.ROUND_HALF_CEIL = 7; - Decimal.ROUND_HALF_FLOOR = 8; - Decimal.EUCLID = 9; - - Decimal.config = Decimal.set = config; - Decimal.clone = clone; - Decimal.isDecimal = isDecimalInstance; - - Decimal.abs = abs; - Decimal.acos = acos; - Decimal.acosh = acosh; // ES6 - Decimal.add = add; - Decimal.asin = asin; - Decimal.asinh = asinh; // ES6 - Decimal.atan = atan; - Decimal.atanh = atanh; // ES6 - Decimal.atan2 = atan2; - Decimal.cbrt = cbrt; // ES6 - Decimal.ceil = ceil; - Decimal.cos = cos; - Decimal.cosh = cosh; // ES6 - Decimal.div = div; - Decimal.exp = exp; - Decimal.floor = floor; - Decimal.hypot = hypot; // ES6 - Decimal.ln = ln; - Decimal.log = log; - Decimal.log10 = log10; // ES6 - Decimal.log2 = log2; // ES6 - Decimal.max = max; - Decimal.min = min; - Decimal.mod = mod; - Decimal.mul = mul; - Decimal.pow = pow; - Decimal.random = random; - Decimal.round = round; - Decimal.sign = sign; // ES6 - Decimal.sin = sin; - Decimal.sinh = sinh; // ES6 - Decimal.sqrt = sqrt; - Decimal.sub = sub; - Decimal.tan = tan; - Decimal.tanh = tanh; // ES6 - Decimal.trunc = trunc; // ES6 - - if (obj === void 0) obj = {}; - if (obj) { - if (obj.defaults !== true) { - ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'maxE', 'minE', 'modulo', 'crypto']; - for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p]; - } + + /* + * Return a new Decimal whose value is the natural exponential of `x`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} The power to which to raise the base of the natural log. + * + */ + function exp(x) { + return new this(x).exp(); } - Decimal.config(obj); - return Decimal; - } - - - /* - * Return a new Decimal whose value is `x` divided by `y`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function div(x, y) { - return new this(x).div(y); - } - - - /* - * Return a new Decimal whose value is the natural exponential of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} The power to which to raise the base of the natural log. - * - */ - function exp(x) { - return new this(x).exp(); - } + /* + * Return a new Decimal whose value is `x` round to an integer using `ROUND_FLOOR`. + * + * x {number|string|Decimal} + * + */ + function floor(x) { + return finalise(x = new this(x), x.e + 1, 3); + } - /* - * Return a new Decimal whose value is `x` round to an integer using `ROUND_FLOOR`. - * - * x {number|string|Decimal} - * - */ - function floor(x) { - return finalise(x = new this(x), x.e + 1, 3); - } + /* + * Return a new Decimal whose value is the square root of the sum of the squares of the arguments, + * rounded to `precision` significant digits using rounding mode `rounding`. + * + * hypot(a, b, ...) = sqrt(a^2 + b^2 + ...) + * + */ + function hypot() { + var i, n, + t = new this(0); + external = false; - /* - * Return a new Decimal whose value is the square root of the sum of the squares of the arguments, - * rounded to `precision` significant digits using rounding mode `rounding`. - * - * hypot(a, b, ...) = sqrt(a^2 + b^2 + ...) - * - */ - function hypot() { - var i, n, - t = new this(0); - - external = false; - - for (i = 0; i < arguments.length;) { - n = new this(arguments[i++]); - if (!n.d) { - if (n.s) { - external = true; - return new this(1 / 0); + for (i = 0; i < arguments.length;) { + n = new this(arguments[i++]); + if (!n.d) { + if (n.s) { + external = true; + return new this(1 / 0); + } + t = n; + } else if (t.d) { + t = t.plus(n.times(n)); } - t = n; - } else if (t.d) { - t = t.plus(n.times(n)); } - } - external = true; + external = true; - return t.sqrt(); - } + return t.sqrt(); + } - /* - * Return true if object is a Decimal instance (where Decimal is any Decimal constructor), - * otherwise return false. - * - */ - function isDecimalInstance(obj) { - return obj instanceof Decimal || obj && obj.name === '[object Decimal]' || false; - } + /* + * Return true if object is a Decimal instance (where Decimal is any Decimal constructor), + * otherwise return false. + * + */ + function isDecimalInstance(obj) { + return obj instanceof Decimal || obj && obj.name === '[object Decimal]' || false; + } - /* - * Return a new Decimal whose value is the natural logarithm of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function ln(x) { - return new this(x).ln(); - } + /* + * Return a new Decimal whose value is the natural logarithm of `x`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * + */ + function ln(x) { + return new this(x).ln(); + } - /* - * Return a new Decimal whose value is the log of `x` to the base `y`, or to base 10 if no base - * is specified, rounded to `precision` significant digits using rounding mode `rounding`. - * - * log[y](x) - * - * x {number|string|Decimal} The argument of the logarithm. - * y {number|string|Decimal} The base of the logarithm. - * - */ - function log(x, y) { - return new this(x).log(y); - } + /* + * Return a new Decimal whose value is the log of `x` to the base `y`, or to base 10 if no base + * is specified, rounded to `precision` significant digits using rounding mode `rounding`. + * + * log[y](x) + * + * x {number|string|Decimal} The argument of the logarithm. + * y {number|string|Decimal} The base of the logarithm. + * + */ + function log(x, y) { + return new this(x).log(y); + } - /* - * Return a new Decimal whose value is the base 2 logarithm of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function log2(x) { - return new this(x).log(2); - } + /* + * Return a new Decimal whose value is the base 2 logarithm of `x`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * + */ + function log2(x) { + return new this(x).log(2); + } - /* - * Return a new Decimal whose value is the base 10 logarithm of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function log10(x) { - return new this(x).log(10); - } + /* + * Return a new Decimal whose value is the base 10 logarithm of `x`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * + */ + function log10(x) { + return new this(x).log(10); + } - /* - * Return a new Decimal whose value is the maximum of the arguments. - * - * arguments {number|string|Decimal} - * - */ - function max() { - return maxOrMin(this, arguments, 'lt'); - } + /* + * Return a new Decimal whose value is the maximum of the arguments. + * + * arguments {number|string|Decimal} + * + */ + function max() { + return maxOrMin(this, arguments, 'lt'); + } - /* - * Return a new Decimal whose value is the minimum of the arguments. - * - * arguments {number|string|Decimal} - * - */ - function min() { - return maxOrMin(this, arguments, 'gt'); - } + /* + * Return a new Decimal whose value is the minimum of the arguments. + * + * arguments {number|string|Decimal} + * + */ + function min() { + return maxOrMin(this, arguments, 'gt'); + } - /* - * Return a new Decimal whose value is `x` modulo `y`, rounded to `precision` significant digits - * using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function mod(x, y) { - return new this(x).mod(y); - } + /* + * Return a new Decimal whose value is `x` modulo `y`, rounded to `precision` significant digits + * using rounding mode `rounding`. + * + * x {number|string|Decimal} + * y {number|string|Decimal} + * + */ + function mod(x, y) { + return new this(x).mod(y); + } - /* - * Return a new Decimal whose value is `x` multiplied by `y`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function mul(x, y) { - return new this(x).mul(y); - } + /* + * Return a new Decimal whose value is `x` multiplied by `y`, rounded to `precision` significant + * digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * y {number|string|Decimal} + * + */ + function mul(x, y) { + return new this(x).mul(y); + } - /* - * Return a new Decimal whose value is `x` raised to the power `y`, rounded to precision - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} The base. - * y {number|string|Decimal} The exponent. - * - */ - function pow(x, y) { - return new this(x).pow(y); - } + /* + * Return a new Decimal whose value is `x` raised to the power `y`, rounded to precision + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} The base. + * y {number|string|Decimal} The exponent. + * + */ + function pow(x, y) { + return new this(x).pow(y); + } - /* - * Returns a new Decimal with a random value equal to or greater than 0 and less than 1, and with - * `sd`, or `Decimal.precision` if `sd` is omitted, significant digits (or less if trailing zeros - * are produced). - * - * [sd] {number} Significant digits. Integer, 0 to MAX_DIGITS inclusive. - * - */ - function random(sd) { - var d, e, k, n, - i = 0, - r = new this(1), - rd = []; + /* + * Returns a new Decimal with a random value equal to or greater than 0 and less than 1, and with + * `sd`, or `Decimal.precision` if `sd` is omitted, significant digits (or less if trailing zeros + * are produced). + * + * [sd] {number} Significant digits. Integer, 0 to MAX_DIGITS inclusive. + * + */ + function random(sd) { + var d, e, k, n, + i = 0, + r = new this(1), + rd = []; - if (sd === void 0) sd = this.precision; - else checkInt32(sd, 1, MAX_DIGITS); + if (sd === void 0) sd = this.precision; + else checkInt32(sd, 1, MAX_DIGITS); - k = Math.ceil(sd / LOG_BASE); + k = Math.ceil(sd / LOG_BASE); - if (!this.crypto) { - for (; i < k;) rd[i++] = Math.random() * 1e7 | 0; + if (!this.crypto) { + for (; i < k;) rd[i++] = Math.random() * 1e7 | 0; - // Browsers supporting crypto.getRandomValues. - } else if (crypto.getRandomValues) { - d = crypto.getRandomValues(new Uint32Array(k)); + // Browsers supporting crypto.getRandomValues. + } else if (crypto.getRandomValues) { + d = crypto.getRandomValues(new Uint32Array(k)); - for (; i < k;) { - n = d[i]; + for (; i < k;) { + n = d[i]; - // 0 <= n < 4294967296 - // Probability n >= 4.29e9, is 4967296 / 4294967296 = 0.00116 (1 in 865). - if (n >= 4.29e9) { - d[i] = crypto.getRandomValues(new Uint32Array(1))[0]; - } else { + // 0 <= n < 4294967296 + // Probability n >= 4.29e9, is 4967296 / 4294967296 = 0.00116 (1 in 865). + if (n >= 4.29e9) { + d[i] = crypto.getRandomValues(new Uint32Array(1))[0]; + } else { - // 0 <= n <= 4289999999 - // 0 <= (n % 1e7) <= 9999999 - rd[i++] = n % 1e7; + // 0 <= n <= 4289999999 + // 0 <= (n % 1e7) <= 9999999 + rd[i++] = n % 1e7; + } } - } - // Node.js supporting crypto.randomBytes. - } else if (crypto.randomBytes) { + // Node.js supporting crypto.randomBytes. + } else if (crypto.randomBytes) { - // buffer - d = crypto.randomBytes(k *= 4); + // buffer + d = crypto.randomBytes(k *= 4); - for (; i < k;) { + for (; i < k;) { - // 0 <= n < 2147483648 - n = d[i] + (d[i + 1] << 8) + (d[i + 2] << 16) + ((d[i + 3] & 0x7f) << 24); + // 0 <= n < 2147483648 + n = d[i] + (d[i + 1] << 8) + (d[i + 2] << 16) + ((d[i + 3] & 0x7f) << 24); - // Probability n >= 2.14e9, is 7483648 / 2147483648 = 0.0035 (1 in 286). - if (n >= 2.14e9) { - crypto.randomBytes(4).copy(d, i); - } else { + // Probability n >= 2.14e9, is 7483648 / 2147483648 = 0.0035 (1 in 286). + if (n >= 2.14e9) { + crypto.randomBytes(4).copy(d, i); + } else { - // 0 <= n <= 2139999999 - // 0 <= (n % 1e7) <= 9999999 - rd.push(n % 1e7); - i += 4; + // 0 <= n <= 2139999999 + // 0 <= (n % 1e7) <= 9999999 + rd.push(n % 1e7); + i += 4; + } } + + i = k / 4; + } else { + throw Error(cryptoUnavailable); } - i = k / 4; - } else { - throw Error(cryptoUnavailable); - } + k = rd[--i]; + sd %= LOG_BASE; - k = rd[--i]; - sd %= LOG_BASE; + // Convert trailing digits to zeros according to sd. + if (k && sd) { + n = mathpow(10, LOG_BASE - sd); + rd[i] = (k / n | 0) * n; + } - // Convert trailing digits to zeros according to sd. - if (k && sd) { - n = mathpow(10, LOG_BASE - sd); - rd[i] = (k / n | 0) * n; - } + // Remove trailing words which are zero. + for (; rd[i] === 0; i--) rd.pop(); + + // Zero? + if (i < 0) { + e = 0; + rd = [0]; + } else { + e = -1; - // Remove trailing words which are zero. - for (; rd[i] === 0; i--) rd.pop(); + // Remove leading words which are zero and adjust exponent accordingly. + for (; rd[0] === 0; e -= LOG_BASE) rd.shift(); - // Zero? - if (i < 0) { - e = 0; - rd = [0]; - } else { - e = -1; + // Count the digits of the first word of rd to determine leading zeros. + for (k = 1, n = rd[0]; n >= 10; n /= 10) k++; - // Remove leading words which are zero and adjust exponent accordingly. - for (; rd[0] === 0; e -= LOG_BASE) rd.shift(); + // Adjust the exponent for leading zeros of the first word of rd. + if (k < LOG_BASE) e -= LOG_BASE - k; + } - // Count the digits of the first word of rd to determine leading zeros. - for (k = 1, n = rd[0]; n >= 10; n /= 10) k++; + r.e = e; + r.d = rd; - // Adjust the exponent for leading zeros of the first word of rd. - if (k < LOG_BASE) e -= LOG_BASE - k; + return r; } - r.e = e; - r.d = rd; - return r; - } + /* + * Return a new Decimal whose value is `x` rounded to an integer using rounding mode `rounding`. + * + * To emulate `Math.round`, set rounding to 7 (ROUND_HALF_CEIL). + * + * x {number|string|Decimal} + * + */ + function round(x) { + return finalise(x = new this(x), x.e + 1, this.rounding); + } - /* - * Return a new Decimal whose value is `x` rounded to an integer using rounding mode `rounding`. - * - * To emulate `Math.round`, set rounding to 7 (ROUND_HALF_CEIL). - * - * x {number|string|Decimal} - * - */ - function round(x) { - return finalise(x = new this(x), x.e + 1, this.rounding); - } + /* + * Return + * 1 if x > 0, + * -1 if x < 0, + * 0 if x is 0, + * -0 if x is -0, + * NaN otherwise + * + */ + function sign(x) { + x = new this(x); + return x.d ? (x.d[0] ? x.s : 0 * x.s) : x.s || NaN; + } - /* - * Return - * 1 if x > 0, - * -1 if x < 0, - * 0 if x is 0, - * -0 if x is -0, - * NaN otherwise - * - */ - function sign(x) { - x = new this(x); - return x.d ? (x.d[0] ? x.s : 0 * x.s) : x.s || NaN; - } + /* + * Return a new Decimal whose value is the sine of `x`, rounded to `precision` significant digits + * using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function sin(x) { + return new this(x).sin(); + } - /* - * Return a new Decimal whose value is the sine of `x`, rounded to `precision` significant digits - * using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function sin(x) { - return new this(x).sin(); - } + /* + * Return a new Decimal whose value is the hyperbolic sine of `x`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function sinh(x) { + return new this(x).sinh(); + } - /* - * Return a new Decimal whose value is the hyperbolic sine of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function sinh(x) { - return new this(x).sinh(); - } + /* + * Return a new Decimal whose value is the square root of `x`, rounded to `precision` significant + * digits using rounding mode `rounding`. + * + * x {number|string|Decimal} + * + */ + function sqrt(x) { + return new this(x).sqrt(); + } - /* - * Return a new Decimal whose value is the square root of `x`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function sqrt(x) { - return new this(x).sqrt(); - } + /* + * Return a new Decimal whose value is `x` minus `y`, rounded to `precision` significant digits + * using rounding mode `rounding`. + * + * x {number|string|Decimal} + * y {number|string|Decimal} + * + */ + function sub(x, y) { + return new this(x).sub(y); + } - /* - * Return a new Decimal whose value is `x` minus `y`, rounded to `precision` significant digits - * using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function sub(x, y) { - return new this(x).sub(y); - } + /* + * Return a new Decimal whose value is the tangent of `x`, rounded to `precision` significant + * digits using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function tan(x) { + return new this(x).tan(); + } - /* - * Return a new Decimal whose value is the tangent of `x`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function tan(x) { - return new this(x).tan(); - } + /* + * Return a new Decimal whose value is the hyperbolic tangent of `x`, rounded to `precision` + * significant digits using rounding mode `rounding`. + * + * x {number|string|Decimal} A value in radians. + * + */ + function tanh(x) { + return new this(x).tanh(); + } - /* - * Return a new Decimal whose value is the hyperbolic tangent of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function tanh(x) { - return new this(x).tanh(); - } + /* + * Return a new Decimal whose value is `x` truncated to an integer. + * + * x {number|string|Decimal} + * + */ + function trunc(x) { + return finalise(x = new this(x), x.e + 1, 1); + } - /* - * Return a new Decimal whose value is `x` truncated to an integer. - * - * x {number|string|Decimal} - * - */ - function trunc(x) { - return finalise(x = new this(x), x.e + 1, 1); - } + // Create and configure initial Decimal constructor. + Decimal = clone(DEFAULTS); + Decimal['default'] = Decimal.Decimal = Decimal; - // Create and configure initial Decimal constructor. - Decimal = clone(DEFAULTS); + // Create the internal constants from their string values. + LN10 = new Decimal(LN10); + PI = new Decimal(PI); - Decimal['default'] = Decimal.Decimal = Decimal; - // Create the internal constants from their string values. - LN10 = new Decimal(LN10); - PI = new Decimal(PI); + // Export. - // Export. + // AMD. + if (typeof undefined == 'function' && undefined.amd) { + undefined(function () { + return Decimal; + }); + // Node and other environments that support module.exports. + } else if ('object' != 'undefined' && module.exports) { + module.exports = Decimal; - // AMD. - if (typeof undefined == 'function' && undefined.amd) { - undefined(function () { - return Decimal; - }); + // Browser. + } else { + if (!globalScope) { + globalScope = typeof self != 'undefined' && self && self.self == self + ? self : Function('return this')(); + } - // Node and other environments that support module.exports. - } else if ('object' != 'undefined' && module.exports) { - module.exports = Decimal; + noConflict = globalScope.Decimal; + Decimal.noConflict = function () { + globalScope.Decimal = noConflict; + return Decimal; + }; - // Browser. - } else { - if (!globalScope) { - globalScope = typeof self != 'undefined' && self && self.self == self - ? self : Function('return this')(); + globalScope.Decimal = Decimal; } - - noConflict = globalScope.Decimal; - Decimal.noConflict = function () { - globalScope.Decimal = noConflict; - return Decimal; - }; - - globalScope.Decimal = Decimal; - } -})(commonjsGlobal); -}); + })(commonjsGlobal); + }); -// make sure to pick the es5 version + // make sure to pick the es5 version -function factory$2 (type, config, load, typed, math) { - var BigNumber = decimal.clone({precision: config.precision}); + function factory$2 (type, config, load, typed, math) { + var BigNumber = decimal.clone({precision: config.precision}); - /** - * Attach type information - */ - BigNumber.prototype.type = 'BigNumber'; - BigNumber.prototype.isBigNumber = true; + /** + * Attach type information + */ + BigNumber.prototype.type = 'BigNumber'; + BigNumber.prototype.isBigNumber = true; - /** - * Get a JSON representation of a BigNumber containing - * type information - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "BigNumber", "value": "0.2"}` - */ - BigNumber.prototype.toJSON = function () { - return { - mathjs: 'BigNumber', - value: this.toString() + /** + * Get a JSON representation of a BigNumber containing + * type information + * @returns {Object} Returns a JSON object structured as: + * `{"mathjs": "BigNumber", "value": "0.2"}` + */ + BigNumber.prototype.toJSON = function () { + return { + mathjs: 'BigNumber', + value: this.toString() + }; }; - }; - - /** - * Instantiate a BigNumber from a JSON object - * @param {Object} json a JSON object structured as: - * `{"mathjs": "BigNumber", "value": "0.2"}` - * @return {BigNumber} - */ - BigNumber.fromJSON = function (json) { - return new BigNumber(json.value); - }; - // listen for changed in the configuration, automatically apply changed precision - math.on('config', function (curr, prev) { - if (curr.precision !== prev.precision) { - BigNumber.config({ precision: curr.precision }); - } - }); + /** + * Instantiate a BigNumber from a JSON object + * @param {Object} json a JSON object structured as: + * `{"mathjs": "BigNumber", "value": "0.2"}` + * @return {BigNumber} + */ + BigNumber.fromJSON = function (json) { + return new BigNumber(json.value); + }; - return BigNumber; -} - -var name$2 = 'BigNumber'; -var path = 'type'; -var factory_1$2 = factory$2; -var math$2 = true; // request access to the math namespace - -var BigNumber = { - name: name$2, - path: path, - factory: factory_1$2, - math: math$2 -}; - -/** - * 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 - */ -var deepMap = 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); + // listen for changed in the configuration, automatically apply changed precision + math.on('config', function (curr, prev) { + if (curr.precision !== prev.precision) { + BigNumber.config({ precision: curr.precision }); + } }); + + return BigNumber; } - else { - return callback(array); - } -}; -function factory$3 (type, config, load, typed) { + var name$2 = 'BigNumber'; + var path = 'type'; + var factory_1$2 = factory$2; + var math$2 = true; // request access to the math namespace + + var BigNumber = { + name: name$2, + path: path, + factory: factory_1$2, + math: math$2 + }; + /** - * Create a BigNumber, which can store numbers with arbitrary precision. - * When a matrix is provided, all elements will be converted to BigNumber. - * - * Syntax: - * - * math.bignumber(x) + * 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. * - * Examples: - * - * 0.1 + 0.2; // returns number 0.30000000000000004 - * math.bignumber(0.1) + math.bignumber(0.2); // returns BigNumber 0.3 - * - * - * 7.2e500; // returns number Infinity - * math.bignumber('7.2e500'); // returns BigNumber 7.2e500 - * - * See also: - * - * boolean, complex, index, matrix, string, unit - * - * @param {number | string | Fraction | BigNumber | Array | Matrix | boolean | null} [value] Value for the big number, - * 0 by default. - * @returns {BigNumber} The created bignumber + * @return {Array | Matrix} res */ - var bignumber = typed('bignumber', { - '': function () { - return new type.BigNumber(0); - }, + var deepMap = 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); + } + }; - 'number': function (x) { - // convert to string to prevent errors in case of >15 digits - return new type.BigNumber(x + ''); - }, + function factory$3 (type, config, load, typed) { + /** + * Create a BigNumber, which can store numbers with arbitrary precision. + * When a matrix is provided, all elements will be converted to BigNumber. + * + * Syntax: + * + * math.bignumber(x) + * + * Examples: + * + * 0.1 + 0.2; // returns number 0.30000000000000004 + * math.bignumber(0.1) + math.bignumber(0.2); // returns BigNumber 0.3 + * + * + * 7.2e500; // returns number Infinity + * math.bignumber('7.2e500'); // returns BigNumber 7.2e500 + * + * See also: + * + * boolean, complex, index, matrix, string, unit + * + * @param {number | string | Fraction | BigNumber | Array | Matrix | boolean | null} [value] Value for the big number, + * 0 by default. + * @returns {BigNumber} The created bignumber + */ + var bignumber = typed('bignumber', { + '': function () { + return new type.BigNumber(0); + }, - 'string': function (x) { - return new type.BigNumber(x); - }, + 'number': function (x) { + // convert to string to prevent errors in case of >15 digits + return new type.BigNumber(x + ''); + }, - 'BigNumber': function (x) { - // we assume a BigNumber is immutable - return x; - }, + 'string': function (x) { + return new type.BigNumber(x); + }, - 'Fraction': function (x) { - return new type.BigNumber(x.n).div(x.d); - }, + 'BigNumber': function (x) { + // we assume a BigNumber is immutable + return x; + }, - 'null': function (x) { - return new type.BigNumber(0); - }, + 'Fraction': function (x) { + return new type.BigNumber(x.n).div(x.d); + }, - 'Array | Matrix': function (x) { - return deepMap(x, bignumber); - } - }); + 'null': function (x) { + return new type.BigNumber(0); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, bignumber); + } + }); + + bignumber.toTex = { + 0: '0', + 1: '\\left(${args[0]}\\right)' + }; + + return bignumber; + } + + var name$3 = 'bignumber'; + var factory_1$3 = factory$3; - bignumber.toTex = { - 0: '0', - 1: '\\left(${args[0]}\\right)' + var bignumber = { + name: name$3, + factory: factory_1$3 }; - return bignumber; -} + var bignumber$1 = [ + // type + BigNumber, -var name$3 = 'bignumber'; -var factory_1$3 = factory$3; + // construction function + bignumber + ]; -var bignumber = { - name: name$3, - factory: factory_1$3 -}; + function factory$4 (type, config, load, typed) { + /** + * Create a boolean or convert a string or number to a boolean. + * In case of a number, `true` is returned for non-zero numbers, and `false` in + * case of zero. + * Strings can be `'true'` or `'false'`, or can contain a number. + * When value is a matrix, all elements will be converted to boolean. + * + * Syntax: + * + * math.boolean(x) + * + * Examples: + * + * math.boolean(0); // returns false + * math.boolean(1); // returns true + * math.boolean(-3); // returns true + * math.boolean('true'); // returns true + * math.boolean('false'); // returns false + * math.boolean([1, 0, 1, 1]); // returns [true, false, true, true] + * + * See also: + * + * bignumber, complex, index, matrix, string, unit + * + * @param {string | number | boolean | Array | Matrix | null} value A value of any type + * @return {boolean | Array | Matrix} The boolean value + */ + var bool = typed('bool', { + '': function () { + return false; + }, -var bignumber$1 = [ - // type - BigNumber, + 'boolean': function (x) { + return x; + }, - // construction function - bignumber -]; + 'number': function (x) { + return !!x; + }, -function factory$4 (type, config, load, typed) { - /** - * Create a boolean or convert a string or number to a boolean. - * In case of a number, `true` is returned for non-zero numbers, and `false` in - * case of zero. - * Strings can be `'true'` or `'false'`, or can contain a number. - * When value is a matrix, all elements will be converted to boolean. - * - * Syntax: - * - * math.boolean(x) - * - * Examples: - * - * math.boolean(0); // returns false - * math.boolean(1); // returns true - * math.boolean(-3); // returns true - * math.boolean('true'); // returns true - * math.boolean('false'); // returns false - * math.boolean([1, 0, 1, 1]); // returns [true, false, true, true] - * - * See also: - * - * bignumber, complex, index, matrix, string, unit - * - * @param {string | number | boolean | Array | Matrix | null} value A value of any type - * @return {boolean | Array | Matrix} The boolean value - */ - var bool = typed('bool', { - '': function () { - return false; - }, + 'null': function (x) { + return false; + }, - 'boolean': function (x) { - return x; - }, + 'BigNumber': function (x) { + return !x.isZero(); + }, - 'number': function (x) { - return !!x; - }, + 'string': function (x) { + // try case insensitive + var lcase = x.toLowerCase(); + if (lcase === 'true') { + return true; + } + else if (lcase === 'false') { + return false; + } - 'null': function (x) { - return false; - }, + // test whether value is a valid number + var num = Number(x); + if (x != '' && !isNaN(num)) { + return !!num; + } - 'BigNumber': function (x) { - return !x.isZero(); - }, + throw new Error('Cannot convert "' + x + '" to a boolean'); + }, - 'string': function (x) { - // try case insensitive - var lcase = x.toLowerCase(); - if (lcase === 'true') { - return true; - } - else if (lcase === 'false') { - return false; + 'Array | Matrix': function (x) { + return deepMap(x, bool); } + }); - // test whether value is a valid number - var num = Number(x); - if (x != '' && !isNaN(num)) { - return !!num; - } + return bool; + } - throw new Error('Cannot convert "' + x + '" to a boolean'); - }, + var name$4 = 'boolean'; + var factory_1$4 = factory$4; - 'Array | Matrix': function (x) { - return deepMap(x, bool); - } - }); + var boolean_1 = { + name: name$4, + factory: factory_1$4 + }; - return bool; -} - -var name$4 = 'boolean'; -var factory_1$4 = factory$4; - -var boolean_1 = { - name: name$4, - factory: factory_1$4 -}; - -var formatter = createCommonjsModule(function (module, exports) { - - - -/** - * Convert a BigNumber 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' - * 'auto' (default) Regular number notation for numbers - * having an absolute value between - * `lower` and `upper` 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' 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. - * {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(12e8, {notation: 'fixed'}); // returns '1200000000' - * format(2.3, {notation: 'fixed', precision: 4}); // returns '2.3000' - * format(52.8, {notation: 'exponential'}); // returns '5.28e+1' - * format(12400, {notation: 'engineering'}); // returns '12.400e+3' - * - * @param {BigNumber} 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.isFinite()) { - return value.isNaN() ? 'NaN' : (value.gt(0) ? 'Infinity' : '-Infinity'); - } - - // default values for options - var notation = 'auto'; - var precision = undefined; - - if (options !== undefined) { - // determine notation from options - if (options.notation) { - notation = options.notation; - } - - // determine precision from options - if (typeof options === 'number') { - precision = options; - } - else if (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); + var formatter = createCommonjsModule(function (module, exports) { - 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 = object.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.format(value, fixedOptions); - } + /** + * Convert a BigNumber 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' + * 'auto' (default) Regular number notation for numbers + * having an absolute value between + * `lower` and `upper` 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' 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. + * {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(12e8, {notation: 'fixed'}); // returns '1200000000' + * format(2.3, {notation: 'fixed', precision: 4}); // returns '2.3000' + * format(52.8, {notation: 'exponential'}); // returns '5.28e+1' + * format(12400, {notation: 'engineering'}); // returns '12.400e+3' + * + * @param {BigNumber} 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); + } - // determine lower and upper bound for exponential notation. - // TODO: implement support for upper and lower to be BigNumbers themselves - var lowerExp = (options && options.lowerExp !== undefined) ? options.lowerExp : -3; - var upperExp = (options && options.upperExp !== undefined) ? options.upperExp : 5; + // handle special cases + if (!value.isFinite()) { + return value.isNaN() ? 'NaN' : (value.gt(0) ? 'Infinity' : '-Infinity'); + } - // handle special case zero - if (value.isZero()) return '0'; + // default values for options + var notation = 'auto'; + var precision = undefined; - // determine whether or not to output exponential notation - var str; - var exp = value.logarithm(); - if (exp.gte(lowerExp) && exp.lt(upperExp)) { - // normal number notation - str = value.toSignificantDigits(precision).toFixed(); - } - else { - // exponential notation - str = exports.toExponential(value, precision); + if (options !== undefined) { + // determine notation from options + if (options.notation) { + notation = options.notation; } - // remove trailing zeros after the decimal point - return str.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".'); - } -}; - -/** - * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3' - * @param {BigNumber} value - * @param {number} [precision] Number of digits in formatted output. - * If not provided, the maximum available digits - * is used. - * @returns {string} str - */ -exports.toExponential = function (value, precision) { - if (precision !== undefined) { - return value.toExponential(precision - 1); // Note the offset of one - } - else { - return value.toExponential(); - } -}; - -/** - * Format a number with fixed notation. - * @param {BigNumber} value - * @param {number} [precision=undefined] Optional number of decimals after the - * decimal point. Undefined by default. - */ -exports.toFixed = function (value, precision) { - return value.toFixed(precision); -}; -}); -var formatter_1 = formatter.format; -var formatter_2 = formatter.toExponential; -var formatter_3 = formatter.toFixed; - -var string = createCommonjsModule(function (module, exports) { - -var formatNumber = number.format; -var formatBigNumber = formatter.format; - - -/** - * Test whether value is a string - * @param {*} value - * @return {boolean} isString - */ -exports.isString = function(value) { - return typeof value === 'string'; -}; - -/** - * Check if a text ends with a certain string. - * @param {string} text - * @param {string} search - */ -exports.endsWith = function(text, search) { - var start = text.length - search.length; - var end = text.length; - return (text.substring(start, end) === search); -}; - -/** - * Format a value of any type into a string. - * - * Usage: - * math.format(value) - * math.format(value, precision) - * - * When value is a function: - * - * - When the function has a property `syntax`, it returns this - * syntax description. - * - In other cases, a string `'function'` is returned. - * - * When `value` is an Object: - * - * - When the object contains a property `format` being a function, this - * function is invoked as `value.format(options)` and the result is returned. - * - When the object has its own `toString` method, this method is invoked - * and the result is returned. - * - In other cases the function will loop over all object properties and - * return JSON object notation like '{"a": 2, "b": 3}'. - * - * Example usage: - * math.format(2/7); // '0.2857142857142857' - * math.format(math.pi, 3); // '3.14' - * math.format(new Complex(2, 3)); // '2 + 3i' - * math.format('hello'); // '"hello"' - * - * @param {*} value Value to be stringified - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @return {string} str - */ -exports.format = function(value, options) { - if (typeof value === 'number') { - return formatNumber(value, options); - } - - if (isBigNumber(value)) { - return formatBigNumber(value, options); - } - - // note: we use unsafe duck-typing here to check for Fractions, this is - // ok here since we're only invoking toString or concatenating its values - if (looksLikeFraction(value)) { - if (!options || options.fraction !== 'decimal') { - // output as ratio, like '1/3' - return (value.s * value.n) + '/' + value.d; - } - else { - // output as decimal, like '0.(3)' - return value.toString(); + // determine precision from options + if (typeof options === 'number') { + precision = options; + } + else if (options.precision) { + precision = options.precision; + } } - } - if (Array.isArray(value)) { - return formatArray(value, options); - } + // handle the various notations + switch (notation) { + case 'fixed': + return exports.toFixed(value, precision); - if (exports.isString(value)) { - return '"' + value + '"'; - } + case 'exponential': + return exports.toExponential(value, precision); - if (typeof value === 'function') { - return value.syntax ? String(value.syntax) : 'function'; - } + 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 = object.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); + } - if (value && typeof value === 'object') { - if (typeof value.format === 'function') { - return value.format(options); - } - else if (value && value.toString() !== {}.toString()) { - // this object has a non-native toString method, use that one - return value.toString(); - } - else { - var entries = []; + 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)); - for (var key in value) { - if (value.hasOwnProperty(key)) { - entries.push('"' + key + '": ' + exports.format(value[key], options)); + return exports.format(value, fixedOptions); } - } - return '{' + entries.join(', ') + '}'; - } - } + // determine lower and upper bound for exponential notation. + // TODO: implement support for upper and lower to be BigNumbers themselves + var lowerExp = (options && options.lowerExp !== undefined) ? options.lowerExp : -3; + var upperExp = (options && options.upperExp !== undefined) ? options.upperExp : 5; - return String(value); -}; + // handle special case zero + if (value.isZero()) return '0'; -/** - * Stringify a value into a string enclosed in double quotes. - * Unescaped double quotes and backslashes inside the value are escaped. - * @param {*} value - * @return {string} - */ -exports.stringify = function (value) { - var text = String(value); - var escaped = ''; - var i = 0; - while (i < text.length) { - var c = text.charAt(i); + // determine whether or not to output exponential notation + var str; + var exp = value.logarithm(); + if (exp.gte(lowerExp) && exp.lt(upperExp)) { + // normal number notation + str = value.toSignificantDigits(precision).toFixed(); + } + else { + // exponential notation + str = exports.toExponential(value, precision); + } - if (c === '\\') { - escaped += c; - i++; + // remove trailing zeros after the decimal point + return str.replace(/((\.\d*?)(0+))($|e)/, function () { + var digits = arguments[2]; + var e = arguments[4]; + return (digits !== '.') ? digits + e : e; + }); - c = text.charAt(i); - if (c === '' || '"\\/bfnrtu'.indexOf(c) === -1) { - escaped += '\\'; // no valid escape character -> escape it - } - escaped += c; - } - else if (c === '"') { - escaped += '\\"'; - } - else { - escaped += c; - } - i++; - } - - return '"' + escaped + '"'; -}; - -/** - * Escape special HTML characters - * @param {*} value - * @return {string} - */ -exports.escape = function (value) { - var text = String(value); - text = text.replace(/&/g, '&') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(//g, '>'); - - return text; -}; - -/** - * Recursively format an n-dimensional matrix - * Example output: "[[1, 2], [3, 4]]" - * @param {Array} array - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ -function formatArray (array, options) { - if (Array.isArray(array)) { - var str = '['; - var len = array.length; - for (var i = 0; i < len; i++) { - if (i != 0) { - str += ', '; - } - str += formatArray(array[i], options); + default: + throw new Error('Unknown notation "' + notation + '". ' + + 'Choose "auto", "exponential", or "fixed".'); } - str += ']'; - return str; - } - else { - return exports.format(array, options); - } -} - -/** - * Check whether a value looks like a Fraction (unsafe duck-type check) - * @param {*} value - * @return {boolean} - */ -function looksLikeFraction (value) { - return (value && - typeof value === 'object' && - typeof value.s === 'number' && - typeof value.n === 'number' && - typeof value.d === 'number') || false; -} -}); -var string_1 = string.isString; -var string_2 = string.endsWith; -var string_3 = string.format; -var string_4 = string.stringify; -var string_5 = string.escape; - -var format = string.format; -var lazy$1 = object.lazy; - -function factory$5 (type, config, load, typed, math) { + }; + /** - * @constructor Chain - * Wrap any value in a chain, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the chain, - * and then will be evaluated with the value itself as first argument. - * The chain can be closed by executing chain.done(), which will return - * the final value. - * - * The Chain has a number of special functions: - * - done() Finalize the chained operation and return the - * chain's value. - * - valueOf() The same as done() - * - toString() Returns a string representation of the chain's value. - * - * @param {*} [value] + * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3' + * @param {BigNumber} value + * @param {number} [precision] Number of digits in formatted output. + * If not provided, the maximum available digits + * is used. + * @returns {string} str */ - function Chain (value) { - if (!(this instanceof Chain)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - if (type.isChain(value)) { - this.value = value.value; + exports.toExponential = function (value, precision) { + if (precision !== undefined) { + return value.toExponential(precision - 1); // Note the offset of one } else { - this.value = value; + return value.toExponential(); } - } - - /** - * Attach type information - */ - Chain.prototype.type = 'Chain'; - Chain.prototype.isChain = true; - - /** - * Close the chain. Returns the final value. - * Does the same as method valueOf() - * @returns {*} value - */ - Chain.prototype.done = function () { - return this.value; }; /** - * Close the chain. Returns the final value. - * Does the same as method done() - * @returns {*} value + * Format a number with fixed notation. + * @param {BigNumber} value + * @param {number} [precision=undefined] Optional number of decimals after the + * decimal point. Undefined by default. */ - Chain.prototype.valueOf = function () { - return this.value; + exports.toFixed = function (value, precision) { + return value.toFixed(precision); }; + }); + var formatter_1 = formatter.format; + var formatter_2 = formatter.toExponential; + var formatter_3 = formatter.toFixed; + + var string = createCommonjsModule(function (module, exports) { + + var formatNumber = number.format; + var formatBigNumber = formatter.format; - /** - * Get a string representation of the value in the chain - * @returns {string} - */ - Chain.prototype.toString = function () { - return format(this.value); - }; /** - * Get a JSON representation of the chain - * @returns {Object} + * Test whether value is a string + * @param {*} value + * @return {boolean} isString */ - Chain.prototype.toJSON = function () { - return { - mathjs: 'Chain', - value: this.value - }; + exports.isString = function(value) { + return typeof value === 'string'; }; /** - * Instantiate a Chain from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "Chain", value: ...}`, - * where mathjs is optional - * @returns {Chain} + * Check if a text ends with a certain string. + * @param {string} text + * @param {string} search */ - Chain.fromJSON = function (json) { - return new Chain(json.value); + exports.endsWith = function(text, search) { + var start = text.length - search.length; + var end = text.length; + return (text.substring(start, end) === search); }; /** - * Create a proxy method for the chain - * @param {string} name - * @param {Function} fn The function to be proxied - * If fn is no function, it is silently ignored. - * @private + * Format a value of any type into a string. + * + * Usage: + * math.format(value) + * math.format(value, precision) + * + * When value is a function: + * + * - When the function has a property `syntax`, it returns this + * syntax description. + * - In other cases, a string `'function'` is returned. + * + * When `value` is an Object: + * + * - When the object contains a property `format` being a function, this + * function is invoked as `value.format(options)` and the result is returned. + * - When the object has its own `toString` method, this method is invoked + * and the result is returned. + * - In other cases the function will loop over all object properties and + * return JSON object notation like '{"a": 2, "b": 3}'. + * + * Example usage: + * math.format(2/7); // '0.2857142857142857' + * math.format(math.pi, 3); // '3.14' + * math.format(new Complex(2, 3)); // '2 + 3i' + * math.format('hello'); // '"hello"' + * + * @param {*} value Value to be stringified + * @param {Object | number | Function} [options] Formatting options. See + * lib/utils/number:format for a + * description of the available + * options. + * @return {string} str */ - function createProxy(name, fn) { - if (typeof fn === 'function') { - Chain.prototype[name] = chainify(fn); + exports.format = function(value, options) { + if (typeof value === 'number') { + return formatNumber(value, options); } - } - /** - * Create a proxy method for the chain - * @param {string} name - * @param {function} resolver The function resolving with the - * function to be proxied - * @private - */ - function createLazyProxy(name, resolver) { - lazy$1(Chain.prototype, name, function outerResolver() { - var fn = resolver(); - if (typeof fn === 'function') { - return chainify(fn); - } - - return undefined; // if not a function, ignore - }); - } + if (isBigNumber(value)) { + return formatBigNumber(value, options); + } - /** - * Make a function chainable - * @param {function} fn - * @return {Function} chain function - * @private - */ - function chainify (fn) { - return function () { - var args = [this.value]; // `this` will be the context of a Chain instance - for (var i = 0; i < arguments.length; i++) { - args[i + 1] = arguments[i]; + // note: we use unsafe duck-typing here to check for Fractions, this is + // ok here since we're only invoking toString or concatenating its values + if (looksLikeFraction(value)) { + if (!options || options.fraction !== 'decimal') { + // output as ratio, like '1/3' + return (value.s * value.n) + '/' + value.d; + } + else { + // output as decimal, like '0.(3)' + return value.toString(); } - - return new Chain(fn.apply(fn, args)); } - } - /** - * Create a proxy for a single method, or an object with multiple methods. - * Example usage: - * - * Chain.createProxy('add', function add (x, y) {...}); - * Chain.createProxy({ - * add: function add (x, y) {...}, - * subtract: function subtract (x, y) {...} - * } - * - * @param {string | Object} arg0 A name (string), or an object with - * functions - * @param {*} [arg1] A function, when arg0 is a name - */ - Chain.createProxy = function (arg0, arg1) { - if (typeof arg0 === 'string') { - // createProxy(name, value) - createProxy(arg0, arg1); - } - else { - // createProxy(values) - for (var prop in arg0) { - if (arg0.hasOwnProperty(prop)) { - createProxy(prop, arg0[prop]); - } - } + if (Array.isArray(value)) { + return formatArray(value, options); } - }; - // create proxy for everything that is in math.js - Chain.createProxy(math); + if (exports.isString(value)) { + return '"' + value + '"'; + } - // register on the import event, automatically add a proxy for every imported function. - math.on('import', function (name, resolver, path) { - if (path === undefined) { - // an imported function (not a data type or something special) - createLazyProxy(name, resolver); + if (typeof value === 'function') { + return value.syntax ? String(value.syntax) : 'function'; } - }); - return Chain; -} + if (value && typeof value === 'object') { + if (typeof value.format === 'function') { + return value.format(options); + } + else if (value && value.toString() !== {}.toString()) { + // this object has a non-native toString method, use that one + return value.toString(); + } + else { + var entries = []; + + for (var key in value) { + if (value.hasOwnProperty(key)) { + entries.push('"' + key + '": ' + exports.format(value[key], options)); + } + } -var name$5 = 'Chain'; -var path$1 = 'type'; -var factory_1$5 = factory$5; -var math$3 = true; // require providing the math namespace as 5th argument -var lazy_1$1 = false; // we need to register a listener on the import events, so no lazy loading + return '{' + entries.join(', ') + '}'; + } + } -var Chain = { - name: name$5, - path: path$1, - factory: factory_1$5, - math: math$3, - lazy: lazy_1$1 -}; + return String(value); + }; -function factory$6 (type, config, load, typed) { /** - * Wrap any value in a chain, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the chain, - * and then will be evaluated with the value itself as first argument. - * The chain can be closed by executing `chain.done()`, which returns - * the final value. - * - * The chain has a number of special functions: - * - * - `done()` Finalize the chain and return the chain's value. - * - `valueOf()` The same as `done()` - * - `toString()` Executes `math.format()` onto the chain's value, returning - * a string representation of the value. - * - * Syntax: - * - * math.chain(value) - * - * Examples: - * - * math.chain(3) - * .add(4) - * .subtract(2) - * .done(); // 5 - * - * math.chain( [[1, 2], [3, 4]] ) - * .subset(math.index(0, 0), 8) - * .multiply(3) - * .done(); // [[24, 6], [9, 12]] - * - * @param {*} [value] A value of any type on which to start a chained operation. - * @return {math.type.Chain} The created chain + * Stringify a value into a string enclosed in double quotes. + * Unescaped double quotes and backslashes inside the value are escaped. + * @param {*} value + * @return {string} */ - return typed('chain', { - '': function() { - return new type.Chain(); - }, + exports.stringify = function (value) { + var text = String(value); + var escaped = ''; + var i = 0; + while (i < text.length) { + var c = text.charAt(i); + + if (c === '\\') { + escaped += c; + i++; - 'any': function(value) { - return new type.Chain(value); + c = text.charAt(i); + if (c === '' || '"\\/bfnrtu'.indexOf(c) === -1) { + escaped += '\\'; // no valid escape character -> escape it + } + escaped += c; + } + else if (c === '"') { + escaped += '\\"'; + } + else { + escaped += c; + } + i++; } - }); -} - -var name$6 = 'chain'; -var factory_1$6 = factory$6; - -var chain = { - name: name$6, - factory: factory_1$6 -}; - -var chain$1 = [ - // type - Chain, - - // construction function - chain -]; - -var complex = createCommonjsModule(function (module, exports) { -/** - * @license Complex.js v2.0.10 11/02/2016 - * - * Copyright (c) 2016, Robert Eisele (robert@xarg.org) - * Dual licensed under the MIT or GPL Version 2 licenses. - **/ - -/** - * - * This class allows the manipulation of complex numbers. - * You can pass a complex number in different formats. Either as object, double, string or two integer parameters. - * - * Object form - * { re: , im: } - * { arg: , abs: } - * { phi: , r: } - * - * Array / Vector form - * [ real, imaginary ] - * - * Double form - * 99.3 - Single double value - * - * String form - * '23.1337' - Simple real number - * '15+3i' - a simple complex number - * '3-i' - a simple complex number - * - * Example: - * - * var c = new Complex('99.3+8i'); - * c.mul({r: 3, i: 9}).div(4.9).sub(3, 2); - * - */ - -(function(root) { - - var cosh = function(x) { - return (Math.exp(x) + Math.exp(-x)) * 0.5; - }; - - var sinh = function(x) { - return (Math.exp(x) - Math.exp(-x)) * 0.5; + + return '"' + escaped + '"'; }; /** - * Calculates cos(x) - 1 using Taylor series if x is small. - * - * @param {number} x - * @returns {number} cos(x) - 1 + * Escape special HTML characters + * @param {*} value + * @return {string} */ - - var cosm1 = function(x) { - var limit = Math.PI/4; - if (x < -limit || x > limit) { - return (Math.cos(x) - 1.0); - } - - var xx = x * x; - return xx * - (-0.5 + xx * - (1/24 + xx * - (-1/720 + xx * - (1/40320 + xx * - (-1/3628800 + xx * - (1/4790014600 + xx * - (-1/87178291200 + xx * - (1/20922789888000) - ) - ) - ) - ) - ) - ) - ) + exports.escape = function (value) { + var text = String(value); + text = text.replace(/&/g, '&') + .replace(/"/g, '"') + .replace(/'/g, ''') + .replace(//g, '>'); + + return text; }; - var hypot = function(x, y) { - - var a = Math.abs(x); - var b = Math.abs(y); - - if (a < 3000 && b < 3000) { - return Math.sqrt(a * a + b * b); + /** + * Recursively format an n-dimensional matrix + * Example output: "[[1, 2], [3, 4]]" + * @param {Array} array + * @param {Object | number | Function} [options] Formatting options. See + * lib/utils/number:format for a + * description of the available + * options. + * @returns {string} str + */ + function formatArray (array, options) { + if (Array.isArray(array)) { + var str = '['; + var len = array.length; + for (var i = 0; i < len; i++) { + if (i != 0) { + str += ', '; + } + str += formatArray(array[i], options); + } + str += ']'; + return str; } - - if (a < b) { - a = b; - b = x / y; - } else { - b = y / x; + else { + return exports.format(array, options); } - return a * Math.sqrt(1 + b * b); - }; - - var parser_exit = function() { - throw SyntaxError('Invalid Param'); - }; + } /** - * Calculates log(sqrt(a^2+b^2)) in a way to avoid overflows - * - * @param {number} a - * @param {number} b - * @returns {number} + * Check whether a value looks like a Fraction (unsafe duck-type check) + * @param {*} value + * @return {boolean} */ - function logHypot(a, b) { - - var _a = Math.abs(a); - var _b = Math.abs(b); - - if (a === 0) { - return Math.log(_b); - } - - if (b === 0) { - return Math.log(_a); - } + function looksLikeFraction (value) { + return (value && + typeof value === 'object' && + typeof value.s === 'number' && + typeof value.n === 'number' && + typeof value.d === 'number') || false; + } + }); + var string_1 = string.isString; + var string_2 = string.endsWith; + var string_3 = string.format; + var string_4 = string.stringify; + var string_5 = string.escape; - if (_a < 3000 && _b < 3000) { - return Math.log(a * a + b * b) * 0.5; - } + var format = string.format; + var lazy$1 = object.lazy; - /* I got 4 ideas to compute this property without overflow: - * - * Testing 1000000 times with random samples for a,b ∈ [1, 1000000000] against a big decimal library to get an error estimate + function factory$5 (type, config, load, typed, math) { + /** + * @constructor Chain + * Wrap any value in a chain, allowing to perform chained operations on + * the value. * - * 1. Only eliminate the square root: (OVERALL ERROR: 3.9122483030951116e-11) - - Math.log(a * a + b * b) / 2 - + * All methods available in the math.js library can be called upon the chain, + * and then will be evaluated with the value itself as first argument. + * The chain can be closed by executing chain.done(), which will return + * the final value. * + * The Chain has a number of special functions: + * - done() Finalize the chained operation and return the + * chain's value. + * - valueOf() The same as done() + * - toString() Returns a string representation of the chain's value. * - * 2. Try to use the non-overflowing pythagoras: (OVERALL ERROR: 8.889760039210159e-10) - - var fn = function(a, b) { - a = Math.abs(a); - b = Math.abs(b); - var t = Math.min(a, b); - a = Math.max(a, b); - t = t / a; - - return Math.log(a) + Math.log(1 + t * t) / 2; - }; - - * 3. Abuse the identity cos(atan(y/x) = x / sqrt(x^2+y^2): (OVERALL ERROR: 3.4780178737037204e-10) - - Math.log(a / Math.cos(Math.atan2(b, a))) + * @param {*} [value] + */ + function Chain (value) { + if (!(this instanceof Chain)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - * 4. Use 3. and apply log rules: (OVERALL ERROR: 1.2014087502620896e-9) + if (type.isChain(value)) { + this.value = value.value; + } + else { + this.value = value; + } + } - Math.log(a) - Math.log(Math.cos(Math.atan2(b, a))) + /** + * Attach type information + */ + Chain.prototype.type = 'Chain'; + Chain.prototype.isChain = true; + /** + * Close the chain. Returns the final value. + * Does the same as method valueOf() + * @returns {*} value */ + Chain.prototype.done = function () { + return this.value; + }; - return Math.log(a / Math.cos(Math.atan2(b, a))); - } + /** + * Close the chain. Returns the final value. + * Does the same as method done() + * @returns {*} value + */ + Chain.prototype.valueOf = function () { + return this.value; + }; - var parse = function(a, b) { + /** + * Get a string representation of the value in the chain + * @returns {string} + */ + Chain.prototype.toString = function () { + return format(this.value); + }; - var z = {'re': 0, 'im': 0}; + /** + * Get a JSON representation of the chain + * @returns {Object} + */ + Chain.prototype.toJSON = function () { + return { + mathjs: 'Chain', + value: this.value + }; + }; - if (a === undefined || a === null) { - z['re'] = - z['im'] = 0; - } else if (b !== undefined) { - z['re'] = a; - z['im'] = b; - } else - switch (typeof a) { + /** + * Instantiate a Chain from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "Chain", value: ...}`, + * where mathjs is optional + * @returns {Chain} + */ + Chain.fromJSON = function (json) { + return new Chain(json.value); + }; - case 'object': + /** + * Create a proxy method for the chain + * @param {string} name + * @param {Function} fn The function to be proxied + * If fn is no function, it is silently ignored. + * @private + */ + function createProxy(name, fn) { + if (typeof fn === 'function') { + Chain.prototype[name] = chainify(fn); + } + } - if ('im' in a && 're' in a) { - z['re'] = a['re']; - z['im'] = a['im']; - } else if ('abs' in a && 'arg' in a) { - if (!Number.isFinite(a['abs']) && Number.isFinite(a['arg'])) { - return Complex['INFINITY']; - } - z['re'] = a['abs'] * Math.cos(a['arg']); - z['im'] = a['abs'] * Math.sin(a['arg']); - } else if ('r' in a && 'phi' in a) { - if (!Number.isFinite(a['r']) && Number.isFinite(a['phi'])) { - return Complex['INFINITY']; - } - z['re'] = a['r'] * Math.cos(a['phi']); - z['im'] = a['r'] * Math.sin(a['phi']); - } else if (a.length === 2) { // Quick array check - z['re'] = a[0]; - z['im'] = a[1]; - } else { - parser_exit(); - } - break; + /** + * Create a proxy method for the chain + * @param {string} name + * @param {function} resolver The function resolving with the + * function to be proxied + * @private + */ + function createLazyProxy(name, resolver) { + lazy$1(Chain.prototype, name, function outerResolver() { + var fn = resolver(); + if (typeof fn === 'function') { + return chainify(fn); + } - case 'string': + return undefined; // if not a function, ignore + }); + } - z['im'] = /* void */ - z['re'] = 0; + /** + * Make a function chainable + * @param {function} fn + * @return {Function} chain function + * @private + */ + function chainify (fn) { + return function () { + var args = [this.value]; // `this` will be the context of a Chain instance + for (var i = 0; i < arguments.length; i++) { + args[i + 1] = arguments[i]; + } - var tokens = a.match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g); - var plus = 1; - var minus = 0; + return new Chain(fn.apply(fn, args)); + } + } - if (tokens === null) { - parser_exit(); + /** + * Create a proxy for a single method, or an object with multiple methods. + * Example usage: + * + * Chain.createProxy('add', function add (x, y) {...}); + * Chain.createProxy({ + * add: function add (x, y) {...}, + * subtract: function subtract (x, y) {...} + * } + * + * @param {string | Object} arg0 A name (string), or an object with + * functions + * @param {*} [arg1] A function, when arg0 is a name + */ + Chain.createProxy = function (arg0, arg1) { + if (typeof arg0 === 'string') { + // createProxy(name, value) + createProxy(arg0, arg1); + } + else { + // createProxy(values) + for (var prop in arg0) { + if (arg0.hasOwnProperty(prop)) { + createProxy(prop, arg0[prop]); } + } + } + }; - for (var i = 0; i < tokens.length; i++) { + // create proxy for everything that is in math.js + Chain.createProxy(math); - var c = tokens[i]; + // register on the import event, automatically add a proxy for every imported function. + math.on('import', function (name, resolver, path) { + if (path === undefined) { + // an imported function (not a data type or something special) + createLazyProxy(name, resolver); + } + }); - if (c === ' ' || c === '\t' || c === '\n') { - /* void */ - } else if (c === '+') { - plus++; - } else if (c === '-') { - minus++; - } else if (c === 'i' || c === 'I') { + return Chain; + } - if (plus + minus === 0) { - parser_exit(); - } + var name$5 = 'Chain'; + var path$1 = 'type'; + var factory_1$5 = factory$5; + var math$3 = true; // require providing the math namespace as 5th argument + var lazy_1$1 = false; // we need to register a listener on the import events, so no lazy loading - if (tokens[i + 1] !== ' ' && !isNaN(tokens[i + 1])) { - z['im'] += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); - i++; - } else { - z['im'] += parseFloat((minus % 2 ? '-' : '') + '1'); - } - plus = minus = 0; + var Chain = { + name: name$5, + path: path$1, + factory: factory_1$5, + math: math$3, + lazy: lazy_1$1 + }; - } else { + function factory$6 (type, config, load, typed) { + /** + * Wrap any value in a chain, allowing to perform chained operations on + * the value. + * + * All methods available in the math.js library can be called upon the chain, + * and then will be evaluated with the value itself as first argument. + * The chain can be closed by executing `chain.done()`, which returns + * the final value. + * + * The chain has a number of special functions: + * + * - `done()` Finalize the chain and return the chain's value. + * - `valueOf()` The same as `done()` + * - `toString()` Executes `math.format()` onto the chain's value, returning + * a string representation of the value. + * + * Syntax: + * + * math.chain(value) + * + * Examples: + * + * math.chain(3) + * .add(4) + * .subtract(2) + * .done(); // 5 + * + * math.chain( [[1, 2], [3, 4]] ) + * .subset(math.index(0, 0), 8) + * .multiply(3) + * .done(); // [[24, 6], [9, 12]] + * + * @param {*} [value] A value of any type on which to start a chained operation. + * @return {math.type.Chain} The created chain + */ + return typed('chain', { + '': function() { + return new type.Chain(); + }, - if (plus + minus === 0 || isNaN(c)) { - parser_exit(); - } + 'any': function(value) { + return new type.Chain(value); + } + }); + } - if (tokens[i + 1] === 'i' || tokens[i + 1] === 'I') { - z['im'] += parseFloat((minus % 2 ? '-' : '') + c); - i++; - } else { - z['re'] += parseFloat((minus % 2 ? '-' : '') + c); - } - plus = minus = 0; - } - } + var name$6 = 'chain'; + var factory_1$6 = factory$6; - // Still something on the stack - if (plus + minus > 0) { - parser_exit(); - } - break; + var chain = { + name: name$6, + factory: factory_1$6 + }; - case 'number': - z['im'] = 0; - z['re'] = a; - break; + var chain$1 = [ + // type + Chain, - default: - parser_exit(); - } + // construction function + chain + ]; - return z; - }; + var complex = createCommonjsModule(function (module, exports) { + /** + * @license Complex.js v2.0.10 11/02/2016 + * + * Copyright (c) 2016, Robert Eisele (robert@xarg.org) + * Dual licensed under the MIT or GPL Version 2 licenses. + **/ /** - * @constructor - * @returns {Complex} + * + * This class allows the manipulation of complex numbers. + * You can pass a complex number in different formats. Either as object, double, string or two integer parameters. + * + * Object form + * { re: , im: } + * { arg: , abs: } + * { phi: , r: } + * + * Array / Vector form + * [ real, imaginary ] + * + * Double form + * 99.3 - Single double value + * + * String form + * '23.1337' - Simple real number + * '15+3i' - a simple complex number + * '3-i' - a simple complex number + * + * Example: + * + * var c = new Complex('99.3+8i'); + * c.mul({r: 3, i: 9}).div(4.9).sub(3, 2); + * */ - function Complex(a, b) { - - if (!(this instanceof Complex)) { - return new Complex(a, b); - } - - var z = parse(a, b); - this['re'] = z['re']; - this['im'] = z['im']; - } + (function(root) { - Complex.prototype = { + var cosh = function(x) { + return (Math.exp(x) + Math.exp(-x)) * 0.5; + }; - 're': 0, - 'im': 0, + var sinh = function(x) { + return (Math.exp(x) - Math.exp(-x)) * 0.5; + }; /** - * Calculates the sign of a complex number, which is a normalized complex + * Calculates cos(x) - 1 using Taylor series if x is small. * - * @returns {Complex} + * @param {number} x + * @returns {number} cos(x) - 1 */ - 'sign': function() { - var abs = this['abs'](); - - return new Complex( - this['re'] / abs, - this['im'] / abs); - }, + var cosm1 = function(x) { + var limit = Math.PI/4; + if (x < -limit || x > limit) { + return (Math.cos(x) - 1.0); + } + + var xx = x * x; + return xx * + (-0.5 + xx * + (1/24 + xx * + (-1/720 + xx * + (1/40320 + xx * + (-1/3628800 + xx * + (1/4790014600 + xx * + (-1/87178291200 + xx * + (1/20922789888000) + ) + ) + ) + ) + ) + ) + ) + }; - /** - * Adds two complex numbers - * - * @returns {Complex} - */ - 'add': function(a, b) { + var hypot = function(x, y) { - var z = new Complex(a, b); + var a = Math.abs(x); + var b = Math.abs(y); - // Infinity + Infinity = NaN - if (this.isInfinite() && z.isInfinite()) { - return Complex['NAN']; + if (a < 3000 && b < 3000) { + return Math.sqrt(a * a + b * b); } - // Infinity + z = Infinity { where z != Infinity } - if (this.isInfinite() || z.isInfinite()) { - return Complex['INFINITY']; + if (a < b) { + a = b; + b = x / y; + } else { + b = y / x; } + return a * Math.sqrt(1 + b * b); + }; - return new Complex( - this['re'] + z['re'], - this['im'] + z['im']); - }, + var parser_exit = function() { + throw SyntaxError('Invalid Param'); + }; /** - * Subtracts two complex numbers + * Calculates log(sqrt(a^2+b^2)) in a way to avoid overflows * - * @returns {Complex} + * @param {number} a + * @param {number} b + * @returns {number} */ - 'sub': function(a, b) { + function logHypot(a, b) { - var z = new Complex(a, b); + var _a = Math.abs(a); + var _b = Math.abs(b); - // Infinity - Infinity = NaN - if (this.isInfinite() && z.isInfinite()) { - return Complex['NAN']; - } - - // Infinity - z = Infinity { where z != Infinity } - if (this.isInfinite() || z.isInfinite()) { - return Complex['INFINITY']; + if (a === 0) { + return Math.log(_b); } - return new Complex( - this['re'] - z['re'], - this['im'] - z['im']); - }, - - /** - * Multiplies two complex numbers - * - * @returns {Complex} - */ - 'mul': function(a, b) { - - var z = new Complex(a, b); - - // Infinity * 0 = NaN - if ((this.isInfinite() && z.isZero()) || (this.isZero() && z.isInfinite())) { - return Complex['NAN']; + if (b === 0) { + return Math.log(_a); } - // Infinity * z = Infinity { where z != 0 } - if (this.isInfinite() || z.isInfinite()) { - return Complex['INFINITY']; + if (_a < 3000 && _b < 3000) { + return Math.log(a * a + b * b) * 0.5; } - // Short circuit for real values - if (z['im'] === 0 && this['im'] === 0) { - return new Complex(this['re'] * z['re'], 0); - } + /* I got 4 ideas to compute this property without overflow: + * + * Testing 1000000 times with random samples for a,b ∈ [1, 1000000000] against a big decimal library to get an error estimate + * + * 1. Only eliminate the square root: (OVERALL ERROR: 3.9122483030951116e-11) - return new Complex( - this['re'] * z['re'] - this['im'] * z['im'], - this['re'] * z['im'] + this['im'] * z['re']); - }, + Math.log(a * a + b * b) / 2 - /** - * Divides two complex numbers - * - * @returns {Complex} - */ - 'div': function(a, b) { + * + * + * 2. Try to use the non-overflowing pythagoras: (OVERALL ERROR: 8.889760039210159e-10) - var z = new Complex(a, b); + var fn = function(a, b) { + a = Math.abs(a); + b = Math.abs(b); + var t = Math.min(a, b); + a = Math.max(a, b); + t = t / a; - // 0 / 0 = NaN and Infinity / Infinity = NaN - if ((this.isZero() && z.isZero()) || (this.isInfinite() && z.isInfinite())) { - return Complex['NAN']; - } + return Math.log(a) + Math.log(1 + t * t) / 2; + }; - // Infinity / 0 = Infinity - if (this.isInfinite() || z.isZero()) { - return Complex['INFINITY']; - } + * 3. Abuse the identity cos(atan(y/x) = x / sqrt(x^2+y^2): (OVERALL ERROR: 3.4780178737037204e-10) - // 0 / Infinity = 0 - if (this.isZero() || z.isInfinite()) { - return Complex['ZERO']; - } + Math.log(a / Math.cos(Math.atan2(b, a))) - a = this['re']; - b = this['im']; + * 4. Use 3. and apply log rules: (OVERALL ERROR: 1.2014087502620896e-9) - var c = z['re']; - var d = z['im']; - var t, x; + Math.log(a) - Math.log(Math.cos(Math.atan2(b, a))) - if (0 === d) { - // Divisor is real - return new Complex(a / c, b / c); - } + */ - if (Math.abs(c) < Math.abs(d)) { + return Math.log(a / Math.cos(Math.atan2(b, a))); + } - x = c / d; - t = c * x + d; + var parse = function(a, b) { - return new Complex( - (a * x + b) / t, - (b * x - a) / t); + var z = {'re': 0, 'im': 0}; - } else { + if (a === undefined || a === null) { + z['re'] = + z['im'] = 0; + } else if (b !== undefined) { + z['re'] = a; + z['im'] = b; + } else + switch (typeof a) { - x = d / c; - t = d * x + c; + case 'object': - return new Complex( - (a + b * x) / t, - (b - a * x) / t); - } - }, - - /** - * Calculate the power of two complex numbers - * - * @returns {Complex} - */ - 'pow': function(a, b) { - - var z = new Complex(a, b); - - a = this['re']; - b = this['im']; + if ('im' in a && 're' in a) { + z['re'] = a['re']; + z['im'] = a['im']; + } else if ('abs' in a && 'arg' in a) { + if (!Number.isFinite(a['abs']) && Number.isFinite(a['arg'])) { + return Complex['INFINITY']; + } + z['re'] = a['abs'] * Math.cos(a['arg']); + z['im'] = a['abs'] * Math.sin(a['arg']); + } else if ('r' in a && 'phi' in a) { + if (!Number.isFinite(a['r']) && Number.isFinite(a['phi'])) { + return Complex['INFINITY']; + } + z['re'] = a['r'] * Math.cos(a['phi']); + z['im'] = a['r'] * Math.sin(a['phi']); + } else if (a.length === 2) { // Quick array check + z['re'] = a[0]; + z['im'] = a[1]; + } else { + parser_exit(); + } + break; - if (z.isZero()) { - return Complex['ONE']; - } + case 'string': - // If the exponent is real - if (z['im'] === 0) { + z['im'] = /* void */ + z['re'] = 0; - if (b === 0 && a >= 0) { + var tokens = a.match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g); + var plus = 1; + var minus = 0; - return new Complex(Math.pow(a, z['re']), 0); + if (tokens === null) { + parser_exit(); + } - } else if (a === 0) { // If base is fully imaginary + for (var i = 0; i < tokens.length; i++) { - switch ((z['re'] % 4 + 4) % 4) { - case 0: - return new Complex(Math.pow(b, z['re']), 0); - case 1: - return new Complex(0, Math.pow(b, z['re'])); - case 2: - return new Complex(-Math.pow(b, z['re']), 0); - case 3: - return new Complex(0, -Math.pow(b, z['re'])); - } - } - } + var c = tokens[i]; - /* I couldn't find a good formula, so here is a derivation and optimization - * - * z_1^z_2 = (a + bi)^(c + di) - * = exp((c + di) * log(a + bi) - * = pow(a^2 + b^2, (c + di) / 2) * exp(i(c + di)atan2(b, a)) - * =>... - * Re = (pow(a^2 + b^2, c / 2) * exp(-d * atan2(b, a))) * cos(d * log(a^2 + b^2) / 2 + c * atan2(b, a)) - * Im = (pow(a^2 + b^2, c / 2) * exp(-d * atan2(b, a))) * sin(d * log(a^2 + b^2) / 2 + c * atan2(b, a)) - * - * =>... - * Re = exp(c * log(sqrt(a^2 + b^2)) - d * atan2(b, a)) * cos(d * log(sqrt(a^2 + b^2)) + c * atan2(b, a)) - * Im = exp(c * log(sqrt(a^2 + b^2)) - d * atan2(b, a)) * sin(d * log(sqrt(a^2 + b^2)) + c * atan2(b, a)) - * - * => - * Re = exp(c * logsq2 - d * arg(z_1)) * cos(d * logsq2 + c * arg(z_1)) - * Im = exp(c * logsq2 - d * arg(z_1)) * sin(d * logsq2 + c * arg(z_1)) - * - */ + if (c === ' ' || c === '\t' || c === '\n') { + /* void */ + } else if (c === '+') { + plus++; + } else if (c === '-') { + minus++; + } else if (c === 'i' || c === 'I') { - if (a === 0 && b === 0 && z['re'] > 0 && z['im'] >= 0) { - return Complex['ZERO']; - } + if (plus + minus === 0) { + parser_exit(); + } - var arg = Math.atan2(b, a); - var loh = logHypot(a, b); + if (tokens[i + 1] !== ' ' && !isNaN(tokens[i + 1])) { + z['im'] += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); + i++; + } else { + z['im'] += parseFloat((minus % 2 ? '-' : '') + '1'); + } + plus = minus = 0; - a = Math.exp(z['re'] * loh - z['im'] * arg); - b = z['im'] * loh + z['re'] * arg; - return new Complex( - a * Math.cos(b), - a * Math.sin(b)); - }, + } else { - /** - * Calculate the complex square root - * - * @returns {Complex} - */ - 'sqrt': function() { + if (plus + minus === 0 || isNaN(c)) { + parser_exit(); + } - var a = this['re']; - var b = this['im']; - var r = this['abs'](); + if (tokens[i + 1] === 'i' || tokens[i + 1] === 'I') { + z['im'] += parseFloat((minus % 2 ? '-' : '') + c); + i++; + } else { + z['re'] += parseFloat((minus % 2 ? '-' : '') + c); + } + plus = minus = 0; + } + } - var re, im; + // Still something on the stack + if (plus + minus > 0) { + parser_exit(); + } + break; - if (a >= 0) { + case 'number': + z['im'] = 0; + z['re'] = a; + break; - if (b === 0) { - return new Complex(Math.sqrt(a), 0); + default: + parser_exit(); } - re = 0.5 * Math.sqrt(2.0 * (r + a)); - } else { - re = Math.abs(b) / Math.sqrt(2 * (r - a)); - } - - if (a <= 0) { - im = 0.5 * Math.sqrt(2.0 * (r - a)); - } else { - im = Math.abs(b) / Math.sqrt(2 * (r + a)); - } - - return new Complex(re, b < 0 ? -im : im); - }, + return z; + }; /** - * Calculate the complex exponent - * + * @constructor * @returns {Complex} */ - 'exp': function() { + function Complex(a, b) { - var tmp = Math.exp(this['re']); - - if (this['im'] === 0) { - //return new Complex(tmp, 0); + if (!(this instanceof Complex)) { + return new Complex(a, b); } - return new Complex( - tmp * Math.cos(this['im']), - tmp * Math.sin(this['im'])); - }, - /** - * Calculate the complex exponent and subtracts one. - * - * This may be more accurate than `Complex(x).exp().sub(1)` if - * `x` is small. - * - * @returns {Complex} - */ - 'expm1': function() { + var z = parse(a, b); + + this['re'] = z['re']; + this['im'] = z['im']; + } + + Complex.prototype = { + + 're': 0, + 'im': 0, /** - * exp(a + i*b) - 1 - = exp(a) * (cos(b) + j*sin(b)) - 1 - = expm1(a)*cos(b) + cosm1(b) + j*exp(a)*sin(b) + * Calculates the sign of a complex number, which is a normalized complex + * + * @returns {Complex} */ + 'sign': function() { - var a = this['re']; - var b = this['im']; + var abs = this['abs'](); - return new Complex( - Math.expm1(a) * Math.cos(b) + cosm1(b), - Math.exp(a) * Math.sin(b)); - }, + return new Complex( + this['re'] / abs, + this['im'] / abs); + }, - /** - * Calculate the natural log - * - * @returns {Complex} - */ - 'log': function() { + /** + * Adds two complex numbers + * + * @returns {Complex} + */ + 'add': function(a, b) { - var a = this['re']; - var b = this['im']; + var z = new Complex(a, b); - return new Complex( - logHypot(a, b), - Math.atan2(b, a)); - }, + // Infinity + Infinity = NaN + if (this.isInfinite() && z.isInfinite()) { + return Complex['NAN']; + } - /** - * Calculate the magnitude of the complex number - * - * @returns {number} - */ - 'abs': function() { + // Infinity + z = Infinity { where z != Infinity } + if (this.isInfinite() || z.isInfinite()) { + return Complex['INFINITY']; + } - return hypot(this['re'], this['im']); - }, + return new Complex( + this['re'] + z['re'], + this['im'] + z['im']); + }, - /** - * Calculate the angle of the complex number - * - * @returns {number} - */ - 'arg': function() { + /** + * Subtracts two complex numbers + * + * @returns {Complex} + */ + 'sub': function(a, b) { - return Math.atan2(this['im'], this['re']); - }, + var z = new Complex(a, b); - /** - * Calculate the sine of the complex number - * - * @returns {Complex} - */ - 'sin': function() { + // Infinity - Infinity = NaN + if (this.isInfinite() && z.isInfinite()) { + return Complex['NAN']; + } - // sin(c) = (e^b - e^(-b)) / (2i) + // Infinity - z = Infinity { where z != Infinity } + if (this.isInfinite() || z.isInfinite()) { + return Complex['INFINITY']; + } - var a = this['re']; - var b = this['im']; + return new Complex( + this['re'] - z['re'], + this['im'] - z['im']); + }, - return new Complex( - Math.sin(a) * cosh(b), - Math.cos(a) * sinh(b)); - }, + /** + * Multiplies two complex numbers + * + * @returns {Complex} + */ + 'mul': function(a, b) { - /** - * Calculate the cosine - * - * @returns {Complex} - */ - 'cos': function() { + var z = new Complex(a, b); - // cos(z) = (e^b + e^(-b)) / 2 + // Infinity * 0 = NaN + if ((this.isInfinite() && z.isZero()) || (this.isZero() && z.isInfinite())) { + return Complex['NAN']; + } - var a = this['re']; - var b = this['im']; + // Infinity * z = Infinity { where z != 0 } + if (this.isInfinite() || z.isInfinite()) { + return Complex['INFINITY']; + } - return new Complex( - Math.cos(a) * cosh(b), - -Math.sin(a) * sinh(b)); - }, + // Short circuit for real values + if (z['im'] === 0 && this['im'] === 0) { + return new Complex(this['re'] * z['re'], 0); + } - /** - * Calculate the tangent - * - * @returns {Complex} - */ - 'tan': function() { + return new Complex( + this['re'] * z['re'] - this['im'] * z['im'], + this['re'] * z['im'] + this['im'] * z['re']); + }, - // tan(c) = (e^(ci) - e^(-ci)) / (i(e^(ci) + e^(-ci))) + /** + * Divides two complex numbers + * + * @returns {Complex} + */ + 'div': function(a, b) { - var a = 2 * this['re']; - var b = 2 * this['im']; - var d = Math.cos(a) + cosh(b); + var z = new Complex(a, b); - return new Complex( - Math.sin(a) / d, - sinh(b) / d); - }, + // 0 / 0 = NaN and Infinity / Infinity = NaN + if ((this.isZero() && z.isZero()) || (this.isInfinite() && z.isInfinite())) { + return Complex['NAN']; + } - /** - * Calculate the cotangent - * - * @returns {Complex} - */ - 'cot': function() { + // Infinity / 0 = Infinity + if (this.isInfinite() || z.isZero()) { + return Complex['INFINITY']; + } - // cot(c) = i(e^(ci) + e^(-ci)) / (e^(ci) - e^(-ci)) + // 0 / Infinity = 0 + if (this.isZero() || z.isInfinite()) { + return Complex['ZERO']; + } - var a = 2 * this['re']; - var b = 2 * this['im']; - var d = Math.cos(a) - cosh(b); + a = this['re']; + b = this['im']; - return new Complex( - -Math.sin(a) / d, - sinh(b) / d); - }, + var c = z['re']; + var d = z['im']; + var t, x; - /** - * Calculate the secant - * - * @returns {Complex} - */ - 'sec': function() { + if (0 === d) { + // Divisor is real + return new Complex(a / c, b / c); + } - // sec(c) = 2 / (e^(ci) + e^(-ci)) + if (Math.abs(c) < Math.abs(d)) { - var a = this['re']; - var b = this['im']; - var d = 0.5 * cosh(2 * b) + 0.5 * Math.cos(2 * a); + x = c / d; + t = c * x + d; - return new Complex( - Math.cos(a) * cosh(b) / d, - Math.sin(a) * sinh(b) / d); - }, + return new Complex( + (a * x + b) / t, + (b * x - a) / t); - /** - * Calculate the cosecans - * - * @returns {Complex} - */ - 'csc': function() { + } else { - // csc(c) = 2i / (e^(ci) - e^(-ci)) + x = d / c; + t = d * x + c; - var a = this['re']; - var b = this['im']; - var d = 0.5 * cosh(2 * b) - 0.5 * Math.cos(2 * a); + return new Complex( + (a + b * x) / t, + (b - a * x) / t); + } + }, - return new Complex( - Math.sin(a) * cosh(b) / d, - -Math.cos(a) * sinh(b) / d); - }, + /** + * Calculate the power of two complex numbers + * + * @returns {Complex} + */ + 'pow': function(a, b) { - /** - * Calculate the complex arcus sinus - * - * @returns {Complex} - */ - 'asin': function() { + var z = new Complex(a, b); - // asin(c) = -i * log(ci + sqrt(1 - c^2)) + a = this['re']; + b = this['im']; - var a = this['re']; - var b = this['im']; + if (z.isZero()) { + return Complex['ONE']; + } - var t1 = new Complex( - b * b - a * a + 1, - -2 * a * b)['sqrt'](); + // If the exponent is real + if (z['im'] === 0) { - var t2 = new Complex( - t1['re'] - b, - t1['im'] + a)['log'](); + if (b === 0 && a >= 0) { - return new Complex(t2['im'], -t2['re']); - }, + return new Complex(Math.pow(a, z['re']), 0); - /** - * Calculate the complex arcus cosinus - * - * @returns {Complex} - */ - 'acos': function() { + } else if (a === 0) { // If base is fully imaginary - // acos(c) = i * log(c - i * sqrt(1 - c^2)) + switch ((z['re'] % 4 + 4) % 4) { + case 0: + return new Complex(Math.pow(b, z['re']), 0); + case 1: + return new Complex(0, Math.pow(b, z['re'])); + case 2: + return new Complex(-Math.pow(b, z['re']), 0); + case 3: + return new Complex(0, -Math.pow(b, z['re'])); + } + } + } - var a = this['re']; - var b = this['im']; + /* I couldn't find a good formula, so here is a derivation and optimization + * + * z_1^z_2 = (a + bi)^(c + di) + * = exp((c + di) * log(a + bi) + * = pow(a^2 + b^2, (c + di) / 2) * exp(i(c + di)atan2(b, a)) + * =>... + * Re = (pow(a^2 + b^2, c / 2) * exp(-d * atan2(b, a))) * cos(d * log(a^2 + b^2) / 2 + c * atan2(b, a)) + * Im = (pow(a^2 + b^2, c / 2) * exp(-d * atan2(b, a))) * sin(d * log(a^2 + b^2) / 2 + c * atan2(b, a)) + * + * =>... + * Re = exp(c * log(sqrt(a^2 + b^2)) - d * atan2(b, a)) * cos(d * log(sqrt(a^2 + b^2)) + c * atan2(b, a)) + * Im = exp(c * log(sqrt(a^2 + b^2)) - d * atan2(b, a)) * sin(d * log(sqrt(a^2 + b^2)) + c * atan2(b, a)) + * + * => + * Re = exp(c * logsq2 - d * arg(z_1)) * cos(d * logsq2 + c * arg(z_1)) + * Im = exp(c * logsq2 - d * arg(z_1)) * sin(d * logsq2 + c * arg(z_1)) + * + */ - var t1 = new Complex( - b * b - a * a + 1, - -2 * a * b)['sqrt'](); + if (a === 0 && b === 0 && z['re'] > 0 && z['im'] >= 0) { + return Complex['ZERO']; + } - var t2 = new Complex( - t1['re'] - b, - t1['im'] + a)['log'](); + var arg = Math.atan2(b, a); + var loh = logHypot(a, b); - return new Complex(Math.PI / 2 - t2['im'], t2['re']); - }, + a = Math.exp(z['re'] * loh - z['im'] * arg); + b = z['im'] * loh + z['re'] * arg; + return new Complex( + a * Math.cos(b), + a * Math.sin(b)); + }, - /** - * Calculate the complex arcus tangent - * - * @returns {Complex} - */ - 'atan': function() { + /** + * Calculate the complex square root + * + * @returns {Complex} + */ + 'sqrt': function() { - // atan(c) = i / 2 log((i + x) / (i - x)) + var a = this['re']; + var b = this['im']; + var r = this['abs'](); - var a = this['re']; - var b = this['im']; + var re, im; - if (a === 0) { + if (a >= 0) { - if (b === 1) { - return new Complex(0, Infinity); + if (b === 0) { + return new Complex(Math.sqrt(a), 0); + } + + re = 0.5 * Math.sqrt(2.0 * (r + a)); + } else { + re = Math.abs(b) / Math.sqrt(2 * (r - a)); } - if (b === -1) { - return new Complex(0, -Infinity); + if (a <= 0) { + im = 0.5 * Math.sqrt(2.0 * (r - a)); + } else { + im = Math.abs(b) / Math.sqrt(2 * (r + a)); } - } - var d = a * a + (1.0 - b) * (1.0 - b); + return new Complex(re, b < 0 ? -im : im); + }, - var t1 = new Complex( - (1 - b * b - a * a) / d, - -2 * a / d).log(); + /** + * Calculate the complex exponent + * + * @returns {Complex} + */ + 'exp': function() { - return new Complex(-0.5 * t1['im'], 0.5 * t1['re']); - }, + var tmp = Math.exp(this['re']); - /** - * Calculate the complex arcus cotangent - * - * @returns {Complex} - */ - 'acot': function() { + if (this['im'] === 0) { + //return new Complex(tmp, 0); + } + return new Complex( + tmp * Math.cos(this['im']), + tmp * Math.sin(this['im'])); + }, - // acot(c) = i / 2 log((c - i) / (c + i)) + /** + * Calculate the complex exponent and subtracts one. + * + * This may be more accurate than `Complex(x).exp().sub(1)` if + * `x` is small. + * + * @returns {Complex} + */ + 'expm1': function() { - var a = this['re']; - var b = this['im']; + /** + * exp(a + i*b) - 1 + = exp(a) * (cos(b) + j*sin(b)) - 1 + = expm1(a)*cos(b) + cosm1(b) + j*exp(a)*sin(b) + */ - if (b === 0) { - return new Complex(Math.atan2(1, a), 0); - } + var a = this['re']; + var b = this['im']; - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).atan() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).atan(); - }, + return new Complex( + Math.expm1(a) * Math.cos(b) + cosm1(b), + Math.exp(a) * Math.sin(b)); + }, - /** - * Calculate the complex arcus secant - * - * @returns {Complex} - */ - 'asec': function() { + /** + * Calculate the natural log + * + * @returns {Complex} + */ + 'log': function() { - // asec(c) = -i * log(1 / c + sqrt(1 - i / c^2)) + var a = this['re']; + var b = this['im']; - var a = this['re']; - var b = this['im']; + return new Complex( + logHypot(a, b), + Math.atan2(b, a)); + }, - if (a === 0 && b === 0) { - return new Complex(0, Infinity); - } + /** + * Calculate the magnitude of the complex number + * + * @returns {number} + */ + 'abs': function() { - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).acos() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).acos(); - }, + return hypot(this['re'], this['im']); + }, - /** - * Calculate the complex arcus cosecans - * - * @returns {Complex} - */ - 'acsc': function() { + /** + * Calculate the angle of the complex number + * + * @returns {number} + */ + 'arg': function() { - // acsc(c) = -i * log(i / c + sqrt(1 - 1 / c^2)) + return Math.atan2(this['im'], this['re']); + }, - var a = this['re']; - var b = this['im']; + /** + * Calculate the sine of the complex number + * + * @returns {Complex} + */ + 'sin': function() { - if (a === 0 && b === 0) { - return new Complex(Math.PI / 2, Infinity); - } + // sin(c) = (e^b - e^(-b)) / (2i) - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).asin() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).asin(); - }, + var a = this['re']; + var b = this['im']; - /** - * Calculate the complex sinh - * - * @returns {Complex} - */ - 'sinh': function() { + return new Complex( + Math.sin(a) * cosh(b), + Math.cos(a) * sinh(b)); + }, - // sinh(c) = (e^c - e^-c) / 2 + /** + * Calculate the cosine + * + * @returns {Complex} + */ + 'cos': function() { - var a = this['re']; - var b = this['im']; + // cos(z) = (e^b + e^(-b)) / 2 - return new Complex( - sinh(a) * Math.cos(b), - cosh(a) * Math.sin(b)); - }, + var a = this['re']; + var b = this['im']; - /** - * Calculate the complex cosh - * - * @returns {Complex} - */ - 'cosh': function() { + return new Complex( + Math.cos(a) * cosh(b), + -Math.sin(a) * sinh(b)); + }, - // cosh(c) = (e^c + e^-c) / 2 + /** + * Calculate the tangent + * + * @returns {Complex} + */ + 'tan': function() { - var a = this['re']; - var b = this['im']; + // tan(c) = (e^(ci) - e^(-ci)) / (i(e^(ci) + e^(-ci))) - return new Complex( - cosh(a) * Math.cos(b), - sinh(a) * Math.sin(b)); - }, + var a = 2 * this['re']; + var b = 2 * this['im']; + var d = Math.cos(a) + cosh(b); - /** - * Calculate the complex tanh - * - * @returns {Complex} - */ - 'tanh': function() { + return new Complex( + Math.sin(a) / d, + sinh(b) / d); + }, - // tanh(c) = (e^c - e^-c) / (e^c + e^-c) + /** + * Calculate the cotangent + * + * @returns {Complex} + */ + 'cot': function() { - var a = 2 * this['re']; - var b = 2 * this['im']; - var d = cosh(a) + Math.cos(b); + // cot(c) = i(e^(ci) + e^(-ci)) / (e^(ci) - e^(-ci)) - return new Complex( - sinh(a) / d, - Math.sin(b) / d); - }, + var a = 2 * this['re']; + var b = 2 * this['im']; + var d = Math.cos(a) - cosh(b); - /** - * Calculate the complex coth - * - * @returns {Complex} - */ - 'coth': function() { + return new Complex( + -Math.sin(a) / d, + sinh(b) / d); + }, - // coth(c) = (e^c + e^-c) / (e^c - e^-c) + /** + * Calculate the secant + * + * @returns {Complex} + */ + 'sec': function() { - var a = 2 * this['re']; - var b = 2 * this['im']; - var d = cosh(a) - Math.cos(b); + // sec(c) = 2 / (e^(ci) + e^(-ci)) - return new Complex( - sinh(a) / d, - -Math.sin(b) / d); - }, + var a = this['re']; + var b = this['im']; + var d = 0.5 * cosh(2 * b) + 0.5 * Math.cos(2 * a); - /** - * Calculate the complex coth - * - * @returns {Complex} - */ - 'csch': function() { + return new Complex( + Math.cos(a) * cosh(b) / d, + Math.sin(a) * sinh(b) / d); + }, - // csch(c) = 2 / (e^c - e^-c) + /** + * Calculate the cosecans + * + * @returns {Complex} + */ + 'csc': function() { - var a = this['re']; - var b = this['im']; - var d = Math.cos(2 * b) - cosh(2 * a); + // csc(c) = 2i / (e^(ci) - e^(-ci)) - return new Complex( - -2 * sinh(a) * Math.cos(b) / d, - 2 * cosh(a) * Math.sin(b) / d); - }, + var a = this['re']; + var b = this['im']; + var d = 0.5 * cosh(2 * b) - 0.5 * Math.cos(2 * a); - /** - * Calculate the complex sech - * - * @returns {Complex} - */ - 'sech': function() { + return new Complex( + Math.sin(a) * cosh(b) / d, + -Math.cos(a) * sinh(b) / d); + }, - // sech(c) = 2 / (e^c + e^-c) + /** + * Calculate the complex arcus sinus + * + * @returns {Complex} + */ + 'asin': function() { - var a = this['re']; - var b = this['im']; - var d = Math.cos(2 * b) + cosh(2 * a); + // asin(c) = -i * log(ci + sqrt(1 - c^2)) - return new Complex( - 2 * cosh(a) * Math.cos(b) / d, - -2 * sinh(a) * Math.sin(b) / d); - }, + var a = this['re']; + var b = this['im']; - /** - * Calculate the complex asinh - * - * @returns {Complex} - */ - 'asinh': function() { + var t1 = new Complex( + b * b - a * a + 1, + -2 * a * b)['sqrt'](); - // asinh(c) = log(c + sqrt(c^2 + 1)) + var t2 = new Complex( + t1['re'] - b, + t1['im'] + a)['log'](); - var tmp = this['im']; - this['im'] = -this['re']; - this['re'] = tmp; - var res = this['asin'](); + return new Complex(t2['im'], -t2['re']); + }, - this['re'] = -this['im']; - this['im'] = tmp; - tmp = res['re']; + /** + * Calculate the complex arcus cosinus + * + * @returns {Complex} + */ + 'acos': function() { - res['re'] = -res['im']; - res['im'] = tmp; - return res; - }, + // acos(c) = i * log(c - i * sqrt(1 - c^2)) - /** - * Calculate the complex asinh - * - * @returns {Complex} - */ - 'acosh': function() { + var a = this['re']; + var b = this['im']; - // acosh(c) = log(c + sqrt(c^2 - 1)) + var t1 = new Complex( + b * b - a * a + 1, + -2 * a * b)['sqrt'](); - var res = this['acos'](); - if (res['im'] <= 0) { - var tmp = res['re']; - res['re'] = -res['im']; - res['im'] = tmp; - } else { - var tmp = res['im']; - res['im'] = -res['re']; - res['re'] = tmp; - } - return res; - }, + var t2 = new Complex( + t1['re'] - b, + t1['im'] + a)['log'](); - /** - * Calculate the complex atanh - * - * @returns {Complex} - */ - 'atanh': function() { + return new Complex(Math.PI / 2 - t2['im'], t2['re']); + }, - // atanh(c) = log((1+c) / (1-c)) / 2 + /** + * Calculate the complex arcus tangent + * + * @returns {Complex} + */ + 'atan': function() { - var a = this['re']; - var b = this['im']; + // atan(c) = i / 2 log((i + x) / (i - x)) - var noIM = a > 1 && b === 0; - var oneMinus = 1 - a; - var onePlus = 1 + a; - var d = oneMinus * oneMinus + b * b; + var a = this['re']; + var b = this['im']; - var x = (d !== 0) - ? new Complex( - (onePlus * oneMinus - b * b) / d, - (b * oneMinus + onePlus * b) / d) - : new Complex( - (a !== -1) ? (a / 0) : 0, - (b !== 0) ? (b / 0) : 0); + if (a === 0) { - var temp = x['re']; - x['re'] = logHypot(x['re'], x['im']) / 2; - x['im'] = Math.atan2(x['im'], temp) / 2; - if (noIM) { - x['im'] = -x['im']; - } - return x; - }, + if (b === 1) { + return new Complex(0, Infinity); + } - /** - * Calculate the complex acoth - * - * @returns {Complex} - */ - 'acoth': function() { + if (b === -1) { + return new Complex(0, -Infinity); + } + } - // acoth(c) = log((c+1) / (c-1)) / 2 + var d = a * a + (1.0 - b) * (1.0 - b); - var a = this['re']; - var b = this['im']; + var t1 = new Complex( + (1 - b * b - a * a) / d, + -2 * a / d).log(); - if (a === 0 && b === 0) { - return new Complex(0, Math.PI / 2); - } + return new Complex(-0.5 * t1['im'], 0.5 * t1['re']); + }, - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).atanh() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).atanh(); - }, + /** + * Calculate the complex arcus cotangent + * + * @returns {Complex} + */ + 'acot': function() { - /** - * Calculate the complex acsch - * - * @returns {Complex} - */ - 'acsch': function() { + // acot(c) = i / 2 log((c - i) / (c + i)) - // acsch(c) = log((1+sqrt(1+c^2))/c) + var a = this['re']; + var b = this['im']; - var a = this['re']; - var b = this['im']; + if (b === 0) { + return new Complex(Math.atan2(1, a), 0); + } - if (b === 0) { + var d = a * a + b * b; + return (d !== 0) + ? new Complex( + a / d, + -b / d).atan() + : new Complex( + (a !== 0) ? a / 0 : 0, + (b !== 0) ? -b / 0 : 0).atan(); + }, - return new Complex( - (a !== 0) - ? Math.log(a + Math.sqrt(a * a + 1)) - : Infinity, 0); - } - - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).asinh() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).asinh(); - }, + /** + * Calculate the complex arcus secant + * + * @returns {Complex} + */ + 'asec': function() { - /** - * Calculate the complex asech - * - * @returns {Complex} - */ - 'asech': function() { + // asec(c) = -i * log(1 / c + sqrt(1 - i / c^2)) - // asech(c) = log((1+sqrt(1-c^2))/c) + var a = this['re']; + var b = this['im']; - var a = this['re']; - var b = this['im']; + if (a === 0 && b === 0) { + return new Complex(0, Infinity); + } - if (this.isZero()) { - return Complex['INFINITY']; - } + var d = a * a + b * b; + return (d !== 0) + ? new Complex( + a / d, + -b / d).acos() + : new Complex( + (a !== 0) ? a / 0 : 0, + (b !== 0) ? -b / 0 : 0).acos(); + }, - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).acosh() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).acosh(); - }, + /** + * Calculate the complex arcus cosecans + * + * @returns {Complex} + */ + 'acsc': function() { - /** - * Calculate the complex inverse 1/z - * - * @returns {Complex} - */ - 'inverse': function() { + // acsc(c) = -i * log(i / c + sqrt(1 - 1 / c^2)) - // 1 / 0 = Infinity and 1 / Infinity = 0 - if (this.isZero()) { - return Complex['INFINITY']; - } + var a = this['re']; + var b = this['im']; - if (this.isInfinite()) { - return Complex['ZERO']; - } + if (a === 0 && b === 0) { + return new Complex(Math.PI / 2, Infinity); + } - var a = this['re']; - var b = this['im']; + var d = a * a + b * b; + return (d !== 0) + ? new Complex( + a / d, + -b / d).asin() + : new Complex( + (a !== 0) ? a / 0 : 0, + (b !== 0) ? -b / 0 : 0).asin(); + }, - var d = a * a + b * b; + /** + * Calculate the complex sinh + * + * @returns {Complex} + */ + 'sinh': function() { - return new Complex(a / d, -b / d); - }, + // sinh(c) = (e^c - e^-c) / 2 - /** - * Returns the complex conjugate - * - * @returns {Complex} - */ - 'conjugate': function() { + var a = this['re']; + var b = this['im']; - return new Complex(this['re'], -this['im']); - }, + return new Complex( + sinh(a) * Math.cos(b), + cosh(a) * Math.sin(b)); + }, - /** - * Gets the negated complex number - * - * @returns {Complex} - */ - 'neg': function() { + /** + * Calculate the complex cosh + * + * @returns {Complex} + */ + 'cosh': function() { - return new Complex(-this['re'], -this['im']); - }, + // cosh(c) = (e^c + e^-c) / 2 - /** - * Ceils the actual complex number - * - * @returns {Complex} - */ - 'ceil': function(places) { + var a = this['re']; + var b = this['im']; - places = Math.pow(10, places || 0); + return new Complex( + cosh(a) * Math.cos(b), + sinh(a) * Math.sin(b)); + }, - return new Complex( - Math.ceil(this['re'] * places) / places, - Math.ceil(this['im'] * places) / places); - }, + /** + * Calculate the complex tanh + * + * @returns {Complex} + */ + 'tanh': function() { - /** - * Floors the actual complex number - * - * @returns {Complex} - */ - 'floor': function(places) { + // tanh(c) = (e^c - e^-c) / (e^c + e^-c) - places = Math.pow(10, places || 0); + var a = 2 * this['re']; + var b = 2 * this['im']; + var d = cosh(a) + Math.cos(b); - return new Complex( - Math.floor(this['re'] * places) / places, - Math.floor(this['im'] * places) / places); - }, + return new Complex( + sinh(a) / d, + Math.sin(b) / d); + }, - /** - * Ceils the actual complex number - * - * @returns {Complex} - */ - 'round': function(places) { + /** + * Calculate the complex coth + * + * @returns {Complex} + */ + 'coth': function() { - places = Math.pow(10, places || 0); + // coth(c) = (e^c + e^-c) / (e^c - e^-c) - return new Complex( - Math.round(this['re'] * places) / places, - Math.round(this['im'] * places) / places); - }, + var a = 2 * this['re']; + var b = 2 * this['im']; + var d = cosh(a) - Math.cos(b); - /** - * Compares two complex numbers - * - * **Note:** new Complex(Infinity).equals(Infinity) === false - * - * @returns {boolean} - */ - 'equals': function(a, b) { + return new Complex( + sinh(a) / d, + -Math.sin(b) / d); + }, - var z = new Complex(a, b); + /** + * Calculate the complex coth + * + * @returns {Complex} + */ + 'csch': function() { - return Math.abs(z['re'] - this['re']) <= Complex['EPSILON'] && - Math.abs(z['im'] - this['im']) <= Complex['EPSILON']; - }, + // csch(c) = 2 / (e^c - e^-c) - /** - * Clones the actual object - * - * @returns {Complex} - */ - 'clone': function() { + var a = this['re']; + var b = this['im']; + var d = Math.cos(2 * b) - cosh(2 * a); - return new Complex(this['re'], this['im']); - }, + return new Complex( + -2 * sinh(a) * Math.cos(b) / d, + 2 * cosh(a) * Math.sin(b) / d); + }, - /** - * Gets a string of the actual complex number - * - * @returns {string} - */ - 'toString': function() { + /** + * Calculate the complex sech + * + * @returns {Complex} + */ + 'sech': function() { - var a = this['re']; - var b = this['im']; - var ret = ''; + // sech(c) = 2 / (e^c + e^-c) - if (this.isNaN()) { - return 'NaN'; - } + var a = this['re']; + var b = this['im']; + var d = Math.cos(2 * b) + cosh(2 * a); - if (this.isZero()) { - return '0'; - } + return new Complex( + 2 * cosh(a) * Math.cos(b) / d, + -2 * sinh(a) * Math.sin(b) / d); + }, - if (this.isInfinite()) { - return 'Infinity'; - } + /** + * Calculate the complex asinh + * + * @returns {Complex} + */ + 'asinh': function() { - if (a !== 0) { - ret += a; - } + // asinh(c) = log(c + sqrt(c^2 + 1)) - if (b !== 0) { + var tmp = this['im']; + this['im'] = -this['re']; + this['re'] = tmp; + var res = this['asin'](); - if (a !== 0) { - ret += b < 0 ? ' - ' : ' + '; - } else if (b < 0) { - ret += '-'; - } + this['re'] = -this['im']; + this['im'] = tmp; + tmp = res['re']; - b = Math.abs(b); + res['re'] = -res['im']; + res['im'] = tmp; + return res; + }, - if (1 !== b) { - ret += b; - } - ret += 'i'; - } + /** + * Calculate the complex asinh + * + * @returns {Complex} + */ + 'acosh': function() { - if (!ret) - return '0'; + // acosh(c) = log(c + sqrt(c^2 - 1)) - return ret; - }, + var res = this['acos'](); + if (res['im'] <= 0) { + var tmp = res['re']; + res['re'] = -res['im']; + res['im'] = tmp; + } else { + var tmp = res['im']; + res['im'] = -res['re']; + res['re'] = tmp; + } + return res; + }, - /** - * Returns the actual number as a vector - * - * @returns {Array} - */ - 'toVector': function() { + /** + * Calculate the complex atanh + * + * @returns {Complex} + */ + 'atanh': function() { - return [this['re'], this['im']]; - }, + // atanh(c) = log((1+c) / (1-c)) / 2 - /** - * Returns the actual real value of the current object - * - * @returns {number|null} - */ - 'valueOf': function() { + var a = this['re']; + var b = this['im']; - if (this['im'] === 0) { - return this['re']; - } - return null; - }, + var noIM = a > 1 && b === 0; + var oneMinus = 1 - a; + var onePlus = 1 + a; + var d = oneMinus * oneMinus + b * b; - /** - * Determines whether a complex number is not on the Riemann sphere. - * - * @returns {boolean} - */ - 'isNaN': function() { - return isNaN(this['re']) || isNaN(this['im']); - }, + var x = (d !== 0) + ? new Complex( + (onePlus * oneMinus - b * b) / d, + (b * oneMinus + onePlus * b) / d) + : new Complex( + (a !== -1) ? (a / 0) : 0, + (b !== 0) ? (b / 0) : 0); - /** - * Determines whether or not a complex number is at the zero pole of the - * Riemann sphere. - * - * @returns {boolean} - */ - 'isZero': function() { - return ( - (this['re'] === 0 || this['re'] === -0) && - (this['im'] === 0 || this['im'] === -0) - ); - }, + var temp = x['re']; + x['re'] = logHypot(x['re'], x['im']) / 2; + x['im'] = Math.atan2(x['im'], temp) / 2; + if (noIM) { + x['im'] = -x['im']; + } + return x; + }, - /** - * Determines whether a complex number is not at the infinity pole of the - * Riemann sphere. - * - * @returns {boolean} - */ - 'isFinite': function() { - return isFinite(this['re']) && isFinite(this['im']); - }, + /** + * Calculate the complex acoth + * + * @returns {Complex} + */ + 'acoth': function() { - /** - * Determines whether or not a complex number is at the infinity pole of the - * Riemann sphere. - * - * @returns {boolean} - */ - 'isInfinite': function() { - return !(this.isNaN() || this.isFinite()); - } - }; + // acoth(c) = log((c+1) / (c-1)) / 2 - Complex['ZERO'] = new Complex(0, 0); - Complex['ONE'] = new Complex(1, 0); - Complex['I'] = new Complex(0, 1); - Complex['PI'] = new Complex(Math.PI, 0); - Complex['E'] = new Complex(Math.E, 0); - Complex['INFINITY'] = new Complex(Infinity, Infinity); - Complex['NAN'] = new Complex(NaN, NaN); - Complex['EPSILON'] = 1e-16; + var a = this['re']; + var b = this['im']; - if (typeof undefined === 'function' && undefined['amd']) { - undefined([], function() { - return Complex; - }); - } else { - Object.defineProperty(exports, "__esModule", {'value': true}); - Complex['default'] = Complex; - Complex['Complex'] = Complex; - module['exports'] = Complex; - } + if (a === 0 && b === 0) { + return new Complex(0, Math.PI / 2); + } -})(commonjsGlobal); -}); + var d = a * a + b * b; + return (d !== 0) + ? new Complex( + a / d, + -b / d).atanh() + : new Complex( + (a !== 0) ? a / 0 : 0, + (b !== 0) ? -b / 0 : 0).atanh(); + }, -unwrapExports(complex); + /** + * Calculate the complex acsch + * + * @returns {Complex} + */ + 'acsch': function() { -var format$1 = number.format; -var isNumber = number.isNumber; + // acsch(c) = log((1+sqrt(1+c^2))/c) -function factory$7 (type, config, load, typed, math) { + var a = this['re']; + var b = this['im']; - /** - * Attach type information - */ - complex.prototype.type = 'Complex'; - complex.prototype.isComplex = true; - - - /** - * Get a JSON representation of the complex number - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Complex", "re": 2, "im": 3}` - */ - complex.prototype.toJSON = function () { - return { - mathjs: 'Complex', - re: this.re, - im: this.im - }; - }; - - /* - * 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: this.abs(), - phi: this.arg() - }; - }; - - /** - * Get a string representation of the complex number, - * with optional formatting options. - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @return {string} str - */ - complex.prototype.format = function (options) { - var str = ''; - var im = this.im; - var re = this.re; - var strRe = format$1(this.re, options); - var strIm = format$1(this.im, options); - - // round either re or im when smaller than the configured precision - var precision = isNumber(options) ? options : options ? options.precision : null; - if (precision !== null) { - var epsilon = Math.pow(10, -precision); - if (Math.abs(re / im) < epsilon) { - re = 0; - } - if (Math.abs(im / re) < epsilon) { - im = 0; - } - } - - if (im == 0) { - // real value - str = strRe; - } else if (re == 0) { - // purely complex value - if (im == 1) { - str = 'i'; - } else if (im == -1) { - str = '-i'; - } else { - str = strIm + 'i'; - } - } else { - // complex value - if (im < 0) { - if (im == -1) { - str = strRe + ' - i'; - } else { - str = strRe + ' - ' + strIm.substring(1) + 'i'; - } - } else { - if (im == 1) { - str = strRe + ' + i'; - } else { - str = strRe + ' + ' + strIm + 'i'; - } - } - } - return str; - }; + if (b === 0) { - /** - * 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 (args) { - switch (arguments.length) { - case 1: - var arg = arguments[0]; - if (typeof arg === 'object') { - return complex(arg); + return new Complex( + (a !== 0) + ? Math.log(a + Math.sqrt(a * a + 1)) + : Infinity, 0); } - 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 (type.isUnit(phi) && phi.hasBase('ANGLE')) { - // convert unit to a number in radians - phi = phi.toNumber('rad'); - } - if (isNumber(phi)) { - return new complex({r: r, phi: phi}); - } - - throw new TypeError('Phi is not a number nor an angle unit.'); - } else { - throw new TypeError('Radius r is not a number.'); - } + var d = a * a + b * b; + return (d !== 0) + ? new Complex( + a / d, + -b / d).asinh() + : new Complex( + (a !== 0) ? a / 0 : 0, + (b !== 0) ? -b / 0 : 0).asinh(); + }, - default: - throw new SyntaxError('Wrong number of arguments in function fromPolar'); - } - }; + /** + * Calculate the complex asech + * + * @returns {Complex} + */ + 'asech': function() { + // asech(c) = log((1+sqrt(1-c^2))/c) - complex.prototype.valueOf = complex.prototype.toString; + var a = this['re']; + var b = this['im']; - /** - * Create a Complex number from a JSON object - * @param {Object} json A JSON Object structured as - * {"mathjs": "Complex", "re": 2, "im": 3} - * All properties are optional, default values - * for `re` and `im` are 0. - * @return {Complex} Returns a new Complex number - */ - complex.fromJSON = function (json) { - return new complex(json); - }; + if (this.isZero()) { + return Complex['INFINITY']; + } - // apply the current epsilon - complex.EPSILON = config.epsilon; + var d = a * a + b * b; + return (d !== 0) + ? new Complex( + a / d, + -b / d).acosh() + : new Complex( + (a !== 0) ? a / 0 : 0, + (b !== 0) ? -b / 0 : 0).acosh(); + }, - // listen for changed in the configuration, automatically apply changed epsilon - math.on('config', function (curr, prev) { - if (curr.epsilon !== prev.epsilon) { - complex.EPSILON = curr.epsilon; - } - }); + /** + * Calculate the complex inverse 1/z + * + * @returns {Complex} + */ + 'inverse': function() { - /** - * Compare two complex numbers, `a` and `b`: - * - * - Returns 1 when the real part of `a` is larger than the real part of `b` - * - Returns -1 when the real part of `a` is smaller than the real part of `b` - * - Returns 1 when the real parts are equal - * and the imaginary part of `a` is larger than the imaginary part of `b` - * - Returns -1 when the real parts are equal - * and the imaginary part of `a` is smaller than the imaginary part of `b` - * - Returns 0 when both real and imaginary parts are equal. - * - * @params {Complex} a - * @params {Complex} b - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ - complex.compare = function (a, b) { - if (a.re > b.re) { return 1; } - if (a.re < b.re) { return -1; } + // 1 / 0 = Infinity and 1 / Infinity = 0 + if (this.isZero()) { + return Complex['INFINITY']; + } - if (a.im > b.im) { return 1; } - if (a.im < b.im) { return -1; } + if (this.isInfinite()) { + return Complex['ZERO']; + } - return 0; - }; + var a = this['re']; + var b = this['im']; - return complex; -} - -var name$7 = 'Complex'; -var path$2 = 'type'; -var factory_1$7 = factory$7; -var math$4 = true; // request access to the math namespace - -var Complex_1 = { - name: name$7, - path: path$2, - factory: factory_1$7, - math: math$4 -}; - -// Map the characters to escape to their escaped values. The list is derived -// from http://www.cespedes.org/blog/85/how-to-escape-latex-special-characters - -var defaultEscapes = { - "{": "\\{", - "}": "\\}", - "\\": "\\textbackslash{}", - "#": "\\#", - $: "\\$", - "%": "\\%", - "&": "\\&", - "^": "\\textasciicircum{}", - _: "\\_", - "~": "\\textasciitilde{}" -}; -var formatEscapes = { - "–": "\\--", - "—": "\\---", - " ": "~", - "\t": "\\qquad{}", - "\r\n": "\\\\newline{}", - "\n": "\\\\newline{}" -}; - -var defaultEscapeMapFn = function defaultEscapeMapFn(defaultEscapes, formatEscapes) { - return Object.assign({}, defaultEscapes, formatEscapes); -}; - -/** - * Escape a string to be used in LaTeX documents. - * @param {string} str the string to be escaped. - * @param {boolean} params.preserveFormatting whether formatting escapes should - * be performed (default: false). - * @param {function} params.escapeMapFn the function to modify the escape maps. - * @return {string} the escaped string, ready to be used in LaTeX. - */ -var dist = function (str) { - var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, - _ref$preserveFormatti = _ref.preserveFormatting, - preserveFormatting = _ref$preserveFormatti === undefined ? false : _ref$preserveFormatti, - _ref$escapeMapFn = _ref.escapeMapFn, - escapeMapFn = _ref$escapeMapFn === undefined ? defaultEscapeMapFn : _ref$escapeMapFn; - - var runningStr = String(str); - var result = ""; - - var escapes = escapeMapFn(Object.assign({}, defaultEscapes), preserveFormatting ? Object.assign({}, formatEscapes) : {}); - var escapeKeys = Object.keys(escapes); // as it is reused later on - - // Algorithm: Go through the string character by character, if it matches - // with one of the special characters then we'll replace it with the escaped - // version. - - var _loop = function _loop() { - var specialCharFound = false; - escapeKeys.forEach(function (key, index) { - if (specialCharFound) { - return; - } - if (runningStr.startsWith(key)) { - result += escapes[escapeKeys[index]]; - runningStr = runningStr.slice(key.length, runningStr.length); - specialCharFound = true; - } - }); - if (!specialCharFound) { - result += runningStr.slice(0, 1); - runningStr = runningStr.slice(1, runningStr.length); - } - }; - - while (runningStr) { - _loop(); - } - return result; -}; - -var latex = createCommonjsModule(function (module, exports) { - - - -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', - '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 dist(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); -}; -}); -var latex_1 = latex.symbols; -var latex_2 = latex.operators; -var latex_3 = latex.defaultTemplate; -var latex_4 = latex.escape; -var latex_5 = latex.toSymbol; - -function factory$8 (type, config, load, typed) { - var latex$$1 = latex; + var d = a * a + b * b; - /** - * Create a complex value or convert a value to a complex value. - * - * Syntax: - * - * math.complex() // creates a complex value with zero - * // as real and imaginary part. - * math.complex(re : number, im : string) // creates a complex value with provided - * // values for real and imaginary part. - * math.complex(re : number) // creates a complex value with provided - * // real value and zero imaginary part. - * math.complex(complex : Complex) // clones the provided complex value. - * math.complex(arg : string) // parses a string into a complex value. - * math.complex(array : Array) // converts the elements of the array - * // or matrix element wise into a - * // complex value. - * math.complex({re: number, im: number}) // creates a complex value with provided - * // values for real an imaginary part. - * math.complex({r: number, phi: number}) // creates a complex value with provided - * // polar coordinates - * - * Examples: - * - * var a = math.complex(3, -4); // a = Complex 3 - 4i - * a.re = 5; // a = Complex 5 - 4i - * var i = a.im; // Number -4; - * var b = math.complex('2 + 6i'); // Complex 2 + 6i - * var c = math.complex(); // Complex 0 + 0i - * var d = math.add(a, b); // Complex 5 + 2i - * - * See also: - * - * bignumber, boolean, index, matrix, number, string, unit - * - * @param {* | Array | Matrix} [args] - * Arguments specifying the real and imaginary part of the complex number - * @return {Complex | Array | Matrix} Returns a complex value - */ - var complex = typed('complex', { - '': function () { - return type.Complex.ZERO; - }, + return new Complex(a / d, -b / d); + }, - 'number': function (x) { - return new type.Complex(x, 0); - }, + /** + * Returns the complex conjugate + * + * @returns {Complex} + */ + 'conjugate': function() { - 'number, number': function (re, im) { - return new type.Complex(re, im); - }, + return new Complex(this['re'], -this['im']); + }, - // TODO: this signature should be redundant - 'BigNumber, BigNumber': function (re, im) { - return new type.Complex(re.toNumber(), im.toNumber()); - }, + /** + * Gets the negated complex number + * + * @returns {Complex} + */ + 'neg': function() { - 'Complex': function (x) { - return x.clone(); - }, + return new Complex(-this['re'], -this['im']); + }, - 'string': function (x) { - return type.Complex(x); // for example '2 + 3i' - }, + /** + * Ceils the actual complex number + * + * @returns {Complex} + */ + 'ceil': function(places) { - 'null': function (x) { - return type.Complex(0); - }, + places = Math.pow(10, places || 0); - 'Object': function (x) { - if('re' in x && 'im' in x) { - return new type.Complex(x.re, x.im); - } + return new Complex( + Math.ceil(this['re'] * places) / places, + Math.ceil(this['im'] * places) / places); + }, - if ('r' in x && 'phi' in x) { - return new type.Complex(x); - } + /** + * Floors the actual complex number + * + * @returns {Complex} + */ + 'floor': function(places) { - throw new Error('Expected object with either properties re and im, or properties r and phi.'); - }, + places = Math.pow(10, places || 0); - 'Array | Matrix': function (x) { - return deepMap(x, complex); - } - }); + return new Complex( + Math.floor(this['re'] * places) / places, + Math.floor(this['im'] * places) / places); + }, - complex.toTex = { - 0: '0', - 1: '\\left(${args[0]}\\right)', - 2: '\\left(\\left(${args[0]}\\right)+' - + latex$$1.symbols['i'] + '\\cdot\\left(${args[1]}\\right)\\right)' - }; - - return complex; -} - -var name$8 = 'complex'; -var factory_1$8 = factory$8; - -var complex$2 = { - name: name$8, - factory: factory_1$8 -}; - -var complex$3 = [ - // type - Complex_1, - - // construction function - complex$2 -]; - -var fraction = createCommonjsModule(function (module, exports) { -/** - * @license Fraction.js v4.0.8 09/09/2015 - * http://www.xarg.org/2014/03/rational-numbers-in-javascript/ - * - * Copyright (c) 2015, Robert Eisele (robert@xarg.org) - * Dual licensed under the MIT or GPL Version 2 licenses. - **/ - - -/** - * - * This class offers the possibility to calculate fractions. - * You can pass a fraction in different formats. Either as array, as double, as string or as an integer. - * - * Array/Object form - * [ 0 => , 1 => ] - * [ n => , d => ] - * - * Integer form - * - Single integer value - * - * Double form - * - Single double value - * - * String form - * 123.456 - a simple double - * 123/456 - a string fraction - * 123.'456' - a double with repeating decimal places - * 123.(456) - synonym - * 123.45'6' - a double with repeating last place - * 123.45(6) - synonym - * - * Example: - * - * var f = new Fraction("9.4'31'"); - * f.mul([-4, 3]).div(4.9); - * - */ - -(function(root) { - - // Maximum search depth for cyclic rational numbers. 2000 should be more than enough. - // Example: 1/7 = 0.(142857) has 6 repeating decimal places. - // If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits - var MAX_CYCLE_LEN = 2000; - - // Parsed data to avoid calling "new" all the time - var P = { - "s": 1, - "n": 0, - "d": 1 - }; - - function createError(name) { - - function errorConstructor() { - var temp = Error.apply(this, arguments); - temp['name'] = this['name'] = name; - this['stack'] = temp['stack']; - this['message'] = temp['message']; - } - - /** - * Error constructor - * - * @constructor - */ - function IntermediateInheritor() {} - IntermediateInheritor.prototype = Error.prototype; - errorConstructor.prototype = new IntermediateInheritor(); + /** + * Ceils the actual complex number + * + * @returns {Complex} + */ + 'round': function(places) { - return errorConstructor; - } + places = Math.pow(10, places || 0); - var DivisionByZero = Fraction['DivisionByZero'] = createError('DivisionByZero'); - var InvalidParameter = Fraction['InvalidParameter'] = createError('InvalidParameter'); + return new Complex( + Math.round(this['re'] * places) / places, + Math.round(this['im'] * places) / places); + }, - function assign(n, s) { + /** + * Compares two complex numbers + * + * **Note:** new Complex(Infinity).equals(Infinity) === false + * + * @returns {boolean} + */ + 'equals': function(a, b) { - if (isNaN(n = parseInt(n, 10))) { - throwInvalidParam(); - } - return n * s; - } + var z = new Complex(a, b); - function throwInvalidParam() { - throw new InvalidParameter(); - } + return Math.abs(z['re'] - this['re']) <= Complex['EPSILON'] && + Math.abs(z['im'] - this['im']) <= Complex['EPSILON']; + }, - var parse = function(p1, p2) { + /** + * Clones the actual object + * + * @returns {Complex} + */ + 'clone': function() { - var n = 0, d = 1, s = 1; - var v = 0, w = 0, x = 0, y = 1, z = 1; + return new Complex(this['re'], this['im']); + }, - var A = 0, B = 1; - var C = 1, D = 1; + /** + * Gets a string of the actual complex number + * + * @returns {string} + */ + 'toString': function() { - var N = 10000000; - var M; + var a = this['re']; + var b = this['im']; + var ret = ''; - if (p1 === undefined || p1 === null) { - /* void */ - } else if (p2 !== undefined) { - n = p1; - d = p2; - s = n * d; - } else - switch (typeof p1) { - - case "object": - { - if ("d" in p1 && "n" in p1) { - n = p1["n"]; - d = p1["d"]; - if ("s" in p1) - n *= p1["s"]; - } else if (0 in p1) { - n = p1[0]; - if (1 in p1) - d = p1[1]; - } else { - throwInvalidParam(); - } - s = n * d; - break; + if (this.isNaN()) { + return 'NaN'; } - case "number": - { - if (p1 < 0) { - s = p1; - p1 = -p1; - } - - if (p1 % 1 === 0) { - n = p1; - } else if (p1 > 0) { // check for != 0, scale would become NaN (log(0)), which converges really slow - - if (p1 >= 1) { - z = Math.pow(10, Math.floor(1 + Math.log(p1) / Math.LN10)); - p1 /= z; - } - - // Using Farey Sequences - // http://www.johndcook.com/blog/2010/10/20/best-rational-approximation/ - - while (B <= N && D <= N) { - M = (A + C) / (B + D); - if (p1 === M) { - if (B + D <= N) { - n = A + C; - d = B + D; - } else if (D > B) { - n = C; - d = D; - } else { - n = A; - d = B; - } - break; - - } else { + if (this.isZero()) { + return '0'; + } - if (p1 > M) { - A += C; - B += D; - } else { - C += A; - D += B; - } + if (this.isInfinite()) { + return 'Infinity'; + } - if (B > N) { - n = C; - d = D; - } else { - n = A; - d = B; - } - } - } - n *= z; - } else if (isNaN(p1) || isNaN(p2)) { - d = n = NaN; - } - break; + if (a !== 0) { + ret += a; } - case "string": - { - B = p1.match(/\d+|./g); - if (B === null) - throwInvalidParam(); + if (b !== 0) { - if (B[A] === '-') {// Check for minus sign at the beginning - s = -1; - A++; - } else if (B[A] === '+') {// Check for plus sign at the beginning - A++; + if (a !== 0) { + ret += b < 0 ? ' - ' : ' + '; + } else if (b < 0) { + ret += '-'; } - if (B.length === A + 1) { // Check if it's just a simple number "1234" - w = assign(B[A++], s); - } else if (B[A + 1] === '.' || B[A] === '.') { // Check if it's a decimal number - - if (B[A] !== '.') { // Handle 0.5 and .5 - v = assign(B[A++], s); - } - A++; - - // Check for decimal places - if (A + 1 === B.length || B[A + 1] === '(' && B[A + 3] === ')' || B[A + 1] === "'" && B[A + 3] === "'") { - w = assign(B[A], s); - y = Math.pow(10, B[A].length); - A++; - } - - // Check for repeating places - if (B[A] === '(' && B[A + 2] === ')' || B[A] === "'" && B[A + 2] === "'") { - x = assign(B[A + 1], s); - z = Math.pow(10, B[A + 1].length) - 1; - A += 3; - } + b = Math.abs(b); - } else if (B[A + 1] === '/' || B[A + 1] === ':') { // Check for a simple fraction "123/456" or "123:456" - w = assign(B[A], s); - y = assign(B[A + 2], 1); - A += 3; - } else if (B[A + 3] === '/' && B[A + 1] === ' ') { // Check for a complex fraction "123 1/2" - v = assign(B[A], s); - w = assign(B[A + 2], s); - y = assign(B[A + 4], 1); - A += 5; - } - - if (B.length <= A) { // Check for more tokens on the stack - d = y * z; - s = /* void */ - n = x + d * v + z * w; - break; + if (1 !== b) { + ret += b; } - - /* Fall through on error */ + ret += 'i'; } - default: - throwInvalidParam(); - } - - if (d === 0) { - throw new DivisionByZero(); - } - P["s"] = s < 0 ? -1 : 1; - P["n"] = Math.abs(n); - P["d"] = Math.abs(d); - }; - - function modpow(b, e, m) { + if (!ret) + return '0'; - var r = 1; - for (; e > 0; b = (b * b) % m, e >>= 1) { - - if (e & 1) { - r = (r * b) % m; - } - } - return r; - } + return ret; + }, + /** + * Returns the actual number as a vector + * + * @returns {Array} + */ + 'toVector': function() { - function cycleLen(n, d) { + return [this['re'], this['im']]; + }, - for (; d % 2 === 0; - d /= 2) { - } + /** + * Returns the actual real value of the current object + * + * @returns {number|null} + */ + 'valueOf': function() { - for (; d % 5 === 0; - d /= 5) { - } + if (this['im'] === 0) { + return this['re']; + } + return null; + }, - if (d === 1) // Catch non-cyclic numbers - return 0; + /** + * Determines whether a complex number is not on the Riemann sphere. + * + * @returns {boolean} + */ + 'isNaN': function() { + return isNaN(this['re']) || isNaN(this['im']); + }, - // If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem: - // 10^(d-1) % d == 1 - // However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone, - // as we want to translate the numbers to strings. + /** + * Determines whether or not a complex number is at the zero pole of the + * Riemann sphere. + * + * @returns {boolean} + */ + 'isZero': function() { + return ( + (this['re'] === 0 || this['re'] === -0) && + (this['im'] === 0 || this['im'] === -0) + ); + }, - var rem = 10 % d; - var t = 1; + /** + * Determines whether a complex number is not at the infinity pole of the + * Riemann sphere. + * + * @returns {boolean} + */ + 'isFinite': function() { + return isFinite(this['re']) && isFinite(this['im']); + }, - for (; rem !== 1; t++) { - rem = rem * 10 % d; + /** + * Determines whether or not a complex number is at the infinity pole of the + * Riemann sphere. + * + * @returns {boolean} + */ + 'isInfinite': function() { + return !(this.isNaN() || this.isFinite()); + } + }; - if (t > MAX_CYCLE_LEN) - return 0; // Returning 0 here means that we don't print it as a cyclic number. It's likely that the answer is `d-1` + Complex['ZERO'] = new Complex(0, 0); + Complex['ONE'] = new Complex(1, 0); + Complex['I'] = new Complex(0, 1); + Complex['PI'] = new Complex(Math.PI, 0); + Complex['E'] = new Complex(Math.E, 0); + Complex['INFINITY'] = new Complex(Infinity, Infinity); + Complex['NAN'] = new Complex(NaN, NaN); + Complex['EPSILON'] = 1e-16; + + if (typeof undefined === 'function' && undefined['amd']) { + undefined([], function() { + return Complex; + }); + } else { + Object.defineProperty(exports, "__esModule", {'value': true}); + Complex['default'] = Complex; + Complex['Complex'] = Complex; + module['exports'] = Complex; } - return t; - } + })(commonjsGlobal); + }); - function cycleStart(n, d, len) { + unwrapExports(complex); - var rem1 = 1; - var rem2 = modpow(10, len, d); + var format$1 = number.format; + var isNumber = number.isNumber; - for (var t = 0; t < 300; t++) { // s < ~log10(Number.MAX_VALUE) - // Solve 10^s == 10^(s+t) (mod d) + function factory$7 (type, config, load, typed, math) { - if (rem1 === rem2) - return t; + /** + * Attach type information + */ + complex.prototype.type = 'Complex'; + complex.prototype.isComplex = true; - rem1 = rem1 * 10 % d; - rem2 = rem2 * 10 % d; - } - return 0; - } - function gcd(a, b) { + /** + * Get a JSON representation of the complex number + * @returns {Object} Returns a JSON object structured as: + * `{"mathjs": "Complex", "re": 2, "im": 3}` + */ + complex.prototype.toJSON = function () { + return { + mathjs: 'Complex', + re: this.re, + im: this.im + }; + }; - if (!a) - return b; - if (!b) - return a; + /* + * 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: this.abs(), + phi: this.arg() + }; + }; - while (1) { - a %= b; - if (!a) - return b; - b %= a; - if (!b) - return a; - } - } - /** - * Module constructor - * - * @constructor - * @param {number|Fraction=} a - * @param {number=} b - */ - function Fraction(a, b) { + /** + * Get a string representation of the complex number, + * with optional formatting options. + * @param {Object | number | Function} [options] Formatting options. See + * lib/utils/number:format for a + * description of the available + * options. + * @return {string} str + */ + complex.prototype.format = function (options) { + var str = ''; + var im = this.im; + var re = this.re; + var strRe = format$1(this.re, options); + var strIm = format$1(this.im, options); + + // round either re or im when smaller than the configured precision + var precision = isNumber(options) ? options : options ? options.precision : null; + if (precision !== null) { + var epsilon = Math.pow(10, -precision); + if (Math.abs(re / im) < epsilon) { + re = 0; + } + if (Math.abs(im / re) < epsilon) { + im = 0; + } + } + + if (im == 0) { + // real value + str = strRe; + } else if (re == 0) { + // purely complex value + if (im == 1) { + str = 'i'; + } else if (im == -1) { + str = '-i'; + } else { + str = strIm + 'i'; + } + } else { + // complex value + if (im < 0) { + if (im == -1) { + str = strRe + ' - i'; + } else { + str = strRe + ' - ' + strIm.substring(1) + 'i'; + } + } else { + if (im == 1) { + str = strRe + ' + i'; + } else { + str = strRe + ' + ' + strIm + 'i'; + } + } + } + return str; + }; - if (!(this instanceof Fraction)) { - return new Fraction(a, b); - } + /** + * 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 (args) { + switch (arguments.length) { + case 1: + var arg = arguments[0]; + if (typeof arg === 'object') { + return complex(arg); + } + throw new TypeError('Input has to be an object with r and phi keys.'); - parse(a, b); + case 2: + var r = arguments[0], + phi = arguments[1]; + if (isNumber(r)) { + if (type.isUnit(phi) && phi.hasBase('ANGLE')) { + // convert unit to a number in radians + phi = phi.toNumber('rad'); + } - if (Fraction['REDUCE']) { - a = gcd(P["d"], P["n"]); // Abuse a - } else { - a = 1; - } + if (isNumber(phi)) { + return new complex({r: r, phi: phi}); + } - this["s"] = P["s"]; - this["n"] = P["n"] / a; - this["d"] = P["d"] / a; - } + throw new TypeError('Phi is not a number nor an angle unit.'); + } else { + throw new TypeError('Radius r is not a number.'); + } - /** - * Boolean global variable to be able to disable automatic reduction of the fraction - * - */ - Fraction['REDUCE'] = 1; + default: + throw new SyntaxError('Wrong number of arguments in function fromPolar'); + } + }; - Fraction.prototype = { - "s": 1, - "n": 0, - "d": 1, + complex.prototype.valueOf = complex.prototype.toString; /** - * Calculates the absolute value - * - * Ex: new Fraction(-4).abs() => 4 - **/ - "abs": function() { + * Create a Complex number from a JSON object + * @param {Object} json A JSON Object structured as + * {"mathjs": "Complex", "re": 2, "im": 3} + * All properties are optional, default values + * for `re` and `im` are 0. + * @return {Complex} Returns a new Complex number + */ + complex.fromJSON = function (json) { + return new complex(json); + }; - return new Fraction(this["n"], this["d"]); - }, + // apply the current epsilon + complex.EPSILON = config.epsilon; + + // listen for changed in the configuration, automatically apply changed epsilon + math.on('config', function (curr, prev) { + if (curr.epsilon !== prev.epsilon) { + complex.EPSILON = curr.epsilon; + } + }); /** - * Inverts the sign of the current fraction + * Compare two complex numbers, `a` and `b`: * - * Ex: new Fraction(-4).neg() => 4 - **/ - "neg": function() { + * - Returns 1 when the real part of `a` is larger than the real part of `b` + * - Returns -1 when the real part of `a` is smaller than the real part of `b` + * - Returns 1 when the real parts are equal + * and the imaginary part of `a` is larger than the imaginary part of `b` + * - Returns -1 when the real parts are equal + * and the imaginary part of `a` is smaller than the imaginary part of `b` + * - Returns 0 when both real and imaginary parts are equal. + * + * @params {Complex} a + * @params {Complex} b + * @returns {number} Returns the comparison result: -1, 0, or 1 + */ + complex.compare = function (a, b) { + if (a.re > b.re) { return 1; } + if (a.re < b.re) { return -1; } - return new Fraction(-this["s"] * this["n"], this["d"]); - }, + if (a.im > b.im) { return 1; } + if (a.im < b.im) { return -1; } - /** - * Adds two rational numbers - * - * Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30 - **/ - "add": function(a, b) { + return 0; + }; - parse(a, b); - return new Fraction( - this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"], - this["d"] * P["d"] - ); - }, + return complex; + } - /** - * Subtracts two rational numbers - * - * Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30 - **/ - "sub": function(a, b) { + var name$7 = 'Complex'; + var path$2 = 'type'; + var factory_1$7 = factory$7; + var math$4 = true; // request access to the math namespace - parse(a, b); - return new Fraction( - this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"], - this["d"] * P["d"] - ); - }, + var Complex_1 = { + name: name$7, + path: path$2, + factory: factory_1$7, + math: math$4 + }; - /** - * Multiplies two rational numbers - * - * Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111 - **/ - "mul": function(a, b) { + // Map the characters to escape to their escaped values. The list is derived + // from http://www.cespedes.org/blog/85/how-to-escape-latex-special-characters - parse(a, b); - return new Fraction( - this["s"] * P["s"] * this["n"] * P["n"], - this["d"] * P["d"] - ); - }, + var defaultEscapes = { + "{": "\\{", + "}": "\\}", + "\\": "\\textbackslash{}", + "#": "\\#", + $: "\\$", + "%": "\\%", + "&": "\\&", + "^": "\\textasciicircum{}", + _: "\\_", + "~": "\\textasciitilde{}" + }; + var formatEscapes = { + "–": "\\--", + "—": "\\---", + " ": "~", + "\t": "\\qquad{}", + "\r\n": "\\\\newline{}", + "\n": "\\\\newline{}" + }; - /** - * Divides two rational numbers - * - * Ex: new Fraction("-17.(345)").inverse().div(3) - **/ - "div": function(a, b) { + var defaultEscapeMapFn = function defaultEscapeMapFn(defaultEscapes, formatEscapes) { + return Object.assign({}, defaultEscapes, formatEscapes); + }; - parse(a, b); - return new Fraction( - this["s"] * P["s"] * this["n"] * P["d"], - this["d"] * P["n"] - ); - }, + /** + * Escape a string to be used in LaTeX documents. + * @param {string} str the string to be escaped. + * @param {boolean} params.preserveFormatting whether formatting escapes should + * be performed (default: false). + * @param {function} params.escapeMapFn the function to modify the escape maps. + * @return {string} the escaped string, ready to be used in LaTeX. + */ + var dist = function (str) { + var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, + _ref$preserveFormatti = _ref.preserveFormatting, + preserveFormatting = _ref$preserveFormatti === undefined ? false : _ref$preserveFormatti, + _ref$escapeMapFn = _ref.escapeMapFn, + escapeMapFn = _ref$escapeMapFn === undefined ? defaultEscapeMapFn : _ref$escapeMapFn; - /** - * Clones the actual object - * - * Ex: new Fraction("-17.(345)").clone() - **/ - "clone": function() { - return new Fraction(this); - }, + var runningStr = String(str); + var result = ""; - /** - * Calculates the modulo of two rational numbers - a more precise fmod - * - * Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6) - **/ - "mod": function(a, b) { + var escapes = escapeMapFn(Object.assign({}, defaultEscapes), preserveFormatting ? Object.assign({}, formatEscapes) : {}); + var escapeKeys = Object.keys(escapes); // as it is reused later on - if (isNaN(this['n']) || isNaN(this['d'])) { - return new Fraction(NaN); - } + // Algorithm: Go through the string character by character, if it matches + // with one of the special characters then we'll replace it with the escaped + // version. - if (a === undefined) { - return new Fraction(this["s"] * this["n"] % this["d"], 1); + var _loop = function _loop() { + var specialCharFound = false; + escapeKeys.forEach(function (key, index) { + if (specialCharFound) { + return; + } + if (runningStr.startsWith(key)) { + result += escapes[escapeKeys[index]]; + runningStr = runningStr.slice(key.length, runningStr.length); + specialCharFound = true; + } + }); + if (!specialCharFound) { + result += runningStr.slice(0, 1); + runningStr = runningStr.slice(1, runningStr.length); } + }; - parse(a, b); - if (0 === P["n"] && 0 === this["d"]) { - Fraction(0, 0); // Throw DivisionByZero - } + while (runningStr) { + _loop(); + } + return result; + }; - /* - * First silly attempt, kinda slow - * - return that["sub"]({ - "n": num["n"] * Math.floor((this.n / this.d) / (num.n / num.d)), - "d": num["d"], - "s": this["s"] - });*/ + var latex = createCommonjsModule(function (module, exports) { + + + + 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', + '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 dist(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); + }; + }); + var latex_1 = latex.symbols; + var latex_2 = latex.operators; + var latex_3 = latex.defaultTemplate; + var latex_4 = latex.escape; + var latex_5 = latex.toSymbol; - /* - * New attempt: a1 / b1 = a2 / b2 * q + r - * => b2 * a1 = a2 * b1 * q + b1 * b2 * r - * => (b2 * a1 % a2 * b1) / (b1 * b2) - */ - return new Fraction( - this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]), - P["d"] * this["d"] - ); - }, + function factory$8 (type, config, load, typed) { + var latex$$1 = latex; /** - * Calculates the fractional gcd of two rational numbers + * Create a complex value or convert a value to a complex value. + * + * Syntax: + * + * math.complex() // creates a complex value with zero + * // as real and imaginary part. + * math.complex(re : number, im : string) // creates a complex value with provided + * // values for real and imaginary part. + * math.complex(re : number) // creates a complex value with provided + * // real value and zero imaginary part. + * math.complex(complex : Complex) // clones the provided complex value. + * math.complex(arg : string) // parses a string into a complex value. + * math.complex(array : Array) // converts the elements of the array + * // or matrix element wise into a + * // complex value. + * math.complex({re: number, im: number}) // creates a complex value with provided + * // values for real an imaginary part. + * math.complex({r: number, phi: number}) // creates a complex value with provided + * // polar coordinates + * + * Examples: + * + * var a = math.complex(3, -4); // a = Complex 3 - 4i + * a.re = 5; // a = Complex 5 - 4i + * var i = a.im; // Number -4; + * var b = math.complex('2 + 6i'); // Complex 2 + 6i + * var c = math.complex(); // Complex 0 + 0i + * var d = math.add(a, b); // Complex 5 + 2i * - * Ex: new Fraction(5,8).gcd(3,7) => 1/56 + * See also: + * + * bignumber, boolean, index, matrix, number, string, unit + * + * @param {* | Array | Matrix} [args] + * Arguments specifying the real and imaginary part of the complex number + * @return {Complex | Array | Matrix} Returns a complex value */ - "gcd": function(a, b) { + var complex = typed('complex', { + '': function () { + return type.Complex.ZERO; + }, - parse(a, b); + 'number': function (x) { + return new type.Complex(x, 0); + }, - // gcd(a / b, c / d) = gcd(a, c) / lcm(b, d) + 'number, number': function (re, im) { + return new type.Complex(re, im); + }, - return new Fraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]); - }, + // TODO: this signature should be redundant + 'BigNumber, BigNumber': function (re, im) { + return new type.Complex(re.toNumber(), im.toNumber()); + }, - /** - * Calculates the fractional lcm of two rational numbers - * - * Ex: new Fraction(5,8).lcm(3,7) => 15 - */ - "lcm": function(a, b) { + 'Complex': function (x) { + return x.clone(); + }, - parse(a, b); + 'string': function (x) { + return type.Complex(x); // for example '2 + 3i' + }, - // lcm(a / b, c / d) = lcm(a, c) / gcd(b, d) + 'null': function (x) { + return type.Complex(0); + }, - if (P["n"] === 0 && this["n"] === 0) { - return new Fraction; - } - return new Fraction(P["n"] * this["n"], gcd(P["n"], this["n"]) * gcd(P["d"], this["d"])); - }, + 'Object': function (x) { + if('re' in x && 'im' in x) { + return new type.Complex(x.re, x.im); + } - /** - * Calculates the ceil of a rational number - * - * Ex: new Fraction('4.(3)').ceil() => (5 / 1) - **/ - "ceil": function(places) { + if ('r' in x && 'phi' in x) { + return new type.Complex(x); + } - places = Math.pow(10, places || 0); + throw new Error('Expected object with either properties re and im, or properties r and phi.'); + }, - if (isNaN(this["n"]) || isNaN(this["d"])) { - return new Fraction(NaN); + 'Array | Matrix': function (x) { + return deepMap(x, complex); } - return new Fraction(Math.ceil(places * this["s"] * this["n"] / this["d"]), places); - }, - - /** - * Calculates the floor of a rational number - * - * Ex: new Fraction('4.(3)').floor() => (4 / 1) - **/ - "floor": function(places) { + }); - places = Math.pow(10, places || 0); + complex.toTex = { + 0: '0', + 1: '\\left(${args[0]}\\right)', + 2: '\\left(\\left(${args[0]}\\right)+' + + latex$$1.symbols['i'] + '\\cdot\\left(${args[1]}\\right)\\right)' + }; - if (isNaN(this["n"]) || isNaN(this["d"])) { - return new Fraction(NaN); - } - return new Fraction(Math.floor(places * this["s"] * this["n"] / this["d"]), places); - }, + return complex; + } - /** - * Rounds a rational numbers - * - * Ex: new Fraction('4.(3)').round() => (4 / 1) - **/ - "round": function(places) { + var name$8 = 'complex'; + var factory_1$8 = factory$8; - places = Math.pow(10, places || 0); + var complex$2 = { + name: name$8, + factory: factory_1$8 + }; - if (isNaN(this["n"]) || isNaN(this["d"])) { - return new Fraction(NaN); - } - return new Fraction(Math.round(places * this["s"] * this["n"] / this["d"]), places); - }, + var complex$3 = [ + // type + Complex_1, - /** - * Gets the inverse of the fraction, means numerator and denumerator are exchanged - * - * Ex: new Fraction([-3, 4]).inverse() => -4 / 3 - **/ - "inverse": function() { + // construction function + complex$2 + ]; - return new Fraction(this["s"] * this["d"], this["n"]); - }, + var fraction = createCommonjsModule(function (module, exports) { + /** + * @license Fraction.js v4.0.8 09/09/2015 + * http://www.xarg.org/2014/03/rational-numbers-in-javascript/ + * + * Copyright (c) 2015, Robert Eisele (robert@xarg.org) + * Dual licensed under the MIT or GPL Version 2 licenses. + **/ - /** - * Calculates the fraction to some integer exponent - * - * Ex: new Fraction(-1,2).pow(-3) => -8 - */ - "pow": function(m) { - if (m < 0) { - return new Fraction(Math.pow(this['s'] * this["d"], -m), Math.pow(this["n"], -m)); - } else { - return new Fraction(Math.pow(this['s'] * this["n"], m), Math.pow(this["d"], m)); - } - }, + /** + * + * This class offers the possibility to calculate fractions. + * You can pass a fraction in different formats. Either as array, as double, as string or as an integer. + * + * Array/Object form + * [ 0 => , 1 => ] + * [ n => , d => ] + * + * Integer form + * - Single integer value + * + * Double form + * - Single double value + * + * String form + * 123.456 - a simple double + * 123/456 - a string fraction + * 123.'456' - a double with repeating decimal places + * 123.(456) - synonym + * 123.45'6' - a double with repeating last place + * 123.45(6) - synonym + * + * Example: + * + * var f = new Fraction("9.4'31'"); + * f.mul([-4, 3]).div(4.9); + * + */ - /** - * Check if two rational numbers are the same - * - * Ex: new Fraction(19.6).equals([98, 5]); - **/ - "equals": function(a, b) { + (function(root) { - parse(a, b); - return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"]; // Same as compare() === 0 - }, + // Maximum search depth for cyclic rational numbers. 2000 should be more than enough. + // Example: 1/7 = 0.(142857) has 6 repeating decimal places. + // If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits + var MAX_CYCLE_LEN = 2000; - /** - * Check if two rational numbers are the same - * - * Ex: new Fraction(19.6).equals([98, 5]); - **/ - "compare": function(a, b) { + // Parsed data to avoid calling "new" all the time + var P = { + "s": 1, + "n": 0, + "d": 1 + }; - parse(a, b); - var t = (this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"]); - return (0 < t) - (t < 0); - }, - - "simplify": function(eps) { - - // First naive implementation, needs improvement - - if (isNaN(this['n']) || isNaN(this['d'])) { - return this; - } + function createError(name) { - var cont = this['abs']()['toContinued'](); - - eps = eps || 0.001; - - function rec(a) { - if (a.length === 1) - return new Fraction(a[0]); - return rec(a.slice(1))['inverse']()['add'](a[0]); - } - - for (var i = 0; i < cont.length; i++) { - var tmp = rec(cont.slice(0, i + 1)); - if (tmp['sub'](this['abs']())['abs']().valueOf() < eps) { - return tmp['mul'](this['s']); - } + function errorConstructor() { + var temp = Error.apply(this, arguments); + temp['name'] = this['name'] = name; + this['stack'] = temp['stack']; + this['message'] = temp['message']; } - return this; - }, - - /** - * Check if two rational numbers are divisible - * - * Ex: new Fraction(19.6).divisible(1.5); - */ - "divisible": function(a, b) { - parse(a, b); - return !(!(P["n"] * this["d"]) || ((this["n"] * P["d"]) % (P["n"] * this["d"]))); - }, + /** + * Error constructor + * + * @constructor + */ + function IntermediateInheritor() {} + IntermediateInheritor.prototype = Error.prototype; + errorConstructor.prototype = new IntermediateInheritor(); - /** - * Returns a decimal representation of the fraction - * - * Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183 - **/ - 'valueOf': function() { + return errorConstructor; + } - return this["s"] * this["n"] / this["d"]; - }, + var DivisionByZero = Fraction['DivisionByZero'] = createError('DivisionByZero'); + var InvalidParameter = Fraction['InvalidParameter'] = createError('InvalidParameter'); - /** - * Returns a string-fraction representation of a Fraction object - * - * Ex: new Fraction("1.'3'").toFraction() => "4 1/3" - **/ - 'toFraction': function(excludeWhole) { + function assign(n, s) { - var whole, str = ""; - var n = this["n"]; - var d = this["d"]; - if (this["s"] < 0) { - str += '-'; + if (isNaN(n = parseInt(n, 10))) { + throwInvalidParam(); } + return n * s; + } - if (d === 1) { - str += n; - } else { + function throwInvalidParam() { + throw new InvalidParameter(); + } - if (excludeWhole && (whole = Math.floor(n / d)) > 0) { - str += whole; - str += " "; - n %= d; - } + var parse = function(p1, p2) { - str += n; - str += '/'; - str += d; - } - return str; - }, + var n = 0, d = 1, s = 1; + var v = 0, w = 0, x = 0, y = 1, z = 1; - /** - * Returns a latex representation of a Fraction object - * - * Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}" - **/ - 'toLatex': function(excludeWhole) { + var A = 0, B = 1; + var C = 1, D = 1; - var whole, str = ""; - var n = this["n"]; - var d = this["d"]; - if (this["s"] < 0) { - str += '-'; - } + var N = 10000000; + var M; - if (d === 1) { - str += n; - } else { + if (p1 === undefined || p1 === null) { + /* void */ + } else if (p2 !== undefined) { + n = p1; + d = p2; + s = n * d; + } else + switch (typeof p1) { - if (excludeWhole && (whole = Math.floor(n / d)) > 0) { - str += whole; - n %= d; - } + case "object": + { + if ("d" in p1 && "n" in p1) { + n = p1["n"]; + d = p1["d"]; + if ("s" in p1) + n *= p1["s"]; + } else if (0 in p1) { + n = p1[0]; + if (1 in p1) + d = p1[1]; + } else { + throwInvalidParam(); + } + s = n * d; + break; + } + case "number": + { + if (p1 < 0) { + s = p1; + p1 = -p1; + } - str += "\\frac{"; - str += n; - str += '}{'; - str += d; - str += '}'; - } - return str; - }, + if (p1 % 1 === 0) { + n = p1; + } else if (p1 > 0) { // check for != 0, scale would become NaN (log(0)), which converges really slow - /** - * Returns an array of continued fraction elements - * - * Ex: new Fraction("7/8").toContinued() => [0,1,7] - */ - 'toContinued': function() { + if (p1 >= 1) { + z = Math.pow(10, Math.floor(1 + Math.log(p1) / Math.LN10)); + p1 /= z; + } - var t; - var a = this['n']; - var b = this['d']; - var res = []; + // Using Farey Sequences + // http://www.johndcook.com/blog/2010/10/20/best-rational-approximation/ + + while (B <= N && D <= N) { + M = (A + C) / (B + D); + + if (p1 === M) { + if (B + D <= N) { + n = A + C; + d = B + D; + } else if (D > B) { + n = C; + d = D; + } else { + n = A; + d = B; + } + break; - if (isNaN(this['n']) || isNaN(this['d'])) { - return res; - } - - do { - res.push(Math.floor(a / b)); - t = a % b; - a = b; - b = t; - } while (a !== 1); - - return res; - }, - - /** - * Creates a string representation of a fraction with all digits - * - * Ex: new Fraction("100.'91823'").toString() => "100.(91823)" - **/ - 'toString': function() { + } else { - var g; - var N = this["n"]; - var D = this["d"]; + if (p1 > M) { + A += C; + B += D; + } else { + C += A; + D += B; + } - if (isNaN(N) || isNaN(D)) { - return "NaN"; - } + if (B > N) { + n = C; + d = D; + } else { + n = A; + d = B; + } + } + } + n *= z; + } else if (isNaN(p1) || isNaN(p2)) { + d = n = NaN; + } + break; + } + case "string": + { + B = p1.match(/\d+|./g); - if (!Fraction['REDUCE']) { - g = gcd(N, D); - N /= g; - D /= g; - } + if (B === null) + throwInvalidParam(); - var dec = 15; // 15 = decimal places when no repitation + if (B[A] === '-') {// Check for minus sign at the beginning + s = -1; + A++; + } else if (B[A] === '+') {// Check for plus sign at the beginning + A++; + } - var cycLen = cycleLen(N, D); // Cycle length - var cycOff = cycleStart(N, D, cycLen); // Cycle start + if (B.length === A + 1) { // Check if it's just a simple number "1234" + w = assign(B[A++], s); + } else if (B[A + 1] === '.' || B[A] === '.') { // Check if it's a decimal number - var str = this['s'] === -1 ? "-" : ""; + if (B[A] !== '.') { // Handle 0.5 and .5 + v = assign(B[A++], s); + } + A++; - str += N / D | 0; + // Check for decimal places + if (A + 1 === B.length || B[A + 1] === '(' && B[A + 3] === ')' || B[A + 1] === "'" && B[A + 3] === "'") { + w = assign(B[A], s); + y = Math.pow(10, B[A].length); + A++; + } - N %= D; - N *= 10; + // Check for repeating places + if (B[A] === '(' && B[A + 2] === ')' || B[A] === "'" && B[A + 2] === "'") { + x = assign(B[A + 1], s); + z = Math.pow(10, B[A + 1].length) - 1; + A += 3; + } - if (N) - str += "."; + } else if (B[A + 1] === '/' || B[A + 1] === ':') { // Check for a simple fraction "123/456" or "123:456" + w = assign(B[A], s); + y = assign(B[A + 2], 1); + A += 3; + } else if (B[A + 3] === '/' && B[A + 1] === ' ') { // Check for a complex fraction "123 1/2" + v = assign(B[A], s); + w = assign(B[A + 2], s); + y = assign(B[A + 4], 1); + A += 5; + } - if (cycLen) { + if (B.length <= A) { // Check for more tokens on the stack + d = y * z; + s = /* void */ + n = x + d * v + z * w; + break; + } - for (var i = cycOff; i--; ) { - str += N / D | 0; - N %= D; - N *= 10; - } - str += "("; - for (var i = cycLen; i--; ) { - str += N / D | 0; - N %= D; - N *= 10; - } - str += ")"; - } else { - for (var i = dec; N && i--; ) { - str += N / D | 0; - N %= D; - N *= 10; + /* Fall through on error */ + } + default: + throwInvalidParam(); } - } - return str; - } - }; - if (typeof undefined === "function" && undefined["amd"]) { - undefined([], function() { - return Fraction; - }); - } else { - Object.defineProperty(exports, "__esModule", {'value': true}); - Fraction['default'] = Fraction; - Fraction['Fraction'] = Fraction; - module['exports'] = Fraction; - } - -})(commonjsGlobal); -}); - -unwrapExports(fraction); - -/** - * Attach type information - */ -fraction.prototype.type = 'Fraction'; -fraction.prototype.isFraction = true; - -/** - * Get a JSON representation of a Fraction containing type information - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Fraction", "n": 3, "d": 8}` - */ -fraction.prototype.toJSON = function () { - return { - mathjs: 'Fraction', - n: this.s * this.n, - d: this.d - }; -}; - -/** - * Instantiate a Fraction from a JSON object - * @param {Object} json a JSON object structured as: - * `{"mathjs": "Fraction", "n": 3, "d": 8}` - * @return {BigNumber} - */ -fraction.fromJSON = function (json) { - return new fraction(json); -}; - - -function factory$9 (type, config, load, typed) { - return fraction; -} - -var name$9 = 'Fraction'; -var path$3 = 'type'; -var factory_1$9 = factory$9; - -var Fraction_1 = { - name: name$9, - path: path$3, - factory: factory_1$9 -}; - -function factory$10 (type, config, load, typed) { - /** - * Create a fraction convert a value to a fraction. - * - * Syntax: - * math.fraction(numerator, denominator) - * math.fraction({n: numerator, d: denominator}) - * math.fraction(matrix: Array | Matrix) Turn all matrix entries - * into fractions - * - * Examples: - * - * math.fraction(1, 3); - * math.fraction('2/3'); - * math.fraction({n: 2, d: 3}); - * math.fraction([0.2, 0.25, 1.25]); - * - * See also: - * - * bignumber, number, string, unit - * - * @param {number | string | Fraction | BigNumber | Array | Matrix} [args] - * Arguments specifying the numerator and denominator of - * the fraction - * @return {Fraction | Array | Matrix} Returns a fraction - */ - var fraction = typed('fraction', { - 'number': function (x) { - if (!isFinite(x) || isNaN(x)) { - throw new Error(x + ' cannot be represented as a fraction'); + if (d === 0) { + throw new DivisionByZero(); } - return new type.Fraction(x); - }, - - 'string': function (x) { - return new type.Fraction(x); - }, - - 'number, number': function (numerator, denominator) { - return new type.Fraction(numerator, denominator); - }, - - 'null': function (x) { - return new type.Fraction(0); - }, - - 'BigNumber': function (x) { - return new type.Fraction(x.toString()); - }, + P["s"] = s < 0 ? -1 : 1; + P["n"] = Math.abs(n); + P["d"] = Math.abs(d); + }; - 'Fraction': function (x) { - return x; // fractions are immutable - }, + function modpow(b, e, m) { - 'Object': function (x) { - return new type.Fraction(x); - }, + var r = 1; + for (; e > 0; b = (b * b) % m, e >>= 1) { - 'Array | Matrix': function (x) { - return deepMap(x, fraction); + if (e & 1) { + r = (r * b) % m; + } + } + return r; } - }); - return fraction; -} - -var name$10 = 'fraction'; -var factory_1$10 = factory$10; - -var fraction$2 = { - name: name$10, - factory: factory_1$10 -}; - -var fraction$3 = [ - // type - Fraction_1, - - // construction function - fraction$2 -]; - -/** - * Create a range error with the message: - * 'Dimension mismatch ( != )' - * @param {number | number[]} actual The actual size - * @param {number | number[]} expected The expected size - * @param {string} [relation='!='] Optional relation between actual - * and expected size: '!=', '<', etc. - * @extends RangeError - */ -function DimensionError(actual, expected, relation) { - if (!(this instanceof DimensionError)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.actual = actual; - this.expected = expected; - this.relation = relation; - - this.message = 'Dimension mismatch (' + - (Array.isArray(actual) ? ('[' + actual.join(', ') + ']') : actual) + - ' ' + (this.relation || '!=') + ' ' + - (Array.isArray(expected) ? ('[' + expected.join(', ') + ']') : expected) + - ')'; - - this.stack = (new Error()).stack; -} - -DimensionError.prototype = new RangeError(); -DimensionError.prototype.constructor = RangeError; -DimensionError.prototype.name = 'DimensionError'; -DimensionError.prototype.isDimensionError = true; - -var DimensionError_1 = DimensionError; - -/** - * Create a range error with the message: - * 'Index out of range (index < min)' - * 'Index out of range (index < max)' - * - * @param {number} index The actual index - * @param {number} [min=0] Minimum index (included) - * @param {number} [max] Maximum index (excluded) - * @extends RangeError - */ -function IndexError(index, min, max) { - if (!(this instanceof IndexError)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.index = index; - if (arguments.length < 3) { - this.min = 0; - this.max = min; - } - else { - this.min = min; - this.max = max; - } - if (this.min !== undefined && this.index < this.min) { - this.message = 'Index out of range (' + this.index + ' < ' + this.min + ')'; - } - else if (this.max !== undefined && this.index >= this.max) { - this.message = 'Index out of range (' + this.index + ' > ' + (this.max - 1) + ')'; - } - else { - this.message = 'Index out of range (' + this.index + ')'; - } + function cycleLen(n, d) { - this.stack = (new Error()).stack; -} + for (; d % 2 === 0; + d /= 2) { + } -IndexError.prototype = new RangeError(); -IndexError.prototype.constructor = RangeError; -IndexError.prototype.name = 'IndexError'; -IndexError.prototype.isIndexError = true; + for (; d % 5 === 0; + d /= 5) { + } -var IndexError_1 = IndexError; + if (d === 1) // Catch non-cyclic numbers + return 0; -var array = createCommonjsModule(function (module, exports) { + // If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem: + // 10^(d-1) % d == 1 + // However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone, + // as we want to translate the numbers to strings. + var rem = 10 % d; + var t = 1; + for (; rem !== 1; t++) { + rem = rem * 10 % d; + if (t > MAX_CYCLE_LEN) + return 0; // Returning 0 here means that we don't print it as a cyclic number. It's likely that the answer is `d-1` + } + return t; + } + function cycleStart(n, d, len) { + var rem1 = 1; + var rem2 = modpow(10, len, d); -/** - * 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 - */ -exports.size = function (x) { - var s = []; + for (var t = 0; t < 300; t++) { // s < ~log10(Number.MAX_VALUE) + // Solve 10^s == 10^(s+t) (mod d) - while (Array.isArray(x)) { - s.push(x.length); - x = x[0]; - } + if (rem1 === rem2) + return t; - return s; -}; + rem1 = rem1 * 10 % d; + rem2 = rem2 * 10 % d; + } + return 0; + } -/** - * 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; + function gcd(a, b) { - if (len != size[dim]) { - throw new DimensionError_1(len, size[dim]); - } + if (!a) + return b; + if (!b) + return a; - 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 DimensionError_1(size.length - 1, size.length, '<'); + while (1) { + a %= b; + if (!a) + return b; + b %= a; + if (!b) + return a; } - _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 DimensionError_1(size.length + 1, size.length, '>'); + /** + * Module constructor + * + * @constructor + * @param {number|Fraction=} a + * @param {number=} b + */ + function Fraction(a, b) { + + if (!(this instanceof Fraction)) { + return new Fraction(a, b); } - } - } -} -/** - * 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 - */ -exports.validate = function(array, size) { - var isScalar = (size.length == 0); - if (isScalar) { - // scalar - if (Array.isArray(array)) { - throw new DimensionError_1(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 - */ -exports.validateIndex = function(index, length) { - if (!number.isNumber(index) || !number.isInteger(index)) { - throw new TypeError('Index must be an integer (value: ' + index + ')'); - } - if (index < 0 || (typeof length === 'number' && index >= length)) { - throw new IndexError_1(index, length); - } -}; - -/** - * Resize a multi dimensional array. The resized array is returned. - * @param {Array} array Array to be resized - * @param {Array.} 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 - */ -exports.resize = function(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.isNumber(value) || !number.isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + string.format(size) + ')'); - } - }); + parse(a, b); - // 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; + if (Fraction['REDUCE']) { + a = gcd(P["d"], P["n"]); // Abuse a + } else { + a = 1; } - _resize(elem, size, dimNext, defaultValue); + + this["s"] = P["s"]; + this["n"] = P["n"] / a; + this["d"] = P["d"] / a; } - // create new child arrays - for (i = minLen; i < newLen; i++) { - // get child array - elem = []; - array[i] = elem; + /** + * Boolean global variable to be able to disable automatic reduction of the fraction + * + */ + Fraction['REDUCE'] = 1; - // resize new child array - _resize(elem, size, dimNext, defaultValue); - } - } - else { - // last dimension + Fraction.prototype = { - // remove dimensions of existing values - for (i = 0; i < minLen; i++) { - while (Array.isArray(array[i])) { - array[i] = array[i][0]; - } - } + "s": 1, + "n": 0, + "d": 1, - // fill new elements with the default value - for (i = minLen; i < newLen; i++) { - array[i] = defaultValue; - } - } -} + /** + * Calculates the absolute value + * + * Ex: new Fraction(-4).abs() => 4 + **/ + "abs": function() { -/** - * Re-shape a multi dimensional array to fit the specified dimensions - * @param {Array} array Array to be reshaped - * @param {Array.} 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 - */ -exports.reshape = function(array, sizes) { - var flatArray = exports.flatten(array); - var newArray; + return new Fraction(this["n"], this["d"]); + }, - var product = function (arr) { - return arr.reduce(function (prev, curr) { - return prev * curr; - }); - }; + /** + * Inverts the sign of the current fraction + * + * Ex: new Fraction(-4).neg() => 4 + **/ + "neg": function() { - if (!Array.isArray(array) || !Array.isArray(sizes)) { - throw new TypeError('Array expected'); - } + return new Fraction(-this["s"] * this["n"], this["d"]); + }, - if (sizes.length === 0) { - throw new DimensionError_1(0, product(exports.size(array)), '!='); - } + /** + * Adds two rational numbers + * + * Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30 + **/ + "add": function(a, b) { + + parse(a, b); + return new Fraction( + this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"], + this["d"] * P["d"] + ); + }, - try { - newArray = _reshape(flatArray, sizes); - } catch (e) { - if (e instanceof DimensionError_1) { - throw new DimensionError_1( - product(sizes), - product(exports.size(array)), - '!=' - ); - } - throw e; - } + /** + * Subtracts two rational numbers + * + * Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30 + **/ + "sub": function(a, b) { + + parse(a, b); + return new Fraction( + this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"], + this["d"] * P["d"] + ); + }, - if (flatArray.length > 0) { - throw new DimensionError_1( - product(sizes), - product(exports.size(array)), - '!=' - ); - } + /** + * Multiplies two rational numbers + * + * Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111 + **/ + "mul": function(a, b) { + + parse(a, b); + return new Fraction( + this["s"] * P["s"] * this["n"] * P["n"], + this["d"] * P["d"] + ); + }, - return newArray; -}; + /** + * Divides two rational numbers + * + * Ex: new Fraction("-17.(345)").inverse().div(3) + **/ + "div": function(a, b) { + + parse(a, b); + return new Fraction( + this["s"] * P["s"] * this["n"] * P["d"], + this["d"] * P["n"] + ); + }, -/** - * Recursively re-shape a multi dimensional array to fit the specified dimensions - * @param {Array} array Array to be reshaped - * @param {Array.} 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 accumulator = []; - var i; + /** + * Clones the actual object + * + * Ex: new Fraction("-17.(345)").clone() + **/ + "clone": function() { + return new Fraction(this); + }, - if (sizes.length === 0) { - if (array.length === 0) { - throw new DimensionError_1(null, null, '!='); - } - return array.shift(); - } - for (i = 0; i < sizes[0]; i += 1) { - accumulator.push(_reshape(array, sizes.slice(1))); - } - return accumulator; -} + /** + * Calculates the modulo of two rational numbers - a more precise fmod + * + * Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6) + **/ + "mod": function(a, b) { + if (isNaN(this['n']) || isNaN(this['d'])) { + return new Fraction(NaN); + } -/** - * Squeeze a multi dimensional array - * @param {Array} array - * @param {Array} [size] - * @returns {Array} returns the array itself - */ -exports.squeeze = function(array, size) { - var s = size || exports.size(array); + if (a === undefined) { + return new Fraction(this["s"] * this["n"] % this["d"], 1); + } - // squeeze outer dimensions - while (Array.isArray(array) && array.length === 1) { - array = array[0]; - s.shift(); - } + parse(a, b); + if (0 === P["n"] && 0 === this["d"]) { + Fraction(0, 0); // Throw DivisionByZero + } - // find the first dimension to be squeezed - var dims = s.length; - while (s[dims - 1] === 1) { - dims--; - } + /* + * First silly attempt, kinda slow + * + return that["sub"]({ + "n": num["n"] * Math.floor((this.n / this.d) / (num.n / num.d)), + "d": num["d"], + "s": this["s"] + });*/ - // squeeze inner dimensions - if (dims < s.length) { - array = _squeeze(array, dims, 0); - s.length = dims; - } + /* + * New attempt: a1 / b1 = a2 / b2 * q + r + * => b2 * a1 = a2 * b1 * q + b1 * b2 * r + * => (b2 * a1 % a2 * b1) / (b1 * b2) + */ + return new Fraction( + this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]), + P["d"] * this["d"] + ); + }, - return array; -}; + /** + * Calculates the fractional gcd of two rational numbers + * + * Ex: new Fraction(5,8).gcd(3,7) => 1/56 + */ + "gcd": function(a, b) { -/** - * 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; + parse(a, b); - 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]; - } - } + // gcd(a / b, c / d) = gcd(a, c) / lcm(b, d) - 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} [size] Current size of array. - * @returns {Array} returns the array itself - * @private - */ -exports.unsqueeze = function(array, dims, outer, size) { - var s = size || exports.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) - */ -exports.flatten = function(array) { - if (!Array.isArray(array)) { - //if not an array, return as is - return array; - } - var flat = []; + return new Fraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]); + }, - array.forEach(function callback(value) { - if (Array.isArray(value)) { - value.forEach(callback); //traverse through sub-arrays recursively - } - else { - flat.push(value); - } - }); + /** + * Calculates the fractional lcm of two rational numbers + * + * Ex: new Fraction(5,8).lcm(3,7) => 15 + */ + "lcm": function(a, b) { - return flat; -}; - -/** - * A safe map - * @param {Array} array - * @param {function} callback - */ -exports.map = function (array, callback) { - return Array.prototype.map.call(array, callback); -}; - -/** - * A safe forEach - * @param {Array} array - * @param {function} callback - */ -exports.forEach = function (array, callback) { - Array.prototype.forEach.call(array, callback); -}; - -/** - * A safe filter - * @param {Array} array - * @param {function} callback - */ -exports.filter = function (array, callback) { - if (exports.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 - */ -exports.filterRegExp = function (array, regexp) { - if (exports.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 - */ -exports.join = function (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 - */ -exports.identify = function(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 (5 / 1) + **/ + "ceil": function(places) { - // get storage format constructor - var constructor = Matrix._storage[format]; - if (!constructor) { - throw new SyntaxError('Unsupported matrix storage format: ' + format); - } + places = Math.pow(10, places || 0); - // return storage constructor - return constructor; - }; + if (isNaN(this["n"]) || isNaN(this["d"])) { + return new Fraction(NaN); + } + return new Fraction(Math.ceil(places * this["s"] * this["n"] / this["d"]), places); + }, - // a map with all constructors for all storage types - Matrix._storage = {}; + /** + * Calculates the floor of a rational number + * + * Ex: new Fraction('4.(3)').floor() => (4 / 1) + **/ + "floor": function(places) { - /** - * Get the storage format used by the matrix. - * - * Usage: - * var format = matrix.storage() // retrieve storage format - * - * @return {string} The storage format. - */ - Matrix.prototype.storage = function () { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke storage on a Matrix interface'); - }; - - /** - * Get the datatype of the data stored in the matrix. - * - * Usage: - * var format = matrix.datatype() // retrieve matrix datatype - * - * @return {string} The datatype. - */ - Matrix.prototype.datatype = function () { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke datatype on a Matrix interface'); - }; + places = Math.pow(10, places || 0); - /** - * Create a new Matrix With the type of the current matrix instance - * @param {Array | Object} data - * @param {string} [datatype] - */ - Matrix.prototype.create = function (data, datatype) { - throw new Error('Cannot invoke create on a Matrix interface'); - }; + if (isNaN(this["n"]) || isNaN(this["d"])) { + return new Fraction(NaN); + } + return new Fraction(Math.floor(places * this["s"] * this["n"] / this["d"]), places); + }, - /** - * 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=0] Default value, filled in on new entries when - * the matrix is resized. If not provided, - * new matrix elements will be filled with zeros. - */ - Matrix.prototype.subset = function (index, replacement, defaultValue) { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke subset on a Matrix interface'); - }; + /** + * Rounds a rational numbers + * + * Ex: new Fraction('4.(3)').round() => (4 / 1) + **/ + "round": function(places) { - /** - * Get a single element from the matrix. - * @param {number[]} index Zero-based index - * @return {*} value - */ - Matrix.prototype.get = function (index) { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke get on a Matrix interface'); - }; + places = Math.pow(10, places || 0); - /** - * 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 (index, value, defaultValue) { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke set on a Matrix interface'); - }; + if (isNaN(this["n"]) || isNaN(this["d"])) { + return new Fraction(NaN); + } + return new Fraction(Math.round(places * this["s"] * this["n"] / this["d"]), places); + }, - /** - * Resize the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (resize in place). - * - * @param {number[]} size The new size the matrix should have. - * @param {*} [defaultValue=0] Default value, filled in on new entries. - * If not provided, the matrix elements will - * be filled with zeros. - * @param {boolean} [copy] Return a resized copy of the matrix - * - * @return {Matrix} The resized matrix - */ - Matrix.prototype.resize = function (size, defaultValue) { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke resize on a Matrix interface'); - }; + /** + * Gets the inverse of the fraction, means numerator and denumerator are exchanged + * + * Ex: new Fraction([-3, 4]).inverse() => -4 / 3 + **/ + "inverse": function() { - /** - * Reshape the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (reshape in place). - * - * @param {number[]} size The new size the matrix should have. - * @param {boolean} [copy] Return a reshaped copy of the matrix - * - * @return {Matrix} The reshaped matrix - */ - Matrix.prototype.reshape = function (size, defaultValue) { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke reshape on a Matrix interface'); - }; + return new Fraction(this["s"] * this["d"], this["n"]); + }, - /** - * Create a clone of the matrix - * @return {Matrix} clone - */ - Matrix.prototype.clone = function () { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke clone on a Matrix interface'); - }; + /** + * Calculates the fraction to some integer exponent + * + * Ex: new Fraction(-1,2).pow(-3) => -8 + */ + "pow": function(m) { - /** - * Retrieve the size of the matrix. - * @returns {number[]} size - */ - Matrix.prototype.size = function() { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke size on a Matrix interface'); - }; + if (m < 0) { + return new Fraction(Math.pow(this['s'] * this["d"], -m), Math.pow(this["n"], -m)); + } else { + return new Fraction(Math.pow(this['s'] * this["n"], m), Math.pow(this["d"], m)); + } + }, - /** - * Create a new matrix with the results of the callback function executed on - * each entry of the matrix. - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * @param {boolean} [skipZeros] Invoke callback function for non-zero values only. - * - * @return {Matrix} matrix - */ - Matrix.prototype.map = function (callback, skipZeros) { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke map on a Matrix interface'); - }; + /** + * Check if two rational numbers are the same + * + * Ex: new Fraction(19.6).equals([98, 5]); + **/ + "equals": function(a, b) { - /** - * Execute a callback function on each entry of the matrix. - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - */ - Matrix.prototype.forEach = function (callback) { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke forEach on a Matrix interface'); - }; + parse(a, b); + return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"]; // Same as compare() === 0 + }, - /** - * Create an Array with a copy of the data of the Matrix - * @returns {Array} array - */ - Matrix.prototype.toArray = function () { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke toArray on a Matrix interface'); - }; + /** + * Check if two rational numbers are the same + * + * Ex: new Fraction(19.6).equals([98, 5]); + **/ + "compare": function(a, b) { - /** - * Get the primitive value of the Matrix: a multidimensional array - * @returns {Array} array - */ - Matrix.prototype.valueOf = function () { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke valueOf on a Matrix interface'); - }; + parse(a, b); + var t = (this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"]); + return (0 < t) - (t < 0); + }, + + "simplify": function(eps) { + + // First naive implementation, needs improvement + + if (isNaN(this['n']) || isNaN(this['d'])) { + return this; + } - /** - * Get a string representation of the matrix, with optional formatting options. - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ - Matrix.prototype.format = function (options) { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke format on a Matrix interface'); - }; + var cont = this['abs']()['toContinued'](); + + eps = eps || 0.001; + + function rec(a) { + if (a.length === 1) + return new Fraction(a[0]); + return rec(a.slice(1))['inverse']()['add'](a[0]); + } + + for (var i = 0; i < cont.length; i++) { + var tmp = rec(cont.slice(0, i + 1)); + if (tmp['sub'](this['abs']())['abs']().valueOf() < eps) { + return tmp['mul'](this['s']); + } + } + return this; + }, - /** - * Get a string representation of the matrix - * @returns {string} str - */ - Matrix.prototype.toString = function () { - // must be implemented by each of the Matrix implementations - throw new Error('Cannot invoke toString on a Matrix interface'); - }; - - // exports - return Matrix; -} + /** + * Check if two rational numbers are divisible + * + * Ex: new Fraction(19.6).divisible(1.5); + */ + "divisible": function(a, b) { + + parse(a, b); + return !(!(P["n"] * this["d"]) || ((this["n"] * P["d"]) % (P["n"] * this["d"]))); + }, + + /** + * Returns a decimal representation of the fraction + * + * Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183 + **/ + 'valueOf': function() { -var name$11 = 'Matrix'; -var path$4 = 'type'; -var factory_1$11 = factory$11; + return this["s"] * this["n"] / this["d"]; + }, -var Matrix = { - name: name$11, - path: path$4, - factory: factory_1$11 -}; + /** + * Returns a string-fraction representation of a Fraction object + * + * Ex: new Fraction("1.'3'").toFraction() => "4 1/3" + **/ + 'toFraction': function(excludeWhole) { -var string$2 = utils.string; -var array$1 = utils.array; -var object$1 = utils.object; -var number$1 = utils.number; + var whole, str = ""; + var n = this["n"]; + var d = this["d"]; + if (this["s"] < 0) { + str += '-'; + } -var isArray = Array.isArray; -var isNumber$1 = number$1.isNumber; -var isInteger = number$1.isInteger; -var isString$1 = string$2.isString; + if (d === 1) { + str += n; + } else { -var validateIndex = array$1.validateIndex; + if (excludeWhole && (whole = Math.floor(n / d)) > 0) { + str += whole; + str += " "; + n %= d; + } -function factory$12 (type, config, load, typed) { - var Matrix$$1 = load(Matrix); // force loading Matrix (do not use via type.Matrix) + str += n; + str += '/'; + str += d; + } + return str; + }, - /** - * Dense Matrix implementation. A regular, dense matrix, supporting multi-dimensional matrices. This is the default matrix type. - * @class DenseMatrix - */ - function DenseMatrix(data, datatype) { - if (!(this instanceof DenseMatrix)) - throw new SyntaxError('Constructor must be called with the new operator'); - if (datatype && !isString$1(datatype)) - throw new Error('Invalid datatype: ' + datatype); + /** + * Returns a latex representation of a Fraction object + * + * Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}" + **/ + 'toLatex': function(excludeWhole) { + + var whole, str = ""; + var n = this["n"]; + var d = this["d"]; + if (this["s"] < 0) { + str += '-'; + } + + if (d === 1) { + str += n; + } else { + + if (excludeWhole && (whole = Math.floor(n / d)) > 0) { + str += whole; + n %= d; + } + + str += "\\frac{"; + str += n; + str += '}{'; + str += d; + str += '}'; + } + return str; + }, + + /** + * Returns an array of continued fraction elements + * + * Ex: new Fraction("7/8").toContinued() => [0,1,7] + */ + 'toContinued': function() { + + var t; + var a = this['n']; + var b = this['d']; + var res = []; + + if (isNaN(this['n']) || isNaN(this['d'])) { + return res; + } + + do { + res.push(Math.floor(a / b)); + t = a % b; + a = b; + b = t; + } while (a !== 1); + + return res; + }, + + /** + * Creates a string representation of a fraction with all digits + * + * Ex: new Fraction("100.'91823'").toString() => "100.(91823)" + **/ + 'toString': function() { + + var g; + var N = this["n"]; + var D = this["d"]; + + if (isNaN(N) || isNaN(D)) { + return "NaN"; + } + + if (!Fraction['REDUCE']) { + g = gcd(N, D); + N /= g; + D /= g; + } + + var dec = 15; // 15 = decimal places when no repitation + + var cycLen = cycleLen(N, D); // Cycle length + var cycOff = cycleStart(N, D, cycLen); // Cycle start + + var str = this['s'] === -1 ? "-" : ""; - if (type.isMatrix(data)) { - // check data is a DenseMatrix - if (data.type === 'DenseMatrix') { - // clone data & size - this._data = object$1.clone(data._data); - this._size = object$1.clone(data._size); - this._datatype = datatype || data._datatype; + str += N / D | 0; + + N %= D; + N *= 10; + + if (N) + str += "."; + + if (cycLen) { + + for (var i = cycOff; i--; ) { + str += N / D | 0; + N %= D; + N *= 10; + } + str += "("; + for (var i = cycLen; i--; ) { + str += N / D | 0; + N %= D; + N *= 10; + } + str += ")"; + } else { + for (var i = dec; N && i--; ) { + str += N / D | 0; + N %= D; + N *= 10; + } + } + return str; } - else { - // build data from existing matrix - this._data = data.toArray(); - this._size = data.size(); - this._datatype = datatype || data._datatype; - } - } - else if (data && isArray(data.data) && isArray(data.size)) { - // initialize fields from JSON representation - this._data = data.data; - this._size = data.size; - this._datatype = datatype || data.datatype; - } - else if (isArray(data)) { - // replace nested Matrices with Arrays - this._data = preprocess(data); - // get the dimensions of the array - this._size = array$1.size(this._data); - // verify the dimensions of the array, TODO: compute size while processing array - array$1.validate(this._data, this._size); - // data type unknown - this._datatype = datatype; - } - else if (data) { - // unsupported type - throw new TypeError('Unsupported type of data (' + utils.types.type(data) + ')'); - } - else { - // nothing provided - this._data = []; - this._size = [0]; - this._datatype = datatype; + }; + + if (typeof undefined === "function" && undefined["amd"]) { + undefined([], function() { + return Fraction; + }); + } else { + Object.defineProperty(exports, "__esModule", {'value': true}); + Fraction['default'] = Fraction; + Fraction['Fraction'] = Fraction; + module['exports'] = Fraction; } - } - - DenseMatrix.prototype = new Matrix$$1(); + + })(commonjsGlobal); + }); + + unwrapExports(fraction); /** * Attach type information */ - DenseMatrix.prototype.type = 'DenseMatrix'; - DenseMatrix.prototype.isDenseMatrix = true; + fraction.prototype.type = 'Fraction'; + fraction.prototype.isFraction = true; /** - * Get the storage format used by the matrix. - * - * Usage: - * var format = matrix.storage() // retrieve storage format - * - * @memberof DenseMatrix - * @return {string} The storage format. + * Get a JSON representation of a Fraction containing type information + * @returns {Object} Returns a JSON object structured as: + * `{"mathjs": "Fraction", "n": 3, "d": 8}` */ - DenseMatrix.prototype.storage = function () { - return 'dense'; + fraction.prototype.toJSON = function () { + return { + mathjs: 'Fraction', + n: this.s * this.n, + d: this.d + }; }; /** - * Get the datatype of the data stored in the matrix. - * - * Usage: - * var format = matrix.datatype() // retrieve matrix datatype - * - * @memberof DenseMatrix - * @return {string} The datatype. + * Instantiate a Fraction from a JSON object + * @param {Object} json a JSON object structured as: + * `{"mathjs": "Fraction", "n": 3, "d": 8}` + * @return {BigNumber} */ - DenseMatrix.prototype.datatype = function () { - return this._datatype; + fraction.fromJSON = function (json) { + return new fraction(json); }; - /** - * Create a new DenseMatrix - * @memberof DenseMatrix - * @param {Array} data - * @param {string} [datatype] - */ - DenseMatrix.prototype.create = function (data, datatype) { - return new DenseMatrix(data, datatype); - }; - /** - * 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 - * - * @memberof DenseMatrix - * @param {Index} index - * @param {Array | DenseMatrix | *} [replacement] - * @param {*} [defaultValue=0] Default value, filled in on new entries when - * the matrix is resized. If not provided, - * new matrix elements will be filled with zeros. - */ - DenseMatrix.prototype.subset = function (index, replacement, defaultValue) { - switch (arguments.length) { - case 1: - return _get(this, index); + function factory$9 (type, config, load, typed) { + return fraction; + } - // intentional fall through - case 2: - case 3: - return _set(this, index, replacement, defaultValue); + var name$9 = 'Fraction'; + var path$3 = 'type'; + var factory_1$9 = factory$9; - default: - throw new SyntaxError('Wrong number of arguments'); - } + var Fraction_1 = { + name: name$9, + path: path$3, + factory: factory_1$9 }; - - /** - * Get a single element from the matrix. - * @memberof DenseMatrix - * @param {number[]} index Zero-based index - * @return {*} value - */ - DenseMatrix.prototype.get = function (index) { - if (!isArray(index)) - throw new TypeError('Array expected'); - if (index.length != this._size.length) - throw new DimensionError_1(index.length, this._size.length); - // check index - for (var x = 0; x < index.length; x++) - validateIndex(index[x], this._size[x]); + function factory$10 (type, config, load, typed) { + /** + * Create a fraction convert a value to a fraction. + * + * Syntax: + * math.fraction(numerator, denominator) + * math.fraction({n: numerator, d: denominator}) + * math.fraction(matrix: Array | Matrix) Turn all matrix entries + * into fractions + * + * Examples: + * + * math.fraction(1, 3); + * math.fraction('2/3'); + * math.fraction({n: 2, d: 3}); + * math.fraction([0.2, 0.25, 1.25]); + * + * See also: + * + * bignumber, number, string, unit + * + * @param {number | string | Fraction | BigNumber | Array | Matrix} [args] + * Arguments specifying the numerator and denominator of + * the fraction + * @return {Fraction | Array | Matrix} Returns a fraction + */ + var fraction = typed('fraction', { + 'number': function (x) { + if (!isFinite(x) || isNaN(x)) { + throw new Error(x + ' cannot be represented as a fraction'); + } - 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 new type.Fraction(x); + }, - return data; - }; - - /** - * Replace a single element in the matrix. - * @memberof DenseMatrix - * @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 {DenseMatrix} self - */ - DenseMatrix.prototype.set = function (index, value, defaultValue) { - if (!isArray(index)) - throw new TypeError('Array expected'); - if (index.length < this._size.length) - throw new DimensionError_1(index.length, this._size.length, '<'); + 'string': function (x) { + return new type.Fraction(x); + }, + + 'number, number': function (numerator, denominator) { + return new type.Fraction(numerator, denominator); + }, + + 'null': function (x) { + return new type.Fraction(0); + }, + + 'BigNumber': function (x) { + return new type.Fraction(x.toString()); + }, + + 'Fraction': function (x) { + return x; // fractions are immutable + }, - var i, ii, index_i; + 'Object': function (x) { + return new type.Fraction(x); + }, - // enlarge matrix when needed - var size = index.map(function (i) { - return i + 1; + 'Array | Matrix': function (x) { + return deepMap(x, fraction); + } }); - _fit(this, size, defaultValue); - // traverse over the dimensions - var data = this._data; - for (i = 0, ii = index.length - 1; i < ii; i++) { - index_i = index[i]; - validateIndex(index_i, data.length); - data = data[index_i]; - } + return fraction; + } - // set new value - index_i = index[index.length - 1]; - validateIndex(index_i, data.length); - data[index_i] = value; + var name$10 = 'fraction'; + var factory_1$10 = factory$10; - return this; + var fraction$2 = { + name: name$10, + factory: factory_1$10 }; - + + var fraction$3 = [ + // type + Fraction_1, + + // construction function + fraction$2 + ]; + /** - * Get a submatrix of this matrix - * @memberof DenseMatrix - * @param {DenseMatrix} matrix - * @param {Index} index Zero-based index - * @private + * Create a range error with the message: + * 'Dimension mismatch ( != )' + * @param {number | number[]} actual The actual size + * @param {number | number[]} expected The expected size + * @param {string} [relation='!='] Optional relation between actual + * and expected size: '!=', '<', etc. + * @extends RangeError */ - function _get (matrix, index) { - if (!type.isIndex(index)) { - throw new TypeError('Invalid index'); + function DimensionError(actual, expected, relation) { + if (!(this instanceof DimensionError)) { + throw new SyntaxError('Constructor must be called with the new operator'); } - 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_1(size.length, matrix._size.length); - } + this.actual = actual; + this.expected = expected; + this.relation = relation; - // validate if any of the ranges in the index is out of range - var min = index.min(); - var max = index.max(); - for (var i = 0, ii = matrix._size.length; i < ii; i++) { - validateIndex(min[i], matrix._size[i]); - validateIndex(max[i], matrix._size[i]); - } + this.message = 'Dimension mismatch (' + + (Array.isArray(actual) ? ('[' + actual.join(', ') + ']') : actual) + + ' ' + (this.relation || '!=') + ' ' + + (Array.isArray(expected) ? ('[' + expected.join(', ') + ']') : expected) + + ')'; - // retrieve submatrix - // TODO: more efficient when creating an empty matrix and setting _data and _size manually - return new DenseMatrix(_getSubmatrix(matrix._data, index, size.length, 0), matrix._datatype); - } + this.stack = (new Error()).stack; } - + + DimensionError.prototype = new RangeError(); + DimensionError.prototype.constructor = RangeError; + DimensionError.prototype.name = 'DimensionError'; + DimensionError.prototype.isDimensionError = true; + + var DimensionError_1 = DimensionError; + /** - * Recursively get a submatrix of a multi dimensional matrix. - * Index is not checked for correct number or length of dimensions. - * @memberof DenseMatrix - * @param {Array} data - * @param {Index} index - * @param {number} dims Total number of dimensions - * @param {number} dim Current dimension - * @return {Array} submatrix - * @private + * Create a range error with the message: + * 'Index out of range (index < min)' + * 'Index out of range (index < max)' + * + * @param {number} index The actual index + * @param {number} [min=0] Minimum index (included) + * @param {number} [max] Maximum index (excluded) + * @extends RangeError */ - function _getSubmatrix (data, index, dims, dim) { - var last = (dim === dims - 1); - var range = index.dimension(dim); + function IndexError(index, min, max) { + if (!(this instanceof IndexError)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - if (last) { - return range.map(function (i) { - validateIndex(i, data.length); - return data[i]; - }).valueOf(); + this.index = index; + if (arguments.length < 3) { + this.min = 0; + this.max = min; } else { - return range.map(function (i) { - validateIndex(i, data.length); - var child = data[i]; - return _getSubmatrix(child, index, dims, dim + 1); - }).valueOf(); - } - } - - /** - * Replace a submatrix in this matrix - * Indexes are zero-based. - * @memberof DenseMatrix - * @param {DenseMatrix} matrix - * @param {Index} index - * @param {DenseMatrix | Array | *} submatrix - * @param {*} defaultValue Default value, filled in on new entries when - * the matrix is resized. - * @return {DenseMatrix} matrix - * @private - */ - function _set (matrix, index, submatrix, defaultValue) { - if (!index || index.isIndex !== true) { - throw new TypeError('Invalid index'); + this.min = min; + this.max = max; } - // 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 (type.isMatrix(submatrix)) { - sSize = submatrix.size(); - submatrix = submatrix.valueOf(); + if (this.min !== undefined && this.index < this.min) { + this.message = 'Index out of range (' + this.index + ' < ' + this.min + ')'; + } + else if (this.max !== undefined && this.index >= this.max) { + this.message = 'Index out of range (' + this.index + ' > ' + (this.max - 1) + ')'; } else { - sSize = array$1.size(submatrix); + this.message = 'Index out of range (' + this.index + ')'; } - if (isScalar) { - // set a scalar + this.stack = (new Error()).stack; + } - // check whether submatrix is a scalar - if (sSize.length !== 0) { - throw new TypeError('Scalar expected'); - } + IndexError.prototype = new RangeError(); + IndexError.prototype.constructor = RangeError; + IndexError.prototype.name = 'IndexError'; + IndexError.prototype.isIndexError = true; - matrix.set(index.min(), submatrix, defaultValue); - } - else { - // set a submatrix + var IndexError_1 = IndexError; + + var array = createCommonjsModule(function (module, exports) { - // validate dimensions - if (iSize.length < matrix._size.length) { - throw new DimensionError_1(iSize.length, matrix._size.length, '<'); - } - if (sSize.length < iSize.length) { - // calculate number of missing outer dimensions - var i = 0; - var outer = 0; - while (iSize[i] === 1 && sSize[i] === 1) { - i++; - } - while (iSize[i] === 1) { - outer++; - i++; - } - // unsqueeze both outer and inner dimensions - submatrix = array$1.unsqueeze(submatrix, iSize.length, outer, sSize); - } - // check whether the size of the submatrix matches the index size - if (!object$1.deepEqual(iSize, sSize)) { - throw new DimensionError_1(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 = iSize.length, - dim = 0; - _setSubmatrix (matrix._data, index, submatrix, dims, dim); - } - return matrix; - } - - /** - * Replace a submatrix of a multi dimensional matrix. - * @memberof DenseMatrix - * @param {Array} data - * @param {Index} index - * @param {Array} submatrix - * @param {number} dims Total number of dimensions - * @param {number} dim - * @private - */ - function _setSubmatrix (data, index, submatrix, dims, dim) { - var last = (dim === dims - 1), - range = index.dimension(dim); - - if (last) { - range.forEach(function (dataIndex, subIndex) { - validateIndex(dataIndex); - data[dataIndex] = submatrix[subIndex[0]]; - }); - } - else { - range.forEach(function (dataIndex, subIndex) { - validateIndex(dataIndex); - _setSubmatrix(data[dataIndex], index, submatrix[subIndex[0]], dims, dim + 1); - }); - } - } - /** - * Resize the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (resize in place). - * - * @memberof DenseMatrix - * @param {number[]} size The new size the matrix should have. - * @param {*} [defaultValue=0] Default value, filled in on new entries. - * If not provided, the matrix elements will - * be filled with zeros. - * @param {boolean} [copy] Return a resized copy of the matrix - * - * @return {Matrix} The resized matrix + * 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 */ - DenseMatrix.prototype.resize = function (size, defaultValue, copy) { - // validate arguments - if (!isArray(size)) - throw new TypeError('Array expected'); + exports.size = function (x) { + var s = []; - // matrix to resize - var m = copy ? this.clone() : this; - // resize matrix - return _resize(m, size, defaultValue); - }; - - var _resize = function (matrix, size, defaultValue) { - // check size - if (size.length === 0) { - // first value in matrix - var v = matrix._data; - // go deep - while (isArray(v)) { - v = v[0]; - } - return v; + while (Array.isArray(x)) { + s.push(x.length); + x = x[0]; } - // resize matrix - matrix._size = size.slice(0); // copy the array - matrix._data = array$1.resize(matrix._data, matrix._size, defaultValue); - // return matrix - return matrix; - }; - /** - * Reshape the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (reshape in place). - * - * NOTE: This might be better suited to copy by default, instead of modifying - * in place. For now, it operates in place to remain consistent with - * resize(). - * - * @memberof DenseMatrix - * @param {number[]} size The new size the matrix should have. - * @param {boolean} [copy] Return a reshaped copy of the matrix - * - * @return {Matrix} The reshaped matrix - */ - DenseMatrix.prototype.reshape = function (size, copy) { - var m = copy ? this.clone() : this; - - m._data = array$1.reshape(m._data, size); - m._size = size.slice(0); - return m; + return s; }; - + /** - * Enlarge the matrix when it is smaller than given size. - * If the matrix is larger or equal sized, nothing is done. - * @memberof DenseMatrix - * @param {DenseMatrix} matrix The matrix to be resized - * @param {number[]} size - * @param {*} defaultValue Default value, filled in on new entries. + * 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 _fit(matrix, size, defaultValue) { - var newSize = matrix._size.slice(0), // copy the array - changed = false; + function _validate(array, size, dim) { + var i; + var len = array.length; - // add dimensions when needed - while (newSize.length < size.length) { - newSize.push(0); - changed = true; + if (len != size[dim]) { + throw new DimensionError_1(len, size[dim]); } - // enlarge size when needed - for (var i = 0, ii = size.length; i < ii; i++) { - if (size[i] > newSize[i]) { - newSize[i] = size[i]; - changed = true; + 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 DimensionError_1(size.length - 1, size.length, '<'); + } + _validate(array[i], size, dimNext); } } - - if (changed) { - // resize only when size is changed - _resize(matrix, newSize, defaultValue); + else { + // last dimension. none of the childs may be an array + for (i = 0; i < len; i++) { + if (Array.isArray(array[i])) { + throw new DimensionError_1(size.length + 1, size.length, '>'); + } + } } } - + /** - * Create a clone of the matrix - * @memberof DenseMatrix - * @return {DenseMatrix} clone + * 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 */ - DenseMatrix.prototype.clone = function () { - var m = new DenseMatrix({ - data: object$1.clone(this._data), - size: object$1.clone(this._size), - datatype: this._datatype - }); - return m; + exports.validate = function(array, size) { + var isScalar = (size.length == 0); + if (isScalar) { + // scalar + if (Array.isArray(array)) { + throw new DimensionError_1(array.length, 0); + } + } + else { + // array + _validate(array, size, 0); + } }; - + /** - * Retrieve the size of the matrix. - * @memberof DenseMatrix - * @returns {number[]} size + * 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 */ - DenseMatrix.prototype.size = function() { - return this._size.slice(0); // return a clone of _size + exports.validateIndex = function(index, length) { + if (!number.isNumber(index) || !number.isInteger(index)) { + throw new TypeError('Index must be an integer (value: ' + index + ')'); + } + if (index < 0 || (typeof length === 'number' && index >= length)) { + throw new IndexError_1(index, length); + } }; - + /** - * Create a new matrix with the results of the callback function executed on - * each entry of the matrix. - * @memberof DenseMatrix - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * - * @return {DenseMatrix} matrix + * Resize a multi dimensional array. The resized array is returned. + * @param {Array} array Array to be resized + * @param {Array.} 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 */ - DenseMatrix.prototype.map = function (callback) { - // matrix instance - var me = this; - var recurse = function (value, index) { - if (isArray(value)) { - return value.map(function (child, i) { - return recurse(child, index.concat(i)); - }); - } - else { - return callback(value, index, me); + exports.resize = function(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.isNumber(value) || !number.isInteger(value) || value < 0) { + throw new TypeError('Invalid size, must contain positive integers ' + + '(size: ' + string.format(size) + ')'); } - }; - // return dense format - return new DenseMatrix({ - data: recurse(this._data, []), - size: object$1.clone(this._size), - datatype: this._datatype }); + + // recursively resize the array + var _defaultValue = (defaultValue !== undefined) ? defaultValue : 0; + _resize(array, size, 0, _defaultValue); + + return array; }; - + /** - * Execute a callback function on each entry of the matrix. - * @memberof DenseMatrix - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. + * 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 */ - DenseMatrix.prototype.forEach = function (callback) { - // matrix instance - var me = this; - var recurse = function (value, index) { - if (isArray(value)) { - value.forEach(function (child, i) { - recurse(child, index.concat(i)); - }); - } - else { - callback(value, index, me); + 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); } - }; - recurse(this._data, []); - }; - - /** - * Create an Array with a copy of the data of the DenseMatrix - * @memberof DenseMatrix - * @returns {Array} array - */ - DenseMatrix.prototype.toArray = function () { - return object$1.clone(this._data); - }; - - /** - * Get the primitive value of the DenseMatrix: a multidimensional array - * @memberof DenseMatrix - * @returns {Array} array - */ - DenseMatrix.prototype.valueOf = function () { - return this._data; - }; - - /** - * Get a string representation of the matrix, with optional formatting options. - * @memberof DenseMatrix - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ - DenseMatrix.prototype.format = function (options) { - return string$2.format(this._data, options); - }; - - /** - * Get a string representation of the matrix - * @memberof DenseMatrix - * @returns {string} str - */ - DenseMatrix.prototype.toString = function () { - return string$2.format(this._data); - }; - - /** - * Get a JSON representation of the matrix - * @memberof DenseMatrix - * @returns {Object} - */ - DenseMatrix.prototype.toJSON = function () { - return { - mathjs: 'DenseMatrix', - data: this._data, - size: this._size, - datatype: this._datatype - }; - }; - - /** - * Get the kth Matrix diagonal. - * - * @memberof DenseMatrix - * @param {number | BigNumber} [k=0] The kth diagonal where the vector will retrieved. - * - * @returns {Array} The array vector with the diagonal values. - */ - DenseMatrix.prototype.diagonal = function(k) { - // validate k if any - if (k) { - // convert BigNumber to a number - if (type.isBigNumber(k)) - k = k.toNumber(); - // is must be an integer - if (!isNumber$1(k) || !isInteger(k)) { - throw new TypeError ('The parameter k must be an integer number'); + + // 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 { - // default value - k = 0; - } - - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; + // last dimension - // rows & columns - var rows = this._size[0]; - var columns = this._size[1]; + // remove dimensions of existing values + for (i = 0; i < minLen; i++) { + while (Array.isArray(array[i])) { + array[i] = array[i][0]; + } + } - // number diagonal values - var n = Math.min(rows - kSub, columns - kSuper); - - // x is a matrix get diagonal from matrix - var data = []; - - // loop rows - for (var i = 0; i < n; i++) { - data[i] = this._data[i + kSub][i + kSuper]; + // fill new elements with the default value + for (i = minLen; i < newLen; i++) { + array[i] = defaultValue; + } } + } - // create DenseMatrix - return new DenseMatrix({ - data: data, - size: [n], - datatype: this._datatype - }); - }; - /** - * Create a diagonal matrix. - * - * @memberof DenseMatrix - * @param {Array} size The matrix size. - * @param {number | Array} value The values for the diagonal. - * @param {number | BigNumber} [k=0] The kth diagonal where the vector will be filled in. - * @param {number} [defaultValue] The default value for non-diagonal + * Re-shape a multi dimensional array to fit the specified dimensions + * @param {Array} array Array to be reshaped + * @param {Array.} sizes List of sizes for each dimension + * @returns {Array} Array whose data has been formatted to fit the + * specified dimensions * - * @returns {DenseMatrix} + * @throws {DimensionError} If the product of the new dimension sizes does + * not equal that of the old ones */ - DenseMatrix.diagonal = function (size, value, k, defaultValue, datatype) { - if (!isArray(size)) - throw new TypeError('Array expected, size parameter'); - if (size.length !== 2) - throw new Error('Only two dimensions matrix are supported'); - - // map size & validate - size = size.map(function (s) { - // check it is a big number - if (type.isBigNumber(s)) { - // convert it - s = s.toNumber(); - } - // validate arguments - if (!isNumber$1(s) || !isInteger(s) || s < 1) { - throw new Error('Size values must be positive integers'); - } - return s; - }); + exports.reshape = function(array, sizes) { + var flatArray = exports.flatten(array); + var newArray; - // validate k if any - if (k) { - // convert BigNumber to a number - if (type.isBigNumber(k)) - k = k.toNumber(); - // is must be an integer - if (!isNumber$1(k) || !isInteger(k)) { - throw new TypeError ('The parameter k must be an integer number'); - } - } - else { - // default value - k = 0; - } - - if (defaultValue && isString$1(datatype)) { - // convert defaultValue to the same datatype - defaultValue = typed.convert(defaultValue, datatype); - } + var product = function (arr) { + return arr.reduce(function (prev, curr) { + return prev * curr; + }); + }; - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // rows and columns - var rows = size[0]; - var columns = size[1]; - - // number of non-zero items - var n = Math.min(rows - kSub, columns - kSuper); - - // value extraction function - var _value; - - // check value - if (isArray(value)) { - // validate array - if (value.length !== n) { - // number of values in array must be n - throw new Error('Invalid value array length'); - } - // define function - _value = function (i) { - // return value @ i - return value[i]; - }; - } - else if (type.isMatrix(value)) { - // matrix size - var ms = value.size(); - // validate matrix - if (ms.length !== 1 || ms[0] !== n) { - // number of values in array must be n - throw new Error('Invalid matrix length'); - } - // define function - _value = function (i) { - // return value @ i - return value.get([i]); - }; - } - else { - // define function - _value = function () { - // return value - return value; - }; - } - - // discover default value if needed - if (!defaultValue) { - // check first value in array - defaultValue = type.isBigNumber(_value(0)) ? new type.BigNumber(0) : 0; + if (!Array.isArray(array) || !Array.isArray(sizes)) { + throw new TypeError('Array expected'); } - // empty array - var data = []; + if (sizes.length === 0) { + throw new DimensionError_1(0, product(exports.size(array)), '!='); + } - // check we need to resize array - if (size.length > 0) { - // resize array - data = array$1.resize(data, size, defaultValue); - // fill diagonal - for (var d = 0; d < n; d++) { - data[d + kSub][d + kSuper] = _value(d); + try { + newArray = _reshape(flatArray, sizes); + } catch (e) { + if (e instanceof DimensionError_1) { + throw new DimensionError_1( + product(sizes), + product(exports.size(array)), + '!=' + ); } + throw e; } - - // create DenseMatrix - return new DenseMatrix({ - data: data, - size: [rows, columns] - }); - }; - /** - * Generate a matrix from a JSON object - * @memberof DenseMatrix - * @param {Object} json An object structured like - * `{"mathjs": "DenseMatrix", data: [], size: []}`, - * where mathjs is optional - * @returns {DenseMatrix} - */ - DenseMatrix.fromJSON = function (json) { - return new DenseMatrix(json); - }; - - /** - * Swap rows i and j in Matrix. - * - * @memberof DenseMatrix - * @param {number} i Matrix row index 1 - * @param {number} j Matrix row index 2 - * - * @return {Matrix} The matrix reference - */ - DenseMatrix.prototype.swapRows = function (i, j) { - // check index - if (!isNumber$1(i) || !isInteger(i) || !isNumber$1(j) || !isInteger(j)) { - throw new Error('Row index must be positive integers'); - } - // check dimensions - if (this._size.length !== 2) { - throw new Error('Only two dimensional matrix is supported'); + if (flatArray.length > 0) { + throw new DimensionError_1( + product(sizes), + product(exports.size(array)), + '!=' + ); } - // validate index - validateIndex(i, this._size[0]); - validateIndex(j, this._size[0]); - // swap rows - DenseMatrix._swapRows(i, j, this._data); - // return current instance - return this; + return newArray; }; /** - * Swap rows i and j in Dense Matrix data structure. + * Recursively re-shape a multi dimensional array to fit the specified dimensions + * @param {Array} array Array to be reshaped + * @param {Array.} sizes List of sizes for each dimension + * @returns {Array} Array whose data has been formatted to fit the + * specified dimensions * - * @param {number} i Matrix row index 1 - * @param {number} j Matrix row index 2 + * @throws {DimensionError} If the product of the new dimension sizes does + * not equal that of the old ones */ - DenseMatrix._swapRows = function (i, j, data) { - // swap values i <-> j - var vi = data[i]; - data[i] = data[j]; - data[j] = vi; - }; + function _reshape(array, sizes) { + var accumulator = []; + var i; - /** - * Preprocess data, which can be an Array or DenseMatrix with nested Arrays and - * Matrices. Replaces all nested Matrices with Arrays - * @memberof DenseMatrix - * @param {Array} data - * @return {Array} data - */ - function preprocess(data) { - for (var i = 0, ii = data.length; i < ii; i++) { - var elem = data[i]; - if (isArray(elem)) { - data[i] = preprocess(elem); - } - else if (elem && elem.isMatrix === true) { - data[i] = preprocess(elem.valueOf()); + if (sizes.length === 0) { + if (array.length === 0) { + throw new DimensionError_1(null, null, '!='); } + return array.shift(); } - - return data; + for (i = 0; i < sizes[0]; i += 1) { + accumulator.push(_reshape(array, sizes.slice(1))); + } + return accumulator; } - // register this type in the base class Matrix - type.Matrix._storage.dense = DenseMatrix; - type.Matrix._storage['default'] = DenseMatrix; - // exports - return DenseMatrix; -} - -var name$12 = 'DenseMatrix'; -var path$5 = 'type'; -var factory_1$12 = factory$12; -var lazy$2 = false; // no lazy loading, as we alter type.Matrix._storage + /** + * Squeeze a multi dimensional array + * @param {Array} array + * @param {Array} [size] + * @returns {Array} returns the array itself + */ + exports.squeeze = function(array, size) { + var s = size || exports.size(array); -var DenseMatrix = { - name: name$12, - path: path$5, - factory: factory_1$12, - lazy: lazy$2 -}; + // squeeze outer dimensions + while (Array.isArray(array) && array.length === 1) { + array = array[0]; + s.shift(); + } -/** - * Compares two BigNumbers. - * @param {BigNumber} x First value to compare - * @param {BigNumber} 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 - */ -var nearlyEqual = function nearlyEqual(x, y, epsilon) { - // if epsilon is null or undefined, test whether x and y are exactly equal - if (epsilon == null) { - return x.eq(y); - } + // 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; + } - // use "==" operator, handles infinities - if (x.eq(y)) { - return true; - } + return array; + }; - // NaN - if (x.isNaN() || y.isNaN()) { - return false; - } + /** + * 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; - // at this point x and y should be finite - if(x.isFinite() && y.isFinite()) { - // check numbers are very close, needed when comparing numbers near zero - var diff = x.minus(y).abs(); - if (diff.isZero()) { - return true; + if (dim < dims) { + var next = dim + 1; + for (i = 0, ii = array.length; i < ii; i++) { + array[i] = _squeeze(array[i], dims, next); + } } else { - // use relative error - var max = x.constructor.max(x.abs(), y.abs()); - return diff.lte(max.times(epsilon)); + while (Array.isArray(array)) { + array = array[0]; + } } - } - - // Infinite and Number or negative Infinite and positive Infinite cases - return false; -}; - -var nearlyEqual$1 = number.nearlyEqual; + return array; + } -function factory$13 (type, config, load, typed) { - /** - * Test whether two values are equal. - * - * @param {number | BigNumber | Fraction | boolean | Complex | Unit} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Complex} y Second value to compare - * @return {boolean} Returns true when the compared values are equal, else returns false + * 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} [size] Current size of array. + * @returns {Array} returns the array itself * @private */ - var equalScalar = typed('equalScalar', { - - 'boolean, boolean': function (x, y) { - return x === y; - }, - - 'number, number': function (x, y) { - return x === y || nearlyEqual$1(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.eq(y) || nearlyEqual(x, y, config.epsilon); - }, - - 'Fraction, Fraction': function (x, y) { - return x.equals(y); - }, - - 'Complex, Complex': function (x, y) { - return x.equals(y); - }, + exports.unsqueeze = function(array, dims, outer, size) { + var s = size || exports.size(array); - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); + // unsqueeze outer dimensions + if (outer) { + for (var i = 0; i < outer; i++) { + array = [array]; + s.unshift(1); } - return equalScalar(x.value, y.value); } - }); - - return equalScalar; -} - -var factory_1$13 = factory$13; - -var equalScalar = { - factory: factory_1$13 -}; - -var array$2 = utils.array; -var object$2 = utils.object; -var string$3 = utils.string; -var number$2 = utils.number; - -var isArray$1 = Array.isArray; -var isNumber$2 = number$2.isNumber; -var isInteger$1 = number$2.isInteger; -var isString$2 = string$3.isString; -var validateIndex$1 = array$2.validateIndex; + // unsqueeze inner dimensions + array = _unsqueeze(array, dims, 0); + while (s.length < dims) { + s.push(1); + } -function factory$14 (type, config, load, typed) { - var Matrix$$1 = load(Matrix); // force loading Matrix (do not use via type.Matrix) - var equalScalar$$1 = load(equalScalar); + return array; + }; /** - * Sparse Matrix implementation. This type implements a Compressed Column Storage format - * for sparse matrices. - * @class SparseMatrix + * 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 SparseMatrix(data, datatype) { - if (!(this instanceof SparseMatrix)) - throw new SyntaxError('Constructor must be called with the new operator'); - if (datatype && !isString$2(datatype)) - throw new Error('Invalid datatype: ' + datatype); - - if (type.isMatrix(data)) { - // create from matrix - _createFromMatrix(this, data, datatype); - } - else if (data && isArray$1(data.index) && isArray$1(data.ptr) && isArray$1(data.size)) { - // initialize fields - this._values = data.values; - this._index = data.index; - this._ptr = data.ptr; - this._size = data.size; - this._datatype = datatype || data.datatype; - } - else if (isArray$1(data)) { - // create from array - _createFromArray(this, data, datatype); - } - else if (data) { - // unsupported type - throw new TypeError('Unsupported type of data (' + utils.types.type(data) + ')'); - } - else { - // nothing provided - this._values = []; - this._index = []; - this._ptr = [0]; - this._size = [0, 0]; - this._datatype = datatype; - } - } - - var _createFromMatrix = function (matrix, source, datatype) { - // check matrix type - if (source.type === 'SparseMatrix') { - // clone arrays - matrix._values = source._values ? object$2.clone(source._values) : undefined; - matrix._index = object$2.clone(source._index); - matrix._ptr = object$2.clone(source._ptr); - matrix._size = object$2.clone(source._size); - matrix._datatype = datatype || source._datatype; + 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 { - // build from matrix data - _createFromArray(matrix, source.valueOf(), datatype || source._datatype); - } - }; - - var _createFromArray = function (matrix, data, datatype) { - // initialize fields - matrix._values = []; - matrix._index = []; - matrix._ptr = []; - matrix._datatype = datatype; - // discover rows & columns, do not use math.size() to avoid looping array twice - var rows = data.length; - var columns = 0; - - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - if (isString$2(datatype)) { - // find signature that matches (datatype, datatype) - eq = typed.find(equalScalar$$1, [datatype, datatype]) || equalScalar$$1; - // convert 0 to the same datatype - zero = typed.convert(0, datatype); - } - - // check we have rows (empty array) - if (rows > 0) { - // column index - var j = 0; - do { - // store pointer to values index - matrix._ptr.push(matrix._index.length); - // loop rows - for (var i = 0; i < rows; i++) { - // current row - var row = data[i]; - // check row is an array - if (isArray$1(row)) { - // update columns if needed (only on first column) - if (j === 0 && columns < row.length) - columns = row.length; - // check row has column - if (j < row.length) { - // value - var v = row[j]; - // check value != 0 - if (!eq(v, zero)) { - // store value - matrix._values.push(v); - // index - matrix._index.push(i); - } - } - } - else { - // update columns if needed (only on first column) - if (j === 0 && columns < 1) - columns = 1; - // check value != 0 (row is a scalar) - if (!eq(row, zero)) { - // store value - matrix._values.push(row); - // index - matrix._index.push(i); - } - } - } - // increment index - j++; + for (var d = dim; d < dims; d++) { + array = [array]; } - while (j < columns); } - // store number of values in ptr - matrix._ptr.push(matrix._index.length); - // size - matrix._size = [rows, columns]; - }; - - SparseMatrix.prototype = new Matrix$$1(); + return array; + } /** - * Attach type information + * 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) */ - SparseMatrix.prototype.type = 'SparseMatrix'; - SparseMatrix.prototype.isSparseMatrix = true; + exports.flatten = function(array) { + if (!Array.isArray(array)) { + //if not an array, return as is + return array; + } + var flat = []; - /** - * Get the storage format used by the matrix. - * - * Usage: - * var format = matrix.storage() // retrieve storage format - * - * @memberof SparseMatrix - * @return {string} The storage format. - */ - SparseMatrix.prototype.storage = function () { - return 'sparse'; + array.forEach(function callback(value) { + if (Array.isArray(value)) { + value.forEach(callback); //traverse through sub-arrays recursively + } + else { + flat.push(value); + } + }); + + return flat; }; /** - * Get the datatype of the data stored in the matrix. - * - * Usage: - * var format = matrix.datatype() // retrieve matrix datatype - * - * @memberof SparseMatrix - * @return {string} The datatype. + * A safe map + * @param {Array} array + * @param {function} callback */ - SparseMatrix.prototype.datatype = function () { - return this._datatype; + exports.map = function (array, callback) { + return Array.prototype.map.call(array, callback); }; /** - * Create a new SparseMatrix - * @memberof SparseMatrix - * @param {Array} data - * @param {string} [datatype] + * A safe forEach + * @param {Array} array + * @param {function} callback */ - SparseMatrix.prototype.create = function (data, datatype) { - return new SparseMatrix(data, datatype); + exports.forEach = function (array, callback) { + Array.prototype.forEach.call(array, callback); }; /** - * Get the matrix density. - * - * Usage: - * var density = matrix.density() // retrieve matrix density - * - * @memberof SparseMatrix - * @return {number} The matrix density. - */ - SparseMatrix.prototype.density = function () { - // rows & columns - var rows = this._size[0]; - var columns = this._size[1]; - // calculate density - return rows !== 0 && columns !== 0 ? (this._index.length / (rows * columns)) : 0; - }; - - /** - * 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 - * - * @memberof SparseMatrix - * @param {Index} index - * @param {Array | Maytrix | *} [replacement] - * @param {*} [defaultValue=0] Default value, filled in on new entries when - * the matrix is resized. If not provided, - * new matrix elements will be filled with zeros. + * A safe filter + * @param {Array} array + * @param {function} callback */ - SparseMatrix.prototype.subset = function (index, replacement, defaultValue) { // check it is a pattern matrix - if (!this._values) - throw new Error('Cannot invoke subset on a Pattern only matrix'); - - // check arguments - switch (arguments.length) { - case 1: - return _getsubset(this, index); - - // intentional fall through - case 2: - case 3: - return _setsubset(this, index, replacement, defaultValue); - - default: - throw new SyntaxError('Wrong number of arguments'); + exports.filter = function (array, callback) { + if (exports.size(array).length !== 1) { + throw new Error('Only one dimensional matrices supported'); } + + return Array.prototype.filter.call(array, callback); }; - - var _getsubset = function (matrix, idx) { - // check idx - if (!type.isIndex(idx)) { - throw new TypeError('Invalid index'); - } - var isScalar = idx.isScalar(); - if (isScalar) { - // return a scalar - return matrix.get(idx.min()); - } - // validate dimensions - var size = idx.size(); - if (size.length != matrix._size.length) { - throw new DimensionError_1(size.length, matrix._size.length); + /** + * Filter values in a callback given a regular expression + * @param {Array} array + * @param {RegExp} regexp + * @return {Array} Returns the filtered array + * @private + */ + exports.filterRegExp = function (array, regexp) { + if (exports.size(array).length !== 1) { + throw new Error('Only one dimensional matrices supported'); } - // vars - var i, ii, k, kk; - - // validate if any of the ranges in the index is out of range - var min = idx.min(); - var max = idx.max(); - for (i = 0, ii = matrix._size.length; i < ii; i++) { - validateIndex$1(min[i], matrix._size[i]); - validateIndex$1(max[i], matrix._size[i]); - } - - // matrix arrays - var mvalues = matrix._values; - var mindex = matrix._index; - var mptr = matrix._ptr; - - // rows & columns dimensions for result matrix - var rows = idx.dimension(0); - var columns = idx.dimension(1); - - // workspace & permutation vector - var w = []; - var pv = []; - - // loop rows in resulting matrix - rows.forEach(function (i, r) { - // update permutation vector - pv[i] = r[0]; - // mark i in workspace - w[i] = true; + return Array.prototype.filter.call(array, function (entry) { + return regexp.test(entry); }); + }; - // result matrix arrays - var values = mvalues ? [] : undefined; - var index = []; - var ptr = []; - - // loop columns in result matrix - columns.forEach(function (j) { - // update ptr - ptr.push(index.length); - // loop values in column j - for (k = mptr[j], kk = mptr[j + 1]; k < kk; k++) { - // row - i = mindex[k]; - // check row is in result matrix - if (w[i] === true) { - // push index - index.push(pv[i]); - // check we need to process values - if (values) - values.push(mvalues[k]); - } - } - }); - // update ptr - ptr.push(index.length); - - // return matrix - return new SparseMatrix({ - values: values, - index: index, - ptr: ptr, - size: size, - datatype: matrix._datatype - }); + /** + * A safe join + * @param {Array} array + * @param {string} separator + */ + exports.join = function (array, separator) { + return Array.prototype.join.call(array, separator); }; - - var _setsubset = function (matrix, index, submatrix, defaultValue) { - // check index - if (!index || index.isIndex !== true) { - 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 (type.isMatrix(submatrix)) { - // submatrix size - sSize = submatrix.size(); - // use array representation - submatrix = submatrix.toArray(); - } - else { - // get submatrix size (array, scalar) - sSize = array$2.size(submatrix); + + /** + * 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 + */ + exports.identify = function(a) { + if (!Array.isArray(a)) { + throw new TypeError('Array input expected'); } - - // check index is a scalar - if (isScalar) { - // verify submatrix is a scalar - if (sSize.length !== 0) { - throw new TypeError('Scalar expected'); - } - // set value - matrix.set(index.min(), submatrix, defaultValue); + + if (a.length === 0) { + return a; } - else { - // validate dimensions, index size must be one or two dimensions - if (iSize.length !== 1 && iSize.length !== 2) { - throw new DimensionError_1(iSize.length, matrix._size.length, '<'); - } - - // check submatrix and index have the same dimensions - if (sSize.length < iSize.length) { - // calculate number of missing outer dimensions - var i = 0; - var outer = 0; - while (iSize[i] === 1 && sSize[i] === 1) { - i++; - } - while (iSize[i] === 1) { - outer++; - i++; - } - // unsqueeze both outer and inner dimensions - submatrix = array$2.unsqueeze(submatrix, iSize.length, outer, sSize); - } - - // check whether the size of the submatrix matches the index size - if (!object$2.deepEqual(iSize, sSize)) { - throw new DimensionError_1(iSize, sSize, '>'); + + var b = []; + var count = 0; + b[0] = {value: a[0], identifier: 0}; + for (var i=1; i rows - 1 || j > columns - 1) { - // resize matrix - _resize(this, Math.max(i + 1, rows), Math.max(j + 1, columns), defaultValue); - // update rows & columns - rows = this._size[0]; - columns = this._size[1]; - } + var boolean_1$1 = { + isBoolean: isBoolean + }; - // check i, j are valid - validateIndex$1(i, rows); - validateIndex$1(j, columns); + // function utils - // find value index - var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index); - // check k is prior to next column k and it is in the correct row - if (k < this._ptr[j + 1] && this._index[k] === i) { - // check value != 0 - if (!eq(v, zero)) { - // update value - this._values[k] = v; - } - else { - // remove value from matrix - _remove(k, j, this._values, this._index, this._ptr); - } - } - else { - // insert value @ (i, j) - _insert(k, i, j, v, this._values, this._index, this._ptr); - } - - return this; - }; - - var _getValueIndex = function(i, top, bottom, index) { - // check row is on the bottom side - if (bottom - top === 0) - return bottom; - // loop rows [top, bottom[ - for (var r = top; r < bottom; r++) { - // check we found value index - if (index[r] === i) - return r; - } - // we did not find row - return top; - }; - - var _remove = function (k, j, values, index, ptr) { - // remove value @ k - values.splice(k, 1); - index.splice(k, 1); - // update pointers - for (var x = j + 1; x < ptr.length; x++) - ptr[x]--; - }; - - var _insert = function (k, i, j, v, values, index, ptr) { - // insert value - values.splice(k, 0, v); - // update row for k - index.splice(k, 0, i); - // update column pointers - for (var x = j + 1; x < ptr.length; x++) - ptr[x]++; - }; - /** - * Resize the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (resize in place). - * - * @memberof SparseMatrix - * @param {number[]} size The new size the matrix should have. - * @param {*} [defaultValue=0] Default value, filled in on new entries. - * If not provided, the matrix elements will - * be filled with zeros. - * @param {boolean} [copy] Return a resized copy of the matrix + * Memoize a given function by caching the computed result. + * The cache of a memoized function can be cleared by deleting the `cache` + * property of the function. * - * @return {Matrix} The resized matrix + * @param {function} fn The function to be memoized. + * Must be a pure function. + * @param {function(args: Array)} [hasher] A custom hash builder. + * Is JSON.stringify by default. + * @return {function} Returns the memoized function */ - SparseMatrix.prototype.resize = function (size, defaultValue, copy) { - // validate arguments - if (!isArray$1(size)) - throw new TypeError('Array expected'); - if (size.length !== 2) - throw new Error('Only two dimensions matrix are supported'); - - // check sizes - size.forEach(function (value) { - if (!number$2.isNumber(value) || !number$2.isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + string$3.format(size) + ')'); + var memoize = function(fn, hasher) { + return function memoize() { + if (typeof memoize.cache !== 'object') { + memoize.cache = {}; } - }); - - // matrix to resize - var m = copy ? this.clone() : this; - // resize matrix - return _resize(m, size[0], size[1], defaultValue); - }; - - var _resize = function (matrix, rows, columns, defaultValue) { - // value to insert at the time of growing matrix - var value = defaultValue || 0; - - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - if (isString$2(matrix._datatype)) { - // find signature that matches (datatype, datatype) - eq = typed.find(equalScalar$$1, [matrix._datatype, matrix._datatype]) || equalScalar$$1; - // convert 0 to the same datatype - zero = typed.convert(0, matrix._datatype); - // convert value to the same datatype - value = typed.convert(value, matrix._datatype); - } - - // should we insert the value? - var ins = !eq(value, zero); - // old columns and rows - var r = matrix._size[0]; - var c = matrix._size[1]; - - var i, j, k; - - // check we need to increase columns - if (columns > c) { - // loop new columns - for (j = c; j < columns; j++) { - // update matrix._ptr for current column - matrix._ptr[j] = matrix._values.length; - // check we need to insert matrix._values - if (ins) { - // loop rows - for (i = 0; i < r; i++) { - // add new matrix._values - matrix._values.push(value); - // update matrix._index - matrix._index.push(i); - } - } - } - // store number of matrix._values in matrix._ptr - matrix._ptr[columns] = matrix._values.length; - } - else if (columns < c) { - // truncate matrix._ptr - matrix._ptr.splice(columns + 1, c - columns); - // truncate matrix._values and matrix._index - matrix._values.splice(matrix._ptr[columns], matrix._values.length); - matrix._index.splice(matrix._ptr[columns], matrix._index.length); - } - // update columns - c = columns; - - // check we need to increase rows - if (rows > r) { - // check we have to insert values - if (ins) { - // inserts - var n = 0; - // loop columns - for (j = 0; j < c; j++) { - // update matrix._ptr for current column - matrix._ptr[j] = matrix._ptr[j] + n; - // where to insert matrix._values - k = matrix._ptr[j + 1] + n; - // pointer - var p = 0; - // loop new rows, initialize pointer - for (i = r; i < rows; i++, p++) { - // add value - matrix._values.splice(k + p, 0, value); - // update matrix._index - matrix._index.splice(k + p, 0, i); - // increment inserts - n++; - } - } - // store number of matrix._values in matrix._ptr - matrix._ptr[c] = matrix._values.length; + var args = []; + for (var i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; } - } - else if (rows < r) { - // deletes - var d = 0; - // loop columns - for (j = 0; j < c; j++) { - // update matrix._ptr for current column - matrix._ptr[j] = matrix._ptr[j] - d; - // where matrix._values start for next column - var k0 = matrix._ptr[j]; - var k1 = matrix._ptr[j + 1] - d; - // loop matrix._index - for (k = k0; k < k1; k++) { - // row - i = matrix._index[k]; - // check we need to delete value and matrix._index - if (i > rows - 1) { - // remove value - matrix._values.splice(k, 1); - // remove item from matrix._index - matrix._index.splice(k, 1); - // increase deletes - d++; - } - } + + var hash = hasher ? hasher(args) : JSON.stringify(args); + if (!(hash in memoize.cache)) { + return memoize.cache[hash] = fn.apply(fn, args); } - // update matrix._ptr for current column - matrix._ptr[j] = matrix._values.length; - } - // update matrix._size - matrix._size[0] = rows; - matrix._size[1] = columns; - // return matrix - return matrix; + return memoize.cache[hash]; + }; }; /** - * Reshape the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (reshape in place). - * - * NOTE: This might be better suited to copy by default, instead of modifying - * in place. For now, it operates in place to remain consistent with - * resize(). - * - * @memberof SparseMatrix - * @param {number[]} size The new size the matrix should have. - * @param {boolean} [copy] Return a reshaped copy of the matrix - * - * @return {Matrix} The reshaped matrix + * Find the maximum number of arguments expected by a typed function. + * @param {function} fn A typed function + * @return {number} Returns the maximum number of expected arguments. + * Returns -1 when no signatures where found on the function. */ - SparseMatrix.prototype.reshape = function (size, copy) { + var maxArgumentCount = function (fn) { + return Object.keys(fn.signatures || {}) + .reduce(function (args, signature) { + var count = (signature.match(/,/g) || []).length + 1; + return Math.max(args, count); + }, -1); + }; - // validate arguments - if (!isArray$1(size)) - throw new TypeError('Array expected'); - if (size.length !== 2) - throw new Error('Sparse matrices can only be reshaped in two dimensions'); + /** + * Call a typed function with the + * @param {function} fn A function or typed function + * @return {number} Returns the maximum number of expected arguments. + * Returns -1 when no signatures where found on the function. + */ + var callWithRightArgumentCount = function (fn, args, argCount) { + return Object.keys(fn.signatures || {}) + .reduce(function (args, signature) { + var count = (signature.match(/,/g) || []).length + 1; + return Math.max(args, count); + }, -1); + }; - // check sizes - size.forEach(function (value) { - if (!number$2.isNumber(value) || !number$2.isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + string$3.format(size) + ')'); - } - }); + var _function = { + memoize: memoize, + maxArgumentCount: maxArgumentCount, + callWithRightArgumentCount: callWithRightArgumentCount + }; - // m * n must not change - if(this._size[0] * this._size[1] !== size[0] * size[1]) { - throw new Error('Reshaping sparse matrix will result in the wrong number of elements'); - } + var utils = createCommonjsModule(function (module, exports) { - // matrix to reshape - var m = copy ? this.clone() : this; + exports.array = array; + exports['boolean'] = boolean_1$1; + exports['function'] = _function; + exports.number = number; + exports.object = object; + exports.string = string; + exports.emitter = emitter; + }); + var utils_1 = utils.array; + var utils_2 = utils.number; + var utils_3 = utils.object; + var utils_4 = utils.string; + var utils_5 = utils.emitter; - // return unchanged if the same shape - if(this._size[0] === size[0] && this._size[1] === size[1]) { - return m; - } + var string$1 = utils.string; + + var isString = string$1.isString; - // Convert to COO format (generate a column index) - var colIndex = []; - for(var i=0; i= minRow && i <= maxRow) { - // zero values - if (!skipZeros) { - for (var x = p; x < i; x++) - invoke(0, x - minRow, j - minColumn); - } - // value @ k - invoke(matrix._values[k], i - minRow, j - minColumn); - } - // update pointer - p = i + 1; - } - // zero values - if (!skipZeros) { - for (var y = p; y <= maxRow; y++) - invoke(0, y - minRow, j - minColumn); - } - } - // store number of values in ptr - ptr.push(values.length); - // return sparse matrix - return new SparseMatrix({ - values: values, - index: index, - ptr: ptr, - size: [maxRow - minRow + 1, maxColumn - minColumn + 1] - }); + /** + * Resize the matrix to the given size. Returns a copy of the matrix when + * `copy=true`, otherwise return the matrix itself (resize in place). + * + * @param {number[]} size The new size the matrix should have. + * @param {*} [defaultValue=0] Default value, filled in on new entries. + * If not provided, the matrix elements will + * be filled with zeros. + * @param {boolean} [copy] Return a resized copy of the matrix + * + * @return {Matrix} The resized matrix + */ + Matrix.prototype.resize = function (size, defaultValue) { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke resize on a Matrix interface'); + }; + + /** + * Reshape the matrix to the given size. Returns a copy of the matrix when + * `copy=true`, otherwise return the matrix itself (reshape in place). + * + * @param {number[]} size The new size the matrix should have. + * @param {boolean} [copy] Return a reshaped copy of the matrix + * + * @return {Matrix} The reshaped matrix + */ + Matrix.prototype.reshape = function (size, defaultValue) { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke reshape on a Matrix interface'); + }; + + /** + * Create a clone of the matrix + * @return {Matrix} clone + */ + Matrix.prototype.clone = function () { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke clone on a Matrix interface'); + }; + + /** + * Retrieve the size of the matrix. + * @returns {number[]} size + */ + Matrix.prototype.size = function() { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke size on a Matrix interface'); + }; + + /** + * Create a new matrix with the results of the callback function executed on + * each entry of the matrix. + * @param {Function} callback The callback function is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + * @param {boolean} [skipZeros] Invoke callback function for non-zero values only. + * + * @return {Matrix} matrix + */ + Matrix.prototype.map = function (callback, skipZeros) { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke map on a Matrix interface'); + }; + + /** + * Execute a callback function on each entry of the matrix. + * @param {Function} callback The callback function is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + */ + Matrix.prototype.forEach = function (callback) { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke forEach on a Matrix interface'); + }; + + /** + * Create an Array with a copy of the data of the Matrix + * @returns {Array} array + */ + Matrix.prototype.toArray = function () { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke toArray on a Matrix interface'); + }; + + /** + * Get the primitive value of the Matrix: a multidimensional array + * @returns {Array} array + */ + Matrix.prototype.valueOf = function () { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke valueOf on a Matrix interface'); + }; + + /** + * Get a string representation of the matrix, with optional formatting options. + * @param {Object | number | Function} [options] Formatting options. See + * lib/utils/number:format for a + * description of the available + * options. + * @returns {string} str + */ + Matrix.prototype.format = function (options) { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke format on a Matrix interface'); + }; + + /** + * Get a string representation of the matrix + * @returns {string} str + */ + Matrix.prototype.toString = function () { + // must be implemented by each of the Matrix implementations + throw new Error('Cannot invoke toString on a Matrix interface'); + }; + + // exports + return Matrix; + } + + var name$11 = 'Matrix'; + var path$4 = 'type'; + var factory_1$11 = factory$11; + + var Matrix = { + name: name$11, + path: path$4, + factory: factory_1$11 }; - - /** - * Execute a callback function on each entry of the matrix. - * @memberof SparseMatrix - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * @param {boolean} [skipZeros] Invoke callback function for non-zero values only. - */ - SparseMatrix.prototype.forEach = function (callback, skipZeros) { - // check it is a pattern matrix - if (!this._values) - throw new Error('Cannot invoke forEach on a Pattern only matrix'); - // matrix instance - var me = this; - // rows and columns - var rows = this._size[0]; - var columns = this._size[1]; - // loop columns - for (var j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = this._ptr[j]; - var k1 = this._ptr[j + 1]; - // column pointer - var p = 0; - // loop k within [k0, k1[ - for (var k = k0; k < k1; k++) { - // row index - var i = this._index[k]; - // check we need to process zeros - if (!skipZeros) { - // zero values - for (var x = p; x < i; x++) - callback(0, [x, j], me); + + var string$2 = utils.string; + var array$1 = utils.array; + var object$1 = utils.object; + var number$1 = utils.number; + + var isArray = Array.isArray; + var isNumber$1 = number$1.isNumber; + var isInteger = number$1.isInteger; + var isString$1 = string$2.isString; + + var validateIndex = array$1.validateIndex; + + function factory$12 (type, config, load, typed) { + var Matrix$$1 = load(Matrix); // force loading Matrix (do not use via type.Matrix) + + /** + * Dense Matrix implementation. A regular, dense matrix, supporting multi-dimensional matrices. This is the default matrix type. + * @class DenseMatrix + */ + function DenseMatrix(data, datatype) { + if (!(this instanceof DenseMatrix)) + throw new SyntaxError('Constructor must be called with the new operator'); + if (datatype && !isString$1(datatype)) + throw new Error('Invalid datatype: ' + datatype); + + if (type.isMatrix(data)) { + // check data is a DenseMatrix + if (data.type === 'DenseMatrix') { + // clone data & size + this._data = object$1.clone(data._data); + this._size = object$1.clone(data._size); + this._datatype = datatype || data._datatype; } - // value @ k - callback(this._values[k], [i, j], me); - // update pointer - p = i + 1; + else { + // build data from existing matrix + this._data = data.toArray(); + this._size = data.size(); + this._datatype = datatype || data._datatype; + } + } + else if (data && isArray(data.data) && isArray(data.size)) { + // initialize fields from JSON representation + this._data = data.data; + this._size = data.size; + this._datatype = datatype || data.datatype; + } + else if (isArray(data)) { + // replace nested Matrices with Arrays + this._data = preprocess(data); + // get the dimensions of the array + this._size = array$1.size(this._data); + // verify the dimensions of the array, TODO: compute size while processing array + array$1.validate(this._data, this._size); + // data type unknown + this._datatype = datatype; + } + else if (data) { + // unsupported type + throw new TypeError('Unsupported type of data (' + utils.types.type(data) + ')'); } - // check we need to process zeros - if (!skipZeros) { - // zero values - for (var y = p; y < rows; y++) - callback(0, [y, j], me); + else { + // nothing provided + this._data = []; + this._size = [0]; + this._datatype = datatype; } } - }; - - /** - * Create an Array with a copy of the data of the SparseMatrix - * @memberof SparseMatrix - * @returns {Array} array - */ - SparseMatrix.prototype.toArray = function () { - return _toArray(this._values, this._index, this._ptr, this._size, true); - }; + + DenseMatrix.prototype = new Matrix$$1(); - /** - * Get the primitive value of the SparseMatrix: a two dimensions array - * @memberof SparseMatrix - * @returns {Array} array - */ - SparseMatrix.prototype.valueOf = function () { - return _toArray(this._values, this._index, this._ptr, this._size, false); - }; - - var _toArray = function (values, index, ptr, size, copy) { - // rows and columns - var rows = size[0]; - var columns = size[1]; - // result - var a = []; - // vars - var i, j; - // initialize array - for (i = 0; i < rows; i++) { - a[i] = []; - for (j = 0; j < columns; j++) - a[i][j] = 0; - } + /** + * Attach type information + */ + DenseMatrix.prototype.type = 'DenseMatrix'; + DenseMatrix.prototype.isDenseMatrix = true; - // loop columns - for (j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // loop k within [k0, k1[ - for (var k = k0; k < k1; k++) { - // row index - i = index[k]; - // set value (use one for pattern matrix) - a[i][j] = values ? (copy ? object$2.clone(values[k]) : values[k]) : 1; - } - } - return a; - }; - - /** - * Get a string representation of the matrix, with optional formatting options. - * @memberof SparseMatrix - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ - SparseMatrix.prototype.format = function (options) { - // rows and columns - var rows = this._size[0]; - var columns = this._size[1]; - // density - var density = this.density(); - // rows & columns - var str = 'Sparse Matrix [' + string$3.format(rows, options) + ' x ' + string$3.format(columns, options) + '] density: ' + string$3.format(density, options) + '\n'; - // loop columns - for (var j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = this._ptr[j]; - var k1 = this._ptr[j + 1]; - // loop k within [k0, k1[ - for (var k = k0; k < k1; k++) { - // row index - var i = this._index[k]; - // append value - str += '\n (' + string$3.format(i, options) + ', ' + string$3.format(j, options) + ') ==> ' + (this._values ? string$3.format(this._values[k], options) : 'X'); + /** + * Get the storage format used by the matrix. + * + * Usage: + * var format = matrix.storage() // retrieve storage format + * + * @memberof DenseMatrix + * @return {string} The storage format. + */ + DenseMatrix.prototype.storage = function () { + return 'dense'; + }; + + /** + * Get the datatype of the data stored in the matrix. + * + * Usage: + * var format = matrix.datatype() // retrieve matrix datatype + * + * @memberof DenseMatrix + * @return {string} The datatype. + */ + DenseMatrix.prototype.datatype = function () { + return this._datatype; + }; + + /** + * Create a new DenseMatrix + * @memberof DenseMatrix + * @param {Array} data + * @param {string} [datatype] + */ + DenseMatrix.prototype.create = function (data, datatype) { + return new DenseMatrix(data, datatype); + }; + + /** + * 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 + * + * @memberof DenseMatrix + * @param {Index} index + * @param {Array | DenseMatrix | *} [replacement] + * @param {*} [defaultValue=0] Default value, filled in on new entries when + * the matrix is resized. If not provided, + * new matrix elements will be filled with zeros. + */ + DenseMatrix.prototype.subset = function (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'); } - } - return str; - }; - - /** - * Get a string representation of the matrix - * @memberof SparseMatrix - * @returns {string} str - */ - SparseMatrix.prototype.toString = function () { - return string$3.format(this.toArray()); - }; - - /** - * Get a JSON representation of the matrix - * @memberof SparseMatrix - * @returns {Object} - */ - SparseMatrix.prototype.toJSON = function () { - return { - mathjs: 'SparseMatrix', - values: this._values, - index: this._index, - ptr: this._ptr, - size: this._size, - datatype: this._datatype }; - }; + + /** + * Get a single element from the matrix. + * @memberof DenseMatrix + * @param {number[]} index Zero-based index + * @return {*} value + */ + DenseMatrix.prototype.get = function (index) { + if (!isArray(index)) + throw new TypeError('Array expected'); + if (index.length != this._size.length) + throw new DimensionError_1(index.length, this._size.length); - /** - * Get the kth Matrix diagonal. - * - * @memberof SparseMatrix - * @param {number | BigNumber} [k=0] The kth diagonal where the vector will retrieved. - * - * @returns {Matrix} The matrix vector with the diagonal values. - */ - SparseMatrix.prototype.diagonal = function(k) { - // validate k if any - if (k) { - // convert BigNumber to a number - if (type.isBigNumber(k)) - k = k.toNumber(); - // is must be an integer - if (!isNumber$2(k) || !isInteger$1(k)) { - throw new TypeError ('The parameter k must be an integer number'); + // check index + for (var x = 0; x < index.length; x++) + validateIndex(index[x], this._size[x]); + + 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]; } - } - else { - // default value - k = 0; - } - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // rows & columns - var rows = this._size[0]; - var columns = this._size[1]; - - // number diagonal values - var n = Math.min(rows - kSub, columns - kSuper); + return data; + }; - // diagonal arrays - var values = []; - var index = []; - var ptr = []; - // initial ptr value - ptr[0] = 0; - // loop columns - for (var j = kSuper; j < columns && values.length < n; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = this._ptr[j]; - var k1 = this._ptr[j + 1]; - // loop x within [k0, k1[ - for (var x = k0; x < k1; x++) { - // row index - var i = this._index[x]; - // check row - if (i === j - kSuper + kSub) { - // value on this column - values.push(this._values[x]); - // store row - index[values.length - 1] = i - kSub; - // exit loop - break; - } + /** + * Replace a single element in the matrix. + * @memberof DenseMatrix + * @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 {DenseMatrix} self + */ + DenseMatrix.prototype.set = function (index, value, defaultValue) { + if (!isArray(index)) + throw new TypeError('Array expected'); + if (index.length < this._size.length) + throw new DimensionError_1(index.length, this._size.length, '<'); + + var i, ii, index_i; + + // 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++) { + index_i = index[i]; + validateIndex(index_i, data.length); + data = data[index_i]; } - } - // close ptr - ptr.push(values.length); - // return matrix - return new SparseMatrix({ - values: values, - index: index, - ptr: ptr, - size: [n, 1] - }); - }; - - /** - * Generate a matrix from a JSON object - * @memberof SparseMatrix - * @param {Object} json An object structured like - * `{"mathjs": "SparseMatrix", "values": [], "index": [], "ptr": [], "size": []}`, - * where mathjs is optional - * @returns {SparseMatrix} - */ - SparseMatrix.fromJSON = function (json) { - return new SparseMatrix(json); - }; - /** - * Create a diagonal matrix. - * - * @memberof SparseMatrix - * @param {Array} size The matrix size. - * @param {number | Array | Matrix } value The values for the diagonal. - * @param {number | BigNumber} [k=0] The kth diagonal where the vector will be filled in. - * @param {string} [datatype] The Matrix datatype, values must be of this datatype. - * - * @returns {SparseMatrix} - */ - SparseMatrix.diagonal = function (size, value, k, defaultValue, datatype) { - if (!isArray$1(size)) - throw new TypeError('Array expected, size parameter'); - if (size.length !== 2) - throw new Error('Only two dimensions matrix are supported'); + // set new value + index_i = index[index.length - 1]; + validateIndex(index_i, data.length); + data[index_i] = value; + + return this; + }; - // map size & validate - size = size.map(function (s) { - // check it is a big number - if (type.isBigNumber(s)) { - // convert it - s = s.toNumber(); + /** + * Get a submatrix of this matrix + * @memberof DenseMatrix + * @param {DenseMatrix} matrix + * @param {Index} index Zero-based index + * @private + */ + function _get (matrix, index) { + if (!type.isIndex(index)) { + throw new TypeError('Invalid index'); } - // validate arguments - if (!isNumber$2(s) || !isInteger$1(s) || s < 1) { - throw new Error('Size values must be positive integers'); - } - return s; - }); - - // validate k if any - if (k) { - // convert BigNumber to a number - if (type.isBigNumber(k)) - k = k.toNumber(); - // is must be an integer - if (!isNumber$2(k) || !isInteger$1(k)) { - throw new TypeError ('The parameter k must be an integer number'); + + var isScalar = index.isScalar(); + if (isScalar) { + // return a scalar + return matrix.get(index.min()); } - } - else { - // default value - k = 0; - } + else { + // validate dimensions + var size = index.size(); + if (size.length != matrix._size.length) { + throw new DimensionError_1(size.length, matrix._size.length); + } - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; + // validate if any of the ranges in the index is out of range + var min = index.min(); + var max = index.max(); + for (var i = 0, ii = matrix._size.length; i < ii; i++) { + validateIndex(min[i], matrix._size[i]); + validateIndex(max[i], matrix._size[i]); + } - if (isString$2(datatype)) { - // find signature that matches (datatype, datatype) - eq = typed.find(equalScalar$$1, [datatype, datatype]) || equalScalar$$1; - // convert 0 to the same datatype - zero = typed.convert(0, datatype); + // retrieve submatrix + // TODO: more efficient when creating an empty matrix and setting _data and _size manually + return new DenseMatrix(_getSubmatrix(matrix._data, index, size.length, 0), matrix._datatype); + } } - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // rows and columns - var rows = size[0]; - var columns = size[1]; - - // number of non-zero items - var n = Math.min(rows - kSub, columns - kSuper); - - // value extraction function - var _value; - - // check value - if (isArray$1(value)) { - // validate array - if (value.length !== n) { - // number of values in array must be n - throw new Error('Invalid value array length'); - } - // define function - _value = function (i) { - // return value @ i - return value[i]; - }; - } - else if (type.isMatrix(value)) { - // matrix size - var ms = value.size(); - // validate matrix - if (ms.length !== 1 || ms[0] !== n) { - // number of values in array must be n - throw new Error('Invalid matrix length'); - } - // define function - _value = function (i) { - // return value @ i - return value.get([i]); - }; - } - else { - // define function - _value = function () { - // return value - return value; - }; + /** + * Recursively get a submatrix of a multi dimensional matrix. + * Index is not checked for correct number or length of dimensions. + * @memberof DenseMatrix + * @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.dimension(dim); + + if (last) { + return range.map(function (i) { + validateIndex(i, data.length); + return data[i]; + }).valueOf(); + } + else { + return range.map(function (i) { + validateIndex(i, data.length); + var child = data[i]; + return _getSubmatrix(child, index, dims, dim + 1); + }).valueOf(); + } } - // create arrays - var values = []; - var index = []; - var ptr = []; - - // loop items - for (var j = 0; j < columns; j++) { - // number of rows with value - ptr.push(values.length); - // diagonal index - var i = j - kSuper; - // check we need to set diagonal value - if (i >= 0 && i < n) { - // get value @ i - var v = _value(i); - // check for zero - if (!eq(v, zero)) { - // column - index.push(i + kSub); - // add value - values.push(v); + /** + * Replace a submatrix in this matrix + * Indexes are zero-based. + * @memberof DenseMatrix + * @param {DenseMatrix} matrix + * @param {Index} index + * @param {DenseMatrix | Array | *} submatrix + * @param {*} defaultValue Default value, filled in on new entries when + * the matrix is resized. + * @return {DenseMatrix} matrix + * @private + */ + function _set (matrix, index, submatrix, defaultValue) { + if (!index || index.isIndex !== true) { + 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 (type.isMatrix(submatrix)) { + sSize = submatrix.size(); + submatrix = submatrix.valueOf(); + } + else { + sSize = array$1.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); } - } - // last value should be number of values - ptr.push(values.length); - // create SparseMatrix - return new SparseMatrix({ - values: values, - index: index, - ptr: ptr, - size: [rows, columns] - }); - }; - - /** - * Swap rows i and j in Matrix. - * - * @memberof SparseMatrix - * @param {number} i Matrix row index 1 - * @param {number} j Matrix row index 2 - * - * @return {Matrix} The matrix reference - */ - SparseMatrix.prototype.swapRows = function (i, j) { - // check index - if (!isNumber$2(i) || !isInteger$1(i) || !isNumber$2(j) || !isInteger$1(j)) { - throw new Error('Row index must be positive integers'); - } - // check dimensions - if (this._size.length !== 2) { - throw new Error('Only two dimensional matrix is supported'); - } - // validate index - validateIndex$1(i, this._size[0]); - validateIndex$1(j, this._size[0]); - - // swap rows - SparseMatrix._swapRows(i, j, this._size[1], this._values, this._index, this._ptr); - // return current instance - return this; - }; - - /** - * Loop rows with data in column j. - * - * @param {number} j Column - * @param {Array} values Matrix values - * @param {Array} index Matrix row indeces - * @param {Array} ptr Matrix column pointers - * @param {Function} callback Callback function invoked for every row in column j - */ - SparseMatrix._forEachRow = function (j, values, index, ptr, callback) { - // indeces for column j - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // loop - for (var k = k0; k < k1; k++) { - // invoke callback - callback(index[k], values[k]); - } - }; - - /** - * Swap rows x and y in Sparse Matrix data structures. - * - * @param {number} x Matrix row index 1 - * @param {number} y Matrix row index 2 - * @param {number} columns Number of columns in matrix - * @param {Array} values Matrix values - * @param {Array} index Matrix row indeces - * @param {Array} ptr Matrix column pointers - */ - SparseMatrix._swapRows = function (x, y, columns, values, index, ptr) { - // loop columns - for (var j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // find value index @ x - var kx = _getValueIndex(x, k0, k1, index); - // find value index @ x - var ky = _getValueIndex(y, k0, k1, index); - // check both rows exist in matrix - if (kx < k1 && ky < k1 && index[kx] === x && index[ky] === y) { - // swap values (check for pattern matrix) - if (values) { - var v = values[kx]; - values[kx] = values[ky]; - values[ky] = v; - } - // next column - continue; - } - // check x row exist & no y row - if (kx < k1 && index[kx] === x && (ky >= k1 || index[ky] !== y)) { - // value @ x (check for pattern matrix) - var vx = values ? values[kx] : undefined; - // insert value @ y - index.splice(ky, 0, y); - if (values) - values.splice(ky, 0, vx); - // remove value @ x (adjust array index if needed) - index.splice(ky <= kx ? kx + 1 : kx, 1); - if (values) - values.splice(ky <= kx ? kx + 1 : kx, 1); - // next column - continue; - } - // check y row exist & no x row - if (ky < k1 && index[ky] === y && (kx >= k1 || index[kx] !== x)) { - // value @ y (check for pattern matrix) - var vy = values ? values[ky] : undefined; - // insert value @ x - index.splice(kx, 0, x); - if (values) - values.splice(kx, 0, vy); - // remove value @ y (adjust array index if needed) - index.splice(kx <= ky ? ky + 1 : ky, 1); - if (values) - values.splice(kx <= ky ? ky + 1 : ky, 1); - } - } - }; + else { + // set a submatrix - // register this type in the base class Matrix - type.Matrix._storage.sparse = SparseMatrix; + // validate dimensions + if (iSize.length < matrix._size.length) { + throw new DimensionError_1(iSize.length, matrix._size.length, '<'); + } - return SparseMatrix; -} + if (sSize.length < iSize.length) { + // calculate number of missing outer dimensions + var i = 0; + var outer = 0; + while (iSize[i] === 1 && sSize[i] === 1) { + i++; + } + while (iSize[i] === 1) { + outer++; + i++; + } -var name$13 = 'SparseMatrix'; -var path$6 = 'type'; -var factory_1$14 = factory$14; -var lazy$3 = false; // no lazy loading, as we alter type.Matrix._storage + // unsqueeze both outer and inner dimensions + submatrix = array$1.unsqueeze(submatrix, iSize.length, outer, sSize); + } -var SparseMatrix = { - name: name$13, - path: path$6, - factory: factory_1$14, - lazy: lazy$3 -}; + // check whether the size of the submatrix matches the index size + if (!object$1.deepEqual(iSize, sSize)) { + throw new DimensionError_1(iSize, sSize, '>'); + } -function factory$15 (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: - * - * var 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([]); - }, + // enlarge matrix when needed + var size = index.max().map(function (i) { + return i + 1; + }); + _fit(matrix, size, defaultValue); - 'string': function (format) { - return _create([], format); - }, - - 'string, string': function (format, datatype) { - return _create([], format, datatype); - }, + // insert the sub matrix + var dims = iSize.length, + dim = 0; + _setSubmatrix (matrix._data, index, submatrix, dims, dim); + } - 'Array': function (data) { - return _create(data); - }, - - 'Matrix': function (data) { - return _create(data, data.storage()); - }, + return matrix; + } - 'Array | Matrix, string': _create, + /** + * Replace a submatrix of a multi dimensional matrix. + * @memberof DenseMatrix + * @param {Array} data + * @param {Index} index + * @param {Array} submatrix + * @param {number} dims Total number of dimensions + * @param {number} dim + * @private + */ + function _setSubmatrix (data, index, submatrix, dims, dim) { + var last = (dim === dims - 1), + range = index.dimension(dim); + + if (last) { + range.forEach(function (dataIndex, subIndex) { + validateIndex(dataIndex); + data[dataIndex] = submatrix[subIndex[0]]; + }); + } + else { + range.forEach(function (dataIndex, subIndex) { + validateIndex(dataIndex); + _setSubmatrix(data[dataIndex], index, submatrix[subIndex[0]], dims, dim + 1); + }); + } + } - 'Array | Matrix, string, string': _create - }); + /** + * Resize the matrix to the given size. Returns a copy of the matrix when + * `copy=true`, otherwise return the matrix itself (resize in place). + * + * @memberof DenseMatrix + * @param {number[]} size The new size the matrix should have. + * @param {*} [defaultValue=0] Default value, filled in on new entries. + * If not provided, the matrix elements will + * be filled with zeros. + * @param {boolean} [copy] Return a resized copy of the matrix + * + * @return {Matrix} The resized matrix + */ + DenseMatrix.prototype.resize = function (size, defaultValue, copy) { + // validate arguments + if (!isArray(size)) + throw new TypeError('Array expected'); - matrix.toTex = { - 0: '\\begin{bmatrix}\\end{bmatrix}', - 1: '\\left(${args[0]}\\right)', - 2: '\\left(${args[0]}\\right)' - }; + // matrix to resize + var m = copy ? this.clone() : this; + // resize matrix + return _resize(m, size, defaultValue); + }; + + var _resize = function (matrix, size, defaultValue) { + // check size + if (size.length === 0) { + // first value in matrix + var v = matrix._data; + // go deep + while (isArray(v)) { + v = v[0]; + } + return v; + } + // resize matrix + matrix._size = size.slice(0); // copy the array + matrix._data = array$1.resize(matrix._data, matrix._size, defaultValue); + // return matrix + return matrix; + }; - return matrix; + /** + * Reshape the matrix to the given size. Returns a copy of the matrix when + * `copy=true`, otherwise return the matrix itself (reshape in place). + * + * NOTE: This might be better suited to copy by default, instead of modifying + * in place. For now, it operates in place to remain consistent with + * resize(). + * + * @memberof DenseMatrix + * @param {number[]} size The new size the matrix should have. + * @param {boolean} [copy] Return a reshaped copy of the matrix + * + * @return {Matrix} The reshaped matrix + */ + DenseMatrix.prototype.reshape = function (size, copy) { + var m = copy ? this.clone() : this; - /** - * 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'); + m._data = array$1.reshape(m._data, size); + m._size = size.slice(0); + return m; + }; + + /** + * Enlarge the matrix when it is smaller than given size. + * If the matrix is larger or equal sized, nothing is done. + * @memberof DenseMatrix + * @param {DenseMatrix} matrix The matrix to be resized + * @param {number[]} size + * @param {*} defaultValue Default value, filled in on new entries. + * @private + */ + function _fit(matrix, size, defaultValue) { + var newSize = matrix._size.slice(0), // copy the array + changed = false; - // create instance - return new M(data, datatype); - } -} + // add dimensions when needed + while (newSize.length < size.length) { + newSize.push(0); + changed = true; + } -var name$14 = 'matrix'; -var factory_1$15 = factory$15; + // enlarge size when needed + for (var i = 0, ii = size.length; i < ii; i++) { + if (size[i] > newSize[i]) { + newSize[i] = size[i]; + changed = true; + } + } -var matrix = { - name: name$14, - factory: factory_1$15 -}; + if (changed) { + // resize only when size is changed + _resize(matrix, newSize, defaultValue); + } + } + + /** + * Create a clone of the matrix + * @memberof DenseMatrix + * @return {DenseMatrix} clone + */ + DenseMatrix.prototype.clone = function () { + var m = new DenseMatrix({ + data: object$1.clone(this._data), + size: object$1.clone(this._size), + datatype: this._datatype + }); + return m; + }; + + /** + * Retrieve the size of the matrix. + * @memberof DenseMatrix + * @returns {number[]} size + */ + DenseMatrix.prototype.size = function() { + return this._size.slice(0); // return a clone of _size + }; + + /** + * Create a new matrix with the results of the callback function executed on + * each entry of the matrix. + * @memberof DenseMatrix + * @param {Function} callback The callback function is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + * + * @return {DenseMatrix} matrix + */ + DenseMatrix.prototype.map = function (callback) { + // matrix instance + var me = this; + var recurse = function (value, index) { + if (isArray(value)) { + return value.map(function (child, i) { + return recurse(child, index.concat(i)); + }); + } + else { + return callback(value, index, me); + } + }; + // return dense format + return new DenseMatrix({ + data: recurse(this._data, []), + size: object$1.clone(this._size), + datatype: this._datatype + }); + }; + + /** + * Execute a callback function on each entry of the matrix. + * @memberof DenseMatrix + * @param {Function} callback The callback function is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + */ + DenseMatrix.prototype.forEach = function (callback) { + // matrix instance + var me = this; + var recurse = function (value, index) { + if (isArray(value)) { + value.forEach(function (child, i) { + recurse(child, index.concat(i)); + }); + } + else { + callback(value, index, me); + } + }; + recurse(this._data, []); + }; + + /** + * Create an Array with a copy of the data of the DenseMatrix + * @memberof DenseMatrix + * @returns {Array} array + */ + DenseMatrix.prototype.toArray = function () { + return object$1.clone(this._data); + }; + + /** + * Get the primitive value of the DenseMatrix: a multidimensional array + * @memberof DenseMatrix + * @returns {Array} array + */ + DenseMatrix.prototype.valueOf = function () { + return this._data; + }; + + /** + * Get a string representation of the matrix, with optional formatting options. + * @memberof DenseMatrix + * @param {Object | number | Function} [options] Formatting options. See + * lib/utils/number:format for a + * description of the available + * options. + * @returns {string} str + */ + DenseMatrix.prototype.format = function (options) { + return string$2.format(this._data, options); + }; + + /** + * Get a string representation of the matrix + * @memberof DenseMatrix + * @returns {string} str + */ + DenseMatrix.prototype.toString = function () { + return string$2.format(this._data); + }; + + /** + * Get a JSON representation of the matrix + * @memberof DenseMatrix + * @returns {Object} + */ + DenseMatrix.prototype.toJSON = function () { + return { + mathjs: 'DenseMatrix', + data: this._data, + size: this._size, + datatype: this._datatype + }; + }; + + /** + * Get the kth Matrix diagonal. + * + * @memberof DenseMatrix + * @param {number | BigNumber} [k=0] The kth diagonal where the vector will retrieved. + * + * @returns {Array} The array vector with the diagonal values. + */ + DenseMatrix.prototype.diagonal = function(k) { + // validate k if any + if (k) { + // convert BigNumber to a number + if (type.isBigNumber(k)) + k = k.toNumber(); + // is must be an integer + if (!isNumber$1(k) || !isInteger(k)) { + throw new TypeError ('The parameter k must be an integer number'); + } + } + else { + // default value + k = 0; + } -function factory$16(type, config, load, typed) { + var kSuper = k > 0 ? k : 0; + var kSub = k < 0 ? -k : 0; - /** - * Add two scalar values, `x + y`. - * This function is meant for internal use: it is used by the public function - * `add` - * - * This function does not support collections (Array or Matrix), and does - * not validate the number of of inputs. - * - * @param {number | BigNumber | Fraction | Complex | Unit} x First value to add - * @param {number | BigNumber | Fraction | Complex} y Second value to add - * @return {number | BigNumber | Fraction | Complex | Unit} Sum of `x` and `y` - * @private - */ - var add = typed('add', { + // rows & columns + var rows = this._size[0]; + var columns = this._size[1]; - 'number, number': function (x, y) { - return x + y; - }, + // number diagonal values + var n = Math.min(rows - kSub, columns - kSuper); + + // x is a matrix get diagonal from matrix + var data = []; + + // loop rows + for (var i = 0; i < n; i++) { + data[i] = this._data[i + kSub][i + kSuper]; + } - 'Complex, Complex': function (x, y) { - return x.add(y); - }, + // create DenseMatrix + return new DenseMatrix({ + data: data, + size: [n], + datatype: this._datatype + }); + }; + + /** + * Create a diagonal matrix. + * + * @memberof DenseMatrix + * @param {Array} size The matrix size. + * @param {number | Array} value The values for the diagonal. + * @param {number | BigNumber} [k=0] The kth diagonal where the vector will be filled in. + * @param {number} [defaultValue] The default value for non-diagonal + * + * @returns {DenseMatrix} + */ + DenseMatrix.diagonal = function (size, value, k, defaultValue, datatype) { + if (!isArray(size)) + throw new TypeError('Array expected, size parameter'); + if (size.length !== 2) + throw new Error('Only two dimensions matrix are supported'); + + // map size & validate + size = size.map(function (s) { + // check it is a big number + if (type.isBigNumber(s)) { + // convert it + s = s.toNumber(); + } + // validate arguments + if (!isNumber$1(s) || !isInteger(s) || s < 1) { + throw new Error('Size values must be positive integers'); + } + return s; + }); - 'BigNumber, BigNumber': function (x, y) { - return x.plus(y); - }, + // validate k if any + if (k) { + // convert BigNumber to a number + if (type.isBigNumber(k)) + k = k.toNumber(); + // is must be an integer + if (!isNumber$1(k) || !isInteger(k)) { + throw new TypeError ('The parameter k must be an integer number'); + } + } + else { + // default value + k = 0; + } + + if (defaultValue && isString$1(datatype)) { + // convert defaultValue to the same datatype + defaultValue = typed.convert(defaultValue, datatype); + } - 'Fraction, Fraction': function (x, y) { - return x.add(y); - }, + var kSuper = k > 0 ? k : 0; + var kSub = k < 0 ? -k : 0; + + // rows and columns + var rows = size[0]; + var columns = size[1]; - 'Unit, Unit': function (x, y) { - if (x.value == null) throw new Error('Parameter x contains a unit with undefined value'); - if (y.value == null) throw new Error('Parameter y contains a unit with undefined value'); - if (!x.equalBase(y)) throw new Error('Units do not match'); + // number of non-zero items + var n = Math.min(rows - kSub, columns - kSuper); - var res = x.clone(); - res.value = add(res.value, y.value); - res.fixPrefix = false; - return res; - } - }); + // value extraction function + var _value; - return add; -} + // check value + if (isArray(value)) { + // validate array + if (value.length !== n) { + // number of values in array must be n + throw new Error('Invalid value array length'); + } + // define function + _value = function (i) { + // return value @ i + return value[i]; + }; + } + else if (type.isMatrix(value)) { + // matrix size + var ms = value.size(); + // validate matrix + if (ms.length !== 1 || ms[0] !== n) { + // number of values in array must be n + throw new Error('Invalid matrix length'); + } + // define function + _value = function (i) { + // return value @ i + return value.get([i]); + }; + } + else { + // define function + _value = function () { + // return value + return value; + }; + } + + // discover default value if needed + if (!defaultValue) { + // check first value in array + defaultValue = type.isBigNumber(_value(0)) ? new type.BigNumber(0) : 0; + } -var factory_1$16 = factory$16; + // empty array + var data = []; -var addScalar = { - factory: factory_1$16 -}; + // check we need to resize array + if (size.length > 0) { + // resize array + data = array$1.resize(data, size, defaultValue); + // fill diagonal + for (var d = 0; d < n; d++) { + data[d + kSub][d + kSuper] = _value(d); + } + } + + // create DenseMatrix + return new DenseMatrix({ + data: data, + size: [rows, columns] + }); + }; -function factory$17 (type, config, load, typed) { + /** + * Generate a matrix from a JSON object + * @memberof DenseMatrix + * @param {Object} json An object structured like + * `{"mathjs": "DenseMatrix", data: [], size: []}`, + * where mathjs is optional + * @returns {DenseMatrix} + */ + DenseMatrix.fromJSON = function (json) { + return new DenseMatrix(json); + }; + + /** + * Swap rows i and j in Matrix. + * + * @memberof DenseMatrix + * @param {number} i Matrix row index 1 + * @param {number} j Matrix row index 2 + * + * @return {Matrix} The matrix reference + */ + DenseMatrix.prototype.swapRows = function (i, j) { + // check index + if (!isNumber$1(i) || !isInteger(i) || !isNumber$1(j) || !isInteger(j)) { + throw new Error('Row index must be positive integers'); + } + // check dimensions + if (this._size.length !== 2) { + throw new Error('Only two dimensional matrix is supported'); + } + // validate index + validateIndex(i, this._size[0]); + validateIndex(j, this._size[0]); - var DenseMatrix = type.DenseMatrix; + // swap rows + DenseMatrix._swapRows(i, j, this._data); + // return current instance + return this; + }; - /** - * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). - * Callback function invoked NNZ times (number of nonzero items in SparseMatrix). - * - * - * ┌ f(Dij, Sij) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ Dij ; otherwise - * - * - * @param {Matrix} denseMatrix The DenseMatrix instance (D) - * @param {Matrix} sparseMatrix The SparseMatrix instance (S) - * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) - * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) - * - * @return {Matrix} DenseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 - */ - var algorithm01 = function (denseMatrix, sparseMatrix, callback, inverse) { - // dense matrix arrays - var adata = denseMatrix._data; - var asize = denseMatrix._size; - var adt = denseMatrix._datatype; - // sparse matrix arrays - var bvalues = sparseMatrix._values; - var bindex = sparseMatrix._index; - var bptr = sparseMatrix._ptr; - var bsize = sparseMatrix._size; - var bdt = sparseMatrix._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // sparse matrix cannot be a Pattern matrix - if (!bvalues) - throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // process data types - var dt = typeof adt === 'string' && adt === bdt ? adt : undefined; - // callback function - var cf = dt ? typed.find(callback, [dt, dt]) : callback; + /** + * Swap rows i and j in Dense Matrix data structure. + * + * @param {number} i Matrix row index 1 + * @param {number} j Matrix row index 2 + */ + DenseMatrix._swapRows = function (i, j, data) { + // swap values i <-> j + var vi = data[i]; + data[i] = data[j]; + data[j] = vi; + }; - // vars - var i, j; - - // result (DenseMatrix) - var cdata = []; - // initialize c - for (i = 0; i < rows; i++) - cdata[i] = []; - - // workspace - var x = []; - // marks indicating we have a value in x for a given column - var w = []; - - // loop columns in b - for (j = 0; j < columns; j++) { - // column mark - var mark = j + 1; - // values in column j - for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - i = bindex[k]; - // update workspace - x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); - // mark i as updated - w[i] = mark; - } - // loop rows - for (i = 0; i < rows; i++) { - // check row is in workspace - if (w[i] === mark) { - // c[i][j] was already calculated - cdata[i][j] = x[i]; + /** + * Preprocess data, which can be an Array or DenseMatrix with nested Arrays and + * Matrices. Replaces all nested Matrices with Arrays + * @memberof DenseMatrix + * @param {Array} data + * @return {Array} data + */ + function preprocess(data) { + for (var i = 0, ii = data.length; i < ii; i++) { + var elem = data[i]; + if (isArray(elem)) { + data[i] = preprocess(elem); } - else { - // item does not exist in S - cdata[i][j] = adata[i][j]; + else if (elem && elem.isMatrix === true) { + data[i] = preprocess(elem.valueOf()); } } + + return data; } - // return dense matrix - return new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); - }; - - return algorithm01; -} + // register this type in the base class Matrix + type.Matrix._storage.dense = DenseMatrix; + type.Matrix._storage['default'] = DenseMatrix; -var name$15 = 'algorithm01'; -var factory_1$17 = factory$17; + // exports + return DenseMatrix; + } -var algorithm01 = { - name: name$15, - factory: factory_1$17 -}; + var name$12 = 'DenseMatrix'; + var path$5 = 'type'; + var factory_1$12 = factory$12; + var lazy$2 = false; // no lazy loading, as we alter type.Matrix._storage -function factory$18 (type, config, load, typed) { - - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; + var DenseMatrix = { + name: name$12, + path: path$5, + factory: factory_1$12, + lazy: lazy$2 + }; /** - * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). - * Callback function invoked MAX(NNZA, NNZB) times - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 - * C(i,j) = ┤ A(i,j) ; A(i,j) !== 0 - * └ B(i,j) ; B(i,j) !== 0 - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + * Compares two BigNumbers. + * @param {BigNumber} x First value to compare + * @param {BigNumber} 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 */ - var algorithm04 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = avalues && bvalues ? [] : undefined; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - - // workspace - var xa = avalues && bvalues ? [] : undefined; - var xb = avalues && bvalues ? [] : undefined; - // marks indicating we have a value in x for a given column - var wa = []; - var wb = []; - - // vars - var i, j, k, k0, k1; - - // loop columns - for (j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // columns mark - var mark = j + 1; - // loop A(:,j) - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // update c - cindex.push(i); - // update workspace - wa[i] = mark; - // check we need to process values - if (xa) - xa[i] = avalues[k]; - } - // loop B(:,j) - for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - i = bindex[k]; - // check row exists in A - if (wa[i] === mark) { - // update record in xa @ i - if (xa) { - // invoke callback - var v = cf(xa[i], bvalues[k]); - // check for zero - if (!eq(v, zero)) { - // update workspace - xa[i] = v; - } - else { - // remove mark (index will be removed later) - wa[i] = null; - } - } - } - else { - // update c - cindex.push(i); - // update workspace - wb[i] = mark; - // check we need to process values - if (xb) - xb[i] = bvalues[k]; - } - } - // check we need to process values (non pattern matrix) - if (xa && xb) { - // initialize first index in j - k = cptr[j]; - // loop index in j - while (k < cindex.length) { - // row - i = cindex[k]; - // check workspace has value @ i - if (wa[i] === mark) { - // push value (Aij != 0 || (Aij != 0 && Bij != 0)) - cvalues[k] = xa[i]; - // increment pointer - k++; - } - else if (wb[i] === mark) { - // push value (bij != 0) - cvalues[k] = xb[i]; - // increment pointer - k++; - } - else { - // remove index @ k - cindex.splice(k, 1); - } - } - } + var nearlyEqual = function nearlyEqual(x, y, epsilon) { + // if epsilon is null or undefined, test whether x and y are exactly equal + if (epsilon == null) { + return x.eq(y); } - // update cptr - cptr[columns] = cindex.length; - - // return sparse matrix - return c; - }; - - return algorithm04; -} -var name$16 = 'algorithm04'; -var factory_1$18 = factory$18; -var algorithm04 = { - name: name$16, - factory: factory_1$18 -}; - -function factory$19 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). - * Callback function invoked NZ times (number of nonzero items in S). - * - * - * ┌ f(Sij, b) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ b ; otherwise - * - * - * @param {Matrix} s The SparseMatrix instance (S) - * @param {Scalar} b The Scalar value - * @param {Function} callback The f(Aij,b) operation to invoke - * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) - * - * @return {Matrix} DenseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 - */ - var algorithm10 = function (s, b, callback, inverse) { - // sparse matrix arrays - var avalues = s._values; - var aindex = s._index; - var aptr = s._ptr; - var asize = s._size; - var adt = s._datatype; - - // sparse matrix cannot be a Pattern matrix - if (!avalues) - throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string') { - // datatype - dt = adt; - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cdata = []; - // matrix - var c = new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); + // use "==" operator, handles infinities + if (x.eq(y)) { + return true; + } - // workspaces - var x = []; - // marks indicating we have a value in x for a given column - var w = []; + // NaN + if (x.isNaN() || y.isNaN()) { + return false; + } - // loop columns - for (var j = 0; j < columns; j++) { - // columns mark - var mark = j + 1; - // values in j - for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - var r = aindex[k]; - // update workspace - x[r] = avalues[k]; - w[r] = mark; + // at this point x and y should be finite + if(x.isFinite() && y.isFinite()) { + // check numbers are very close, needed when comparing numbers near zero + var diff = x.minus(y).abs(); + if (diff.isZero()) { + return true; } - // loop rows - for (var i = 0; i < rows; i++) { - // initialize C on first column - if (j === 0) { - // create row array - cdata[i] = []; - } - // check sparse matrix has a value @ i,j - if (w[i] === mark) { - // invoke callback, update C - cdata[i][j] = inverse ? cf(b, x[i]) : cf(x[i], b); - } - else { - // dense matrix value @ i, j - cdata[i][j] = b; - } + else { + // use relative error + var max = x.constructor.max(x.abs(), y.abs()); + return diff.lte(max.times(epsilon)); } } - // return sparse matrix - return c; + // Infinite and Number or negative Infinite and positive Infinite cases + return false; }; - return algorithm10; -} - -var name$17 = 'algorithm10'; -var factory_1$19 = factory$19; - -var algorithm10 = { - name: name$17, - factory: factory_1$19 -}; - -var string$4 = utils.string, - isString$3 = string$4.isString; + var nearlyEqual$1 = number.nearlyEqual; -function factory$20 (type, config, load, typed) { - var DenseMatrix = type.DenseMatrix; + function factory$13 (type, config, load, typed) { + + /** + * Test whether two values are equal. + * + * @param {number | BigNumber | Fraction | boolean | Complex | Unit} x First value to compare + * @param {number | BigNumber | Fraction | boolean | Complex} y Second value to compare + * @return {boolean} Returns true when the compared values are equal, else returns false + * @private + */ + var equalScalar = typed('equalScalar', { - /** - * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, Bij..z). - * Callback function invoked MxN times. - * - * C(i,j,...z) = f(Aij..z, Bij..z) - * - * @param {Matrix} a The DenseMatrix instance (A) - * @param {Matrix} b The DenseMatrix instance (B) - * @param {Function} callback The f(Aij..z,Bij..z) operation to invoke - * - * @return {Matrix} DenseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97658658 - */ - var algorithm13 = function (a, b, callback) { - // a arrays - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b arrays - var bdata = b._data; - var bsize = b._size; - var bdt = b._datatype; - // c arrays - var csize = []; + 'boolean, boolean': function (x, y) { + return x === y; + }, - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); + 'number, number': function (x, y) { + return x === y || nearlyEqual$1(x, y, config.epsilon); + }, - // validate each one of the dimension sizes - for (var s = 0; s < asize.length; s++) { - // must match - if (asize[s] !== bsize[s]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - // update dimension in c - csize[s] = asize[s]; - } + 'BigNumber, BigNumber': function (x, y) { + return x.eq(y) || nearlyEqual(x, y, config.epsilon); + }, - // datatype - var dt; - // callback signature to use - var cf = callback; + 'Fraction, Fraction': function (x, y) { + return x.equals(y); + }, - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } + 'Complex, Complex': function (x, y) { + return x.equals(y); + }, - // populate cdata, iterate through dimensions - var cdata = csize.length > 0 ? _iterate(cf, 0, csize, csize[0], adata, bdata) : []; - - // c matrix - return new DenseMatrix({ - data: cdata, - size: csize, - datatype: dt - }); - }; - - // recursive function - var _iterate = function (f, level, s, n, av, bv) { - // initialize array for this level - var cv = []; - // check we reach the last level - if (level === s.length - 1) { - // loop arrays in last level - for (var i = 0; i < n; i++) { - // invoke callback and store value - cv[i] = f(av[i], bv[i]); - } - } - else { - // iterate current level - for (var j = 0; j < n; j++) { - // iterate next level - cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv[j]); + 'Unit, Unit': function (x, y) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return equalScalar(x.value, y.value); } - } - return cv; - }; - - return algorithm13; -} + }); + + return equalScalar; + } -var name$18 = 'algorithm13'; -var factory_1$20 = factory$20; + var factory_1$13 = factory$13; -var algorithm13 = { - name: name$18, - factory: factory_1$20 -}; + var equalScalar = { + factory: factory_1$13 + }; -var clone = object.clone; + var array$2 = utils.array; + var object$2 = utils.object; + var string$3 = utils.string; + var number$2 = utils.number; -function factory$21 (type, config, load, typed) { + var isArray$1 = Array.isArray; + var isNumber$2 = number$2.isNumber; + var isInteger$1 = number$2.isInteger; + var isString$2 = string$3.isString; - var DenseMatrix = type.DenseMatrix; + var validateIndex$1 = array$2.validateIndex; - /** - * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, b). - * Callback function invoked MxN times. - * - * C(i,j,...z) = f(Aij..z, b) - * - * @param {Matrix} a The DenseMatrix instance (A) - * @param {Scalar} b The Scalar value - * @param {Function} callback The f(Aij..z,b) operation to invoke - * @param {boolean} inverse A true value indicates callback should be invoked f(b,Aij..z) - * - * @return {Matrix} DenseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97659042 - */ - var algorithm14 = function (a, b, callback, inverse) { - // a arrays - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - - // datatype - var dt; - // callback signature to use - var cf = callback; + function factory$14 (type, config, load, typed) { + var Matrix$$1 = load(Matrix); // force loading Matrix (do not use via type.Matrix) + var equalScalar$$1 = load(equalScalar); - // process data types - if (typeof adt === 'string') { - // datatype - dt = adt; - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); + /** + * Sparse Matrix implementation. This type implements a Compressed Column Storage format + * for sparse matrices. + * @class SparseMatrix + */ + function SparseMatrix(data, datatype) { + if (!(this instanceof SparseMatrix)) + throw new SyntaxError('Constructor must be called with the new operator'); + if (datatype && !isString$2(datatype)) + throw new Error('Invalid datatype: ' + datatype); + + if (type.isMatrix(data)) { + // create from matrix + _createFromMatrix(this, data, datatype); + } + else if (data && isArray$1(data.index) && isArray$1(data.ptr) && isArray$1(data.size)) { + // initialize fields + this._values = data.values; + this._index = data.index; + this._ptr = data.ptr; + this._size = data.size; + this._datatype = datatype || data.datatype; + } + else if (isArray$1(data)) { + // create from array + _createFromArray(this, data, datatype); + } + else if (data) { + // unsupported type + throw new TypeError('Unsupported type of data (' + utils.types.type(data) + ')'); + } + else { + // nothing provided + this._values = []; + this._index = []; + this._ptr = [0]; + this._size = [0, 0]; + this._datatype = datatype; + } } - // populate cdata, iterate through dimensions - var cdata = asize.length > 0 ? _iterate(cf, 0, asize, asize[0], adata, b, inverse) : []; - - // c matrix - return new DenseMatrix({ - data: cdata, - size: clone(asize), - datatype: dt - }); - }; - - // recursive function - var _iterate = function (f, level, s, n, av, bv, inverse) { - // initialize array for this level - var cv = []; - // check we reach the last level - if (level === s.length - 1) { - // loop arrays in last level - for (var i = 0; i < n; i++) { - // invoke callback and store value - cv[i] = inverse ? f(bv, av[i]) : f(av[i], bv); + var _createFromMatrix = function (matrix, source, datatype) { + // check matrix type + if (source.type === 'SparseMatrix') { + // clone arrays + matrix._values = source._values ? object$2.clone(source._values) : undefined; + matrix._index = object$2.clone(source._index); + matrix._ptr = object$2.clone(source._ptr); + matrix._size = object$2.clone(source._size); + matrix._datatype = datatype || source._datatype; } - } - else { - // iterate current level - for (var j = 0; j < n; j++) { - // iterate next level - cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv, inverse); + else { + // build from matrix data + _createFromArray(matrix, source.valueOf(), datatype || source._datatype); } - } - return cv; - }; - - return algorithm14; -} - -var name$19 = 'algorithm14'; -var factory_1$21 = factory$21; - -var algorithm14 = { - name: name$19, - factory: factory_1$21 -}; - -var extend = object.extend; - -function factory$22 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var addScalar$$1 = load(addScalar); - var latex$$1 = latex; - - var algorithm01$$1 = load(algorithm01); - var algorithm04$$1 = load(algorithm04); - var algorithm10$$1 = load(algorithm10); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Add two or more values, `x + y`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.add(x, y) - * math.add(x, y, z, ...) - * - * Examples: - * - * math.add(2, 3); // returns number 5 - * math.add(2, 3, 4); // returns number 9 - * - * var a = math.complex(2, 3); - * var b = math.complex(-4, 1); - * math.add(a, b); // returns Complex -2 + 4i - * - * math.add([1, 2, 3], 4); // returns Array [5, 6, 7] - * - * var c = math.unit('5 cm'); - * var d = math.unit('2.1 mm'); - * math.add(c, d); // returns Unit 52.1 mm - * - * math.add("2.3", "4"); // returns number 6.3 - * - * See also: - * - * subtract, sum - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to add - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to add - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Sum of `x` and `y` - */ - var add = typed('add', extend({ - // we extend the signatures of addScalar with signatures dealing with matrices - - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, addScalar$$1); - }, - - 'DenseMatrix, SparseMatrix': function (x, y) { - return algorithm01$$1(x, y, addScalar$$1, false); - }, - - 'SparseMatrix, DenseMatrix': function (x, y) { - return algorithm01$$1(y, x, addScalar$$1, true); - }, - - 'SparseMatrix, SparseMatrix': function (x, y) { - return algorithm04$$1(x, y, addScalar$$1); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return add(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return add(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return add(x, matrix$$1(y)); - }, + }; + + var _createFromArray = function (matrix, data, datatype) { + // initialize fields + matrix._values = []; + matrix._index = []; + matrix._ptr = []; + matrix._datatype = datatype; + // discover rows & columns, do not use math.size() to avoid looping array twice + var rows = data.length; + var columns = 0; + + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + + if (isString$2(datatype)) { + // find signature that matches (datatype, datatype) + eq = typed.find(equalScalar$$1, [datatype, datatype]) || equalScalar$$1; + // convert 0 to the same datatype + zero = typed.convert(0, datatype); + } + + // check we have rows (empty array) + if (rows > 0) { + // column index + var j = 0; + do { + // store pointer to values index + matrix._ptr.push(matrix._index.length); + // loop rows + for (var i = 0; i < rows; i++) { + // current row + var row = data[i]; + // check row is an array + if (isArray$1(row)) { + // update columns if needed (only on first column) + if (j === 0 && columns < row.length) + columns = row.length; + // check row has column + if (j < row.length) { + // value + var v = row[j]; + // check value != 0 + if (!eq(v, zero)) { + // store value + matrix._values.push(v); + // index + matrix._index.push(i); + } + } + } + else { + // update columns if needed (only on first column) + if (j === 0 && columns < 1) + columns = 1; + // check value != 0 (row is a scalar) + if (!eq(row, zero)) { + // store value + matrix._values.push(row); + // index + matrix._index.push(i); + } + } + } + // increment index + j++; + } + while (j < columns); + } + // store number of values in ptr + matrix._ptr.push(matrix._index.length); + // size + matrix._size = [rows, columns]; + }; + + SparseMatrix.prototype = new Matrix$$1(); - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, addScalar$$1, false); - }, + /** + * Attach type information + */ + SparseMatrix.prototype.type = 'SparseMatrix'; + SparseMatrix.prototype.isSparseMatrix = true; - 'SparseMatrix, any': function (x, y) { - return algorithm10$$1(x, y, addScalar$$1, false); - }, + /** + * Get the storage format used by the matrix. + * + * Usage: + * var format = matrix.storage() // retrieve storage format + * + * @memberof SparseMatrix + * @return {string} The storage format. + */ + SparseMatrix.prototype.storage = function () { + return 'sparse'; + }; - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, addScalar$$1, true); - }, + /** + * Get the datatype of the data stored in the matrix. + * + * Usage: + * var format = matrix.datatype() // retrieve matrix datatype + * + * @memberof SparseMatrix + * @return {string} The datatype. + */ + SparseMatrix.prototype.datatype = function () { + return this._datatype; + }; - 'any, SparseMatrix': function (x, y) { - return algorithm10$$1(y, x, addScalar$$1, true); - }, + /** + * Create a new SparseMatrix + * @memberof SparseMatrix + * @param {Array} data + * @param {string} [datatype] + */ + SparseMatrix.prototype.create = function (data, datatype) { + return new SparseMatrix(data, datatype); + }; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, addScalar$$1, false).valueOf(); - }, + /** + * Get the matrix density. + * + * Usage: + * var density = matrix.density() // retrieve matrix density + * + * @memberof SparseMatrix + * @return {number} The matrix density. + */ + SparseMatrix.prototype.density = function () { + // rows & columns + var rows = this._size[0]; + var columns = this._size[1]; + // calculate density + return rows !== 0 && columns !== 0 ? (this._index.length / (rows * columns)) : 0; + }; + + /** + * 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 + * + * @memberof SparseMatrix + * @param {Index} index + * @param {Array | Maytrix | *} [replacement] + * @param {*} [defaultValue=0] Default value, filled in on new entries when + * the matrix is resized. If not provided, + * new matrix elements will be filled with zeros. + */ + SparseMatrix.prototype.subset = function (index, replacement, defaultValue) { // check it is a pattern matrix + if (!this._values) + throw new Error('Cannot invoke subset on a Pattern only matrix'); - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, addScalar$$1, true).valueOf(); - }, + // check arguments + switch (arguments.length) { + case 1: + return _getsubset(this, index); - 'any, any': addScalar$$1, + // intentional fall through + case 2: + case 3: + return _setsubset(this, index, replacement, defaultValue); - 'any, any, ...any': function (x, y, rest) { - var result = add(x, y); + default: + throw new SyntaxError('Wrong number of arguments'); + } + }; + + var _getsubset = function (matrix, idx) { + // check idx + if (!type.isIndex(idx)) { + throw new TypeError('Invalid index'); + } - for (var i = 0; i < rest.length; i++) { - result = add(result, rest[i]); + var isScalar = idx.isScalar(); + if (isScalar) { + // return a scalar + return matrix.get(idx.min()); + } + // validate dimensions + var size = idx.size(); + if (size.length != matrix._size.length) { + throw new DimensionError_1(size.length, matrix._size.length); } - return result; - } - }, addScalar$$1.signatures)); - - add.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['add'] + '${args[1]}\\right)' - }; - - return add; -} - -var name$20 = 'add'; -var factory_1$22 = factory$22; - -var add = { - name: name$20, - factory: factory_1$22 -}; + // vars + var i, ii, k, kk; + + // validate if any of the ranges in the index is out of range + var min = idx.min(); + var max = idx.max(); + for (i = 0, ii = matrix._size.length; i < ii; i++) { + validateIndex$1(min[i], matrix._size[i]); + validateIndex$1(max[i], matrix._size[i]); + } + + // matrix arrays + var mvalues = matrix._values; + var mindex = matrix._index; + var mptr = matrix._ptr; + + // rows & columns dimensions for result matrix + var rows = idx.dimension(0); + var columns = idx.dimension(1); + + // workspace & permutation vector + var w = []; + var pv = []; + + // loop rows in resulting matrix + rows.forEach(function (i, r) { + // update permutation vector + pv[i] = r[0]; + // mark i in workspace + w[i] = true; + }); -function factory$23 (type, config, load) { - - var add$$1 = load(add); - var equalScalar$$1 = load(equalScalar); - - /** - * An ordered Sparse Accumulator is a representation for a sparse vector that includes a dense array - * of the vector elements and an ordered list of non-zero elements. - */ - function Spa() { - if (!(this instanceof Spa)) - throw new SyntaxError('Constructor must be called with the new operator'); + // result matrix arrays + var values = mvalues ? [] : undefined; + var index = []; + var ptr = []; + + // loop columns in result matrix + columns.forEach(function (j) { + // update ptr + ptr.push(index.length); + // loop values in column j + for (k = mptr[j], kk = mptr[j + 1]; k < kk; k++) { + // row + i = mindex[k]; + // check row is in result matrix + if (w[i] === true) { + // push index + index.push(pv[i]); + // check we need to process values + if (values) + values.push(mvalues[k]); + } + } + }); + // update ptr + ptr.push(index.length); + + // return matrix + return new SparseMatrix({ + values: values, + index: index, + ptr: ptr, + size: size, + datatype: matrix._datatype + }); + }; - // allocate vector, TODO use typed arrays - this._values = []; - this._heap = new type.FibonacciHeap(); - } - - /** - * Attach type information - */ - Spa.prototype.type = 'Spa'; - Spa.prototype.isSpa = true; - - /** - * Set the value for index i. - * - * @param {number} i The index - * @param {number | BigNumber | Complex} The value at index i - */ - Spa.prototype.set = function (i, v) { - // check we have a value @ i - if (!this._values[i]) { - // insert in heap - var node = this._heap.insert(i, v); - // set the value @ i - this._values[i] = node; - } - else { - // update the value @ i - this._values[i].value = v; - } - }; - - Spa.prototype.get = function (i) { - var node = this._values[i]; - if (node) - return node.value; - return 0; - }; - - Spa.prototype.accumulate = function (i, v) { - // node @ i - var node = this._values[i]; - if (!node) { - // insert in heap - node = this._heap.insert(i, v); - // initialize value - this._values[i] = node; - } - else { - // accumulate value - node.value = add$$1(node.value, v); - } - }; - - Spa.prototype.forEach = function (from, to, callback) { - // references - var heap = this._heap; - var values = this._values; - // nodes - var nodes = []; - // node with minimum key, save it - var node = heap.extractMinimum(); - if (node) - nodes.push(node); - // extract nodes from heap (ordered) - while (node && node.key <= to) { - // check it is in range - if (node.key >= from) { - // check value is not zero - if (!equalScalar$$1(node.value, 0)) { - // invoke callback - callback(node.key, node.value, this); + var _setsubset = function (matrix, index, submatrix, defaultValue) { + // check index + if (!index || index.isIndex !== true) { + 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 (type.isMatrix(submatrix)) { + // submatrix size + sSize = submatrix.size(); + // use array representation + submatrix = submatrix.toArray(); + } + else { + // get submatrix size (array, scalar) + sSize = array$2.size(submatrix); + } + + // check index is a scalar + if (isScalar) { + // verify submatrix is a scalar + if (sSize.length !== 0) { + throw new TypeError('Scalar expected'); } + // set value + matrix.set(index.min(), submatrix, defaultValue); } - // extract next node, save it - node = heap.extractMinimum(); - if (node) - nodes.push(node); - } - // reinsert all nodes in heap - for (var i = 0; i < nodes.length; i++) { - // current node - var n = nodes[i]; - // insert node in heap - node = heap.insert(n.key, n.value); - // update values - values[node.key] = node; - } - }; - - Spa.prototype.swap = function (i, j) { - // node @ i and j - var nodei = this._values[i]; - var nodej = this._values[j]; - // check we need to insert indeces - if (!nodei && nodej) { - // insert in heap - nodei = this._heap.insert(i, nodej.value); - // remove from heap - this._heap.remove(nodej); - // set values - this._values[i] = nodei; - this._values[j] = undefined; - } - else if (nodei && !nodej) { - // insert in heap - nodej = this._heap.insert(j, nodei.value); - // remove from heap - this._heap.remove(nodei); - // set values - this._values[j] = nodej; - this._values[i] = undefined; - } - else if (nodei && nodej) { - // swap values - var v = nodei.value; - nodei.value = nodej.value; - nodej.value = v; - } - }; - - return Spa; -} - -var name$21 = 'Spa'; -var path$7 = 'type'; -var factory_1$23 = factory$23; - -var Spa = { - name: name$21, - path: path$7, - factory: factory_1$23 -}; - -function factory$24 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over SparseMatrix items and invokes the callback function f(Dij, Sij). - * Callback function invoked M*N times. - * - * - * ┌ f(Dij, Sij) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ f(Dij, 0) ; otherwise - * - * - * @param {Matrix} denseMatrix The DenseMatrix instance (D) - * @param {Matrix} sparseMatrix The SparseMatrix instance (C) - * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) - * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) - * - * @return {Matrix} DenseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 - */ - var algorithm03 = function (denseMatrix, sparseMatrix, callback, inverse) { - // dense matrix arrays - var adata = denseMatrix._data; - var asize = denseMatrix._size; - var adt = denseMatrix._datatype; - // sparse matrix arrays - var bvalues = sparseMatrix._values; - var bindex = sparseMatrix._index; - var bptr = sparseMatrix._ptr; - var bsize = sparseMatrix._size; - var bdt = sparseMatrix._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // sparse matrix cannot be a Pattern matrix - if (!bvalues) - throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result (DenseMatrix) - var cdata = []; + else { + // validate dimensions, index size must be one or two dimensions + if (iSize.length !== 1 && iSize.length !== 2) { + throw new DimensionError_1(iSize.length, matrix._size.length, '<'); + } + + // check submatrix and index have the same dimensions + if (sSize.length < iSize.length) { + // calculate number of missing outer dimensions + var i = 0; + var outer = 0; + while (iSize[i] === 1 && sSize[i] === 1) { + i++; + } + while (iSize[i] === 1) { + outer++; + i++; + } + // unsqueeze both outer and inner dimensions + submatrix = array$2.unsqueeze(submatrix, iSize.length, outer, sSize); + } + + // check whether the size of the submatrix matches the index size + if (!object$2.deepEqual(iSize, sSize)) { + throw new DimensionError_1(iSize, sSize, '>'); + } + + // offsets + var x0 = index.min()[0]; + var y0 = index.min()[1]; + + // submatrix rows and columns + var m = sSize[0]; + var n = sSize[1]; + + // loop submatrix + for (var x = 0; x < m; x++) { + // loop columns + for (var y = 0; y < n; y++) { + // value at i, j + var v = submatrix[x][y]; + // invoke set (zero value will remove entry from matrix) + matrix.set([x + x0, y + y0], v, defaultValue); + } + } + } + return matrix; + }; - // initialize dense matrix - for (var z = 0; z < rows; z++) { - // initialize row - cdata[z] = []; - } + /** + * Get a single element from the matrix. + * @memberof SparseMatrix + * @param {number[]} index Zero-based index + * @return {*} value + */ + SparseMatrix.prototype.get = function (index) { + if (!isArray$1(index)) + throw new TypeError('Array expected'); + if (index.length != this._size.length) + throw new DimensionError_1(index.length, this._size.length); + + // check it is a pattern matrix + if (!this._values) + throw new Error('Cannot invoke get on a Pattern only matrix'); + + // row and column + var i = index[0]; + var j = index[1]; + + // check i, j are valid + validateIndex$1(i, this._size[0]); + validateIndex$1(j, this._size[1]); + + // find value index + var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index); + // check k is prior to next column k and it is in the correct row + if (k < this._ptr[j + 1] && this._index[k] === i) + return this._values[k]; - // workspace - var x = []; - // marks indicating we have a value in x for a given column - var w = []; + return 0; + }; + + /** + * Replace a single element in the matrix. + * @memberof SparseMatrix + * @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 set to zero. + * @return {SparseMatrix} self + */ + SparseMatrix.prototype.set = function (index, v, defaultValue) { + if (!isArray$1(index)) + throw new TypeError('Array expected'); + if (index.length != this._size.length) + throw new DimensionError_1(index.length, this._size.length); + + // check it is a pattern matrix + if (!this._values) + throw new Error('Cannot invoke set on a Pattern only matrix'); + + // row and column + var i = index[0]; + var j = index[1]; - // loop columns in b - for (var j = 0; j < columns; j++) { - // column mark - var mark = j + 1; - // values in column j - for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - var i = bindex[k]; - // update workspace - x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); - w[i] = mark; - } - // process workspace - for (var y = 0; y < rows; y++) { - // check we have a calculated value for current row - if (w[y] === mark) { - // use calculated value - cdata[y][j] = x[y]; + // rows & columns + var rows = this._size[0]; + var columns = this._size[1]; + + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + + if (isString$2(this._datatype)) { + // find signature that matches (datatype, datatype) + eq = typed.find(equalScalar$$1, [this._datatype, this._datatype]) || equalScalar$$1; + // convert 0 to the same datatype + zero = typed.convert(0, this._datatype); + } + + // check we need to resize matrix + if (i > rows - 1 || j > columns - 1) { + // resize matrix + _resize(this, Math.max(i + 1, rows), Math.max(j + 1, columns), defaultValue); + // update rows & columns + rows = this._size[0]; + columns = this._size[1]; + } + + // check i, j are valid + validateIndex$1(i, rows); + validateIndex$1(j, columns); + + // find value index + var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index); + // check k is prior to next column k and it is in the correct row + if (k < this._ptr[j + 1] && this._index[k] === i) { + // check value != 0 + if (!eq(v, zero)) { + // update value + this._values[k] = v; } else { - // calculate value - cdata[y][j] = inverse ? cf(zero, adata[y][j]) : cf(adata[y][j], zero); + // remove value from matrix + _remove(k, j, this._values, this._index, this._ptr); } } - } - - // return dense matrix - return new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); - }; - - return algorithm03; -} - -var name$22 = 'algorithm03'; -var factory_1$24 = factory$24; - -var algorithm03 = { - name: name$22, - factory: factory_1$24 -}; - -function factory$25 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over SparseMatrix A and SparseMatrix B items (zero and nonzero) and invokes the callback function f(Aij, Bij). - * Callback function invoked MxN times. - * - * C(i,j) = f(Aij, Bij) - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} DenseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm07 = function (a, b, callback) { - // sparse matrix arrays - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } + else { + // insert value @ (i, j) + _insert(k, i, j, v, this._values, this._index, this._ptr); + } - // vars - var i, j; + return this; + }; - // result arrays - var cdata = []; - // initialize c - for (i = 0; i < rows; i++) - cdata[i] = []; - - // matrix - var c = new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); - - // workspaces - var xa = []; - var xb = []; - // marks indicating we have a value in x for a given column - var wa = []; - var wb = []; - - // loop columns - for (j = 0; j < columns; j++) { - // columns mark - var mark = j + 1; - // scatter the values of A(:,j) into workspace - _scatter(a, j, wa, xa, mark); - // scatter the values of B(:,j) into workspace - _scatter(b, j, wb, xb, mark); - // loop rows - for (i = 0; i < rows; i++) { - // matrix values @ i,j - var va = wa[i] === mark ? xa[i] : zero; - var vb = wb[i] === mark ? xb[i] : zero; - // invoke callback - cdata[i][j] = cf(va, vb); - } - } - - // return sparse matrix - return c; - }; - - var _scatter = function (m, j, w, x, mark) { - // a arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // loop values in column j - for (var k = ptr[j], k1 = ptr[j + 1]; k < k1; k++) { - // row - var i = index[k]; - // update workspace - w[i] = mark; - x[i] = values[k]; - } - }; - - return algorithm07; -} - -var name$23 = 'algorithm07'; -var factory_1$25 = factory$25; - -var algorithm07 = { - name: name$23, - factory: factory_1$25 -}; + var _getValueIndex = function(i, top, bottom, index) { + // check row is on the bottom side + if (bottom - top === 0) + return bottom; + // loop rows [top, bottom[ + for (var r = top; r < bottom; r++) { + // check we found value index + if (index[r] === i) + return r; + } + // we did not find row + return top; + }; -function factory$26 (type, config, load, typed) { + var _remove = function (k, j, values, index, ptr) { + // remove value @ k + values.splice(k, 1); + index.splice(k, 1); + // update pointers + for (var x = j + 1; x < ptr.length; x++) + ptr[x]--; + }; - var DenseMatrix = type.DenseMatrix; + var _insert = function (k, i, j, v, values, index, ptr) { + // insert value + values.splice(k, 0, v); + // update row for k + index.splice(k, 0, i); + // update column pointers + for (var x = j + 1; x < ptr.length; x++) + ptr[x]++; + }; + + /** + * Resize the matrix to the given size. Returns a copy of the matrix when + * `copy=true`, otherwise return the matrix itself (resize in place). + * + * @memberof SparseMatrix + * @param {number[]} size The new size the matrix should have. + * @param {*} [defaultValue=0] Default value, filled in on new entries. + * If not provided, the matrix elements will + * be filled with zeros. + * @param {boolean} [copy] Return a resized copy of the matrix + * + * @return {Matrix} The resized matrix + */ + SparseMatrix.prototype.resize = function (size, defaultValue, copy) { + // validate arguments + if (!isArray$1(size)) + throw new TypeError('Array expected'); + if (size.length !== 2) + throw new Error('Only two dimensions matrix are supported'); - /** - * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). - * Callback function invoked MxN times. - * - * - * ┌ f(Sij, b) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ f(0, b) ; otherwise - * - * - * @param {Matrix} s The SparseMatrix instance (S) - * @param {Scalar} b The Scalar value - * @param {Function} callback The f(Aij,b) operation to invoke - * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) - * - * @return {Matrix} DenseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 - */ - var algorithm12 = function (s, b, callback, inverse) { - // sparse matrix arrays - var avalues = s._values; - var aindex = s._index; - var aptr = s._ptr; - var asize = s._size; - var adt = s._datatype; - - // sparse matrix cannot be a Pattern matrix - if (!avalues) - throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string') { - // datatype - dt = adt; - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } + // check sizes + size.forEach(function (value) { + if (!number$2.isNumber(value) || !number$2.isInteger(value) || value < 0) { + throw new TypeError('Invalid size, must contain positive integers ' + + '(size: ' + string$3.format(size) + ')'); + } + }); + + // matrix to resize + var m = copy ? this.clone() : this; + // resize matrix + return _resize(m, size[0], size[1], defaultValue); + }; - // result arrays - var cdata = []; - // matrix - var c = new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); + var _resize = function (matrix, rows, columns, defaultValue) { + // value to insert at the time of growing matrix + var value = defaultValue || 0; + + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + + if (isString$2(matrix._datatype)) { + // find signature that matches (datatype, datatype) + eq = typed.find(equalScalar$$1, [matrix._datatype, matrix._datatype]) || equalScalar$$1; + // convert 0 to the same datatype + zero = typed.convert(0, matrix._datatype); + // convert value to the same datatype + value = typed.convert(value, matrix._datatype); + } + + // should we insert the value? + var ins = !eq(value, zero); - // workspaces - var x = []; - // marks indicating we have a value in x for a given column - var w = []; + // old columns and rows + var r = matrix._size[0]; + var c = matrix._size[1]; - // loop columns - for (var j = 0; j < columns; j++) { - // columns mark - var mark = j + 1; - // values in j - for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - var r = aindex[k]; - // update workspace - x[r] = avalues[k]; - w[r] = mark; - } - // loop rows - for (var i = 0; i < rows; i++) { - // initialize C on first column - if (j === 0) { - // create row array - cdata[i] = []; + var i, j, k; + + // check we need to increase columns + if (columns > c) { + // loop new columns + for (j = c; j < columns; j++) { + // update matrix._ptr for current column + matrix._ptr[j] = matrix._values.length; + // check we need to insert matrix._values + if (ins) { + // loop rows + for (i = 0; i < r; i++) { + // add new matrix._values + matrix._values.push(value); + // update matrix._index + matrix._index.push(i); + } + } } - // check sparse matrix has a value @ i,j - if (w[i] === mark) { - // invoke callback, update C - cdata[i][j] = inverse ? cf(b, x[i]) : cf(x[i], b); + // store number of matrix._values in matrix._ptr + matrix._ptr[columns] = matrix._values.length; + } + else if (columns < c) { + // truncate matrix._ptr + matrix._ptr.splice(columns + 1, c - columns); + // truncate matrix._values and matrix._index + matrix._values.splice(matrix._ptr[columns], matrix._values.length); + matrix._index.splice(matrix._ptr[columns], matrix._index.length); + } + // update columns + c = columns; + + // check we need to increase rows + if (rows > r) { + // check we have to insert values + if (ins) { + // inserts + var n = 0; + // loop columns + for (j = 0; j < c; j++) { + // update matrix._ptr for current column + matrix._ptr[j] = matrix._ptr[j] + n; + // where to insert matrix._values + k = matrix._ptr[j + 1] + n; + // pointer + var p = 0; + // loop new rows, initialize pointer + for (i = r; i < rows; i++, p++) { + // add value + matrix._values.splice(k + p, 0, value); + // update matrix._index + matrix._index.splice(k + p, 0, i); + // increment inserts + n++; + } + } + // store number of matrix._values in matrix._ptr + matrix._ptr[c] = matrix._values.length; } - else { - // dense matrix value @ i, j - cdata[i][j] = inverse ? cf(b, 0) : cf(0, b); + } + else if (rows < r) { + // deletes + var d = 0; + // loop columns + for (j = 0; j < c; j++) { + // update matrix._ptr for current column + matrix._ptr[j] = matrix._ptr[j] - d; + // where matrix._values start for next column + var k0 = matrix._ptr[j]; + var k1 = matrix._ptr[j + 1] - d; + // loop matrix._index + for (k = k0; k < k1; k++) { + // row + i = matrix._index[k]; + // check we need to delete value and matrix._index + if (i > rows - 1) { + // remove value + matrix._values.splice(k, 1); + // remove item from matrix._index + matrix._index.splice(k, 1); + // increase deletes + d++; + } + } } + // update matrix._ptr for current column + matrix._ptr[j] = matrix._values.length; } - } - - // return sparse matrix - return c; - }; - - return algorithm12; -} - -var name$24 = 'algorithm12'; -var factory_1$26 = factory$26; + // update matrix._size + matrix._size[0] = rows; + matrix._size[1] = columns; + // return matrix + return matrix; + }; -var algorithm12 = { - name: name$24, - factory: factory_1$26 -}; + /** + * Reshape the matrix to the given size. Returns a copy of the matrix when + * `copy=true`, otherwise return the matrix itself (reshape in place). + * + * NOTE: This might be better suited to copy by default, instead of modifying + * in place. For now, it operates in place to remain consistent with + * resize(). + * + * @memberof SparseMatrix + * @param {number[]} size The new size the matrix should have. + * @param {boolean} [copy] Return a reshaped copy of the matrix + * + * @return {Matrix} The reshaped matrix + */ + SparseMatrix.prototype.reshape = function (size, copy) { -var nearlyEqual$2 = number.nearlyEqual; + // validate arguments + if (!isArray$1(size)) + throw new TypeError('Array expected'); + if (size.length !== 2) + throw new Error('Sparse matrices can only be reshaped in two dimensions'); + // check sizes + size.forEach(function (value) { + if (!number$2.isNumber(value) || !number$2.isInteger(value) || value < 0) { + throw new TypeError('Invalid size, must contain positive integers ' + + '(size: ' + string$3.format(size) + ')'); + } + }); -function factory$27 (type, config, load, typed) { + // m * n must not change + if(this._size[0] * this._size[1] !== size[0] * size[1]) { + throw new Error('Reshaping sparse matrix will result in the wrong number of elements'); + } - var matrix$$1 = load(matrix); + // matrix to reshape + var m = copy ? this.clone() : this; - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + // return unchanged if the same shape + if(this._size[0] === size[0] && this._size[1] === size[1]) { + return m; + } - var latex$$1 = latex; + // Convert to COO format (generate a column index) + var colIndex = []; + for(var i=0; i= minRow && i <= maxRow) { + // zero values + if (!skipZeros) { + for (var x = p; x < i; x++) + invoke(0, x - minRow, j - minColumn); + } + // value @ k + invoke(matrix._values[k], i - minRow, j - minColumn); + } + // update pointer + p = i + 1; + } + // zero values + if (!skipZeros) { + for (var y = p; y <= maxRow; y++) + invoke(0, y - minRow, j - minColumn); + } + } + // store number of values in ptr + ptr.push(values.length); + // return sparse matrix + return new SparseMatrix({ + values: values, + index: index, + ptr: ptr, + size: [maxRow - minRow + 1, maxColumn - minColumn + 1] + }); + }; + + /** + * Execute a callback function on each entry of the matrix. + * @memberof SparseMatrix + * @param {Function} callback The callback function is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix being traversed. + * @param {boolean} [skipZeros] Invoke callback function for non-zero values only. + */ + SparseMatrix.prototype.forEach = function (callback, skipZeros) { + // check it is a pattern matrix + if (!this._values) + throw new Error('Cannot invoke forEach on a Pattern only matrix'); + // matrix instance + var me = this; + // rows and columns + var rows = this._size[0]; + var columns = this._size[1]; + // loop columns + for (var j = 0; j < columns; j++) { + // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] + var k0 = this._ptr[j]; + var k1 = this._ptr[j + 1]; + // column pointer + var p = 0; + // loop k within [k0, k1[ + for (var k = k0; k < k1; k++) { + // row index + var i = this._index[k]; + // check we need to process zeros + if (!skipZeros) { + // zero values + for (var x = p; x < i; x++) + callback(0, [x, j], me); + } + // value @ k + callback(this._values[k], [i, j], me); + // update pointer + p = i + 1; + } + // check we need to process zeros + if (!skipZeros) { + // zero values + for (var y = p; y < rows; y++) + callback(0, [y, j], me); + } + } + }; + + /** + * Create an Array with a copy of the data of the SparseMatrix + * @memberof SparseMatrix + * @returns {Array} array + */ + SparseMatrix.prototype.toArray = function () { + return _toArray(this._values, this._index, this._ptr, this._size, true); + }; - 'Array, Array': function (x, y) { - // use matrix implementation - return smaller(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + /** + * Get the primitive value of the SparseMatrix: a two dimensions array + * @memberof SparseMatrix + * @returns {Array} array + */ + SparseMatrix.prototype.valueOf = function () { + return _toArray(this._values, this._index, this._ptr, this._size, false); + }; + + var _toArray = function (values, index, ptr, size, copy) { + // rows and columns + var rows = size[0]; + var columns = size[1]; + // result + var a = []; + // vars + var i, j; + // initialize array + for (i = 0; i < rows; i++) { + a[i] = []; + for (j = 0; j < columns; j++) + a[i][j] = 0; + } - 'Array, Matrix': function (x, y) { - // use matrix implementation - return smaller(matrix$$1(x), y); - }, + // loop columns + for (j = 0; j < columns; j++) { + // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] + var k0 = ptr[j]; + var k1 = ptr[j + 1]; + // loop k within [k0, k1[ + for (var k = k0; k < k1; k++) { + // row index + i = index[k]; + // set value (use one for pattern matrix) + a[i][j] = values ? (copy ? object$2.clone(values[k]) : values[k]) : 1; + } + } + return a; + }; + + /** + * Get a string representation of the matrix, with optional formatting options. + * @memberof SparseMatrix + * @param {Object | number | Function} [options] Formatting options. See + * lib/utils/number:format for a + * description of the available + * options. + * @returns {string} str + */ + SparseMatrix.prototype.format = function (options) { + // rows and columns + var rows = this._size[0]; + var columns = this._size[1]; + // density + var density = this.density(); + // rows & columns + var str = 'Sparse Matrix [' + string$3.format(rows, options) + ' x ' + string$3.format(columns, options) + '] density: ' + string$3.format(density, options) + '\n'; + // loop columns + for (var j = 0; j < columns; j++) { + // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] + var k0 = this._ptr[j]; + var k1 = this._ptr[j + 1]; + // loop k within [k0, k1[ + for (var k = k0; k < k1; k++) { + // row index + var i = this._index[k]; + // append value + str += '\n (' + string$3.format(i, options) + ', ' + string$3.format(j, options) + ') ==> ' + (this._values ? string$3.format(this._values[k], options) : 'X'); + } + } + return str; + }; + + /** + * Get a string representation of the matrix + * @memberof SparseMatrix + * @returns {string} str + */ + SparseMatrix.prototype.toString = function () { + return string$3.format(this.toArray()); + }; + + /** + * Get a JSON representation of the matrix + * @memberof SparseMatrix + * @returns {Object} + */ + SparseMatrix.prototype.toJSON = function () { + return { + mathjs: 'SparseMatrix', + values: this._values, + index: this._index, + ptr: this._ptr, + size: this._size, + datatype: this._datatype + }; + }; - 'Matrix, Array': function (x, y) { - // use matrix implementation - return smaller(x, matrix$$1(y)); - }, + /** + * Get the kth Matrix diagonal. + * + * @memberof SparseMatrix + * @param {number | BigNumber} [k=0] The kth diagonal where the vector will retrieved. + * + * @returns {Matrix} The matrix vector with the diagonal values. + */ + SparseMatrix.prototype.diagonal = function(k) { + // validate k if any + if (k) { + // convert BigNumber to a number + if (type.isBigNumber(k)) + k = k.toNumber(); + // is must be an integer + if (!isNumber$2(k) || !isInteger$1(k)) { + throw new TypeError ('The parameter k must be an integer number'); + } + } + else { + // default value + k = 0; + } - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, smaller, false); - }, + var kSuper = k > 0 ? k : 0; + var kSub = k < 0 ? -k : 0; + + // rows & columns + var rows = this._size[0]; + var columns = this._size[1]; + + // number diagonal values + var n = Math.min(rows - kSub, columns - kSuper); + + // diagonal arrays + var values = []; + var index = []; + var ptr = []; + // initial ptr value + ptr[0] = 0; + // loop columns + for (var j = kSuper; j < columns && values.length < n; j++) { + // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] + var k0 = this._ptr[j]; + var k1 = this._ptr[j + 1]; + // loop x within [k0, k1[ + for (var x = k0; x < k1; x++) { + // row index + var i = this._index[x]; + // check row + if (i === j - kSuper + kSub) { + // value on this column + values.push(this._values[x]); + // store row + index[values.length - 1] = i - kSub; + // exit loop + break; + } + } + } + // close ptr + ptr.push(values.length); + // return matrix + return new SparseMatrix({ + values: values, + index: index, + ptr: ptr, + size: [n, 1] + }); + }; + + /** + * Generate a matrix from a JSON object + * @memberof SparseMatrix + * @param {Object} json An object structured like + * `{"mathjs": "SparseMatrix", "values": [], "index": [], "ptr": [], "size": []}`, + * where mathjs is optional + * @returns {SparseMatrix} + */ + SparseMatrix.fromJSON = function (json) { + return new SparseMatrix(json); + }; - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, smaller, false); - }, + /** + * Create a diagonal matrix. + * + * @memberof SparseMatrix + * @param {Array} size The matrix size. + * @param {number | Array | Matrix } value The values for the diagonal. + * @param {number | BigNumber} [k=0] The kth diagonal where the vector will be filled in. + * @param {string} [datatype] The Matrix datatype, values must be of this datatype. + * + * @returns {SparseMatrix} + */ + SparseMatrix.diagonal = function (size, value, k, defaultValue, datatype) { + if (!isArray$1(size)) + throw new TypeError('Array expected, size parameter'); + if (size.length !== 2) + throw new Error('Only two dimensions matrix are supported'); + + // map size & validate + size = size.map(function (s) { + // check it is a big number + if (type.isBigNumber(s)) { + // convert it + s = s.toNumber(); + } + // validate arguments + if (!isNumber$2(s) || !isInteger$1(s) || s < 1) { + throw new Error('Size values must be positive integers'); + } + return s; + }); + + // validate k if any + if (k) { + // convert BigNumber to a number + if (type.isBigNumber(k)) + k = k.toNumber(); + // is must be an integer + if (!isNumber$2(k) || !isInteger$1(k)) { + throw new TypeError ('The parameter k must be an integer number'); + } + } + else { + // default value + k = 0; + } - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, smaller, true); - }, + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, smaller, true); - }, + if (isString$2(datatype)) { + // find signature that matches (datatype, datatype) + eq = typed.find(equalScalar$$1, [datatype, datatype]) || equalScalar$$1; + // convert 0 to the same datatype + zero = typed.convert(0, datatype); + } + + var kSuper = k > 0 ? k : 0; + var kSub = k < 0 ? -k : 0; + + // rows and columns + var rows = size[0]; + var columns = size[1]; + + // number of non-zero items + var n = Math.min(rows - kSub, columns - kSuper); + + // value extraction function + var _value; + + // check value + if (isArray$1(value)) { + // validate array + if (value.length !== n) { + // number of values in array must be n + throw new Error('Invalid value array length'); + } + // define function + _value = function (i) { + // return value @ i + return value[i]; + }; + } + else if (type.isMatrix(value)) { + // matrix size + var ms = value.size(); + // validate matrix + if (ms.length !== 1 || ms[0] !== n) { + // number of values in array must be n + throw new Error('Invalid matrix length'); + } + // define function + _value = function (i) { + // return value @ i + return value.get([i]); + }; + } + else { + // define function + _value = function () { + // return value + return value; + }; + } + + // create arrays + var values = []; + var index = []; + var ptr = []; + + // loop items + for (var j = 0; j < columns; j++) { + // number of rows with value + ptr.push(values.length); + // diagonal index + var i = j - kSuper; + // check we need to set diagonal value + if (i >= 0 && i < n) { + // get value @ i + var v = _value(i); + // check for zero + if (!eq(v, zero)) { + // column + index.push(i + kSub); + // add value + values.push(v); + } + } + } + // last value should be number of values + ptr.push(values.length); + // create SparseMatrix + return new SparseMatrix({ + values: values, + index: index, + ptr: ptr, + size: [rows, columns] + }); + }; + + /** + * Swap rows i and j in Matrix. + * + * @memberof SparseMatrix + * @param {number} i Matrix row index 1 + * @param {number} j Matrix row index 2 + * + * @return {Matrix} The matrix reference + */ + SparseMatrix.prototype.swapRows = function (i, j) { + // check index + if (!isNumber$2(i) || !isInteger$1(i) || !isNumber$2(j) || !isInteger$1(j)) { + throw new Error('Row index must be positive integers'); + } + // check dimensions + if (this._size.length !== 2) { + throw new Error('Only two dimensional matrix is supported'); + } + // validate index + validateIndex$1(i, this._size[0]); + validateIndex$1(j, this._size[0]); + + // swap rows + SparseMatrix._swapRows(i, j, this._size[1], this._values, this._index, this._ptr); + // return current instance + return this; + }; + + /** + * Loop rows with data in column j. + * + * @param {number} j Column + * @param {Array} values Matrix values + * @param {Array} index Matrix row indeces + * @param {Array} ptr Matrix column pointers + * @param {Function} callback Callback function invoked for every row in column j + */ + SparseMatrix._forEachRow = function (j, values, index, ptr, callback) { + // indeces for column j + var k0 = ptr[j]; + var k1 = ptr[j + 1]; + // loop + for (var k = k0; k < k1; k++) { + // invoke callback + callback(index[k], values[k]); + } + }; + + /** + * Swap rows x and y in Sparse Matrix data structures. + * + * @param {number} x Matrix row index 1 + * @param {number} y Matrix row index 2 + * @param {number} columns Number of columns in matrix + * @param {Array} values Matrix values + * @param {Array} index Matrix row indeces + * @param {Array} ptr Matrix column pointers + */ + SparseMatrix._swapRows = function (x, y, columns, values, index, ptr) { + // loop columns + for (var j = 0; j < columns; j++) { + // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] + var k0 = ptr[j]; + var k1 = ptr[j + 1]; + // find value index @ x + var kx = _getValueIndex(x, k0, k1, index); + // find value index @ x + var ky = _getValueIndex(y, k0, k1, index); + // check both rows exist in matrix + if (kx < k1 && ky < k1 && index[kx] === x && index[ky] === y) { + // swap values (check for pattern matrix) + if (values) { + var v = values[kx]; + values[kx] = values[ky]; + values[ky] = v; + } + // next column + continue; + } + // check x row exist & no y row + if (kx < k1 && index[kx] === x && (ky >= k1 || index[ky] !== y)) { + // value @ x (check for pattern matrix) + var vx = values ? values[kx] : undefined; + // insert value @ y + index.splice(ky, 0, y); + if (values) + values.splice(ky, 0, vx); + // remove value @ x (adjust array index if needed) + index.splice(ky <= kx ? kx + 1 : kx, 1); + if (values) + values.splice(ky <= kx ? kx + 1 : kx, 1); + // next column + continue; + } + // check y row exist & no x row + if (ky < k1 && index[ky] === y && (kx >= k1 || index[kx] !== x)) { + // value @ y (check for pattern matrix) + var vy = values ? values[ky] : undefined; + // insert value @ x + index.splice(kx, 0, x); + if (values) + values.splice(kx, 0, vy); + // remove value @ y (adjust array index if needed) + index.splice(kx <= ky ? ky + 1 : ky, 1); + if (values) + values.splice(kx <= ky ? ky + 1 : ky, 1); + } + } + }; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, smaller, false).valueOf(); - }, + // register this type in the base class Matrix + type.Matrix._storage.sparse = SparseMatrix; - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, smaller, true).valueOf(); - } - }); + return SparseMatrix; + } - smaller.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['smaller'] + '${args[1]}\\right)' - }; + var name$13 = 'SparseMatrix'; + var path$6 = 'type'; + var factory_1$14 = factory$14; + var lazy$3 = false; // no lazy loading, as we alter type.Matrix._storage - return smaller; -} + var SparseMatrix = { + name: name$13, + path: path$6, + factory: factory_1$14, + lazy: lazy$3 + }; -var name$25 = 'smaller'; -var factory_1$27 = factory$27; + function factory$15 (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: + * + * var 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([]); + }, -var smaller = { - name: name$25, - factory: factory_1$27 -}; + 'string': function (format) { + return _create([], format); + }, + + 'string, string': function (format, datatype) { + return _create([], format, datatype); + }, -var nearlyEqual$3 = number.nearlyEqual; + 'Array': function (data) { + return _create(data); + }, + + 'Matrix': function (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)' + }; -function factory$28 (type, config, load, typed) { - - var matrix$$1 = load(matrix); + return matrix; - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + /** + * 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'); - var latex$$1 = latex; + // create instance + return new M(data, datatype); + } + } - /** - * Test whether value x is larger than y. - * - * The function returns true when x is larger than y and the relative - * difference between x and y is larger than the configured epsilon. The - * function cannot be used to compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.larger(x, y) - * - * Examples: - * - * math.larger(2, 3); // returns false - * math.larger(5, 2 + 2); // returns true - * - * var a = math.unit('5 cm'); - * var b = math.unit('2 inch'); - * math.larger(a, b); // returns false - * - * See also: - * - * equal, unequal, smaller, smallerEq, largerEq, compare - * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the x is larger than y, else returns false - */ - var larger = typed('larger', { + var name$14 = 'matrix'; + var factory_1$15 = factory$15; - 'boolean, boolean': function (x, y) { - return x > y; - }, + var matrix = { + name: name$14, + factory: factory_1$15 + }; - 'number, number': function (x, y) { - return x > y && !nearlyEqual$3(x, y, config.epsilon); - }, + function factory$16(type, config, load, typed) { - 'BigNumber, BigNumber': function (x, y) { - return x.gt(y) && !nearlyEqual(x, y, config.epsilon); - }, + /** + * Add two scalar values, `x + y`. + * This function is meant for internal use: it is used by the public function + * `add` + * + * This function does not support collections (Array or Matrix), and does + * not validate the number of of inputs. + * + * @param {number | BigNumber | Fraction | Complex | Unit} x First value to add + * @param {number | BigNumber | Fraction | Complex} y Second value to add + * @return {number | BigNumber | Fraction | Complex | Unit} Sum of `x` and `y` + * @private + */ + var add = typed('add', { - 'Fraction, Fraction': function (x, y) { - return x.compare(y) === 1; - }, + 'number, number': function (x, y) { + return x + y; + }, - 'Complex, Complex': function () { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, + 'Complex, Complex': function (x, y) { + return x.add(y); + }, - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return larger(x.value, y.value); - }, + 'BigNumber, BigNumber': function (x, y) { + return x.plus(y); + }, - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, larger); - }, + 'Fraction, Fraction': function (x, y) { + return x.add(y); + }, - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, larger, true); - }, + 'Unit, Unit': function (x, y) { + if (x.value == null) throw new Error('Parameter x contains a unit with undefined value'); + if (y.value == null) throw new Error('Parameter y contains a unit with undefined value'); + if (!x.equalBase(y)) throw new Error('Units do not match'); - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, larger, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, larger); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return larger(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return larger(matrix$$1(x), y); - }, + var res = x.clone(); + res.value = add(res.value, y.value); + res.fixPrefix = false; + return res; + } + }); - 'Matrix, Array': function (x, y) { - // use matrix implementation - return larger(x, matrix$$1(y)); - }, + return add; + } - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, larger, false); - }, + var factory_1$16 = factory$16; - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, larger, false); - }, + var addScalar = { + factory: factory_1$16 + }; - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, larger, true); - }, + function factory$17 (type, config, load, typed) { - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, larger, true); - }, + var DenseMatrix = type.DenseMatrix; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, larger, false).valueOf(); - }, + /** + * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). + * Callback function invoked NNZ times (number of nonzero items in SparseMatrix). + * + * + * ┌ f(Dij, Sij) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ Dij ; otherwise + * + * + * @param {Matrix} denseMatrix The DenseMatrix instance (D) + * @param {Matrix} sparseMatrix The SparseMatrix instance (S) + * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) + * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) + * + * @return {Matrix} DenseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 + */ + var algorithm01 = function (denseMatrix, sparseMatrix, callback, inverse) { + // dense matrix arrays + var adata = denseMatrix._data; + var asize = denseMatrix._size; + var adt = denseMatrix._datatype; + // sparse matrix arrays + var bvalues = sparseMatrix._values; + var bindex = sparseMatrix._index; + var bptr = sparseMatrix._ptr; + var bsize = sparseMatrix._size; + var bdt = sparseMatrix._datatype; - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, larger, true).valueOf(); - } - }); + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - larger.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['larger'] + '${args[1]}\\right)' - }; + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - return larger; -} + // sparse matrix cannot be a Pattern matrix + if (!bvalues) + throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); -var name$26 = 'larger'; -var factory_1$28 = factory$28; + // rows & columns + var rows = asize[0]; + var columns = asize[1]; -var larger = { - name: name$26, - factory: factory_1$28 -}; + // process data types + var dt = typeof adt === 'string' && adt === bdt ? adt : undefined; + // callback function + var cf = dt ? typed.find(callback, [dt, dt]) : callback; -function factory$29 (type, config, load, typed) { - - var smaller$$1 = load(smaller); - var larger$$1 = load(larger); - - var oneOverLogPhi = 1.0 / Math.log((1.0 + Math.sqrt(5.0)) / 2.0); - - /** - * Fibonacci Heap implementation, used interally for Matrix math. - * @class FibonacciHeap - * @constructor FibonacciHeap - */ - function FibonacciHeap() { - if (!(this instanceof FibonacciHeap)) - throw new SyntaxError('Constructor must be called with the new operator'); + // vars + var i, j; + + // result (DenseMatrix) + var cdata = []; + // initialize c + for (i = 0; i < rows; i++) + cdata[i] = []; + + // workspace + var x = []; + // marks indicating we have a value in x for a given column + var w = []; + + // loop columns in b + for (j = 0; j < columns; j++) { + // column mark + var mark = j + 1; + // values in column j + for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + i = bindex[k]; + // update workspace + x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); + // mark i as updated + w[i] = mark; + } + // loop rows + for (i = 0; i < rows; i++) { + // check row is in workspace + if (w[i] === mark) { + // c[i][j] was already calculated + cdata[i][j] = x[i]; + } + else { + // item does not exist in S + cdata[i][j] = adata[i][j]; + } + } + } - // initialize fields - this._minimum = null; - this._size = 0; + // return dense matrix + return new DenseMatrix({ + data: cdata, + size: [rows, columns], + datatype: dt + }); + }; + + return algorithm01; } - /** - * Attach type information - */ - FibonacciHeap.prototype.type = 'FibonacciHeap'; - FibonacciHeap.prototype.isFibonacciHeap = true; + var name$15 = 'algorithm01'; + var factory_1$17 = factory$17; - /** - * Inserts a new data element into the heap. No heap consolidation is - * performed at this time, the new node is simply inserted into the root - * list of this heap. Running time: O(1) actual. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.insert = function (key, value) { - // create node - var node = { - key: key, - value: value, - degree: 0 - }; - // check we have a node in the minimum - if (this._minimum) { - // minimum node - var minimum = this._minimum; - // update left & right of node - node.left = minimum; - node.right = minimum.right; - minimum.right = node; - node.right.left = node; - // update minimum node in heap if needed - if (smaller$$1(key, minimum.key)) { - // node has a smaller key, use it as minimum - this._minimum = node; - } - } - else { - // set left & right - node.left = node; - node.right = node; - // this is the first node - this._minimum = node; - } - // increment number of nodes in heap - this._size++; - // return node - return node; + var algorithm01 = { + name: name$15, + factory: factory_1$17 }; - /** - * Returns the number of nodes in heap. Running time: O(1) actual. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.size = function () { - return this._size; - }; + function factory$18 (type, config, load, typed) { - /** - * Removes all elements from this heap. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.clear = function () { - this._minimum = null; - this._size = 0; - }; + var equalScalar$$1 = load(equalScalar); - /** - * Returns true if the heap is empty, otherwise false. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.isEmpty = function () { - return this._size === 0; - }; - - /** - * Extracts the node with minimum key from heap. Amortized running - * time: O(log n). - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.extractMinimum = function () { - // node to remove - var node = this._minimum; - // check we have a minimum - if (node === null) - return node; - // current minimum - var minimum = this._minimum; - // get number of children - var numberOfChildren = node.degree; - // pointer to the first child - var x = node.child; - // for each child of node do... - while (numberOfChildren > 0) { - // store node in right side - var tempRight = x.right; - // remove x from child list - x.left.right = x.right; - x.right.left = x.left; - // add x to root list of heap - x.left = minimum; - x.right = minimum.right; - minimum.right = x; - x.right.left = x; - // set Parent[x] to null - x.parent = null; - x = tempRight; - numberOfChildren--; - } - // remove node from root list of heap - node.left.right = node.right; - node.right.left = node.left; - // update minimum - if (node == node.right) { - // empty - minimum = null; - } - else { - // update minimum - minimum = node.right; - // we need to update the pointer to the root with minimum key - minimum = _findMinimumNode(minimum, this._size); - } - // decrement size of heap - this._size--; - // update minimum - this._minimum = minimum; - // return node - return node; - }; - - /** - * Removes a node from the heap given the reference to the node. The trees - * in the heap will be consolidated, if necessary. This operation may fail - * to remove the correct element if there are nodes with key value -Infinity. - * Running time: O(log n) amortized. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.remove = function (node) { - // decrease key value - this._minimum = _decreaseKey(this._minimum, node, -1); - // remove the smallest - this.extractMinimum(); - }; - - /** - * Decreases the key value for a heap node, given the new value to take on. - * The structure of the heap may be changed and will not be consolidated. - * Running time: O(1) amortized. - * @memberof FibonacciHeap - */ - var _decreaseKey = function (minimum, node, key) { - // set node key - node.key = key; - // get parent node - var parent = node.parent; - if (parent && smaller$$1(node.key, parent.key)) { - // remove node from parent - _cut(minimum, node, parent); - // remove all nodes from parent to the root parent - _cascadingCut(minimum, parent); - } - // update minimum node if needed - if (smaller$$1(node.key, minimum.key)) - minimum = node; - // return minimum - return minimum; - }; - - /** - * The reverse of the link operation: removes node from the child list of parent. - * This method assumes that min is non-null. Running time: O(1). - * @memberof FibonacciHeap - */ - var _cut = function (minimum, node, parent) { - // remove node from parent children and decrement Degree[parent] - node.left.right = node.right; - node.right.left = node.left; - parent.degree--; - // reset y.child if necessary - if (parent.child == node) - parent.child = node.right; - // remove child if degree is 0 - if (parent.degree === 0) - parent.child = null; - // add node to root list of heap - node.left = minimum; - node.right = minimum.right; - minimum.right = node; - node.right.left = node; - // set parent[node] to null - node.parent = null; - // set mark[node] to false - node.mark = false; - }; - - /** - * Performs a cascading cut operation. This cuts node from its parent and then - * does the same for its parent, and so on up the tree. - * Running time: O(log n); O(1) excluding the recursion. - * @memberof FibonacciHeap - */ - var _cascadingCut= function (minimum, node) { - // store parent node - var parent = node.parent; - // if there's a parent... - if (!parent) - return; - // if node is unmarked, set it marked - if (!node.mark) { - node.mark = true; - } - else { - // it's marked, cut it from parent - _cut(minimum, node, parent); - // cut its parent as well - _cascadingCut(parent); - } - }; - - /** - * Make the first node a child of the second one. Running time: O(1) actual. - * @memberof FibonacciHeap - */ - var _linkNodes = function (node, parent) { - // remove node from root list of heap - node.left.right = node.right; - node.right.left = node.left; - // make node a Child of parent - node.parent = parent; - if (!parent.child) { - parent.child = node; - node.right = node; - node.left = node; - } - else { - node.left = parent.child; - node.right = parent.child.right; - parent.child.right = node; - node.right.left = node; - } - // increase degree[parent] - parent.degree++; - // set mark[node] false - node.mark = false; - }; - - var _findMinimumNode = function (minimum, size) { - // to find trees of the same degree efficiently we use an array of length O(log n) in which we keep a pointer to one root of each degree - var arraySize = Math.floor(Math.log(size) * oneOverLogPhi) + 1; - // create list with initial capacity - var array = new Array(arraySize); - // find the number of root nodes. - var numRoots = 0; - var x = minimum; - if (x) { - numRoots++; - x = x.right; - while (x !== minimum) { - numRoots++; - x = x.right; - } - } - // vars - var y; - // For each node in root list do... - while (numRoots > 0) { - // access this node's degree.. - var d = x.degree; - // get next node - var next = x.right; - // check if there is a node already in array with the same degree - while (true) { - // get node with the same degree is any - y = array[d]; - if (!y) - break; - // make one node with the same degree a child of the other, do this based on the key value. - if (larger$$1(x.key, y.key)) { - var temp = y; - y = x; - x = temp; - } - // make y a child of x - _linkNodes(y, x); - // we have handled this degree, go to next one. - array[d] = null; - d++; - } - // save this node for later when we might encounter another of the same degree. - array[d] = x; - // move forward through list. - x = next; - numRoots--; - } - // Set min to null (effectively losing the root list) and reconstruct the root list from the array entries in array[]. - minimum = null; - // loop nodes in array - for (var i = 0; i < arraySize; i++) { - // get current node - y = array[i]; - if (!y) - continue; - // check if we have a linked list - if (minimum) { - // First remove node from root list. - y.left.right = y.right; - y.right.left = y.left; - // now add to root list, again. - y.left = minimum; - y.right = minimum.right; - minimum.right = y; - y.right.left = y; - // check if this is a new min. - if (smaller$$1(y.key, minimum.key)) - minimum = y; - } - else - minimum = y; - } - return minimum; - }; - - return FibonacciHeap; -} + var SparseMatrix = type.SparseMatrix; -var name$27 = 'FibonacciHeap'; -var path$8 = 'type'; -var factory_1$29 = factory$29; + /** + * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). + * Callback function invoked MAX(NNZA, NNZB) times + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 + * C(i,j) = ┤ A(i,j) ; A(i,j) !== 0 + * └ B(i,j) ; B(i,j) !== 0 + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {Function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm04 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + // sparse matrix arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; -var FibonacciHeap = { - name: name$27, - path: path$8, - factory: factory_1$29 -}; + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); -var string$5 = utils.string; -var object$3 = utils.object; + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); -var isArray$2 = Array.isArray; -var isString$4 = string$5.isString; + // rows & columns + var rows = asize[0]; + var columns = asize[1]; -function factory$30 (type, config, load) { + // datatype + var dt; + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // find signature that matches (dt, dt) + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result arrays + var cvalues = avalues && bvalues ? [] : undefined; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); - var DenseMatrix$$1 = load(DenseMatrix); + // workspace + var xa = avalues && bvalues ? [] : undefined; + var xb = avalues && bvalues ? [] : undefined; + // marks indicating we have a value in x for a given column + var wa = []; + var wb = []; - var smaller$$1 = load(smaller); + // vars + var i, j, k, k0, k1; + + // loop columns + for (j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // columns mark + var mark = j + 1; + // loop A(:,j) + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // update c + cindex.push(i); + // update workspace + wa[i] = mark; + // check we need to process values + if (xa) + xa[i] = avalues[k]; + } + // loop B(:,j) + for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + i = bindex[k]; + // check row exists in A + if (wa[i] === mark) { + // update record in xa @ i + if (xa) { + // invoke callback + var v = cf(xa[i], bvalues[k]); + // check for zero + if (!eq(v, zero)) { + // update workspace + xa[i] = v; + } + else { + // remove mark (index will be removed later) + wa[i] = null; + } + } + } + else { + // update c + cindex.push(i); + // update workspace + wb[i] = mark; + // check we need to process values + if (xb) + xb[i] = bvalues[k]; + } + } + // check we need to process values (non pattern matrix) + if (xa && xb) { + // initialize first index in j + k = cptr[j]; + // loop index in j + while (k < cindex.length) { + // row + i = cindex[k]; + // check workspace has value @ i + if (wa[i] === mark) { + // push value (Aij != 0 || (Aij != 0 && Bij != 0)) + cvalues[k] = xa[i]; + // increment pointer + k++; + } + else if (wb[i] === mark) { + // push value (bij != 0) + cvalues[k] = xb[i]; + // increment pointer + k++; + } + else { + // remove index @ k + cindex.splice(k, 1); + } + } + } + } + // update cptr + cptr[columns] = cindex.length; - function ImmutableDenseMatrix(data, datatype) { - if (!(this instanceof ImmutableDenseMatrix)) - throw new SyntaxError('Constructor must be called with the new operator'); - if (datatype && !isString$4(datatype)) - throw new Error('Invalid datatype: ' + datatype); - - if (type.isMatrix(data) || isArray$2(data)) { - // use DenseMatrix implementation - var matrix = new DenseMatrix$$1(data, datatype); - // internal structures - this._data = matrix._data; - this._size = matrix._size; - this._datatype = matrix._datatype; - this._min = null; - this._max = null; - } - else if (data && isArray$2(data.data) && isArray$2(data.size)) { - // initialize fields from JSON representation - this._data = data.data; - this._size = data.size; - this._datatype = data.datatype; - this._min = typeof data.min !== 'undefined' ? data.min : null; - this._max = typeof data.max !== 'undefined' ? data.max : null; - } - else if (data) { - // unsupported type - throw new TypeError('Unsupported type of data (' + utils.types.type(data) + ')'); - } - else { - // nothing provided - this._data = []; - this._size = [0]; - this._datatype = datatype; - this._min = null; - this._max = null; - } + // return sparse matrix + return c; + }; + + return algorithm04; } - ImmutableDenseMatrix.prototype = new DenseMatrix$$1(); + var name$16 = 'algorithm04'; + var factory_1$18 = factory$18; - /** - * Attach type information - */ - ImmutableDenseMatrix.prototype.type = 'ImmutableDenseMatrix'; - ImmutableDenseMatrix.prototype.isImmutableDenseMatrix = true; + var algorithm04 = { + name: name$16, + factory: factory_1$18 + }; - /** - * 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 | ImmutableDenseMatrix | *} [replacement] - * @param {*} [defaultValue=0] Default value, filled in on new entries when - * the matrix is resized. If not provided, - * new matrix elements will be filled with zeros. - */ - ImmutableDenseMatrix.prototype.subset = function (index) { - switch (arguments.length) { - case 1: - // use base implementation - var m = DenseMatrix$$1.prototype.subset.call(this, index); - // check result is a matrix - if (type.isMatrix(m)) { - // return immutable matrix - return new ImmutableDenseMatrix({ - data: m._data, - size: m._size, - datatype: m._datatype - }); - } - return m; - - // intentional fall through - case 2: - case 3: - throw new Error('Cannot invoke set subset on an Immutable Matrix instance'); + function factory$19 (type, config, load, typed) { - default: - throw new SyntaxError('Wrong number of arguments'); - } - }; + var DenseMatrix = type.DenseMatrix; - /** - * 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 {ImmutableDenseMatrix} self - */ - ImmutableDenseMatrix.prototype.set = function () { - throw new Error('Cannot invoke set on an Immutable Matrix instance'); - }; + /** + * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). + * Callback function invoked NZ times (number of nonzero items in S). + * + * + * ┌ f(Sij, b) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ b ; otherwise + * + * + * @param {Matrix} s The SparseMatrix instance (S) + * @param {Scalar} b The Scalar value + * @param {Function} callback The f(Aij,b) operation to invoke + * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) + * + * @return {Matrix} DenseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 + */ + var algorithm10 = function (s, b, callback, inverse) { + // sparse matrix arrays + var avalues = s._values; + var aindex = s._index; + var aptr = s._ptr; + var asize = s._size; + var adt = s._datatype; + + // sparse matrix cannot be a Pattern matrix + if (!avalues) + throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; - /** - * Resize the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (resize in place). - * - * @param {Number[]} size The new size the matrix should have. - * @param {*} [defaultValue=0] Default value, filled in on new entries. - * If not provided, the matrix elements will - * be filled with zeros. - * @param {boolean} [copy] Return a resized copy of the matrix - * - * @return {Matrix} The resized matrix - */ - ImmutableDenseMatrix.prototype.resize = function () { - throw new Error('Cannot invoke resize on an Immutable Matrix instance'); - }; + // datatype + var dt; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string') { + // datatype + dt = adt; + // convert b to the same datatype + b = typed.convert(b, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result arrays + var cdata = []; + // matrix + var c = new DenseMatrix({ + data: cdata, + size: [rows, columns], + datatype: dt + }); - /** - * Disallows reshaping in favor of immutability. - * - * @throws {Error} Operation not allowed - */ - ImmutableDenseMatrix.prototype.reshape = function () { - throw new Error('Cannot invoke reshape on an Immutable Matrix instance'); - }; + // workspaces + var x = []; + // marks indicating we have a value in x for a given column + var w = []; - /** - * Create a clone of the matrix - * @return {ImmutableDenseMatrix} clone - */ - ImmutableDenseMatrix.prototype.clone = function () { - var m = new ImmutableDenseMatrix({ - data: object$3.clone(this._data), - size: object$3.clone(this._size), - datatype: this._datatype - }); - return m; - }; + // loop columns + for (var j = 0; j < columns; j++) { + // columns mark + var mark = j + 1; + // values in j + for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + var r = aindex[k]; + // update workspace + x[r] = avalues[k]; + w[r] = mark; + } + // loop rows + for (var i = 0; i < rows; i++) { + // initialize C on first column + if (j === 0) { + // create row array + cdata[i] = []; + } + // check sparse matrix has a value @ i,j + if (w[i] === mark) { + // invoke callback, update C + cdata[i][j] = inverse ? cf(b, x[i]) : cf(x[i], b); + } + else { + // dense matrix value @ i, j + cdata[i][j] = b; + } + } + } - /** - * Get a JSON representation of the matrix - * @returns {Object} - */ - ImmutableDenseMatrix.prototype.toJSON = function () { - return { - mathjs: 'ImmutableDenseMatrix', - data: this._data, - size: this._size, - datatype: this._datatype + // return sparse matrix + return c; }; - }; - - /** - * Generate a matrix from a JSON object - * @param {Object} json An object structured like - * `{"mathjs": "ImmutableDenseMatrix", data: [], size: []}`, - * where mathjs is optional - * @returns {ImmutableDenseMatrix} - */ - ImmutableDenseMatrix.fromJSON = function (json) { - return new ImmutableDenseMatrix(json); - }; - /** - * Swap rows i and j in Matrix. - * - * @param {Number} i Matrix row index 1 - * @param {Number} j Matrix row index 2 - * - * @return {Matrix} The matrix reference - */ - ImmutableDenseMatrix.prototype.swapRows = function () { - throw new Error('Cannot invoke swapRows on an Immutable Matrix instance'); - }; + return algorithm10; + } - /** - * Calculate the minimum value in the set - * @return {Number | undefined} min - */ - ImmutableDenseMatrix.prototype.min = function () { - // check min has been calculated before - if (this._min === null) { - // minimum - var m = null; - // compute min - this.forEach(function (v) { - if (m === null || smaller$$1(v, m)) - m = v; - }); - this._min = m !== null ? m : undefined; - } - return this._min; - }; + var name$17 = 'algorithm10'; + var factory_1$19 = factory$19; - /** - * Calculate the maximum value in the set - * @return {Number | undefined} max - */ - ImmutableDenseMatrix.prototype.max = function () { - // check max has been calculated before - if (this._max === null) { - // maximum - var m = null; - // compute max - this.forEach(function (v) { - if (m === null || smaller$$1(m, v)) - m = v; - }); - this._max = m !== null ? m : undefined; - } - return this._max; + var algorithm10 = { + name: name$17, + factory: factory_1$19 }; - // exports - return ImmutableDenseMatrix; -} - -var name$28 = 'ImmutableDenseMatrix'; -var path$9 = 'type'; -var factory_1$30 = factory$30; + var string$4 = utils.string, + isString$3 = string$4.isString; -var ImmutableDenseMatrix = { - name: name$28, - path: path$9, - factory: factory_1$30 -}; + function factory$20 (type, config, load, typed) { -var clone$1 = object.clone; -var isInteger$2 = number.isInteger; + var DenseMatrix = type.DenseMatrix; -function factory$31 (type) { - - /** - * Create an index. An Index can store ranges and sets for multiple dimensions. - * Matrix.get, Matrix.set, and math.subset accept an Index as input. - * - * Usage: - * var index = new Index(range1, range2, matrix1, array1, ...); - * - * Where each parameter can be any of: - * A number - * A string (containing a name of an object property) - * An instance of Range - * An Array with the Set values - * A Matrix with the Set values - * - * The parameters start, end, and step must be integer numbers. - * - * @class Index - * @Constructor Index - * @param {...*} ranges - */ - function Index(ranges) { - if (!(this instanceof Index)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this._dimensions = []; - this._isScalar = true; + /** + * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, Bij..z). + * Callback function invoked MxN times. + * + * C(i,j,...z) = f(Aij..z, Bij..z) + * + * @param {Matrix} a The DenseMatrix instance (A) + * @param {Matrix} b The DenseMatrix instance (B) + * @param {Function} callback The f(Aij..z,Bij..z) operation to invoke + * + * @return {Matrix} DenseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97658658 + */ + var algorithm13 = function (a, b, callback) { + // a arrays + var adata = a._data; + var asize = a._size; + var adt = a._datatype; + // b arrays + var bdata = b._data; + var bsize = b._size; + var bdt = b._datatype; + // c arrays + var csize = []; - for (var i = 0, ii = arguments.length; i < ii; i++) { - var arg = arguments[i]; + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - if (type.isRange(arg)) { - this._dimensions.push(arg); - this._isScalar = false; + // validate each one of the dimension sizes + for (var s = 0; s < asize.length; s++) { + // must match + if (asize[s] !== bsize[s]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); + // update dimension in c + csize[s] = asize[s]; } - else if (Array.isArray(arg) || type.isMatrix(arg)) { - // create matrix - var m = _createImmutableMatrix(arg.valueOf()); - this._dimensions.push(m); - // size - var size = m.size(); - // scalar - if (size.length !== 1 || size[0] !== 1) { - this._isScalar = false; + + // datatype + var dt; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // convert b to the same datatype + b = typed.convert(b, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // populate cdata, iterate through dimensions + var cdata = csize.length > 0 ? _iterate(cf, 0, csize, csize[0], adata, bdata) : []; + + // c matrix + return new DenseMatrix({ + data: cdata, + size: csize, + datatype: dt + }); + }; + + // recursive function + var _iterate = function (f, level, s, n, av, bv) { + // initialize array for this level + var cv = []; + // check we reach the last level + if (level === s.length - 1) { + // loop arrays in last level + for (var i = 0; i < n; i++) { + // invoke callback and store value + cv[i] = f(av[i], bv[i]); } } - else if (typeof arg === 'number') { - this._dimensions.push(_createImmutableMatrix([arg])); - } - else if (typeof arg === 'string') { - // object property (arguments.count should be 1) - this._dimensions.push(arg); - } - // TODO: implement support for wildcard '*' else { - throw new TypeError('Dimension must be an Array, Matrix, number, string, or Range'); - } - } - } - - /** - * Attach type information - */ - Index.prototype.type = 'Index'; - Index.prototype.isIndex = true; - - function _createImmutableMatrix(arg) { - // loop array elements - for (var i = 0, l = arg.length; i < l; i++) { - if (typeof arg[i] !== 'number' || !isInteger$2(arg[i])) { - throw new TypeError('Index parameters must be positive integer numbers'); + // iterate current level + for (var j = 0; j < n; j++) { + // iterate next level + cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv[j]); + } } - } - // create matrix - return new type.ImmutableDenseMatrix(arg); + return cv; + }; + + return algorithm13; } - /** - * Create a clone of the index - * @memberof Index - * @return {Index} clone - */ - Index.prototype.clone = function () { - var index = new Index(); - index._dimensions = clone$1(this._dimensions); - index._isScalar = this._isScalar; - return index; - }; + var name$18 = 'algorithm13'; + var factory_1$20 = factory$20; - /** - * Create an index from an array with ranges/numbers - * @memberof Index - * @param {Array.} ranges - * @return {Index} index - * @private - */ - Index.create = function (ranges) { - var index = new Index(); - Index.apply(index, ranges); - return index; + var algorithm13 = { + name: name$18, + factory: factory_1$20 }; - /** - * Retrieve the size of the index, the number of elements for each dimension. - * @memberof Index - * @returns {number[]} size - */ - Index.prototype.size = function () { - var size = []; - - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var d = this._dimensions[i]; - size[i] = (typeof d === 'string') ? 1 : d.size()[0]; - } - - return size; - }; + var clone = object.clone; - /** - * Get the maximum value for each of the indexes ranges. - * @memberof Index - * @returns {number[]} max - */ - Index.prototype.max = function () { - var values = []; + function factory$21 (type, config, load, typed) { - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var range = this._dimensions[i]; - values[i] = (typeof range === 'string') ? range : range.max(); - } + var DenseMatrix = type.DenseMatrix; - return values; - }; + /** + * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, b). + * Callback function invoked MxN times. + * + * C(i,j,...z) = f(Aij..z, b) + * + * @param {Matrix} a The DenseMatrix instance (A) + * @param {Scalar} b The Scalar value + * @param {Function} callback The f(Aij..z,b) operation to invoke + * @param {boolean} inverse A true value indicates callback should be invoked f(b,Aij..z) + * + * @return {Matrix} DenseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97659042 + */ + var algorithm14 = function (a, b, callback, inverse) { + // a arrays + var adata = a._data; + var asize = a._size; + var adt = a._datatype; + + // datatype + var dt; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string') { + // datatype + dt = adt; + // convert b to the same datatype + b = typed.convert(b, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // populate cdata, iterate through dimensions + var cdata = asize.length > 0 ? _iterate(cf, 0, asize, asize[0], adata, b, inverse) : []; + + // c matrix + return new DenseMatrix({ + data: cdata, + size: clone(asize), + datatype: dt + }); + }; + + // recursive function + var _iterate = function (f, level, s, n, av, bv, inverse) { + // initialize array for this level + var cv = []; + // check we reach the last level + if (level === s.length - 1) { + // loop arrays in last level + for (var i = 0; i < n; i++) { + // invoke callback and store value + cv[i] = inverse ? f(bv, av[i]) : f(av[i], bv); + } + } + else { + // iterate current level + for (var j = 0; j < n; j++) { + // iterate next level + cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv, inverse); + } + } + return cv; + }; - /** - * Get the minimum value for each of the indexes ranges. - * @memberof Index - * @returns {number[]} min - */ - Index.prototype.min = function () { - var values = []; + return algorithm14; + } - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var range = this._dimensions[i]; - values[i] = (typeof range === 'string') ? range : range.min(); - } + var name$19 = 'algorithm14'; + var factory_1$21 = factory$21; - return values; + var algorithm14 = { + name: name$19, + factory: factory_1$21 }; - /** - * Loop over each of the ranges of the index - * @memberof 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 (callback) { - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - callback(this._dimensions[i], i, this); - } - }; + var extend = object.extend; - /** - * Retrieve the dimension for the given index - * @memberof Index - * @param {Number} dim Number of the dimension - * @returns {Range | null} range - */ - Index.prototype.dimension = function (dim) { - return this._dimensions[dim] || null; - }; + function factory$22 (type, config, load, typed) { - /** - * Test whether this index contains an object property - * @returns {boolean} Returns true if the index is an object property - */ - Index.prototype.isObjectProperty = function () { - return this._dimensions.length === 1 && typeof this._dimensions[0] === 'string'; - }; + var matrix$$1 = load(matrix); + var addScalar$$1 = load(addScalar); + var latex$$1 = latex; + + var algorithm01$$1 = load(algorithm01); + var algorithm04$$1 = load(algorithm04); + var algorithm10$$1 = load(algorithm10); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - /** - * Returns the object property name when the Index holds a single object property, - * else returns null - * @returns {string | null} - */ - Index.prototype.getObjectProperty = function () { - return this.isObjectProperty() ? this._dimensions[0] : null; - }; + /** + * Add two or more values, `x + y`. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.add(x, y) + * math.add(x, y, z, ...) + * + * Examples: + * + * math.add(2, 3); // returns number 5 + * math.add(2, 3, 4); // returns number 9 + * + * var a = math.complex(2, 3); + * var b = math.complex(-4, 1); + * math.add(a, b); // returns Complex -2 + 4i + * + * math.add([1, 2, 3], 4); // returns Array [5, 6, 7] + * + * var c = math.unit('5 cm'); + * var d = math.unit('2.1 mm'); + * math.add(c, d); // returns Unit 52.1 mm + * + * math.add("2.3", "4"); // returns number 6.3 + * + * See also: + * + * subtract, sum + * + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to add + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to add + * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Sum of `x` and `y` + */ + var add = typed('add', extend({ + // we extend the signatures of addScalar with signatures dealing with matrices - /** - * Test whether this index contains only a single value. - * - * This is the case when the index is created with only scalar values as ranges, - * not for ranges resolving into a single value. - * @memberof Index - * @return {boolean} isScalar - */ - Index.prototype.isScalar = function () { - return this._isScalar; - }; + 'DenseMatrix, DenseMatrix': function (x, y) { + return algorithm13$$1(x, y, addScalar$$1); + }, - /** - * Expand the Index into an array. - * For example new Index([0,3], [2,7]) returns [[0,1,2], [2,3,4,5,6]] - * @memberof Index - * @returns {Array} array - */ - Index.prototype.toArray = function () { - var array = []; - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var dimension = this._dimensions[i]; - array.push((typeof dimension === 'string') ? dimension : dimension.toArray()); - } - return array; - }; + 'DenseMatrix, SparseMatrix': function (x, y) { + return algorithm01$$1(x, y, addScalar$$1, false); + }, - /** - * Get the primitive value of the Index, a two dimensional array. - * Equivalent to Index.toArray(). - * @memberof Index - * @returns {Array} array - */ - Index.prototype.valueOf = Index.prototype.toArray; + 'SparseMatrix, DenseMatrix': function (x, y) { + return algorithm01$$1(y, x, addScalar$$1, true); + }, - /** - * Get the string representation of the index, for example '[2:6]' or '[0:2:10, 4:7, [1,2,3]]' - * @memberof Index - * @returns {String} str - */ - Index.prototype.toString = function () { - var strings = []; + 'SparseMatrix, SparseMatrix': function (x, y) { + return algorithm04$$1(x, y, addScalar$$1); + }, - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var dimension = this._dimensions[i]; - if (typeof dimension === 'string') { - strings.push(JSON.stringify(dimension)); - } - else { - strings.push(dimension.toString()); - } - } + 'Array, Array': function (x, y) { + // use matrix implementation + return add(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - return '[' + strings.join(', ') + ']'; - }; + 'Array, Matrix': function (x, y) { + // use matrix implementation + return add(matrix$$1(x), y); + }, - /** - * Get a JSON representation of the Index - * @memberof Index - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Index", "ranges": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}` - */ - Index.prototype.toJSON = function () { - return { - mathjs: 'Index', - dimensions: this._dimensions - }; - }; + 'Matrix, Array': function (x, y) { + // use matrix implementation + return add(x, matrix$$1(y)); + }, - /** - * Instantiate an Index from a JSON object - * @memberof Index - * @param {Object} json A JSON object structured as: - * `{"mathjs": "Index", "dimensions": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}` - * @return {Index} - */ - Index.fromJSON = function (json) { - return Index.create(json.dimensions); - }; + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, addScalar$$1, false); + }, - return Index; -} + 'SparseMatrix, any': function (x, y) { + return algorithm10$$1(x, y, addScalar$$1, false); + }, -var name$29 = 'Index'; -var path$10 = 'type'; -var factory_1$31 = factory$31; + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, addScalar$$1, true); + }, -var MatrixIndex = { - name: name$29, - path: path$10, - factory: factory_1$31 -}; + 'any, SparseMatrix': function (x, y) { + return algorithm10$$1(y, x, addScalar$$1, true); + }, -function factory$32 (type, config, load, typed) { - /** - * 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] - * - * @class Range - * @constructor Range - * @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'); - } + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, addScalar$$1, false).valueOf(); + }, - if (start != null) { - if (type.isBigNumber(start)) - start = start.toNumber(); - else if (typeof start !== 'number') - throw new TypeError('Parameter start must be a number'); - } - if (end != null) { - if (type.isBigNumber(end)) - end = end.toNumber(); - else if (typeof end !== 'number') - throw new TypeError('Parameter end must be a number'); - } - if (step != null) { - if (type.isBigNumber(step)) - step = step.toNumber(); - else if (typeof step !== 'number') - throw new TypeError('Parameter step must be a number'); - } + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, addScalar$$1, true).valueOf(); + }, - this.start = (start != null) ? parseFloat(start) : 0; - this.end = (end != null) ? parseFloat(end) : 0; - this.step = (step != null) ? parseFloat(step) : 1; - } + 'any, any': addScalar$$1, - /** - * Attach type information - */ - Range.prototype.type = 'Range'; - Range.prototype.isRange = true; + 'any, any, ...any': function (x, y, rest) { + var result = add(x, y); - /** - * 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'. - * @memberof Range - * @param {string} str - * @return {Range | null} range - */ - Range.parse = function (str) { - if (typeof str !== 'string') { - return null; - } + for (var i = 0; i < rest.length; i++) { + result = add(result, rest[i]); + } - var args = str.split(':'); - var nums = args.map(function (arg) { - return parseFloat(arg); - }); + return result; + } + }, addScalar$$1.signatures)); - var invalid = nums.some(function (num) { - return isNaN(num); - }); - if (invalid) { - return null; - } + add.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['add'] + '${args[1]}\\right)' + }; + + return add; + } - 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; - } - }; + var name$20 = 'add'; + var factory_1$22 = factory$22; - /** - * Create a clone of the range - * @return {Range} clone - */ - Range.prototype.clone = function () { - return new Range(this.start, this.end, this.step); + var add = { + name: name$20, + factory: factory_1$22 }; - /** - * Retrieve the size of the range. - * Returns an array containing one number, the number of elements in the range. - * @memberof Range - * @returns {number[]} size - */ - Range.prototype.size = function () { - 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; + function factory$23 (type, config, load) { + + var add$$1 = load(add); + var equalScalar$$1 = load(equalScalar); + + /** + * An ordered Sparse Accumulator is a representation for a sparse vector that includes a dense array + * of the vector elements and an ordered list of non-zero elements. + */ + function Spa() { + if (!(this instanceof Spa)) + throw new SyntaxError('Constructor must be called with the new operator'); + + // allocate vector, TODO use typed arrays + this._values = []; + this._heap = new type.FibonacciHeap(); } - return [len]; - }; - /** - * Calculate the minimum value in the range - * @memberof Range - * @return {number | undefined} min - */ - Range.prototype.min = function () { - var size = this.size()[0]; + /** + * Attach type information + */ + Spa.prototype.type = 'Spa'; + Spa.prototype.isSpa = true; - if (size > 0) { - if (this.step > 0) { - // positive step - return this.start; + /** + * Set the value for index i. + * + * @param {number} i The index + * @param {number | BigNumber | Complex} The value at index i + */ + Spa.prototype.set = function (i, v) { + // check we have a value @ i + if (!this._values[i]) { + // insert in heap + var node = this._heap.insert(i, v); + // set the value @ i + this._values[i] = node; } else { - // negative step - return this.start + (size - 1) * this.step; + // update the value @ i + this._values[i].value = v; } - } - else { - return undefined; - } - }; - - /** - * Calculate the maximum value in the range - * @memberof Range - * @return {number | undefined} max - */ - Range.prototype.max = function () { - var size = this.size()[0]; - - if (size > 0) { - if (this.step > 0) { - // positive step - return this.start + (size - 1) * this.step; + }; + + Spa.prototype.get = function (i) { + var node = this._values[i]; + if (node) + return node.value; + return 0; + }; + + Spa.prototype.accumulate = function (i, v) { + // node @ i + var node = this._values[i]; + if (!node) { + // insert in heap + node = this._heap.insert(i, v); + // initialize value + this._values[i] = node; } else { - // negative step - return this.start; + // accumulate value + node.value = add$$1(node.value, v); } - } - else { - return undefined; - } - }; - - - /** - * Execute a callback function for each value in the range. - * @memberof Range - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Range being traversed. - */ - Range.prototype.forEach = function (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++; + }; + + Spa.prototype.forEach = function (from, to, callback) { + // references + var heap = this._heap; + var values = this._values; + // nodes + var nodes = []; + // node with minimum key, save it + var node = heap.extractMinimum(); + if (node) + nodes.push(node); + // extract nodes from heap (ordered) + while (node && node.key <= to) { + // check it is in range + if (node.key >= from) { + // check value is not zero + if (!equalScalar$$1(node.value, 0)) { + // invoke callback + callback(node.key, node.value, this); + } + } + // extract next node, save it + node = heap.extractMinimum(); + if (node) + nodes.push(node); } - } - else if (step < 0) { - while (x > end) { - callback(x, [i], this); - x += step; - i++; + // reinsert all nodes in heap + for (var i = 0; i < nodes.length; i++) { + // current node + var n = nodes[i]; + // insert node in heap + node = heap.insert(n.key, n.value); + // update values + values[node.key] = node; } - } - }; + }; + + Spa.prototype.swap = function (i, j) { + // node @ i and j + var nodei = this._values[i]; + var nodej = this._values[j]; + // check we need to insert indeces + if (!nodei && nodej) { + // insert in heap + nodei = this._heap.insert(i, nodej.value); + // remove from heap + this._heap.remove(nodej); + // set values + this._values[i] = nodei; + this._values[j] = undefined; + } + else if (nodei && !nodej) { + // insert in heap + nodej = this._heap.insert(j, nodei.value); + // remove from heap + this._heap.remove(nodei); + // set values + this._values[j] = nodej; + this._values[i] = undefined; + } + else if (nodei && nodej) { + // swap values + var v = nodei.value; + nodei.value = nodej.value; + nodej.value = v; + } + }; + + return Spa; + } - /** - * Execute a callback function for each value in the Range, and return the - * results as an array - * @memberof 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. - * @returns {Array} array - */ - Range.prototype.map = function (callback) { - var array = []; - this.forEach(function (value, index, obj) { - array[index[0]] = callback(value, index, obj); - }); - return array; + var name$21 = 'Spa'; + var path$7 = 'type'; + var factory_1$23 = factory$23; + + var Spa = { + name: name$21, + path: path$7, + factory: factory_1$23 }; - /** - * Create an Array with a copy of the Ranges data - * @memberof Range - * @returns {Array} array - */ - Range.prototype.toArray = function () { - var array = []; - this.forEach(function (value, index) { - array[index[0]] = value; - }); - return array; - }; + function factory$24 (type, config, load, typed) { - /** - * Get the primitive value of the Range, a one dimensional array - * @memberof Range - * @returns {Array} array - */ - Range.prototype.valueOf = function () { - // TODO: implement a caching mechanism for range.valueOf() - return this.toArray(); - }; + var DenseMatrix = type.DenseMatrix; - /** - * 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' - * @memberof Range - * @param {Object | number | function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ - Range.prototype.format = function (options) { - var str = number.format(this.start, options); + /** + * Iterates over SparseMatrix items and invokes the callback function f(Dij, Sij). + * Callback function invoked M*N times. + * + * + * ┌ f(Dij, Sij) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ f(Dij, 0) ; otherwise + * + * + * @param {Matrix} denseMatrix The DenseMatrix instance (D) + * @param {Matrix} sparseMatrix The SparseMatrix instance (C) + * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) + * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) + * + * @return {Matrix} DenseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 + */ + var algorithm03 = function (denseMatrix, sparseMatrix, callback, inverse) { + // dense matrix arrays + var adata = denseMatrix._data; + var asize = denseMatrix._size; + var adt = denseMatrix._datatype; + // sparse matrix arrays + var bvalues = sparseMatrix._values; + var bindex = sparseMatrix._index; + var bptr = sparseMatrix._ptr; + var bsize = sparseMatrix._size; + var bdt = sparseMatrix._datatype; - if (this.step != 1) { - str += ':' + number.format(this.step, options); - } - str += ':' + number.format(this.end, options); - return str; - }; + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - /** - * Get a string representation of the range. - * @memberof Range - * @returns {string} - */ - Range.prototype.toString = function () { - return this.format(); - }; + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - /** - * Get a JSON representation of the range - * @memberof Range - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}` - */ - Range.prototype.toJSON = function () { - return { - mathjs: 'Range', - start: this.start, - end: this.end, - step: this.step + // sparse matrix cannot be a Pattern matrix + if (!bvalues) + throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // datatype + var dt; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result (DenseMatrix) + var cdata = []; + + // initialize dense matrix + for (var z = 0; z < rows; z++) { + // initialize row + cdata[z] = []; + } + + // workspace + var x = []; + // marks indicating we have a value in x for a given column + var w = []; + + // loop columns in b + for (var j = 0; j < columns; j++) { + // column mark + var mark = j + 1; + // values in column j + for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + var i = bindex[k]; + // update workspace + x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); + w[i] = mark; + } + // process workspace + for (var y = 0; y < rows; y++) { + // check we have a calculated value for current row + if (w[y] === mark) { + // use calculated value + cdata[y][j] = x[y]; + } + else { + // calculate value + cdata[y][j] = inverse ? cf(zero, adata[y][j]) : cf(adata[y][j], zero); + } + } + } + + // return dense matrix + return new DenseMatrix({ + data: cdata, + size: [rows, columns], + datatype: dt + }); }; - }; + + return algorithm03; + } - /** - * Instantiate a Range from a JSON object - * @memberof Range - * @param {Object} json A JSON object structured as: - * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}` - * @return {Range} - */ - Range.fromJSON = function (json) { - return new Range(json.start, json.end, json.step); + var name$22 = 'algorithm03'; + var factory_1$24 = factory$24; + + var algorithm03 = { + name: name$22, + factory: factory_1$24 }; - return Range; -} + function factory$25 (type, config, load, typed) { -var name$30 = 'Range'; -var path$11 = 'type'; -var factory_1$32 = factory$32; + var DenseMatrix = type.DenseMatrix; -var Range = { - name: name$30, - path: path$11, - factory: factory_1$32 -}; + /** + * Iterates over SparseMatrix A and SparseMatrix B items (zero and nonzero) and invokes the callback function f(Aij, Bij). + * Callback function invoked MxN times. + * + * C(i,j) = f(Aij, Bij) + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {Function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} DenseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm07 = function (a, b, callback) { + // sparse matrix arrays + var asize = a._size; + var adt = a._datatype; + // sparse matrix arrays + var bsize = b._size; + var bdt = b._datatype; -function factory$33 (type, config, load, typed) { - /** - * 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. - * - * Syntax: - * - * math.index(range1, range2, ...) - * - * Where each range can be any of: - * - * - A number - * - A string for getting/setting an object property - * - An instance of `Range` - * - A one-dimensional Array or a Matrix with numbers - * - * Indexes must be zero-based, integer numbers. - * - * Examples: - * - * var math = math.js - * - * var b = [1, 2, 3, 4, 5]; - * math.subset(b, math.index([1, 2, 3])); // returns [2, 3, 4] - * - * var a = math.matrix([[1, 2], [3, 4]]); - * a.subset(math.index(0, 1)); // returns 2 - * - * See also: - * - * bignumber, boolean, complex, matrix, number, string, unit - * - * @param {...*} ranges Zero or more ranges or numbers. - * @return {Index} Returns the created index - */ - return typed('index', { - '...number | string | BigNumber | Range | Array | Matrix': function (args) { - var ranges = args.map(function (arg) { - if (type.isBigNumber(arg)) { - return arg.toNumber(); // convert BigNumber to Number - } - else if (Array.isArray(arg) || type.isMatrix(arg)) { - return arg.map(function (elem) { - // convert BigNumber to Number - return type.isBigNumber(elem) ? elem.toNumber() : elem; - }); - } - else { - return arg; - } - }); + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - var res = new type.Index(); - type.Index.apply(res, ranges); - return res; - } - }); -} + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); -var name$31 = 'index'; -var factory_1$33 = factory$33; + // rows & columns + var rows = asize[0]; + var columns = asize[1]; -var _function$1 = { - name: name$31, - factory: factory_1$33 -}; + // datatype + var dt; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // vars + var i, j; + + // result arrays + var cdata = []; + // initialize c + for (i = 0; i < rows; i++) + cdata[i] = []; + + // matrix + var c = new DenseMatrix({ + data: cdata, + size: [rows, columns], + datatype: dt + }); -function factory$34 (type, config, load, typed) { + // workspaces + var xa = []; + var xb = []; + // marks indicating we have a value in x for a given column + var wa = []; + var wb = []; - var SparseMatrix = type.SparseMatrix; + // loop columns + for (j = 0; j < columns; j++) { + // columns mark + var mark = j + 1; + // scatter the values of A(:,j) into workspace + _scatter(a, j, wa, xa, mark); + // scatter the values of B(:,j) into workspace + _scatter(b, j, wb, xb, mark); + // loop rows + for (i = 0; i < rows; i++) { + // matrix values @ i,j + var va = wa[i] === mark ? xa[i] : zero; + var vb = wb[i] === mark ? xb[i] : zero; + // invoke callback + cdata[i][j] = cf(va, vb); + } + } - /** - * Create a Sparse 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. - * - * Syntax: - * - * math.sparse() // creates an empty sparse matrix. - * math.sparse(data) // creates a sparse matrix with initial data. - * math.sparse(data, 'number') // creates a sparse matrix with initial data, number datatype. - * - * Examples: - * - * var m = math.sparse([[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, matrix - * - * @param {Array | Matrix} [data] A two dimensional array - * - * @return {Matrix} The created matrix - */ - var sparse = typed('sparse', { - '': function () { - return new SparseMatrix([]); - }, + // return sparse matrix + return c; + }; - 'string': function (datatype) { - return new SparseMatrix([], datatype); - }, - - 'Array | Matrix': function (data) { - return new SparseMatrix(data); - }, + var _scatter = function (m, j, w, x, mark) { + // a arrays + var values = m._values; + var index = m._index; + var ptr = m._ptr; + // loop values in column j + for (var k = ptr[j], k1 = ptr[j + 1]; k < k1; k++) { + // row + var i = index[k]; + // update workspace + w[i] = mark; + x[i] = values[k]; + } + }; - 'Array | Matrix, string': function (data, datatype) { - return new SparseMatrix(data, datatype); - } - }); - - sparse.toTex = { - 0: '\\begin{bsparse}\\end{bsparse}', - 1: '\\left(${args[0]}\\right)' - }; + return algorithm07; + } - return sparse; -} + var name$23 = 'algorithm07'; + var factory_1$25 = factory$25; -var name$32 = 'sparse'; -var factory_1$34 = factory$34; + var algorithm07 = { + name: name$23, + factory: factory_1$25 + }; -var sparse = { - name: name$32, - factory: factory_1$34 -}; + function factory$26 (type, config, load, typed) { -var matrix$1 = [ - // types - Matrix, - DenseMatrix, - SparseMatrix, - Spa, - FibonacciHeap, - ImmutableDenseMatrix, - MatrixIndex, - Range, + var DenseMatrix = type.DenseMatrix; - // construction functions - _function$1, - matrix, - sparse -]; + /** + * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). + * Callback function invoked MxN times. + * + * + * ┌ f(Sij, b) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ f(0, b) ; otherwise + * + * + * @param {Matrix} s The SparseMatrix instance (S) + * @param {Scalar} b The Scalar value + * @param {Function} callback The f(Aij,b) operation to invoke + * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) + * + * @return {Matrix} DenseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 + */ + var algorithm12 = function (s, b, callback, inverse) { + // sparse matrix arrays + var avalues = s._values; + var aindex = s._index; + var aptr = s._ptr; + var asize = s._size; + var adt = s._datatype; + + // sparse matrix cannot be a Pattern matrix + if (!avalues) + throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; -function factory$35 (type, config, load, typed) { - /** - * Create a number or convert a string, boolean, or unit to a number. - * When value is a matrix, all elements will be converted to number. - * - * Syntax: - * - * math.number(value) - * math.number(unit, valuelessUnit) - * - * Examples: - * - * math.number(2); // returns number 2 - * math.number('7.2'); // returns number 7.2 - * math.number(true); // returns number 1 - * math.number([true, false, true, true]); // returns [1, 0, 1, 1] - * math.number(math.unit('52cm'), 'm'); // returns 0.52 - * - * See also: - * - * bignumber, boolean, complex, index, matrix, string, unit - * - * @param {string | number | BigNumber | Fraction | boolean | Array | Matrix | Unit | null} [value] Value to be converted - * @param {Unit | string} [valuelessUnit] A valueless unit, used to convert a unit to a number - * @return {number | Array | Matrix} The created number - */ - var number = typed('number', { - '': function () { - return 0; - }, + // datatype + var dt; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string') { + // datatype + dt = adt; + // convert b to the same datatype + b = typed.convert(b, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result arrays + var cdata = []; + // matrix + var c = new DenseMatrix({ + data: cdata, + size: [rows, columns], + datatype: dt + }); - 'number': function (x) { - return x; - }, + // workspaces + var x = []; + // marks indicating we have a value in x for a given column + var w = []; - 'string': function (x) { - var num = Number(x); - if (isNaN(num)) { - throw new SyntaxError('String "' + x + '" is no valid number'); + // loop columns + for (var j = 0; j < columns; j++) { + // columns mark + var mark = j + 1; + // values in j + for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + var r = aindex[k]; + // update workspace + x[r] = avalues[k]; + w[r] = mark; + } + // loop rows + for (var i = 0; i < rows; i++) { + // initialize C on first column + if (j === 0) { + // create row array + cdata[i] = []; + } + // check sparse matrix has a value @ i,j + if (w[i] === mark) { + // invoke callback, update C + cdata[i][j] = inverse ? cf(b, x[i]) : cf(x[i], b); + } + else { + // dense matrix value @ i, j + cdata[i][j] = inverse ? cf(b, 0) : cf(0, b); + } + } } - return num; - }, - 'BigNumber': function (x) { - return x.toNumber(); - }, + // return sparse matrix + return c; + }; + + return algorithm12; + } - 'Fraction': function (x) { - return x.valueOf(); - }, + var name$24 = 'algorithm12'; + var factory_1$26 = factory$26; - 'Unit': function (x) { - throw new Error('Second argument with valueless unit expected'); - }, + var algorithm12 = { + name: name$24, + factory: factory_1$26 + }; - 'null': function (x) { - return 0; - }, + var nearlyEqual$2 = number.nearlyEqual; - 'Unit, string | Unit': function (unit, valuelessUnit) { - return unit.toNumber(valuelessUnit); - }, - 'Array | Matrix': function (x) { - return deepMap(x, number); - } - }); + function factory$27 (type, config, load, typed) { - number.toTex = { - 0: '0', - 1: '\\left(${args[0]}\\right)', - 2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)' - }; + var matrix$$1 = load(matrix); - return number; -} + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); -var name$33 = 'number'; -var factory_1$35 = factory$35; + var latex$$1 = latex; -var number$3 = { - name: name$33, - factory: factory_1$35 -}; + /** + * Test whether value x is smaller than y. + * + * The function returns true when x is smaller than y and the relative + * difference between x and y is smaller than the configured epsilon. The + * function cannot be used to compare values smaller than approximately 2.22e-16. + * + * For matrices, the function is evaluated element wise. + * Strings are compared by their numerical value. + * + * Syntax: + * + * math.smaller(x, y) + * + * Examples: + * + * math.smaller(2, 3); // returns true + * math.smaller(5, 2 * 2); // returns false + * + * var a = math.unit('5 cm'); + * var b = math.unit('2 inch'); + * math.smaller(a, b); // returns true + * + * See also: + * + * equal, unequal, smallerEq, smaller, smallerEq, compare + * + * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare + * @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false + */ + var smaller = typed('smaller', { -function factory$36 (type, config, load, typed) { - /** - * A ResultSet contains a list or results - * @class ResultSet - * @param {Array} entries - * @constructor ResultSet - */ - function ResultSet(entries) { - if (!(this instanceof ResultSet)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + 'boolean, boolean': function (x, y) { + return x < y; + }, - this.entries = entries || []; - } + 'number, number': function (x, y) { + return x < y && !nearlyEqual$2(x, y, config.epsilon); + }, - /** - * Attach type information - */ - ResultSet.prototype.type = 'ResultSet'; - ResultSet.prototype.isResultSet = true; + 'BigNumber, BigNumber': function (x, y) { + return x.lt(y) && !nearlyEqual(x, y, config.epsilon); + }, - /** - * Returns the array with results hold by this ResultSet - * @memberof ResultSet - * @returns {Array} entries - */ - ResultSet.prototype.valueOf = function () { - return this.entries; - }; + 'Fraction, Fraction': function (x, y) { + return x.compare(y) === -1; + }, - /** - * Returns the stringified results of the ResultSet - * @memberof ResultSet - * @returns {string} string - */ - ResultSet.prototype.toString = function () { - return '[' + this.entries.join(', ') + ']'; - }; + 'Complex, Complex': function (x, y) { + throw new TypeError('No ordering relation is defined for complex numbers'); + }, - /** - * Get a JSON representation of the ResultSet - * @memberof ResultSet - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "ResultSet", "entries": [...]}` - */ - ResultSet.prototype.toJSON = function () { - return { - mathjs: 'ResultSet', - entries: this.entries - }; - }; + 'Unit, Unit': function (x, y) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return smaller(x.value, y.value); + }, - /** - * Instantiate a ResultSet from a JSON object - * @memberof ResultSet - * @param {Object} json A JSON object structured as: - * `{"mathjs": "ResultSet", "entries": [...]}` - * @return {ResultSet} - */ - ResultSet.fromJSON = function (json) { - return new ResultSet(json.entries); - }; + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm07$$1(x, y, smaller); + }, - return ResultSet; -} + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, smaller, true); + }, -var name$34 = 'ResultSet'; -var path$12 = 'type'; -var factory_1$36 = factory$36; + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, smaller, false); + }, -var ResultSet = { - name: name$34, - path: path$12, - factory: factory_1$36 -}; + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, smaller); + }, -var resultset = [ - // type - ResultSet -]; + 'Array, Array': function (x, y) { + // use matrix implementation + return smaller(matrix$$1(x), matrix$$1(y)).valueOf(); + }, -function factory$37 (type, config, load, typed) { - /** - * Create a string or convert any object into a string. - * Elements of Arrays and Matrices are processed element wise. - * - * Syntax: - * - * math.string(value) - * - * Examples: - * - * math.string(4.2); // returns string '4.2' - * math.string(math.complex(3, 2); // returns string '3 + 2i' - * - * var u = math.unit(5, 'km'); - * math.string(u.to('m')); // returns string '5000 m' - * - * math.string([true, false]); // returns ['true', 'false'] - * - * See also: - * - * bignumber, boolean, complex, index, matrix, number, unit - * - * @param {* | Array | Matrix | null} [value] A value to convert to a string - * @return {string | Array | Matrix} The created string - */ - var string = typed('string', { - '': function () { - return ''; - }, + 'Array, Matrix': function (x, y) { + // use matrix implementation + return smaller(matrix$$1(x), y); + }, - 'number': number.format, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return smaller(x, matrix$$1(y)); + }, - 'null': function (x) { - return 'null'; - }, + 'SparseMatrix, any': function (x, y) { + return algorithm12$$1(x, y, smaller, false); + }, - 'boolean': function (x) { - return x + ''; - }, + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, smaller, false); + }, - 'string': function (x) { - return x; - }, + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, smaller, true); + }, - 'Array | Matrix': function (x) { - return deepMap(x, string); - }, - - 'any': function (x) { - return String(x); - } - }); - - string.toTex = { - 0: '\\mathtt{""}', - 1: '\\mathrm{string}\\left(${args[0]}\\right)' - }; - - return string; -} - -var name$35 = 'string'; -var factory_1$37 = factory$37; - -var string$6 = { - name: name$35, - factory: factory_1$37 -}; - -var type = [ - bignumber$1, - boolean_1, - chain$1, - complex$3, - fraction$3, - matrix$1, - number$3, - resultset, - string$6, -]; - -var constants = createCommonjsModule(function (module, exports) { -var memoize = _function.memoize; - -/** - * Calculate BigNumber e - * @param {function} BigNumber BigNumber constructor - * @returns {BigNumber} Returns e - */ -exports.e = memoize(function (BigNumber) { - return new BigNumber(1).exp(); -}, hasher); - -/** - * Calculate BigNumber golden ratio, phi = (1+sqrt(5))/2 - * @param {function} BigNumber BigNumber constructor - * @returns {BigNumber} Returns phi - */ -exports.phi = memoize(function (BigNumber) { - return new BigNumber(1).plus(new BigNumber(5).sqrt()).div(2); -}, hasher); - -/** - * Calculate BigNumber pi. - * @param {function} BigNumber BigNumber constructor - * @returns {BigNumber} Returns pi - */ -exports.pi = memoize(function (BigNumber) { - return BigNumber.acos(-1); -}, hasher); - -/** - * Calculate BigNumber tau, tau = 2 * pi - * @param {function} BigNumber BigNumber constructor - * @returns {BigNumber} Returns tau - */ -exports.tau = memoize(function (BigNumber) { - return exports.pi(BigNumber).times(2); -}, hasher); - -/** - * Create a hash for a BigNumber constructor function. The created has is - * the configured precision - * @param {Array} args Supposed to contain a single entry with - * a BigNumber constructor - * @return {number} precision - * @private - */ -function hasher (args) { - return args[0].precision; -} -}); -var constants_1 = constants.e; -var constants_2 = constants.phi; -var constants_3 = constants.pi; -var constants_4 = constants.tau; - -function factory$38 (type, config, load, typed, math) { - // listen for changed in the configuration, automatically reload - // constants when needed - math.on('config', function (curr, prev) { - if (curr.number !== prev.number || curr.define_pi !== prev.define_pi - || curr.define_e !== prev.define_e || curr.define_i !== prev.define_i) { - factory$38(type, config, load, typed, math); - } - }); + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, smaller, true); + }, - setConstant(math, 'true', true); - setConstant(math, 'false', false); - setConstant(math, 'null', null); - setConstant(math, 'uninitialized', 'Error: Constant uninitialized is removed since v4.0.0. Use null instead'); + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, smaller, false).valueOf(); + }, - if (config.number === 'BigNumber') { - setConstant(math, 'Infinity', new type.BigNumber(Infinity)); - setConstant(math, 'NaN', new type.BigNumber(NaN)); + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, smaller, true).valueOf(); + } + }); - if(config.define_pi === false) - deleteConstant(math, 'pi'); - else - setLazyConstant(math, 'pi', function () {return constants.pi(type.BigNumber)}); - if(config.define_e === false) - deleteConstant(math, 'e'); - else - setLazyConstant(math, 'e', function () {return constants.e(type.BigNumber)}); - } - else { - setConstant(math, 'Infinity', Infinity); - setConstant(math, 'NaN', NaN); + smaller.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['smaller'] + '${args[1]}\\right)' + }; - if(config.define_pi === false) - deleteConstant(math, 'pi'); - else - setConstant(math, 'pi', Math.PI); - if(config.define_e === false) - deleteConstant(math, 'e'); - else - setConstant(math, 'e', Math.E); + return smaller; } - if(config.define_i===false) - deleteConstant(math, 'i'); - else - // complex i - setConstant(math, 'i', type.Complex.I); - -} - -// delete a constant in both math and mathWithTransform -function deleteConstant(math, name) { - delete math[name]; - delete math.expression.mathWithTransform[name]; -} - -// create a constant in both math and mathWithTransform -function setConstant(math, name, value) { - math[name] = value; - math.expression.mathWithTransform[name] = value; -} - -// create a lazy constant in both math and mathWithTransform -function setLazyConstant (math, name, resolver) { - object.lazy(math, name, resolver); - object.lazy(math.expression.mathWithTransform, name, resolver); -} - -const lazy$4 = false; // no lazy loading of constants, the constants themselves are lazy when needed -const math$5 = true; // request access to the math namespace - -var constants$1 = { factory: factory$38, lazy: lazy$4, math: math$5 }; - -var bignumber$2 = { - 'name': 'bignumber', - 'category': 'Construction', - 'syntax': [ - 'bignumber(x)' - ], - 'description': - 'Create a big number from a number or string.', - 'examples': [ - '0.1 + 0.2', - 'bignumber(0.1) + bignumber(0.2)', - 'bignumber("7.2")', - 'bignumber("7.2e500")', - 'bignumber([0.1, 0.2, 0.3])' - ], - 'seealso': [ - 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' - ] -}; - -var boolean_1$2 = { - 'name': 'boolean', - 'category': 'Construction', - 'syntax': [ - 'x', - 'boolean(x)' - ], - 'description': - 'Convert a string or number into a boolean.', - 'examples': [ - 'boolean(0)', - 'boolean(1)', - 'boolean(3)', - 'boolean("true")', - 'boolean("false")', - 'boolean([1, 0, 1, 1])' - ], - 'seealso': [ - 'bignumber', 'complex', 'index', 'matrix', 'number', 'string', 'unit' - ] -}; - -var complex$4 = { - 'name': 'complex', - 'category': 'Construction', - 'syntax': [ - 'complex()', - 'complex(re, im)', - 'complex(string)' - ], - 'description': - 'Create a complex number.', - 'examples': [ - 'complex()', - 'complex(2, 3)', - 'complex("7 - 2i")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'index', 'matrix', 'number', 'string', 'unit' - ] -}; - -var createUnit = { - 'name': 'createUnit', - 'category': 'Construction', - 'syntax': [ - 'createUnit(definitions)', - 'createUnit(name, definition)' - ], - 'description': - 'Create a user-defined unit and register it with the Unit type.', - 'examples': [ - 'createUnit("foo")', - 'createUnit("knot", {definition: "0.514444444 m/s", aliases: ["knots", "kt", "kts"]})', - 'createUnit("mph", "1 mile/hour")' - ], - 'seealso': [ - 'unit', 'splitUnit' - ] -}; - -var fraction$4 = { - 'name': 'fraction', - 'category': 'Construction', - 'syntax': [ - 'fraction(num)', - 'fraction(num,den)' - ], - 'description': - 'Create a fraction from a number or from a numerator and denominator.', - 'examples': [ - 'fraction(0.125)', - 'fraction(1, 3) + fraction(2, 5)' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'string', 'unit' - ] -}; - -var construction = { - 'name': 'index', - 'category': 'Construction', - 'syntax': [ - '[start]', - '[start:end]', - '[start:step:end]', - '[start1, start 2, ...]', - '[start1:end1, start2:end2, ...]', - '[start1:step1:end1, start2:step2:end2, ...]' - ], - 'description': - 'Create an index to get or replace a subset of a matrix', - 'examples': [ - '[]', - '[1, 2, 3]', - 'A = [1, 2, 3; 4, 5, 6]', - 'A[1, :]', - 'A[1, 2] = 50', - 'A[0:2, 0:2] = ones(2, 2)' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'matrix,', 'number', 'range', 'string', 'unit' - ] -}; - -var matrix$2 = { - 'name': 'matrix', - 'category': 'Construction', - 'syntax': [ - '[]', - '[a1, b1, ...; a2, b2, ...]', - 'matrix()', - 'matrix("dense")', - 'matrix([...])' - ], - 'description': - 'Create a matrix.', - 'examples': [ - '[]', - '[1, 2, 3]', - '[1, 2, 3; 4, 5, 6]', - 'matrix()', - 'matrix([3, 4])', - 'matrix([3, 4; 5, 6], "sparse")', - 'matrix([3, 4; 5, 6], "sparse", "number")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit', 'sparse' - ] -}; - -var number$4 = { - 'name': 'number', - 'category': 'Construction', - 'syntax': [ - 'x', - 'number(x)', - 'number(unit, valuelessUnit)' - ], - 'description': - 'Create a number or convert a string or boolean into a number.', - 'examples': [ - '2', - '2e3', - '4.05', - 'number(2)', - 'number("7.2")', - 'number(true)', - 'number([true, false, true, true])', - 'number(unit("52cm"), "m")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' - ] -}; - -var sparse$1 = { - 'name': 'sparse', - 'category': 'Construction', - 'syntax': [ - 'sparse()', - 'sparse([a1, b1, ...; a1, b2, ...])', - 'sparse([a1, b1, ...; a1, b2, ...], "number")' - ], - 'description': - 'Create a sparse matrix.', - 'examples': [ - 'sparse()', - 'sparse([3, 4; 5, 6])', - 'sparse([3, 0; 5, 0], "number")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit', 'matrix' - ] -}; - -var splitUnit = { - 'name': 'splitUnit', - 'category': 'Construction', - 'syntax': [ - 'splitUnit(unit: Unit, parts: Unit[])' - ], - 'description': - 'Split a unit in an array of units whose sum is equal to the original unit.', - 'examples': [ - 'splitUnit(1 m, ["feet", "inch"])' - ], - 'seealso': [ - 'unit', 'createUnit' - ] -}; - -var string$7 = { - 'name': 'string', - 'category': 'Construction', - 'syntax': [ - '"text"', - 'string(x)' - ], - 'description': - 'Create a string or convert a value to a string', - 'examples': [ - '"Hello World!"', - 'string(4.2)', - 'string(3 + 2i)' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'number', 'unit' - ] -}; - -var unit = { - 'name': 'unit', - 'category': 'Construction', - 'syntax': [ - 'value unit', - 'unit(value, unit)', - 'unit(string)' - ], - 'description': - 'Create a unit.', - 'examples': [ - '5.5 mm', - '3 inch', - 'unit(7.1, "kilogram")', - 'unit("23 deg")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'number', 'string' - ] -}; - -var e = { - 'name': 'e', - 'category': 'Constants', - 'syntax': [ - 'e' - ], - 'description': 'Euler\'s number, the base of the natural logarithm. Approximately equal to 2.71828', - 'examples': [ - 'e', - 'e ^ 2', - 'exp(2)', - 'log(e)' - ], - 'seealso': ['exp'] -}; - -var _false = { - 'name': 'false', - 'category': 'Constants', - 'syntax': [ - 'false' - ], - 'description': 'Boolean value false', - 'examples': [ - 'false' - ], - 'seealso': ['true'] -}; - -var i = { - 'name': 'i', - 'category': 'Constants', - 'syntax': [ - 'i' - ], - 'description': 'Imaginary unit, defined as i*i=-1. A complex number is described as a + b*i, where a is the real part, and b is the imaginary part.', - 'examples': [ - 'i', - 'i * i', - 'sqrt(-1)' - ], - 'seealso': [] -}; - -var _Infinity = { - 'name': 'Infinity', - 'category': 'Constants', - 'syntax': [ - 'Infinity' - ], - 'description': 'Infinity, a number which is larger than the maximum number that can be handled by a floating point number.', - 'examples': [ - 'Infinity', - '1 / 0' - ], - 'seealso': [] -}; - -var LN2 = { - 'name': 'LN2', - 'category': 'Constants', - 'syntax': [ - 'LN2' - ], - 'description': 'Returns the natural logarithm of 2, approximately equal to 0.693', - 'examples': [ - 'LN2', - 'log(2)' - ], - 'seealso': [] -}; - -var LN10 = { - 'name': 'LN10', - 'category': 'Constants', - 'syntax': [ - 'LN10' - ], - 'description': 'Returns the natural logarithm of 10, approximately equal to 2.302', - 'examples': [ - 'LN10', - 'log(10)' - ], - 'seealso': [] -}; - -var LOG2E = { - 'name': 'LOG2E', - 'category': 'Constants', - 'syntax': [ - 'LOG2E' - ], - 'description': 'Returns the base-2 logarithm of E, approximately equal to 1.442', - 'examples': [ - 'LOG2E', - 'log(e, 2)' - ], - 'seealso': [] -}; - -var LOG10E = { - 'name': 'LOG10E', - 'category': 'Constants', - 'syntax': [ - 'LOG10E' - ], - 'description': 'Returns the base-10 logarithm of E, approximately equal to 0.434', - 'examples': [ - 'LOG10E', - 'log(e, 10)' - ], - 'seealso': [] -}; - -var _NaN = { - 'name': 'NaN', - 'category': 'Constants', - 'syntax': [ - 'NaN' - ], - 'description': 'Not a number', - 'examples': [ - 'NaN', - '0 / 0' - ], - 'seealso': [] -}; - -var _null = { - 'name': 'null', - 'category': 'Constants', - 'syntax': [ - 'null' - ], - 'description': 'Value null', - 'examples': [ - 'null' - ], - 'seealso': ['true', 'false'] -}; - -var pi = { - 'name': 'pi', - 'category': 'Constants', - 'syntax': [ - 'pi' - ], - 'description': 'The number pi is a mathematical constant that is the ratio of a circle\'s circumference to its diameter, and is approximately equal to 3.14159', - 'examples': [ - 'pi', - 'sin(pi/2)' - ], - 'seealso': ['tau'] -}; - -var phi = { - 'name': 'phi', - 'category': 'Constants', - 'syntax': [ - 'phi' - ], - 'description': 'Phi is the golden ratio. Two quantities are in the golden ratio if their ratio is the same as the ratio of their sum to the larger of the two quantities. Phi is defined as `(1 + sqrt(5)) / 2` and is approximately 1.618034...', - 'examples': [ - 'phi' - ], - 'seealso': [] -}; - -var SQRT1_2 = { - 'name': 'SQRT1_2', - 'category': 'Constants', - 'syntax': [ - 'SQRT1_2' - ], - 'description': 'Returns the square root of 1/2, approximately equal to 0.707', - 'examples': [ - 'SQRT1_2', - 'sqrt(1/2)' - ], - 'seealso': [] -}; - -var SQRT2 = { - 'name': 'SQRT2', - 'category': 'Constants', - 'syntax': [ - 'SQRT2' - ], - 'description': 'Returns the square root of 2, approximately equal to 1.414', - 'examples': [ - 'SQRT2', - 'sqrt(2)' - ], - 'seealso': [] -}; - -var tau = { - 'name': 'tau', - 'category': 'Constants', - 'syntax': [ - 'tau' - ], - 'description': 'Tau is the ratio constant of a circle\'s circumference to radius, equal to 2 * pi, approximately 6.2832.', - 'examples': [ - 'tau', - '2 * pi' - ], - 'seealso': ['pi'] -}; - -var _true = { - 'name': 'true', - 'category': 'Constants', - 'syntax': [ - 'true' - ], - 'description': 'Boolean value true', - 'examples': [ - 'true' - ], - 'seealso': ['false'] -}; - -var version = { - 'name': 'version', - 'category': 'Constants', - 'syntax': [ - 'version' - ], - 'description': 'A string with the version number of math.js', - 'examples': [ - 'version' - ], - 'seealso': [] -}; - -var derivative = { - 'name': 'derivative', - 'category': 'Algebra', - 'syntax': [ - 'derivative(expr, variable)', - 'derivative(expr, variable, {simplify: boolean})' - ], - 'description': 'Takes the derivative of an expression expressed in parser Nodes. The derivative will be taken over the supplied variable in the second parameter. If there are multiple variables in the expression, it will return a partial derivative.', - 'examples': [ - 'derivative("2x^3", "x")', - 'derivative("2x^3", "x", {simplify: false})', - 'derivative("2x^2 + 3x + 4", "x")', - 'derivative("sin(2x)", "x")', - 'f = parse("x^2 + x")', - 'x = parse("x")', - 'df = derivative(f, x)', - 'df.eval({x: 3})' - ], - 'seealso': [ - 'simplify', 'parse', 'eval' - ] -}; - -var lsolve = { - 'name': 'lsolve', - 'category': 'Algebra', - 'syntax': [ - 'x=lsolve(L, b)' - ], - 'description': - 'Solves the linear system L * x = b where L is an [n x n] lower triangular matrix and b is a [n] column vector.', - 'examples': [ - 'a = [-2, 3; 2, 1]', - 'b = [11, 9]', - 'x = lsolve(a, b)' - ], - 'seealso': [ - 'lup', 'lusolve', 'usolve', 'matrix', 'sparse' - ] -}; - -var lup = { - 'name': 'lup', - 'category': 'Algebra', - 'syntax': [ - 'lup(m)' - ], - 'description': - 'Calculate the Matrix LU decomposition with partial pivoting. Matrix A is decomposed in three matrices (L, U, P) where P * A = L * U', - 'examples': [ - 'lup([[2, 1], [1, 4]])', - 'lup(matrix([[2, 1], [1, 4]]))', - 'lup(sparse([[2, 1], [1, 4]]))' - ], - 'seealso': [ - 'lusolve', 'lsolve', 'usolve', 'matrix', 'sparse', 'slu', 'qr' - ] -}; - -var lusolve = { - 'name': 'lusolve', - 'category': 'Algebra', - 'syntax': [ - 'x=lusolve(A, b)', - 'x=lusolve(lu, b)' - ], - 'description': 'Solves the linear system A * x = b where A is an [n x n] matrix and b is a [n] column vector.', - 'examples': [ - 'a = [-2, 3; 2, 1]', - 'b = [11, 9]', - 'x = lusolve(a, b)' - ], - 'seealso': [ - 'lup', 'slu', 'lsolve', 'usolve', 'matrix', 'sparse' - ] -}; - -var simplify = { - 'name': 'simplify', - 'category': 'Algebra', - 'syntax': [ - 'simplify(expr)', - 'simplify(expr, rules)' - ], - 'description': 'Simplify an expression tree.', - 'examples': [ - 'simplify("3 + 2 / 4")', - 'simplify("2x + x")', - 'f = parse("x * (x + 2 + x)")', - 'simplified = simplify(f)', - 'simplified.eval({x: 2})' - ], - 'seealso': [ - 'derivative', 'parse', 'eval' - ] -}; - -var rationalize = { - 'name': 'rationalize', - 'category': 'Algebra', - 'syntax': [ - 'rationalize(expr)', - 'rationalize(expr, scope)', - 'rationalize(expr, scope, detailed)' - ], - 'description': 'Transform a rationalizable expression in a rational fraction. If rational fraction is one variable polynomial then converts the numerator and denominator in canonical form, with decreasing exponents, returning the coefficients of numerator.', - 'examples': [ - 'rationalize("2x/y - y/(x+1)")', - 'rationalize("2x/y - y/(x+1)", true)', - ], - 'seealso': [ - 'simplify' - ] -}; - -var slu = { - 'name': 'slu', - 'category': 'Algebra', - 'syntax': [ - 'slu(A, order, threshold)' - ], - 'description': 'Calculate the Matrix LU decomposition with full pivoting. Matrix A is decomposed in two matrices (L, U) and two permutation vectors (pinv, q) where P * A * Q = L * U', - 'examples': [ - 'slu(sparse([4.5, 0, 3.2, 0; 3.1, 2.9, 0, 0.9; 0, 1.7, 3, 0; 3.5, 0.4, 0, 1]), 1, 0.001)' - ], - 'seealso': [ - 'lusolve', 'lsolve', 'usolve', 'matrix', 'sparse', 'lup', 'qr' - ] -}; - -var usolve = { - 'name': 'usolve', - 'category': 'Algebra', - 'syntax': [ - 'x=usolve(U, b)' - ], - 'description': - 'Solves the linear system U * x = b where U is an [n x n] upper triangular matrix and b is a [n] column vector.', - 'examples': [ - 'x=usolve(sparse([1, 1, 1, 1; 0, 1, 1, 1; 0, 0, 1, 1; 0, 0, 0, 1]), [1; 2; 3; 4])' - ], - 'seealso': [ - 'lup', 'lusolve', 'lsolve', 'matrix', 'sparse' - ] -}; - -var qr = { - 'name': 'qr', - 'category': 'Algebra', - 'syntax': [ - 'qr(A)' - ], - 'description': - 'Calculates the Matrix QR decomposition. Matrix `A` is decomposed in two matrices (`Q`, `R`) where `Q` is an orthogonal matrix and `R` is an upper triangular matrix.', - 'examples': [ - 'qr([[1, -1, 4], [1, 4, -2], [1, 4, 2], [1, -1, 0]])' - ], - 'seealso': [ - 'lup', 'slu', 'matrix' - ] -}; - -var abs = { - 'name': 'abs', - 'category': 'Arithmetic', - 'syntax': [ - 'abs(x)' - ], - 'description': 'Compute the absolute value.', - 'examples': [ - 'abs(3.5)', - 'abs(-4.2)' - ], - 'seealso': ['sign'] -}; - -var add$1 = { - 'name': 'add', - 'category': 'Operators', - 'syntax': [ - 'x + y', - 'add(x, y)' - ], - 'description': 'Add two values.', - 'examples': [ - 'a = 2.1 + 3.6', - 'a - 3.6', - '3 + 2i', - '3 cm + 2 inch', - '"2.3" + "4"' - ], - 'seealso': [ - 'subtract' - ] -}; - -var cbrt = { - 'name': 'cbrt', - 'category': 'Arithmetic', - 'syntax': [ - 'cbrt(x)', - 'cbrt(x, allRoots)' - ], - 'description': - 'Compute the cubic root value. If x = y * y * y, then y is the cubic root of x. When `x` is a number or complex number, an optional second argument `allRoots` can be provided to return all three cubic roots. If not provided, the principal root is returned', - 'examples': [ - 'cbrt(64)', - 'cube(4)', - 'cbrt(-8)', - 'cbrt(2 + 3i)', - 'cbrt(8i)', - 'cbrt(8i, true)', - 'cbrt(27 m^3)' - ], - 'seealso': [ - 'square', - 'sqrt', - 'cube', - 'multiply' - ] -}; - -var ceil = { - 'name': 'ceil', - 'category': 'Arithmetic', - 'syntax': [ - 'ceil(x)' - ], - 'description': - 'Round a value towards plus infinity. If x is complex, both real and imaginary part are rounded towards plus infinity.', - 'examples': [ - 'ceil(3.2)', - 'ceil(3.8)', - 'ceil(-4.2)' - ], - 'seealso': ['floor', 'fix', 'round'] -}; - -var cube = { - 'name': 'cube', - 'category': 'Arithmetic', - 'syntax': [ - 'cube(x)' - ], - 'description': 'Compute the cube of a value. The cube of x is x * x * x.', - 'examples': [ - 'cube(2)', - '2^3', - '2 * 2 * 2' - ], - 'seealso': [ - 'multiply', - 'square', - 'pow' - ] -}; - -var divide = { - 'name': 'divide', - 'category': 'Operators', - 'syntax': [ - 'x / y', - 'divide(x, y)' - ], - 'description': 'Divide two values.', - 'examples': [ - 'a = 2 / 3', - 'a * 3', - '4.5 / 2', - '3 + 4 / 2', - '(3 + 4) / 2', - '18 km / 4.5' - ], - 'seealso': [ - 'multiply' - ] -}; - -var dotDivide = { - 'name': 'dotDivide', - 'category': 'Operators', - 'syntax': [ - 'x ./ y', - 'dotDivide(x, y)' - ], - 'description': 'Divide two values element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'b = [2, 1, 1; 3, 2, 5]', - 'a ./ b' - ], - 'seealso': [ - 'multiply', - 'dotMultiply', - 'divide' - ] -}; - -var dotMultiply = { - 'name': 'dotMultiply', - 'category': 'Operators', - 'syntax': [ - 'x .* y', - 'dotMultiply(x, y)' - ], - 'description': 'Multiply two values element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'b = [2, 1, 1; 3, 2, 5]', - 'a .* b' - ], - 'seealso': [ - 'multiply', - 'divide', - 'dotDivide' - ] -}; - -var dotPow = { - 'name': 'dotpow', - 'category': 'Operators', - 'syntax': [ - 'x .^ y', - 'dotpow(x, y)' - ], - 'description': - 'Calculates the power of x to y element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'a .^ 2' - ], - 'seealso': [ - 'pow' - ] -}; - -var exp = { - 'name': 'exp', - 'category': 'Arithmetic', - 'syntax': [ - 'exp(x)' - ], - 'description': 'Calculate the exponent of a value.', - 'examples': [ - 'exp(1.3)', - 'e ^ 1.3', - 'log(exp(1.3))', - 'x = 2.4', - '(exp(i*x) == cos(x) + i*sin(x)) # Euler\'s formula' - ], - 'seealso': [ - 'expm', - 'expm1', - 'pow', - 'log' - ] -}; - -var expm = { - 'name': 'expm', - 'category': 'Arithmetic', - 'syntax': [ - 'exp(x)' - ], - 'description': 'Compute the matrix exponential, expm(A) = e^A. ' + - 'The matrix must be square. ' + - 'Not to be confused with exp(a), which performs element-wise exponentiation.', - 'examples': [ - 'expm([[0,2],[0,0]])' - ], - 'seealso': [ - 'exp' - ] -}; - -var expm1 = { - 'name': 'expm1', - 'category': 'Arithmetic', - 'syntax': [ - 'expm1(x)' - ], - 'description': 'Calculate the value of subtracting 1 from the exponential value.', - 'examples': [ - 'expm1(2)', - 'pow(e, 2) - 1', - 'log(expm1(2) + 1)' - ], - 'seealso': [ - 'exp', - 'pow', - 'log' - ] -}; - -var fix = { - 'name': 'fix', - 'category': 'Arithmetic', - 'syntax': [ - 'fix(x)' - ], - 'description': - 'Round a value towards zero. If x is complex, both real and imaginary part are rounded towards zero.', - 'examples': [ - 'fix(3.2)', - 'fix(3.8)', - 'fix(-4.2)', - 'fix(-4.8)' - ], - 'seealso': ['ceil', 'floor', 'round'] -}; - -var floor = { - 'name': 'floor', - 'category': 'Arithmetic', - 'syntax': [ - 'floor(x)' - ], - 'description': - 'Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.', - 'examples': [ - 'floor(3.2)', - 'floor(3.8)', - 'floor(-4.2)' - ], - 'seealso': ['ceil', 'fix', 'round'] -}; - -var gcd = { - 'name': 'gcd', - 'category': 'Arithmetic', - 'syntax': [ - 'gcd(a, b)', - 'gcd(a, b, c, ...)' - ], - 'description': 'Compute the greatest common divisor.', - 'examples': [ - 'gcd(8, 12)', - 'gcd(-4, 6)', - 'gcd(25, 15, -10)' - ], - 'seealso': [ 'lcm', 'xgcd' ] -}; - -var hypot = { - 'name': 'hypot', - 'category': 'Arithmetic', - 'syntax': [ - 'hypot(a, b, c, ...)', - 'hypot([a, b, c, ...])' - ], - 'description': 'Calculate the hypotenusa of a list with values. ', - 'examples': [ - 'hypot(3, 4)', - 'sqrt(3^2 + 4^2)', - 'hypot(-2)', - 'hypot([3, 4, 5])' - ], - 'seealso': [ 'abs', 'norm' ] -}; - -var lcm = { - 'name': 'lcm', - 'category': 'Arithmetic', - 'syntax': [ - 'lcm(x, y)' - ], - 'description': 'Compute the least common multiple.', - 'examples': [ - 'lcm(4, 6)', - 'lcm(6, 21)', - 'lcm(6, 21, 5)' - ], - 'seealso': [ 'gcd' ] -}; - -var log = { - 'name': 'log', - 'category': 'Arithmetic', - 'syntax': [ - 'log(x)', - 'log(x, base)' - ], - 'description': 'Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).', - 'examples': [ - 'log(3.5)', - 'a = log(2.4)', - 'exp(a)', - '10 ^ 4', - 'log(10000, 10)', - 'log(10000) / log(10)', - 'b = log(1024, 2)', - '2 ^ b' - ], - 'seealso': [ - 'exp', - 'log1p', - 'log2', - 'log10' - ] -}; - -var log2 = { - 'name': 'log2', - 'category': 'Arithmetic', - 'syntax': [ - 'log2(x)' - ], - 'description': 'Calculate the 2-base of a value. This is the same as calculating `log(x, 2)`.', - 'examples': [ - 'log2(0.03125)', - 'log2(16)', - 'log2(16) / log2(2)', - 'pow(2, 4)' - ], - 'seealso': [ - 'exp', - 'log1p', - 'log', - 'log10' - ] -}; - -var log1p = { - 'name': 'log1p', - 'category': 'Arithmetic', - 'syntax': [ - 'log1p(x)', - 'log1p(x, base)' - ], - 'description': 'Calculate the logarithm of a `value+1`', - 'examples': [ - 'log1p(2.5)', - 'exp(log1p(1.4))', - 'pow(10, 4)', - 'log1p(9999, 10)', - 'log1p(9999) / log(10)' - ], - 'seealso': [ - 'exp', - 'log', - 'log2', - 'log10' - ] -}; - -var log10 = { - 'name': 'log10', - 'category': 'Arithmetic', - 'syntax': [ - 'log10(x)' - ], - 'description': 'Compute the 10-base logarithm of a value.', - 'examples': [ - 'log10(0.00001)', - 'log10(10000)', - '10 ^ 4', - 'log(10000) / log(10)', - 'log(10000, 10)' - ], - 'seealso': [ - 'exp', - 'log' - ] -}; - -var mod = { - 'name': 'mod', - 'category': 'Operators', - 'syntax': [ - 'x % y', - 'x mod y', - 'mod(x, y)' - ], - 'description': - 'Calculates the modulus, the remainder of an integer division.', - 'examples': [ - '7 % 3', - '11 % 2', - '10 mod 4', - 'isOdd(x) = x % 2', - 'isOdd(2)', - 'isOdd(3)' - ], - 'seealso': ['divide'] -}; - -var multiply = { - 'name': 'multiply', - 'category': 'Operators', - 'syntax': [ - 'x * y', - 'multiply(x, y)' - ], - 'description': 'multiply two values.', - 'examples': [ - 'a = 2.1 * 3.4', - 'a / 3.4', - '2 * 3 + 4', - '2 * (3 + 4)', - '3 * 2.1 km' - ], - 'seealso': [ - 'divide' - ] -}; - -var norm = { - 'name': 'norm', - 'category': 'Arithmetic', - 'syntax': [ - 'norm(x)', - 'norm(x, p)' - ], - 'description': 'Calculate the norm of a number, vector or matrix.', - 'examples': [ - 'abs(-3.5)', - 'norm(-3.5)', - 'norm(3 - 4i)', - 'norm([1, 2, -3], Infinity)', - 'norm([1, 2, -3], -Infinity)', - 'norm([3, 4], 2)', - 'norm([[1, 2], [3, 4]], 1)', - 'norm([[1, 2], [3, 4]], "inf")', - 'norm([[1, 2], [3, 4]], "fro")' - ] -}; - -var nthRoot = { - 'name': 'nthRoot', - 'category': 'Arithmetic', - 'syntax': [ - 'nthRoot(a)', - 'nthRoot(a, root)' - ], - 'description': 'Calculate the nth root of a value. ' + - 'The principal nth root of a positive real number A, ' + - 'is the positive real solution of the equation "x^root = A".', - 'examples': [ - '4 ^ 3', - 'nthRoot(64, 3)', - 'nthRoot(9, 2)', - 'sqrt(9)' - ], - 'seealso': [ - 'sqrt', - 'pow' - ] -}; - -var pow = { - 'name': 'pow', - 'category': 'Operators', - 'syntax': [ - 'x ^ y', - 'pow(x, y)' - ], - 'description': - 'Calculates the power of x to y, x^y.', - 'examples': [ - '2^3', - '2*2*2', - '1 + e ^ (pi * i)' - ], - 'seealso': [ 'multiply' ] -}; - -var round = { - 'name': 'round', - 'category': 'Arithmetic', - 'syntax': [ - 'round(x)', - 'round(x, n)' - ], - 'description': - 'round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.', - 'examples': [ - 'round(3.2)', - 'round(3.8)', - 'round(-4.2)', - 'round(-4.8)', - 'round(pi, 3)', - 'round(123.45678, 2)' - ], - 'seealso': ['ceil', 'floor', 'fix'] -}; - -var sign = { - 'name': 'sign', - 'category': 'Arithmetic', - 'syntax': [ - 'sign(x)' - ], - 'description': - 'Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.', - 'examples': [ - 'sign(3.5)', - 'sign(-4.2)', - 'sign(0)' - ], - 'seealso': [ - 'abs' - ] -}; - -var sqrt = { - 'name': 'sqrt', - 'category': 'Arithmetic', - 'syntax': [ - 'sqrt(x)' - ], - 'description': - 'Compute the square root value. If x = y * y, then y is the square root of x.', - 'examples': [ - 'sqrt(25)', - '5 * 5', - 'sqrt(-1)' - ], - 'seealso': [ - 'square', - 'sqrtm', - 'multiply' - ] -}; - -var sqrtm = { - 'name': 'sqrtm', - 'category': 'Arithmetic', - 'syntax': [ - 'sqrtm(x)' - ], - 'description': - 'Calculate the principal square root of a square matrix. The principal square root matrix `X` of another matrix `A` is such that `X * X = A`.', - 'examples': [ - 'sqrtm([[1, 2], [3, 4]])' - ], - 'seealso': [ - 'sqrt', - 'abs', - 'square', - 'multiply' - ] -}; - -var square = { - 'name': 'square', - 'category': 'Arithmetic', - 'syntax': [ - 'square(x)' - ], - 'description': - 'Compute the square of a value. The square of x is x * x.', - 'examples': [ - 'square(3)', - 'sqrt(9)', - '3^2', - '3 * 3' - ], - 'seealso': [ - 'multiply', - 'pow', - 'sqrt', - 'cube' - ] -}; - -var subtract = { - 'name': 'subtract', - 'category': 'Operators', - 'syntax': [ - 'x - y', - 'subtract(x, y)' - ], - 'description': 'subtract two values.', - 'examples': [ - 'a = 5.3 - 2', - 'a + 2', - '2/3 - 1/6', - '2 * 3 - 3', - '2.1 km - 500m' - ], - 'seealso': [ - 'add' - ] -}; - -var unaryMinus = { - 'name': 'unaryMinus', - 'category': 'Operators', - 'syntax': [ - '-x', - 'unaryMinus(x)' - ], - 'description': - 'Inverse the sign of a value. Converts booleans and strings to numbers.', - 'examples': [ - '-4.5', - '-(-5.6)', - '-"22"' - ], - 'seealso': [ - 'add', 'subtract', 'unaryPlus' - ] -}; - -var unaryPlus = { - 'name': 'unaryPlus', - 'category': 'Operators', - 'syntax': [ - '+x', - 'unaryPlus(x)' - ], - 'description': - 'Converts booleans and strings to numbers.', - 'examples': [ - '+true', - '+"2"' - ], - 'seealso': [ - 'add', 'subtract', 'unaryMinus' - ] -}; - -var xgcd = { - 'name': 'xgcd', - 'category': 'Arithmetic', - 'syntax': [ - 'xgcd(a, b)' - ], - 'description': 'Calculate the extended greatest common divisor for two values. The result is an array [d, x, y] with 3 entries, where d is the greatest common divisor, and d = x * a + y * b.', - 'examples': [ - 'xgcd(8, 12)', - 'gcd(8, 12)', - 'xgcd(36163, 21199)' - ], - 'seealso': [ 'gcd', 'lcm' ] -}; - -var bitAnd = { - 'name': 'bitAnd', - 'category': 'Bitwise', - 'syntax': [ - 'x & y', - 'bitAnd(x, y)' - ], - 'description': 'Bitwise AND operation. Performs the logical AND operation on each pair of the corresponding bits of the two given values by multiplying them. If both bits in the compared position are 1, the bit in the resulting binary representation is 1, otherwise, the result is 0', - 'examples': [ - '5 & 3', - 'bitAnd(53, 131)', - '[1, 12, 31] & 42' - ], - 'seealso': [ - 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' - ] -}; - -var bitNot = { - 'name': 'bitNot', - 'category': 'Bitwise', - 'syntax': [ - '~x', - 'bitNot(x)' - ], - 'description': 'Bitwise NOT operation. Performs a logical negation on each bit of the given value. Bits that are 0 become 1, and those that are 1 become 0.', - 'examples': [ - '~1', - '~2', - 'bitNot([2, -3, 4])' - ], - 'seealso': [ - 'bitAnd', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' - ] -}; - -var bitOr = { - 'name': 'bitOr', - 'category': 'Bitwise', - 'syntax': [ - 'x | y', - 'bitOr(x, y)' - ], - 'description': 'Bitwise OR operation. Performs the logical inclusive OR operation on each pair of corresponding bits of the two given values. The result in each position is 1 if the first bit is 1 or the second bit is 1 or both bits are 1, otherwise, the result is 0.', - 'examples': [ - '5 | 3', - 'bitOr([1, 2, 3], 4)' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' - ] -}; - -var bitXor = { - 'name': 'bitXor', - 'category': 'Bitwise', - 'syntax': [ - 'bitXor(x, y)' - ], - 'description': 'Bitwise XOR operation, exclusive OR. Performs the logical exclusive OR operation on each pair of corresponding bits of the two given values. The result in each position is 1 if only the first bit is 1 or only the second bit is 1, but will be 0 if both are 0 or both are 1.', - 'examples': [ - 'bitOr(1, 2)', - 'bitXor([2, 3, 4], 4)' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitOr', 'leftShift', 'rightArithShift', 'rightLogShift' - ] -}; - -var leftShift = { - 'name': 'leftShift', - 'category': 'Bitwise', - 'syntax': [ - 'x << y', - 'leftShift(x, y)' - ], - 'description': 'Bitwise left logical shift of a value x by y number of bits.', - 'examples': [ - '4 << 1', - '8 >> 1' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'rightArithShift', 'rightLogShift' - ] -}; - -var rightArithShift = { - 'name': 'rightArithShift', - 'category': 'Bitwise', - 'syntax': [ - 'x >> y', - 'rightArithShift(x, y)' - ], - 'description': 'Bitwise right arithmetic shift of a value x by y number of bits.', - 'examples': [ - '8 >> 1', - '4 << 1', - '-12 >> 2' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightLogShift' - ] -}; - -var rightLogShift = { - 'name': 'rightLogShift', - 'category': 'Bitwise', - 'syntax': [ - 'x >>> y', - 'rightLogShift(x, y)' - ], - 'description': 'Bitwise right logical shift of a value x by y number of bits.', - 'examples': [ - '8 >>> 1', - '4 << 1', - '-12 >>> 2' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift' - ] -}; - -var bellNumbers = { - 'name': 'bellNumbers', - 'category': 'Combinatorics', - 'syntax': [ - 'bellNumbers(n)' - ], - 'description': 'The Bell Numbers count the number of partitions of a set. A partition is a pairwise disjoint subset of S whose union is S. `bellNumbers` only takes integer arguments. The following condition must be enforced: n >= 0.', - 'examples': [ - 'bellNumbers(3)', - 'bellNumbers(8)' - ], - 'seealso': ['stirlingS2'] -}; - -var catalan = { - 'name': 'catalan', - 'category': 'Combinatorics', - 'syntax': [ - 'catalan(n)' - ], - 'description': 'The Catalan Numbers enumerate combinatorial structures of many different types. catalan only takes integer arguments. The following condition must be enforced: n >= 0.', - 'examples': [ - 'catalan(3)', - 'catalan(8)' - ], - 'seealso': ['bellNumbers'] -}; - -var composition = { - 'name': 'composition', - 'category': 'Combinatorics', - 'syntax': [ - 'composition(n, k)' - ], - 'description': 'The composition counts of n into k parts. composition only takes integer arguments. The following condition must be enforced: k <= n.', - 'examples': [ - 'composition(5, 3)' - ], - 'seealso': ['combinations'] -}; - -var stirlingS2 = { - 'name': 'stirlingS2', - 'category': 'Combinatorics', - 'syntax': [ - 'stirlingS2(n, k)' - ], - 'description': 'he Stirling numbers of the second kind, counts the number of ways to partition a set of n labelled objects into k nonempty unlabelled subsets. `stirlingS2` only takes integer arguments. The following condition must be enforced: k <= n. If n = k or k = 1, then s(n,k) = 1.', - 'examples': [ - 'stirlingS2(5, 3)' - ], - 'seealso': ['bellNumbers'] -}; - -var config$1 = { - 'name': 'config', - 'category': 'Core', - 'syntax': [ - 'config()', - 'config(options)' - ], - 'description': 'Get configuration or change configuration.', - 'examples': [ - 'config()', - '1/3 + 1/4', - 'config({number: "Fraction"})', - '1/3 + 1/4' - ], - 'seealso': [] -}; - -var _import$1 = { - 'name': 'import', - 'category': 'Core', - 'syntax': [ - 'import(functions)', - 'import(functions, options)' - ], - 'description': 'Import functions or constants from an object.', - 'examples': [ - 'import({myFn: f(x)=x^2, myConstant: 32 })', - 'myFn(2)', - 'myConstant' - ], - 'seealso': [] -}; - -var typed$1 = { - 'name': 'typed', - 'category': 'Core', - 'syntax': [ - 'typed(signatures)', - 'typed(name, signatures)' - ], - 'description': 'Create a typed function.', - 'examples': [ - 'double = typed({ "number, number": f(x)=x+x })', - 'double(2)', - 'double("hello")' - ], - 'seealso': [] -}; - -var arg = { - 'name': 'arg', - 'category': 'Complex', - 'syntax': [ - 'arg(x)' - ], - 'description': - 'Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).', - 'examples': [ - 'arg(2 + 2i)', - 'atan2(3, 2)', - 'arg(2 + 3i)' - ], - 'seealso': [ - 're', - 'im', - 'conj', - 'abs' - ] -}; - -var conj = { - 'name': 'conj', - 'category': 'Complex', - 'syntax': [ - 'conj(x)' - ], - 'description': - 'Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.', - 'examples': [ - 'conj(2 + 3i)', - 'conj(2 - 3i)', - 'conj(-5.2i)' - ], - 'seealso': [ - 're', - 'im', - 'abs', - 'arg' - ] -}; - -var re = { - 'name': 're', - 'category': 'Complex', - 'syntax': [ - 're(x)' - ], - 'description': 'Get the real part of a complex number.', - 'examples': [ - 're(2 + 3i)', - 'im(2 + 3i)', - 're(-5.2i)', - 're(2.4)' - ], - 'seealso': [ - 'im', - 'conj', - 'abs', - 'arg' - ] -}; - -var im = { - 'name': 'im', - 'category': 'Complex', - 'syntax': [ - 'im(x)' - ], - 'description': 'Get the imaginary part of a complex number.', - 'examples': [ - 'im(2 + 3i)', - 're(2 + 3i)', - 'im(-5.2i)', - 'im(2.4)' - ], - 'seealso': [ - 're', - 'conj', - 'abs', - 'arg' - ] -}; - -var _eval = { - 'name': 'eval', - 'category': 'Expression', - 'syntax': [ - 'eval(expression)', - 'eval([expr1, expr2, expr3, ...])' - ], - 'description': 'Evaluate an expression or an array with expressions.', - 'examples': [ - 'eval("2 + 3")', - 'eval("sqrt(" + 4 + ")")' - ], - 'seealso': [] -}; - -var help = { - 'name': 'help', - 'category': 'Expression', - 'syntax': [ - 'help(object)', - 'help(string)' - ], - 'description': 'Display documentation on a function or data type.', - 'examples': [ - 'help(sqrt)', - 'help("complex")' - ], - 'seealso': [] -}; - -var distance = { - 'name': 'distance', - 'category': 'Geometry', - 'syntax': [ - 'distance([x1, y1], [x2, y2])', - 'distance([[x1, y1], [x2, y2])' - ], - 'description': 'Calculates the Euclidean distance between two points.', - 'examples': [ - 'distance([0,0], [4,4])', - 'distance([[0,0], [4,4]])' - ], - 'seealso': [] -}; - -var intersect = { - 'name': 'intersect', - 'category': 'Geometry', - 'syntax': [ - 'intersect(expr1, expr2, expr3, expr4)', - 'intersect(expr1, expr2, expr3)' - ], - 'description': 'Computes the intersection point of lines and/or planes.', - 'examples': [ - 'intersect([0, 0], [10, 10], [10, 0], [0, 10])', - 'intersect([1, 0, 1], [4, -2, 2], [1, 1, 1, 6])' - ], - 'seealso': [] -}; - -var and = { - 'name': 'and', - 'category': 'Logical', - 'syntax': [ - 'x and y', - 'and(x, y)' - ], - 'description': 'Logical and. Test whether two values are both defined with a nonzero/nonempty value.', - 'examples': [ - 'true and false', - 'true and true', - '2 and 4' - ], - 'seealso': [ - 'not', 'or', 'xor' - ] -}; - -var not = { - 'name': 'not', - 'category': 'Logical', - 'syntax': [ - 'not x', - 'not(x)' - ], - 'description': 'Logical not. Flips the boolean value of given argument.', - 'examples': [ - 'not true', - 'not false', - 'not 2', - 'not 0' - ], - 'seealso': [ - 'and', 'or', 'xor' - ] -}; - -var or = { - 'name': 'or', - 'category': 'Logical', - 'syntax': [ - 'x or y', - 'or(x, y)' - ], - 'description': 'Logical or. Test if at least one value is defined with a nonzero/nonempty value.', - 'examples': [ - 'true or false', - 'false or false', - '0 or 4' - ], - 'seealso': [ - 'not', 'and', 'xor' - ] -}; - -var xor = { - 'name': 'xor', - 'category': 'Logical', - 'syntax': [ - 'x xor y', - 'xor(x, y)' - ], - 'description': 'Logical exclusive or, xor. Test whether one and only one value is defined with a nonzero/nonempty value.', - 'examples': [ - 'true xor false', - 'false xor false', - 'true xor true', - '0 xor 4' - ], - 'seealso': [ - 'not', 'and', 'or' - ] -}; - -var concat = { - 'name': 'concat', - 'category': 'Matrix', - 'syntax': [ - 'concat(A, B, C, ...)', - 'concat(A, B, C, ..., dim)' - ], - 'description': 'Concatenate matrices. By default, the matrices are concatenated by the last dimension. The dimension on which to concatenate can be provided as last argument.', - 'examples': [ - 'A = [1, 2; 5, 6]', - 'B = [3, 4; 7, 8]', - 'concat(A, B)', - 'concat(A, B, 1)', - 'concat(A, B, 2)' - ], - 'seealso': [ - 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var cross = { - 'name': 'cross', - 'category': 'Matrix', - 'syntax': [ - 'cross(A, B)' - ], - 'description': 'Calculate the cross product for two vectors in three dimensional space.', - 'examples': [ - 'cross([1, 1, 0], [0, 1, 1])', - 'cross([3, -3, 1], [4, 9, 2])', - 'cross([2, 3, 4], [5, 6, 7])' - ], - 'seealso': [ - 'multiply', - 'dot' - ] -}; - -var det = { - 'name': 'det', - 'category': 'Matrix', - 'syntax': [ - 'det(x)' - ], - 'description': 'Calculate the determinant of a matrix', - 'examples': [ - 'det([1, 2; 3, 4])', - 'det([-2, 2, 3; -1, 1, 3; 2, 0, -1])' - ], - 'seealso': [ - 'concat', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var diag = { - 'name': 'diag', - 'category': 'Matrix', - 'syntax': [ - 'diag(x)', - 'diag(x, k)' - ], - 'description': 'Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned. When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.', - 'examples': [ - 'diag(1:3)', - 'diag(1:3, 1)', - 'a = [1, 2, 3; 4, 5, 6; 7, 8, 9]', - 'diag(a)' - ], - 'seealso': [ - 'concat', 'det', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var dot = { - 'name': 'dot', - 'category': 'Matrix', - 'syntax': [ - 'dot(A, B)', - 'A * B' - ], - 'description': 'Calculate the dot product of two vectors. ' + - 'The dot product of A = [a1, a2, a3, ..., an] and B = [b1, b2, b3, ..., bn] ' + - 'is defined as dot(A, B) = a1 * b1 + a2 * b2 + a3 * b3 + ... + an * bn', - 'examples': [ - 'dot([2, 4, 1], [2, 2, 3])', - '[2, 4, 1] * [2, 2, 3]' - ], - 'seealso': [ - 'multiply', - 'cross' - ] -}; - -var eye = { - 'name': 'eye', - 'category': 'Matrix', - 'syntax': [ - 'eye(n)', - 'eye(m, n)', - 'eye([m, n])' - ], - 'description': 'Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.', - 'examples': [ - 'eye(3)', - 'eye(3, 5)', - 'a = [1, 2, 3; 4, 5, 6]', - 'eye(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var filter = { - 'name': 'filter', - 'category': 'Matrix', - 'syntax': [ - 'filter(x, test)' - ], - 'description': 'Filter items in a matrix.', - 'examples': [ - 'isPositive(x) = x > 0', - 'filter([6, -2, -1, 4, 3], isPositive)', - 'filter([6, -2, 0, 1, 0], x != 0)' - ], - 'seealso': ['sort', 'map', 'forEach'] -}; - -var flatten$1 = { - 'name': 'flatten', - 'category': 'Matrix', - 'syntax': [ - 'flatten(x)' - ], - 'description': 'Flatten a multi dimensional matrix into a single dimensional matrix.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'size(a)', - 'b = flatten(a)', - 'size(b)' - ], - 'seealso': [ - 'concat', 'resize', 'size', 'squeeze' - ] -}; - -var forEach = { - 'name': 'forEach', - 'category': 'Matrix', - 'syntax': [ - 'forEach(x, callback)' - ], - 'description': 'Iterates over all elements of a matrix/array, and executes the given callback function.', - 'examples': [ - 'forEach([1, 2, 3], function(val) { console.log(val) })' - ], - 'seealso': ['map', 'sort', 'filter'] -}; - -var inv = { - 'name': 'inv', - 'category': 'Matrix', - 'syntax': [ - 'inv(x)' - ], - 'description': 'Calculate the inverse of a matrix', - 'examples': [ - 'inv([1, 2; 3, 4])', - 'inv(4)', - '1 / 4' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var kron = { - 'name': 'kron', - 'category': 'Matrix', - 'syntax': [ - 'kron(x, y)' - ], - 'description': 'Calculates the kronecker product of 2 matrices or vectors.', - 'examples': [ - 'kron([[1, 0], [0, 1]], [[1, 2], [3, 4]])', - 'kron([1,1], [2,3,4])' - ], - 'seealso': [ - 'multiply', 'dot', 'cross' - ] -}; - -var map = { - 'name': 'map', - 'category': 'Matrix', - 'syntax': [ - 'map(x, callback)' - ], - 'description': 'Create a new matrix or array with the results of the callback function executed on each entry of the matrix/array.', - 'examples': [ - 'map([1, 2, 3], square)' - ], - 'seealso': ['filter', 'forEach'] -}; - -var ones = { - 'name': 'ones', - 'category': 'Matrix', - 'syntax': [ - 'ones(m)', - 'ones(m, n)', - 'ones(m, n, p, ...)', - 'ones([m])', - 'ones([m, n])', - 'ones([m, n, p, ...])' - ], - 'description': 'Create a matrix containing ones.', - 'examples': [ - 'ones(3)', - 'ones(3, 5)', - 'ones([2,3]) * 4.5', - 'a = [1, 2, 3; 4, 5, 6]', - 'ones(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var partitionSelect = { - 'name': 'partitionSelect', - 'category': 'Matrix', - 'syntax': [ - 'partitionSelect(x, k)', - 'partitionSelect(x, k, compare)' - ], - 'description': 'Partition-based selection of an array or 1D matrix. Will find the kth smallest value, and mutates the input array. Uses Quickselect.', - 'examples': [ - 'partitionSelect([5, 10, 1], 2)', - 'partitionSelect(["C", "B", "A", "D"], 1)' - ], - 'seealso': ['sort'] -}; - -var range = { - 'name': 'range', - 'category': 'Type', - 'syntax': [ - 'start:end', - 'start:step:end', - 'range(start, end)', - 'range(start, end, step)', - 'range(string)' - ], - 'description': - 'Create a range. Lower bound of the range is included, upper bound is excluded.', - 'examples': [ - '1:5', - '3:-1:-3', - 'range(3, 7)', - 'range(0, 12, 2)', - 'range("4:10")', - 'a = [1, 2, 3, 4; 5, 6, 7, 8]', - 'a[1:2, 1:2]' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var resize = { - 'name': 'resize', - 'category': 'Matrix', - 'syntax': [ - 'resize(x, size)', - 'resize(x, size, defaultValue)' - ], - 'description': 'Resize a matrix.', - 'examples': [ - 'resize([1,2,3,4,5], [3])', - 'resize([1,2,3], [5])', - 'resize([1,2,3], [5], -1)', - 'resize(2, [2, 3])', - 'resize("hello", [8], "!")' - ], - 'seealso': [ - 'size', 'subset', 'squeeze', 'reshape' - ] -}; - -var reshape = { - 'name': 'reshape', - 'category': 'Matrix', - 'syntax': [ - 'reshape(x, sizes)' - ], - 'description': 'Reshape a multi dimensional array to fit the specified dimensions.', - 'examples': [ - 'reshape([1, 2, 3, 4, 5, 6], [2, 3])', - 'reshape([[1, 2], [3, 4]], [1, 4])', - 'reshape([[1, 2], [3, 4]], [4])' - ], - 'seealso': [ - 'size', 'squeeze', 'resize' - ] -}; - -var size = { - 'name': 'size', - 'category': 'Matrix', - 'syntax': [ - 'size(x)' - ], - 'description': 'Calculate the size of a matrix.', - 'examples': [ - 'size(2.3)', - 'size("hello world")', - 'a = [1, 2; 3, 4; 5, 6]', - 'size(a)', - 'size(1:6)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var sort = { - 'name': 'sort', - 'category': 'Matrix', - 'syntax': [ - 'sort(x)', - 'sort(x, compare)' - ], - 'description': 'Sort the items in a matrix. Compare can be a string "asc", "desc", "natural", or a custom sort function.', - 'examples': [ - 'sort([5, 10, 1])', - 'sort(["C", "B", "A", "D"])', - 'sortByLength(a, b) = size(a)[1] - size(b)[1]', - 'sort(["Langdon", "Tom", "Sara"], sortByLength)', - 'sort(["10", "1", "2"], "natural")' - ], - 'seealso': ['map', 'filter', 'forEach'] -}; - -var squeeze = { - 'name': 'squeeze', - 'category': 'Matrix', - 'syntax': [ - 'squeeze(x)' - ], - 'description': 'Remove inner and outer singleton dimensions from a matrix.', - 'examples': [ - 'a = zeros(3,2,1)', - 'size(squeeze(a))', - 'b = zeros(1,1,3)', - 'size(squeeze(b))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'subset', 'trace', 'transpose', 'zeros' - ] -}; - -var subset = { - 'name': 'subset', - 'category': 'Matrix', - 'syntax': [ - 'value(index)', - 'value(index) = replacement', - 'subset(value, [index])', - 'subset(value, [index], replacement)' - ], - 'description': 'Get or set a subset of a matrix or string. ' + - 'Indexes are one-based. ' + - 'Both the ranges lower-bound and upper-bound are included.', - 'examples': [ - 'd = [1, 2; 3, 4]', - 'e = []', - 'e[1, 1:2] = [5, 6]', - 'e[2, :] = [7, 8]', - 'f = d * e', - 'f[2, 1]', - 'f[:, 1]' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'trace', 'transpose', 'zeros' - ] -}; - -var trace = { - 'name': 'trace', - 'category': 'Matrix', - 'syntax': [ - 'trace(A)' - ], - 'description': 'Calculate the trace of a matrix: the sum of the elements on the main diagonal of a square matrix.', - 'examples': [ - 'A = [1, 2, 3; -1, 2, 3; 2, 0, 3]', - 'trace(A)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] -}; - -var transpose = { - 'name': 'transpose', - 'category': 'Matrix', - 'syntax': [ - 'x\'', - 'transpose(x)' - ], - 'description': 'Transpose a matrix', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'a\'', - 'transpose(a)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'zeros' - ] -}; - -var zeros = { - 'name': 'zeros', - 'category': 'Matrix', - 'syntax': [ - 'zeros(m)', - 'zeros(m, n)', - 'zeros(m, n, p, ...)', - 'zeros([m])', - 'zeros([m, n])', - 'zeros([m, n, p, ...])' - ], - 'description': 'Create a matrix containing zeros.', - 'examples': [ - 'zeros(3)', - 'zeros(3, 5)', - 'a = [1, 2, 3; 4, 5, 6]', - 'zeros(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose' - ] -}; - -var combinations = { - 'name': 'combinations', - 'category': 'Probability', - 'syntax': [ - 'combinations(n, k)' - ], - 'description': 'Compute the number of combinations of n items taken k at a time', - 'examples': [ - 'combinations(7, 5)' - ], - 'seealso': ['permutations', 'factorial'] -}; - -var factorial = { - 'name': 'factorial', - 'category': 'Probability', - 'syntax': [ - 'n!', - 'factorial(n)' - ], - 'description': 'Compute the factorial of a value', - 'examples': [ - '5!', - '5 * 4 * 3 * 2 * 1', - '3!' - ], - 'seealso': ['combinations', 'permutations', 'gamma'] -}; - -var gamma = { - 'name': 'gamma', - 'category': 'Probability', - 'syntax': [ - 'gamma(n)' - ], - 'description': 'Compute the gamma function. For small values, the Lanczos approximation is used, and for large values the extended Stirling approximation.', - 'examples': [ - 'gamma(4)', - '3!', - 'gamma(1/2)', - 'sqrt(pi)' - ], - 'seealso': ['factorial'] -}; - -var kldivergence = { - 'name': 'kldivergence', - 'category': 'Probability', - 'syntax': [ - 'kldivergence(x, y)' - ], - 'description': 'Calculate the Kullback-Leibler (KL) divergence between two distributions.', - 'examples': [ - 'kldivergence([0.7,0.5,0.4], [0.2,0.9,0.5])' - ], - 'seealso': [] -}; - -var multinomial = { - 'name': 'multinomial', - 'category': 'Probability', - 'syntax': [ - 'multinomial(A)' - ], - 'description': 'Multinomial Coefficients compute the number of ways of picking a1, a2, ..., ai unordered outcomes from `n` possibilities. multinomial takes one array of integers as an argument. The following condition must be enforced: every ai > 0.', - 'examples': [ - 'multinomial([1, 2, 1])' - ], - 'seealso': ['combinations', 'factorial'] -}; - -var permutations = { - 'name': 'permutations', - 'category': 'Probability', - 'syntax': [ - 'permutations(n)', - 'permutations(n, k)' - ], - 'description': 'Compute the number of permutations of n items taken k at a time', - 'examples': [ - 'permutations(5)', - 'permutations(5, 3)' - ], - 'seealso': ['combinations', 'factorial'] -}; - -var pickRandom = { - 'name': 'pickRandom', - 'category': 'Probability', - 'syntax': [ - 'pickRandom(array)', - 'pickRandom(array, number)', - 'pickRandom(array, weights)', - 'pickRandom(array, number, weights)', - 'pickRandom(array, weights, number)' - ], - 'description': - 'Pick a random entry from a given array.', - 'examples': [ - 'pickRandom(0:10)', - 'pickRandom([1, 3, 1, 6])', - 'pickRandom([1, 3, 1, 6], 2)', - 'pickRandom([1, 3, 1, 6], [2, 3, 2, 1])', - 'pickRandom([1, 3, 1, 6], 2, [2, 3, 2, 1])', - 'pickRandom([1, 3, 1, 6], [2, 3, 2, 1], 2)' - ], - 'seealso': ['random', 'randomInt'] -}; - -var random = { - 'name': 'random', - 'category': 'Probability', - 'syntax': [ - 'random()', - 'random(max)', - 'random(min, max)', - 'random(size)', - 'random(size, max)', - 'random(size, min, max)' - ], - 'description': - 'Return a random number.', - 'examples': [ - 'random()', - 'random(10, 20)', - 'random([2, 3])' - ], - 'seealso': ['pickRandom', 'randomInt'] -}; - -var randomInt = { - 'name': 'randomInt', - 'category': 'Probability', - 'syntax': [ - 'randomInt(max)', - 'randomInt(min, max)', - 'randomInt(size)', - 'randomInt(size, max)', - 'randomInt(size, min, max)' - ], - 'description': - 'Return a random integer number', - 'examples': [ - 'randomInt(10, 20)', - 'randomInt([2, 3], 10)' - ], - 'seealso': ['pickRandom', 'random'] -}; - -var compare = { - 'name': 'compare', - 'category': 'Relational', - 'syntax': [ - 'compare(x, y)' - ], - 'description': - 'Compare two values. ' + - 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', - 'examples': [ - 'compare(2, 3)', - 'compare(3, 2)', - 'compare(2, 2)', - 'compare(5cm, 40mm)', - 'compare(2, [1, 2, 3])' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compareNatural', 'compareText' - ] -}; - -var compareNatural = { - 'name': 'compareNatural', - 'category': 'Relational', - 'syntax': [ - 'compareNatural(x, y)' - ], - 'description': - 'Compare two values of any type in a deterministic, natural way. ' + - 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', - 'examples': [ - 'compareNatural(2, 3)', - 'compareNatural(3, 2)', - 'compareNatural(2, 2)', - 'compareNatural(5cm, 40mm)', - 'compareNatural("2", "10")', - 'compareNatural(2 + 3i, 2 + 4i)', - 'compareNatural([1, 2, 4], [1, 2, 3])', - 'compareNatural([1, 5], [1, 2, 3])', - 'compareNatural([1, 2], [1, 2])', - 'compareNatural({a: 2}, {a: 4})' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compare', 'compareText' - ] -}; - -var compareText = { - 'name': 'compareText', - 'category': 'Relational', - 'syntax': [ - 'compareText(x, y)' - ], - 'description': - 'Compare two strings lexically. Comparison is case sensitive. ' + - 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', - 'examples': [ - 'compareText("B", "A")', - 'compareText("A", "B")', - 'compareText("A", "A")', - 'compareText("2", "10")', - 'compare("2", "10")', - 'compare(2, 10)', - 'compareNatural("2", "10")', - 'compareText("B", ["A", "B", "C"])' - ], - 'seealso': [ - 'compare', 'compareNatural' - ] -}; - -var deepEqual = { - 'name': 'deepEqual', - 'category': 'Relational', - 'syntax': [ - 'deepEqual(x, y)' - ], - 'description': - 'Check equality of two matrices element wise. Returns true if the size of both matrices is equal and when and each of the elements are equal.', - 'examples': [ - 'deepEqual([1,3,4], [1,3,4])', - 'deepEqual([1,3,4], [1,3])' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare' - ] -}; - -var equal = { - 'name': 'equal', - 'category': 'Relational', - 'syntax': [ - 'x == y', - 'equal(x, y)' - ], - 'description': - 'Check equality of two values. Returns true if the values are equal, and false if not.', - 'examples': [ - '2+2 == 3', - '2+2 == 4', - 'a = 3.2', - 'b = 6-2.8', - 'a == b', - '50cm == 0.5m' - ], - 'seealso': [ - 'unequal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare', 'deepEqual', 'equalText' - ] -}; - -var equalText = { - 'name': 'equalText', - 'category': 'Relational', - 'syntax': [ - 'equalText(x, y)' - ], - 'description': - 'Check equality of two strings. Comparison is case sensitive. Returns true if the values are equal, and false if not.', - 'examples': [ - 'equalText("Hello", "Hello")', - 'equalText("a", "A")', - 'equal("2e3", "2000")', - 'equalText("2e3", "2000")', - 'equalText("B", ["A", "B", "C"])' - ], - 'seealso': [ - 'compare', 'compareNatural', 'compareText', 'equal' - ] -}; - -var larger$1 = { - 'name': 'larger', - 'category': 'Relational', - 'syntax': [ - 'x > y', - 'larger(x, y)' - ], - 'description': - 'Check if value x is larger than y. Returns true if x is larger than y, and false if not.', - 'examples': [ - '2 > 3', - '5 > 2*2', - 'a = 3.3', - 'b = 6-2.8', - '(a > b)', - '(b < a)', - '5 cm > 2 inch' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compare' - ] -}; - -var largerEq = { - 'name': 'largerEq', - 'category': 'Relational', - 'syntax': [ - 'x >= y', - 'largerEq(x, y)' - ], - 'description': - 'Check if value x is larger or equal to y. Returns true if x is larger or equal to y, and false if not.', - 'examples': [ - '2 >= 1+1', - '2 > 1+1', - 'a = 3.2', - 'b = 6-2.8', - '(a >= b)' - ], - 'seealso': [ - 'equal', 'unequal', 'smallerEq', 'smaller', 'compare' - ] -}; - -var smaller$1 = { - 'name': 'smaller', - 'category': 'Relational', - 'syntax': [ - 'x < y', - 'smaller(x, y)' - ], - 'description': - 'Check if value x is smaller than value y. Returns true if x is smaller than y, and false if not.', - 'examples': [ - '2 < 3', - '5 < 2*2', - 'a = 3.3', - 'b = 6-2.8', - '(a < b)', - '5 cm < 2 inch' - ], - 'seealso': [ - 'equal', 'unequal', 'larger', 'smallerEq', 'largerEq', 'compare' - ] -}; - -var smallerEq = { - 'name': 'smallerEq', - 'category': 'Relational', - 'syntax': [ - 'x <= y', - 'smallerEq(x, y)' - ], - 'description': - 'Check if value x is smaller or equal to value y. Returns true if x is smaller than y, and false if not.', - 'examples': [ - '2 <= 1+1', - '2 < 1+1', - 'a = 3.2', - 'b = 6-2.8', - '(a <= b)' - ], - 'seealso': [ - 'equal', 'unequal', 'larger', 'smaller', 'largerEq', 'compare' - ] -}; - -var unequal = { - 'name': 'unequal', - 'category': 'Relational', - 'syntax': [ - 'x != y', - 'unequal(x, y)' - ], - 'description': - 'Check unequality of two values. Returns true if the values are unequal, and false if they are equal.', - 'examples': [ - '2+2 != 3', - '2+2 != 4', - 'a = 3.2', - 'b = 6-2.8', - 'a != b', - '50cm != 0.5m', - '5 cm != 2 inch' - ], - 'seealso': [ - 'equal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare', 'deepEqual' - ] -}; - -var setCartesian = { - 'name': 'setCartesian', - 'category': 'Set', - 'syntax': [ - 'setCartesian(set1, set2)' - ], - 'description': - 'Create the cartesian product of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setCartesian([1, 2], [3, 4])' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setDifference', 'setPowerset' - ] -}; - -var setDifference = { - 'name': 'setDifference', - 'category': 'Set', - 'syntax': [ - 'setDifference(set1, set2)' - ], - 'description': - 'Create the difference of two (multi)sets: every element of set1, that is not the element of set2. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setDifference([1, 2, 3, 4], [3, 4, 5, 6])', - 'setDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]])' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setSymDifference' - ] -}; - -var setDistinct = { - 'name': 'setDistinct', - 'category': 'Set', - 'syntax': [ - 'setDistinct(set)' - ], - 'description': - 'Collect the distinct elements of a multiset. A multi-dimension array will be converted to a single-dimension array before the operation.', - 'examples': [ - 'setDistinct([1, 1, 1, 2, 2, 3])' - ], - 'seealso': [ - 'setMultiplicity' - ] -}; - -var setIntersect = { - 'name': 'setIntersect', - 'category': 'Set', - 'syntax': [ - 'setIntersect(set1, set2)' - ], - 'description': - 'Create the intersection of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setIntersect([1, 2, 3, 4], [3, 4, 5, 6])', - 'setIntersect([[1, 2], [3, 4]], [[3, 4], [5, 6]])' - ], - 'seealso': [ - 'setUnion', 'setDifference' - ] -}; - -var setIsSubset = { - 'name': 'setIsSubset', - 'category': 'Set', - 'syntax': [ - 'setIsSubset(set1, set2)' - ], - 'description': - 'Check whether a (multi)set is a subset of another (multi)set: every element of set1 is the element of set2. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setIsSubset([1, 2], [3, 4, 5, 6])', - 'setIsSubset([3, 4], [3, 4, 5, 6])' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setDifference' - ] -}; - -var setMultiplicity = { - 'name': 'setMultiplicity', - 'category': 'Set', - 'syntax': [ - 'setMultiplicity(element, set)' - ], - 'description': - 'Count the multiplicity of an element in a multiset. A multi-dimension array will be converted to a single-dimension array before the operation.', - 'examples': [ - 'setMultiplicity(1, [1, 2, 2, 4])', - 'setMultiplicity(2, [1, 2, 2, 4])' - ], - 'seealso': [ - 'setDistinct', 'setSize' - ] -}; - -var setPowerset = { - 'name': 'setPowerset', - 'category': 'Set', - 'syntax': [ - 'setPowerset(set)' - ], - 'description': - 'Create the powerset of a (multi)set: the powerset contains very possible subsets of a (multi)set. A multi-dimension array will be converted to a single-dimension array before the operation.', - 'examples': [ - 'setPowerset([1, 2, 3])' - ], - 'seealso': [ - 'setCartesian' - ] -}; - -var setSize = { - 'name': 'setSize', - 'category': 'Set', - 'syntax': [ - 'setSize(set)', - 'setSize(set, unique)' - ], - 'description': - 'Count the number of elements of a (multi)set. When the second parameter "unique" is true, count only the unique values. A multi-dimension array will be converted to a single-dimension array before the operation.', - 'examples': [ - 'setSize([1, 2, 2, 4])', - 'setSize([1, 2, 2, 4], true)' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setDifference' - ] -}; - -var setSymDifference = { - 'name': 'setSymDifference', - 'category': 'Set', - 'syntax': [ - 'setSymDifference(set1, set2)' - ], - 'description': - 'Create the symmetric difference of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setSymDifference([1, 2, 3, 4], [3, 4, 5, 6])', - 'setSymDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]])' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setDifference' - ] -}; - -var setUnion = { - 'name': 'setUnion', - 'category': 'Set', - 'syntax': [ - 'setUnion(set1, set2)' - ], - 'description': - 'Create the union of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setUnion([1, 2, 3, 4], [3, 4, 5, 6])', - 'setUnion([[1, 2], [3, 4]], [[3, 4], [5, 6]])' - ], - 'seealso': [ - 'setIntersect', 'setDifference' - ] -}; - -var erf = { - 'name': 'erf', - 'category': 'Special', - 'syntax': [ - 'erf(x)' - ], - 'description': 'Compute the erf function of a value using a rational Chebyshev approximations for different intervals of x', - 'examples': [ - 'erf(0.2)', - 'erf(-0.5)', - 'erf(4)' - ], - 'seealso': [] -}; - -var mad = { - 'name': 'mad', - 'category': 'Statistics', - 'syntax': [ - 'mad(a, b, c, ...)', - 'mad(A)' - ], - 'description': 'Compute the median absolute deviation of a matrix or a list with values. The median absolute deviation is defined as the median of the absolute deviations from the median.', - 'examples': [ - 'mad(10, 20, 30)', - 'mad([1, 2, 3])' - ], - 'seealso': [ - 'mean', - 'median', - 'std', - 'abs' - ] -}; - -var max = { - 'name': 'max', - 'category': 'Statistics', - 'syntax': [ - 'max(a, b, c, ...)', - 'max(A)', - 'max(A, dim)' - ], - 'description': 'Compute the maximum value of a list of values.', - 'examples': [ - 'max(2, 3, 4, 1)', - 'max([2, 3, 4, 1])', - 'max([2, 5; 4, 3])', - 'max([2, 5; 4, 3], 1)', - 'max([2, 5; 4, 3], 2)', - 'max(2.7, 7.1, -4.5, 2.0, 4.1)', - 'min(2.7, 7.1, -4.5, 2.0, 4.1)' - ], - 'seealso': [ - 'mean', - 'median', - 'min', - 'prod', - 'std', - 'sum', - 'var' - ] -}; - -var mean = { - 'name': 'mean', - 'category': 'Statistics', - 'syntax': [ - 'mean(a, b, c, ...)', - 'mean(A)', - 'mean(A, dim)' - ], - 'description': 'Compute the arithmetic mean of a list of values.', - 'examples': [ - 'mean(2, 3, 4, 1)', - 'mean([2, 3, 4, 1])', - 'mean([2, 5; 4, 3])', - 'mean([2, 5; 4, 3], 1)', - 'mean([2, 5; 4, 3], 2)', - 'mean([1.0, 2.7, 3.2, 4.0])' - ], - 'seealso': [ - 'max', - 'median', - 'min', - 'prod', - 'std', - 'sum', - 'var' - ] -}; - -var median = { - 'name': 'median', - 'category': 'Statistics', - 'syntax': [ - 'median(a, b, c, ...)', - 'median(A)' - ], - 'description': 'Compute the median of all values. The values are sorted and the middle value is returned. In case of an even number of values, the average of the two middle values is returned.', - 'examples': [ - 'median(5, 2, 7)', - 'median([3, -1, 5, 7])' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'prod', - 'std', - 'sum', - 'var', - 'quantileSeq' - ] -}; - -var min = { - 'name': 'min', - 'category': 'Statistics', - 'syntax': [ - 'min(a, b, c, ...)', - 'min(A)', - 'min(A, dim)' - ], - 'description': 'Compute the minimum value of a list of values.', - 'examples': [ - 'min(2, 3, 4, 1)', - 'min([2, 3, 4, 1])', - 'min([2, 5; 4, 3])', - 'min([2, 5; 4, 3], 1)', - 'min([2, 5; 4, 3], 2)', - 'min(2.7, 7.1, -4.5, 2.0, 4.1)', - 'max(2.7, 7.1, -4.5, 2.0, 4.1)' - ], - 'seealso': [ - 'max', - 'mean', - 'median', - 'prod', - 'std', - 'sum', - 'var' - ] -}; - -var mode = { - 'name': 'mode', - 'category': 'Statistics', - 'syntax': [ - 'mode(a, b, c, ...)', - 'mode(A)', - 'mode(A, a, b, B, c, ...)' - ], - 'description': 'Computes the mode of all values as an array. In case mode being more than one, multiple values are returned in an array.', - 'examples': [ - 'mode(2, 1, 4, 3, 1)', - 'mode([1, 2.7, 3.2, 4, 2.7])', - 'mode(1, 4, 6, 1, 6)' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'median', - 'prod', - 'std', - 'sum', - 'var' - ] -}; - -var prod = { - 'name': 'prod', - 'category': 'Statistics', - 'syntax': [ - 'prod(a, b, c, ...)', - 'prod(A)' - ], - 'description': 'Compute the product of all values.', - 'examples': [ - 'prod(2, 3, 4)', - 'prod([2, 3, 4])', - 'prod([2, 5; 4, 3])' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'median', - 'min', - 'std', - 'sum', - 'var' - ] -}; - -var quantileSeq = { - 'name': 'quantileSeq', - 'category': 'Statistics', - 'syntax': [ - 'quantileSeq(A, prob[, sorted])', - 'quantileSeq(A, [prob1, prob2, ...][, sorted])', - 'quantileSeq(A, N[, sorted])' - ], - 'description': 'Compute the prob order quantile of a matrix or a list with values. The sequence is sorted and the middle value is returned. Supported types of sequence values are: Number, BigNumber, Unit Supported types of probablity are: Number, BigNumber. \n\nIn case of a (multi dimensional) array or matrix, the prob order quantile of all elements will be calculated.', - 'examples': [ - 'quantileSeq([3, -1, 5, 7], 0.5)', - 'quantileSeq([3, -1, 5, 7], [1/3, 2/3])', - 'quantileSeq([3, -1, 5, 7], 2)', - 'quantileSeq([-1, 3, 5, 7], 0.5, true)' - ], - 'seealso': [ - 'mean', - 'median', - 'min', - 'max', - 'prod', - 'std', - 'sum', - 'var' - ] -}; - -var std = { - 'name': 'std', - 'category': 'Statistics', - 'syntax': [ - 'std(a, b, c, ...)', - 'std(A)', - 'std(A, normalization)' - ], - 'description': 'Compute the standard deviation of all values, defined as std(A) = sqrt(var(A)). Optional parameter normalization can be "unbiased" (default), "uncorrected", or "biased".', - 'examples': [ - 'std(2, 4, 6)', - 'std([2, 4, 6, 8])', - 'std([2, 4, 6, 8], "uncorrected")', - 'std([2, 4, 6, 8], "biased")', - 'std([1, 2, 3; 4, 5, 6])' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'median', - 'min', - 'prod', - 'sum', - 'var' - ] -}; - -var sum = { - 'name': 'sum', - 'category': 'Statistics', - 'syntax': [ - 'sum(a, b, c, ...)', - 'sum(A)' - ], - 'description': 'Compute the sum of all values.', - 'examples': [ - 'sum(2, 3, 4, 1)', - 'sum([2, 3, 4, 1])', - 'sum([2, 5; 4, 3])' - ], - 'seealso': [ - 'max', - 'mean', - 'median', - 'min', - 'prod', - 'std', - 'sum', - 'var' - ] -}; - -var _var = { - 'name': 'var', - 'category': 'Statistics', - 'syntax': [ - 'var(a, b, c, ...)', - 'var(A)', - 'var(A, normalization)' - ], - 'description': 'Compute the variance of all values. Optional parameter normalization can be "unbiased" (default), "uncorrected", or "biased".', - 'examples': [ - 'var(2, 4, 6)', - 'var([2, 4, 6, 8])', - 'var([2, 4, 6, 8], "uncorrected")', - 'var([2, 4, 6, 8], "biased")', - 'var([1, 2, 3; 4, 5, 6])' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'median', - 'min', - 'prod', - 'std', - 'sum' - ] -}; - -var acos = { - 'name': 'acos', - 'category': 'Trigonometry', - 'syntax': [ - 'acos(x)' - ], - 'description': 'Compute the inverse cosine of a value in radians.', - 'examples': [ - 'acos(0.5)', - 'acos(cos(2.3))' - ], - 'seealso': [ - 'cos', - 'atan', - 'asin' - ] -}; - -var acosh = { - 'name': 'acosh', - 'category': 'Trigonometry', - 'syntax': [ - 'acosh(x)' - ], - 'description': 'Calculate the hyperbolic arccos of a value, defined as `acosh(x) = ln(sqrt(x^2 - 1) + x)`.', - 'examples': [ - 'acosh(1.5)' - ], - 'seealso': [ - 'cosh', - 'asinh', - 'atanh' - ] -}; - -var acot = { - 'name': 'acot', - 'category': 'Trigonometry', - 'syntax': [ - 'acot(x)' - ], - 'description': 'Calculate the inverse cotangent of a value.', - 'examples': [ - 'acot(0.5)', - 'acot(cot(0.5))', - 'acot(2)' - ], - 'seealso': [ - 'cot', - 'atan' - ] -}; - -var acoth = { - 'name': 'acoth', - 'category': 'Trigonometry', - 'syntax': [ - 'acoth(x)' - ], - 'description': 'Calculate the hyperbolic arccotangent of a value, defined as `acoth(x) = (ln((x+1)/x) + ln(x/(x-1))) / 2`.', - 'examples': [ - 'acoth(2)', - 'acoth(0.5)' - ], - 'seealso': [ - 'acsch', - 'asech' - ] -}; - -var acsc = { - 'name': 'acsc', - 'category': 'Trigonometry', - 'syntax': [ - 'acsc(x)' - ], - 'description': 'Calculate the inverse cotangent of a value.', - 'examples': [ - 'acsc(2)', - 'acsc(csc(0.5))', - 'acsc(0.5)' - ], - 'seealso': [ - 'csc', - 'asin', - 'asec' - ] -}; - -var acsch = { - 'name': 'acsch', - 'category': 'Trigonometry', - 'syntax': [ - 'acsch(x)' - ], - 'description': 'Calculate the hyperbolic arccosecant of a value, defined as `acsch(x) = ln(1/x + sqrt(1/x^2 + 1))`.', - 'examples': [ - 'acsch(0.5)' - ], - 'seealso': [ - 'asech', - 'acoth' - ] -}; - -var asec = { - 'name': 'asec', - 'category': 'Trigonometry', - 'syntax': [ - 'asec(x)' - ], - 'description': 'Calculate the inverse secant of a value.', - 'examples': [ - 'asec(0.5)', - 'asec(sec(0.5))', - 'asec(2)' - ], - 'seealso': [ - 'acos', - 'acot', - 'acsc' - ] -}; - -var asech = { - 'name': 'asech', - 'category': 'Trigonometry', - 'syntax': [ - 'asech(x)' - ], - 'description': 'Calculate the inverse secant of a value.', - 'examples': [ - 'asech(0.5)' - ], - 'seealso': [ - 'acsch', - 'acoth' - ] -}; - -var asin = { - 'name': 'asin', - 'category': 'Trigonometry', - 'syntax': [ - 'asin(x)' - ], - 'description': 'Compute the inverse sine of a value in radians.', - 'examples': [ - 'asin(0.5)', - 'asin(sin(0.5))' - ], - 'seealso': [ - 'sin', - 'acos', - 'atan' - ] -}; - -var asinh = { - 'name': 'asinh', - 'category': 'Trigonometry', - 'syntax': [ - 'asinh(x)' - ], - 'description': 'Calculate the hyperbolic arcsine of a value, defined as `asinh(x) = ln(x + sqrt(x^2 + 1))`.', - 'examples': [ - 'asinh(0.5)' - ], - 'seealso': [ - 'acosh', - 'atanh' - ] -}; - -var atan = { - 'name': 'atan', - 'category': 'Trigonometry', - 'syntax': [ - 'atan(x)' - ], - 'description': 'Compute the inverse tangent of a value in radians.', - 'examples': [ - 'atan(0.5)', - 'atan(tan(0.5))' - ], - 'seealso': [ - 'tan', - 'acos', - 'asin' - ] -}; - -var atanh = { - 'name': 'atanh', - 'category': 'Trigonometry', - 'syntax': [ - 'atanh(x)' - ], - 'description': 'Calculate the hyperbolic arctangent of a value, defined as `atanh(x) = ln((1 + x)/(1 - x)) / 2`.', - 'examples': [ - 'atanh(0.5)' - ], - 'seealso': [ - 'acosh', - 'asinh' - ] -}; - -var atan2 = { - 'name': 'atan2', - 'category': 'Trigonometry', - 'syntax': [ - 'atan2(y, x)' - ], - 'description': - 'Computes the principal value of the arc tangent of y/x in radians.', - 'examples': [ - 'atan2(2, 2) / pi', - 'angle = 60 deg in rad', - 'x = cos(angle)', - 'y = sin(angle)', - 'atan2(y, x)' - ], - 'seealso': [ - 'sin', - 'cos', - 'tan' - ] -}; - -var cos = { - 'name': 'cos', - 'category': 'Trigonometry', - 'syntax': [ - 'cos(x)' - ], - 'description': 'Compute the cosine of x in radians.', - 'examples': [ - 'cos(2)', - 'cos(pi / 4) ^ 2', - 'cos(180 deg)', - 'cos(60 deg)', - 'sin(0.2)^2 + cos(0.2)^2' - ], - 'seealso': [ - 'acos', - 'sin', - 'tan' - ] -}; - -var cosh = { - 'name': 'cosh', - 'category': 'Trigonometry', - 'syntax': [ - 'cosh(x)' - ], - 'description': 'Compute the hyperbolic cosine of x in radians.', - 'examples': [ - 'cosh(0.5)' - ], - 'seealso': [ - 'sinh', - 'tanh', - 'coth' - ] -}; - -var cot = { - 'name': 'cot', - 'category': 'Trigonometry', - 'syntax': [ - 'cot(x)' - ], - 'description': 'Compute the cotangent of x in radians. Defined as 1/tan(x)', - 'examples': [ - 'cot(2)', - '1 / tan(2)' - ], - 'seealso': [ - 'sec', - 'csc', - 'tan' - ] -}; - -var coth = { - 'name': 'coth', - 'category': 'Trigonometry', - 'syntax': [ - 'coth(x)' - ], - 'description': 'Compute the hyperbolic cotangent of x in radians.', - 'examples': [ - 'coth(2)', - '1 / tanh(2)' - ], - 'seealso': [ - 'sech', - 'csch', - 'tanh' - ] -}; - -var csc = { - 'name': 'csc', - 'category': 'Trigonometry', - 'syntax': [ - 'csc(x)' - ], - 'description': 'Compute the cosecant of x in radians. Defined as 1/sin(x)', - 'examples': [ - 'csc(2)', - '1 / sin(2)' - ], - 'seealso': [ - 'sec', - 'cot', - 'sin' - ] -}; - -var csch = { - 'name': 'csch', - 'category': 'Trigonometry', - 'syntax': [ - 'csch(x)' - ], - 'description': 'Compute the hyperbolic cosecant of x in radians. Defined as 1/sinh(x)', - 'examples': [ - 'csch(2)', - '1 / sinh(2)' - ], - 'seealso': [ - 'sech', - 'coth', - 'sinh' - ] -}; - -var sec = { - 'name': 'sec', - 'category': 'Trigonometry', - 'syntax': [ - 'sec(x)' - ], - 'description': 'Compute the secant of x in radians. Defined as 1/cos(x)', - 'examples': [ - 'sec(2)', - '1 / cos(2)' - ], - 'seealso': [ - 'cot', - 'csc', - 'cos' - ] -}; - -var sech = { - 'name': 'sech', - 'category': 'Trigonometry', - 'syntax': [ - 'sech(x)' - ], - 'description': 'Compute the hyperbolic secant of x in radians. Defined as 1/cosh(x)', - 'examples': [ - 'sech(2)', - '1 / cosh(2)' - ], - 'seealso': [ - 'coth', - 'csch', - 'cosh' - ] -}; - -var sin = { - 'name': 'sin', - 'category': 'Trigonometry', - 'syntax': [ - 'sin(x)' - ], - 'description': 'Compute the sine of x in radians.', - 'examples': [ - 'sin(2)', - 'sin(pi / 4) ^ 2', - 'sin(90 deg)', - 'sin(30 deg)', - 'sin(0.2)^2 + cos(0.2)^2' - ], - 'seealso': [ - 'asin', - 'cos', - 'tan' - ] -}; - -var sinh = { - 'name': 'sinh', - 'category': 'Trigonometry', - 'syntax': [ - 'sinh(x)' - ], - 'description': 'Compute the hyperbolic sine of x in radians.', - 'examples': [ - 'sinh(0.5)' - ], - 'seealso': [ - 'cosh', - 'tanh' - ] -}; - -var tan = { - 'name': 'tan', - 'category': 'Trigonometry', - 'syntax': [ - 'tan(x)' - ], - 'description': 'Compute the tangent of x in radians.', - 'examples': [ - 'tan(0.5)', - 'sin(0.5) / cos(0.5)', - 'tan(pi / 4)', - 'tan(45 deg)' - ], - 'seealso': [ - 'atan', - 'sin', - 'cos' - ] -}; - -var tanh = { - 'name': 'tanh', - 'category': 'Trigonometry', - 'syntax': [ - 'tanh(x)' - ], - 'description': 'Compute the hyperbolic tangent of x in radians.', - 'examples': [ - 'tanh(0.5)', - 'sinh(0.5) / cosh(0.5)' - ], - 'seealso': [ - 'sinh', - 'cosh' - ] -}; - -var to = { - 'name': 'to', - 'category': 'Units', - 'syntax': [ - 'x to unit', - 'to(x, unit)' - ], - 'description': 'Change the unit of a value.', - 'examples': [ - '5 inch to cm', - '3.2kg to g', - '16 bytes in bits' - ], - 'seealso': [] -}; - -var clone$2 = { - 'name': 'clone', - 'category': 'Utils', - 'syntax': [ - 'clone(x)' - ], - 'description': 'Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices', - 'examples': [ - 'clone(3.5)', - 'clone(2 - 4i)', - 'clone(45 deg)', - 'clone([1, 2; 3, 4])', - 'clone("hello world")' - ], - 'seealso': [] -}; - -var format$2 = { - 'name': 'format', - 'category': 'Utils', - 'syntax': [ - 'format(value)', - 'format(value, precision)' - ], - 'description': 'Format a value of any type as string.', - 'examples': [ - 'format(2.3)', - 'format(3 - 4i)', - 'format([])', - 'format(pi, 3)' - ], - 'seealso': ['print'] -}; - -var _isNaN = { - 'name': 'isNaN', - 'category': 'Utils', - 'syntax': [ - 'isNaN(x)' - ], - 'description': 'Test whether a value is NaN (not a number)', - 'examples': [ - 'isNaN(2)', - 'isNaN(0 / 0)', - 'isNaN(NaN)', - 'isNaN(Infinity)' - ], - 'seealso': ['isNegative', 'isNumeric', 'isPositive', 'isZero'] -}; - -var isInteger$3 = { - 'name': 'isInteger', - 'category': 'Utils', - 'syntax': [ - 'isInteger(x)' - ], - 'description': 'Test whether a value is an integer number.', - 'examples': [ - 'isInteger(2)', - 'isInteger(3.5)', - 'isInteger([3, 0.5, -2])' - ], - 'seealso': ['isNegative', 'isNumeric', 'isPositive', 'isZero'] -}; - -var isNegative = { - 'name': 'isNegative', - 'category': 'Utils', - 'syntax': [ - 'isNegative(x)' - ], - 'description': 'Test whether a value is negative: smaller than zero.', - 'examples': [ - 'isNegative(2)', - 'isNegative(0)', - 'isNegative(-4)', - 'isNegative([3, 0.5, -2])' - ], - 'seealso': ['isInteger', 'isNumeric', 'isPositive', 'isZero'] -}; - -var isNumeric = { - 'name': 'isNumeric', - 'category': 'Utils', - 'syntax': [ - 'isNumeric(x)' - ], - 'description': 'Test whether a value is a numeric value. ' + - 'Returns true when the input is a number, BigNumber, Fraction, or boolean.', - 'examples': [ - 'isNumeric(2)', - 'isNumeric(0)', - 'isNumeric(bignumber(500))', - 'isNumeric(fraction(0.125))', - 'isNumeric("3")', - 'isNumeric(2 + 3i)', - 'isNumeric([2.3, "foo", false])' - ], - 'seealso': ['isInteger', 'isZero', 'isNegative', 'isPositive', 'isNaN'] -}; - -var isPositive = { - 'name': 'isPositive', - 'category': 'Utils', - 'syntax': [ - 'isPositive(x)' - ], - 'description': 'Test whether a value is positive: larger than zero.', - 'examples': [ - 'isPositive(2)', - 'isPositive(0)', - 'isPositive(-4)', - 'isPositive([3, 0.5, -2])' - ], - 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isZero'] -}; - -var isPrime = { - 'name': 'isPrime', - 'category': 'Utils', - 'syntax': [ - 'isPrime(x)' - ], - 'description': 'Test whether a value is prime: has no divisors other than itself and one.', - 'examples': [ - 'isPrime(3)', - 'isPrime(-2)', - 'isPrime([2, 17, 100])' - ], - 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isZero'] -}; - -var isZero = { - 'name': 'isZero', - 'category': 'Utils', - 'syntax': [ - 'isZero(x)' - ], - 'description': 'Test whether a value is zero.', - 'examples': [ - 'isZero(2)', - 'isZero(0)', - 'isZero(-4)', - 'isZero([3, 0, -2, 0])' - ], - 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isPositive'] -}; - -var _typeof = { - 'name': 'typeof', - 'category': 'Utils', - 'syntax': [ - 'typeof(x)' - ], - 'description': 'Get the type of a variable.', - 'examples': [ - 'typeof(3.5)', - 'typeof(2 - 4i)', - 'typeof(45 deg)', - 'typeof("hello world")' - ], - 'seealso': [] -}; - -function factory$39 (construction$$1, config, load, typed) { - var docs = {}; - - - // construction functions - docs.bignumber = bignumber$2; - docs['boolean'] = boolean_1$2; - docs.complex = complex$4; - docs.createUnit = createUnit; - docs.fraction = fraction$4; - docs.index = construction; - docs.matrix = matrix$2; - docs.number = number$4; - docs.sparse = sparse$1; - docs.splitUnit = splitUnit; - docs.string = string$7; - docs.unit = unit; - - // constants - docs.e = e; - docs.E = e; - docs['false'] = _false; - docs.i = i; - docs['Infinity'] = _Infinity; - docs.LN2 = LN2; - docs.LN10 = LN10; - docs.LOG2E = LOG2E; - docs.LOG10E = LOG10E; - docs.NaN = _NaN; - docs['null'] = _null; - docs.pi = pi; - docs.PI = pi; - docs.phi = phi; - docs.SQRT1_2 = SQRT1_2; - docs.SQRT2 = SQRT2; - docs.tau = tau; - docs['true'] = _true; - docs.version = version; - - // physical constants - // TODO: more detailed docs for physical constants - docs.speedOfLight = {description: 'Speed of light in vacuum', examples: ['speedOfLight']}; - docs.gravitationConstant = {description: 'Newtonian constant of gravitation', examples: ['gravitationConstant']}; - docs.planckConstant = {description: 'Planck constant', examples: ['planckConstant']}; - docs.reducedPlanckConstant = {description: 'Reduced Planck constant', examples: ['reducedPlanckConstant']}; - - docs.magneticConstant = {description: 'Magnetic constant (vacuum permeability)', examples: ['magneticConstant']}; - docs.electricConstant = {description: 'Electric constant (vacuum permeability)', examples: ['electricConstant']}; - docs.vacuumImpedance = {description: 'Characteristic impedance of vacuum', examples: ['vacuumImpedance']}; - docs.coulomb = {description: 'Coulomb\'s constant', examples: ['coulomb']}; - docs.elementaryCharge = {description: 'Elementary charge', examples: ['elementaryCharge']}; - docs.bohrMagneton = {description: 'Borh magneton', examples: ['bohrMagneton']}; - docs.conductanceQuantum = {description: 'Conductance quantum', examples: ['conductanceQuantum']}; - docs.inverseConductanceQuantum = {description: 'Inverse conductance quantum', examples: ['inverseConductanceQuantum']}; - //docs.josephson = {description: 'Josephson constant', examples: ['josephson']}; - docs.magneticFluxQuantum = {description: 'Magnetic flux quantum', examples: ['magneticFluxQuantum']}; - docs.nuclearMagneton = {description: 'Nuclear magneton', examples: ['nuclearMagneton']}; - docs.klitzing = {description: 'Von Klitzing constant', examples: ['klitzing']}; - - docs.bohrRadius = {description: 'Borh radius', examples: ['bohrRadius']}; - docs.classicalElectronRadius = {description: 'Classical electron radius', examples: ['classicalElectronRadius']}; - docs.electronMass = {description: 'Electron mass', examples: ['electronMass']}; - docs.fermiCoupling = {description: 'Fermi coupling constant', examples: ['fermiCoupling']}; - docs.fineStructure = {description: 'Fine-structure constant', examples: ['fineStructure']}; - docs.hartreeEnergy = {description: 'Hartree energy', examples: ['hartreeEnergy']}; - docs.protonMass = {description: 'Proton mass', examples: ['protonMass']}; - docs.deuteronMass = {description: 'Deuteron Mass', examples: ['deuteronMass']}; - docs.neutronMass = {description: 'Neutron mass', examples: ['neutronMass']}; - docs.quantumOfCirculation = {description: 'Quantum of circulation', examples: ['quantumOfCirculation']}; - docs.rydberg = {description: 'Rydberg constant', examples: ['rydberg']}; - docs.thomsonCrossSection = {description: 'Thomson cross section', examples: ['thomsonCrossSection']}; - docs.weakMixingAngle = {description: 'Weak mixing angle', examples: ['weakMixingAngle']}; - docs.efimovFactor = {description: 'Efimov factor', examples: ['efimovFactor']}; - - docs.atomicMass = {description: 'Atomic mass constant', examples: ['atomicMass']}; - docs.avogadro = {description: 'Avogadro\'s number', examples: ['avogadro']}; - docs.boltzmann = {description: 'Boltzmann constant', examples: ['boltzmann']}; - docs.faraday = {description: 'Faraday constant', examples: ['faraday']}; - docs.firstRadiation = {description: 'First radiation constant', examples: ['firstRadiation']}; - docs.loschmidt = {description: 'Loschmidt constant at T=273.15 K and p=101.325 kPa', examples: ['loschmidt']}; - docs.gasConstant = {description: 'Gas constant', examples: ['gasConstant']}; - docs.molarPlanckConstant = {description: 'Molar Planck constant', examples: ['molarPlanckConstant']}; - docs.molarVolume = {description: 'Molar volume of an ideal gas at T=273.15 K and p=101.325 kPa', examples: ['molarVolume']}; - docs.sackurTetrode = {description: 'Sackur-Tetrode constant at T=1 K and p=101.325 kPa', examples: ['sackurTetrode']}; - docs.secondRadiation = {description: 'Second radiation constant', examples: ['secondRadiation']}; - docs.stefanBoltzmann = {description: 'Stefan-Boltzmann constant', examples: ['stefanBoltzmann']}; - docs.wienDisplacement = {description: 'Wien displacement law constant', examples: ['wienDisplacement']}; - //docs.spectralRadiance = {description: 'First radiation constant for spectral radiance', examples: ['spectralRadiance']}; - - docs.molarMass = {description: 'Molar mass constant', examples: ['molarMass']}; - docs.molarMassC12 = {description: 'Molar mass constant of carbon-12', examples: ['molarMassC12']}; - docs.gravity = {description: 'Standard acceleration of gravity (standard acceleration of free-fall on Earth)', examples: ['gravity']}; - - docs.planckLength = {description: 'Planck length', examples: ['planckLength']}; - docs.planckMass = {description: 'Planck mass', examples: ['planckMass']}; - docs.planckTime = {description: 'Planck time', examples: ['planckTime']}; - docs.planckCharge = {description: 'Planck charge', examples: ['planckCharge']}; - docs.planckTemperature = {description: 'Planck temperature', examples: ['planckTemperature']}; - - // functions - algebra - docs.derivative = derivative; - docs.lsolve = lsolve; - docs.lup = lup; - docs.lusolve = lusolve; - docs.simplify = simplify; - docs.rationalize = rationalize; - docs.slu = slu; - docs.usolve = usolve; - docs.qr = qr; - - // functions - arithmetic - docs.abs = abs; - docs.add = add$1; - docs.cbrt = cbrt; - docs.ceil = ceil; - docs.cube = cube; - docs.divide = divide; - docs.dotDivide = dotDivide; - docs.dotMultiply = dotMultiply; - docs.dotPow = dotPow; - docs.exp = exp; - docs.expm = expm; - docs.expm1 = expm1; - docs.fix = fix; - docs.floor = floor; - docs.gcd = gcd; - docs.hypot = hypot; - docs.lcm = lcm; - docs.log = log; - docs.log2 = log2; - docs.log1p = log1p; - docs.log10 = log10; - docs.mod = mod; - docs.multiply = multiply; - docs.norm = norm; - docs.nthRoot = nthRoot; - docs.pow = pow; - docs.round = round; - docs.sign = sign; - docs.sqrt = sqrt; - docs.sqrtm = sqrtm; - docs.square = square; - docs.subtract = subtract; - docs.unaryMinus = unaryMinus; - docs.unaryPlus = unaryPlus; - docs.xgcd = xgcd; - - // functions - bitwise - docs.bitAnd = bitAnd; - docs.bitNot = bitNot; - docs.bitOr = bitOr; - docs.bitXor = bitXor; - docs.leftShift = leftShift; - docs.rightArithShift = rightArithShift; - docs.rightLogShift = rightLogShift; - - // functions - combinatorics - docs.bellNumbers = bellNumbers; - docs.catalan = catalan; - docs.composition = composition; - docs.stirlingS2 = stirlingS2; - - // functions - core - docs['config'] = config$1; - docs['import'] = _import$1; - docs['typed'] = typed$1; - - // functions - complex - docs.arg = arg; - docs.conj = conj; - docs.re = re; - docs.im = im; - - // functions - expression - docs['eval'] = _eval; - docs.help = help; - - // functions - geometry - docs.distance = distance; - docs.intersect = intersect; - - // functions - logical - docs['and'] = and; - docs['not'] = not; - docs['or'] = or; - docs['xor'] = xor; - - // functions - matrix - docs['concat'] = concat; - docs.cross = cross; - docs.det = det; - docs.diag = diag; - docs.dot = dot; - docs.eye = eye; - docs.filter = filter; - docs.flatten = flatten$1; - docs.forEach = forEach; - docs.inv = inv; - docs.kron = kron; - docs.map = map; - docs.ones = ones; - docs.partitionSelect = partitionSelect; - docs.range = range; - docs.resize = resize; - docs.reshape = reshape; - docs.size = size; - docs.sort = sort; - docs.squeeze = squeeze; - docs.subset = subset; - docs.trace = trace; - docs.transpose = transpose; - docs.zeros = zeros; - - // functions - probability - docs.combinations = combinations; - //docs.distribution = require('./function/probability/distribution'); - docs.factorial = factorial; - docs.gamma = gamma; - docs.kldivergence = kldivergence; - docs.multinomial = multinomial; - docs.permutations = permutations; - docs.pickRandom = pickRandom; - docs.random = random; - docs.randomInt = randomInt; - - // functions - relational - docs.compare = compare; - docs.compareNatural = compareNatural; - docs.compareText = compareText; - docs.deepEqual = deepEqual; - docs['equal'] = equal; - docs.equalText = equalText; - docs.larger = larger$1; - docs.largerEq = largerEq; - docs.smaller = smaller$1; - docs.smallerEq = smallerEq; - docs.unequal = unequal; - - // functions - set - docs.setCartesian = setCartesian; - docs.setDifference = setDifference; - docs.setDistinct = setDistinct; - docs.setIntersect = setIntersect; - docs.setIsSubset = setIsSubset; - docs.setMultiplicity = setMultiplicity; - docs.setPowerset = setPowerset; - docs.setSize = setSize; - docs.setSymDifference = setSymDifference; - docs.setUnion = setUnion; - - // functions - special - docs.erf = erf; - - // functions - statistics - docs.mad = mad; - docs.max = max; - docs.mean = mean; - docs.median = median; - docs.min = min; - docs.mode = mode; - docs.prod = prod; - docs.quantileSeq = quantileSeq; - docs.std = std; - docs.sum = sum; - docs['var'] = _var; - - // functions - trigonometry - docs.acos = acos; - docs.acosh = acosh; - docs.acot = acot; - docs.acoth = acoth; - docs.acsc = acsc; - docs.acsch = acsch; - docs.asec = asec; - docs.asech = asech; - docs.asin = asin; - docs.asinh = asinh; - docs.atan = atan; - docs.atanh = atanh; - docs.atan2 = atan2; - docs.cos = cos; - docs.cosh = cosh; - docs.cot = cot; - docs.coth = coth; - docs.csc = csc; - docs.csch = csch; - docs.sec = sec; - docs.sech = sech; - docs.sin = sin; - docs.sinh = sinh; - docs.tan = tan; - docs.tanh = tanh; - - // functions - units - docs.to = to; - - // functions - utils - docs.clone = clone$2; - docs.format = format$2; - docs.isNaN = _isNaN; - docs.isInteger = isInteger$3; - docs.isNegative = isNegative; - docs.isNumeric = isNumeric; - docs.isPositive = isPositive; - docs.isPrime = isPrime; - docs.isZero = isZero; - // docs.print = require('./function/utils/print'); // TODO: add documentation for print as soon as the parser supports objects. - docs['typeof'] = _typeof; - - return docs; -} - -var name$36 = 'docs'; -var path$13 = 'expression'; -var factory_1$38 = factory$39; - -var embeddedDocs = { - name: name$36, - path: path$13, - factory: factory_1$38 -}; - -function factory$40(type, config, load, typed) { - - // TODO: expose this function to mathjs, add documentation - - /** - * Create a numeric value with a specific type: number, BigNumber, or Fraction - * - * @param {string | number} value - * @param {'number' | 'BigNumber' | 'Fraction'} - * @return {number | BigNumber | Fraction} Returns an instance of the - * numeric requested type - */ - return function numeric (value, valueType) { - if (valueType === 'BigNumber') { - return new type.BigNumber(value); - } - else if (valueType === 'Fraction') { - return new type.Fraction(value); - } - else { - // valueType === 'number' or undefined // TODO: check this - if (typeof value === 'number') { - return value; - } - else { - if (value === 'Infinity') { - return Infinity; - } - - if (value === 'NaN') { - return NaN; - } - - // The following regexp is relatively permissive - if (!/^[\-+]?((\d+\.?\d*)|(\d*\.?\d+))([eE][+\-]?\d+)?$/.test(value)) { - throw new Error('Invalid numeric value "' + value + '"'); - } + var name$25 = 'smaller'; + var factory_1$27 = factory$27; - // remove leading zeros like '003.2' which are not allowed by JavaScript - return parseFloat(value.replace(/^(0*)[0-9]/, function (match, zeros) { - return match.substring(zeros.length); - })); - } - } - } -} + var smaller = { + name: name$25, + factory: factory_1$27 + }; -var factory_1$39 = factory$40; + var nearlyEqual$3 = number.nearlyEqual; -var numeric = { - factory: factory_1$39 -}; -var hasOwnProperty = object.hasOwnProperty; + function factory$28 (type, config, load, typed) { + + var matrix$$1 = load(matrix); -/** - * Get a property of a plain object - * Throws an error in case the object is not a plain object or the - * property is not defined on the object itself - * @param {Object} object - * @param {string} prop - * @return {*} Returns the property value when safe - */ -function getSafeProperty (object$$1, prop) { - // only allow getting safe properties of a plain object - if (isPlainObject(object$$1) && isSafeProperty(object$$1, prop)) { - return object$$1[prop]; - } + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - if (typeof object$$1[prop] === 'function' && isSafeMethod(object$$1, prop)) { - throw new Error('Cannot access method "' + prop + '" as a property'); - } + var latex$$1 = latex; - throw new Error('No access to property "' + prop + '"'); -} + /** + * Test whether value x is larger than y. + * + * The function returns true when x is larger than y and the relative + * difference between x and y is larger than the configured epsilon. The + * function cannot be used to compare values smaller than approximately 2.22e-16. + * + * For matrices, the function is evaluated element wise. + * Strings are compared by their numerical value. + * + * Syntax: + * + * math.larger(x, y) + * + * Examples: + * + * math.larger(2, 3); // returns false + * math.larger(5, 2 + 2); // returns true + * + * var a = math.unit('5 cm'); + * var b = math.unit('2 inch'); + * math.larger(a, b); // returns false + * + * See also: + * + * equal, unequal, smaller, smallerEq, largerEq, compare + * + * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare + * @return {boolean | Array | Matrix} Returns true when the x is larger than y, else returns false + */ + var larger = typed('larger', { -/** - * Set a property on a plain object. - * Throws an error in case the object is not a plain object or the - * property would override an inherited property like .constructor or .toString - * @param {Object} object - * @param {string} prop - * @param {*} value - * @return {*} Returns the value - */ -// TODO: merge this function into access.js? -function setSafeProperty (object$$1, prop, value) { - // only allow setting safe properties of a plain object - if (isPlainObject(object$$1) && isSafeProperty(object$$1, prop)) { - return object$$1[prop] = value; - } + 'boolean, boolean': function (x, y) { + return x > y; + }, - throw new Error('No access to property "' + prop + '"'); -} + 'number, number': function (x, y) { + return x > y && !nearlyEqual$3(x, y, config.epsilon); + }, -/** - * Test whether a property is safe to use for an object. - * For example .toString and .constructor are not safe - * @param {string} prop - * @return {boolean} Returns true when safe - */ -function isSafeProperty (object$$1, prop) { - if (!object$$1 || typeof object$$1 !== 'object') { - return false; - } - // SAFE: whitelisted - // e.g length - if (hasOwnProperty(safeNativeProperties, prop)) { - return true; - } - // UNSAFE: inherited from Object prototype - // e.g constructor - if (prop in Object.prototype) { - // 'in' is used instead of hasOwnProperty for nodejs v0.10 - // which is inconsistent on root prototypes. It is safe - // here because Object.prototype is a root object - return false; - } - // UNSAFE: inherited from Function prototype - // e.g call, apply - if (prop in Function.prototype) { - // 'in' is used instead of hasOwnProperty for nodejs v0.10 - // which is inconsistent on root prototypes. It is safe - // here because Function.prototype is a root object - return false; - } - return true; -} - -/** - * Validate whether a method is safe. - * Throws an error when that's not the case. - * @param {Object} object - * @param {string} method - */ -// TODO: merge this function into assign.js? -function validateSafeMethod (object$$1, method) { - if (!isSafeMethod(object$$1, method)) { - throw new Error('No access to method "' + method + '"'); - } -} - -/** - * Check whether a method is safe. - * Throws an error when that's not the case (for example for `constructor`). - * @param {Object} object - * @param {string} method - * @return {boolean} Returns true when safe, false otherwise - */ -function isSafeMethod (object$$1, method) { - if (!object$$1 || typeof object$$1[method] !== 'function') { - return false; - } - // UNSAFE: ghosted - // e.g overridden toString - // Note that IE10 doesn't support __proto__ and we can't do this check there. - if (hasOwnProperty(object$$1, method) && - (object$$1.__proto__ && (method in object$$1.__proto__))) { - return false; - } - // SAFE: whitelisted - // e.g toString - if (hasOwnProperty(safeNativeMethods, method)) { - return true; - } - // UNSAFE: inherited from Object prototype - // e.g constructor - if (method in Object.prototype) { - // 'in' is used instead of hasOwnProperty for nodejs v0.10 - // which is inconsistent on root prototypes. It is safe - // here because Object.prototype is a root object - return false; - } - // UNSAFE: inherited from Function prototype - // e.g call, apply - if (method in Function.prototype) { - // 'in' is used instead of hasOwnProperty for nodejs v0.10 - // which is inconsistent on root prototypes. It is safe - // here because Function.prototype is a root object - return false; - } - return true; -} - -function isPlainObject (object$$1) { - return typeof object$$1 === 'object' && object$$1 && object$$1.constructor === Object; -} - -var safeNativeProperties = { - length: true, - name: true -}; - -var safeNativeMethods = { - toString: true, - valueOf: true, - toLocaleString: true -}; - -var getSafeProperty_1 = getSafeProperty; -var setSafeProperty_1 = setSafeProperty; -var isSafeProperty_1 = isSafeProperty; -var validateSafeMethod_1 = validateSafeMethod; -var isSafeMethod_1 = isSafeMethod; -var isPlainObject_1 = isPlainObject; - -var customs = { - getSafeProperty: getSafeProperty_1, - setSafeProperty: setSafeProperty_1, - isSafeProperty: isSafeProperty_1, - validateSafeMethod: validateSafeMethod_1, - isSafeMethod: isSafeMethod_1, - isPlainObject: isPlainObject_1 -}; - -// Reserved keywords not allowed to use in the parser -var keywords = { - end: true -}; - -var deepEqual$1= object.deepEqual; -var hasOwnProperty$1 = object.hasOwnProperty; - -function factory$41 (type, config, load, typed, math) { + 'BigNumber, BigNumber': function (x, y) { + return x.gt(y) && !nearlyEqual(x, y, config.epsilon); + }, - /** - * Node - */ - function Node() { - if (!(this instanceof Node)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - } + 'Fraction, Fraction': function (x, y) { + return x.compare(y) === 1; + }, - /** - * Evaluate the node - * @param {Object} [scope] Scope to read/write variables - * @return {*} Returns the result - */ - Node.prototype.eval = function(scope) { - return this.compile().eval(scope); - }; + 'Complex, Complex': function () { + throw new TypeError('No ordering relation is defined for complex numbers'); + }, - Node.prototype.type = 'Node'; + 'Unit, Unit': function (x, y) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return larger(x.value, y.value); + }, - Node.prototype.isNode = true; + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm07$$1(x, y, larger); + }, - Node.prototype.comment = ''; + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, larger, true); + }, - /** - * Compile the node into an optimized, evauatable JavaScript function - * @return {{eval: function([Object])}} expr Returns an object with a function 'eval', - * which can be invoked as expr.eval([scope: Object]), - * where scope is an optional object with - * variables. - */ - Node.prototype.compile = function () { - var expr = this._compile(math.expression.mathWithTransform, {}); - var args = {}; - var context = null; - return { - eval: function evalNode(scope) { - var s = scope ? scope : {}; - _validateScope(s); - return expr(s, args, context); - } - } - }; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - Node.prototype._compile = function (math, argNames) { - throw new Error('Method _compile should be implemented by type ' + this.type); - }; + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, larger, false); + }, - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - Node.prototype.forEach = function (callback) { - // must be implemented by each of the Node implementations - throw new Error('Cannot run forEach on a Node interface'); - }; + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, larger); + }, - /** - * Create a new Node having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {OperatorNode} Returns a transformed copy of the node - */ - Node.prototype.map = function (callback) { - // must be implemented by each of the Node implementations - throw new Error('Cannot run map on a Node interface'); - }; + 'Array, Array': function (x, y) { + // use matrix implementation + return larger(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - /** - * Validate whether an object is a Node, for use with map - * @param {Node} node - * @returns {Node} Returns the input if it's a node, else throws an Error - * @protected - */ - Node.prototype._ifNode = function (node) { - if (!type.isNode(node)) { - throw new TypeError('Callback function must return a Node'); - } + 'Array, Matrix': function (x, y) { + // use matrix implementation + return larger(matrix$$1(x), y); + }, - return node; - }; + 'Matrix, Array': function (x, y) { + // use matrix implementation + return larger(x, matrix$$1(y)); + }, - /** - * Recursively traverse all nodes in a node tree. Executes given callback for - * this node and each of its child nodes. - * @param {function(node: Node, path: string, parent: Node)} callback - * A callback called for every node in the node tree. - */ - Node.prototype.traverse = function (callback) { - // execute callback for itself - callback(this, null, null); - - // recursively traverse over all childs of a node - function _traverse(node, callback) { - node.forEach(function (child, path, parent) { - callback(child, path, parent); - _traverse(child, callback); - }); - } + 'SparseMatrix, any': function (x, y) { + return algorithm12$$1(x, y, larger, false); + }, - _traverse(this, callback); - }; + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, larger, false); + }, - /** - * Recursively transform a node tree via a transform function. - * - * For example, to replace all nodes of type SymbolNode having name 'x' with a - * ConstantNode with value 2: - * - * var res = Node.transform(function (node, path, parent) { - * if (node && node.isSymbolNode) && (node.name == 'x')) { - * return new ConstantNode(2); - * } - * else { - * return node; - * } - * }); - * - * @param {function(node: Node, path: string, parent: Node) : Node} callback - * A mapping function accepting a node, and returning - * a replacement for the node or the original node. - * Signature: callback(node: Node, index: string, parent: Node) : Node - * @return {Node} Returns the original node or its replacement - */ - Node.prototype.transform = function (callback) { - // traverse over all childs - function _transform (node, callback) { - return node.map(function(child, path, parent) { - var replacement = callback(child, path, parent); - return _transform(replacement, callback); - }); - } + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, larger, true); + }, - var replacement = callback(this, null, null); - return _transform(replacement, callback); - }; + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, larger, true); + }, - /** - * Find any node in the node tree matching given filter function. For example, to - * find all nodes of type SymbolNode having name 'x': - * - * var results = Node.filter(function (node) { - * return (node && node.isSymbolNode) && (node.name == 'x'); - * }); - * - * @param {function(node: Node, path: string, parent: Node) : Node} callback - * A test function returning true when a node matches, and false - * otherwise. Function signature: - * callback(node: Node, index: string, parent: Node) : boolean - * @return {Node[]} nodes An array with nodes matching given filter criteria - */ - Node.prototype.filter = function (callback) { - var nodes = []; + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, larger, false).valueOf(); + }, - this.traverse(function (node, path, parent) { - if (callback(node, path, parent)) { - nodes.push(node); + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, larger, true).valueOf(); } }); - return nodes; - }; - - // TODO: deprecated since version 1.1.0, remove this some day - Node.prototype.find = function () { - throw new Error('Function Node.find is deprecated. Use Node.filter instead.'); - }; - - // TODO: deprecated since version 1.1.0, remove this some day - Node.prototype.match = function () { - throw new Error('Function Node.match is deprecated. See functions Node.filter, Node.transform, Node.traverse.'); - }; + larger.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['larger'] + '${args[1]}\\right)' + }; - /** - * Create a shallow clone of this node - * @return {Node} - */ - Node.prototype.clone = function () { - // must be implemented by each of the Node implementations - throw new Error('Cannot clone a Node interface'); - }; + return larger; + } - /** - * Create a deep clone of this node - * @return {Node} - */ - Node.prototype.cloneDeep = function () { - return this.map(function (node) { - return node.cloneDeep(); - }); - }; + var name$26 = 'larger'; + var factory_1$28 = factory$28; - /** - * Deep compare this node with another node. - * @param {Node} other - * @return {boolean} Returns true when both nodes are of the same type and - * contain the same values (as do their childs) - */ - Node.prototype.equals = function (other) { - return other - ? deepEqual$1(this, other) - : false + var larger = { + name: name$26, + factory: factory_1$28 }; - /** - * Get string representation. (wrapper function) - * - * This function can get an object of the following form: - * { - * handler: //This can be a callback function of the form - * // "function callback(node, options)"or - * // a map that maps function names (used in FunctionNodes) - * // to callbacks - * parenthesis: "keep" //the parenthesis option (This is optional) - * } - * - * @param {Object} [options] - * @return {string} - */ - Node.prototype.toString = function (options) { - var customString; - if (options && typeof options === 'object') { - switch (typeof options.handler) { - case 'object': - case 'undefined': - break; - case 'function': - customString = options.handler(this, options); - break; - default: - throw new TypeError('Object or function expected as callback'); - } - } + function factory$29 (type, config, load, typed) { + + var smaller$$1 = load(smaller); + var larger$$1 = load(larger); + + var oneOverLogPhi = 1.0 / Math.log((1.0 + Math.sqrt(5.0)) / 2.0); + + /** + * Fibonacci Heap implementation, used interally for Matrix math. + * @class FibonacciHeap + * @constructor FibonacciHeap + */ + function FibonacciHeap() { + if (!(this instanceof FibonacciHeap)) + throw new SyntaxError('Constructor must be called with the new operator'); - if (typeof customString !== 'undefined') { - return customString; + // initialize fields + this._minimum = null; + this._size = 0; } - return this._toString(options); - }; - - /** - * Get a JSON representation of the node - * Both .toJSON() and the static .fromJSON(json) should be implemented by all - * implementations of Node - * @returns {Object} - */ - Node.prototype.toJSON = function () { - throw new Error('Cannot serialize object: toJSON not implemented by ' + this.type); - }; + /** + * Attach type information + */ + FibonacciHeap.prototype.type = 'FibonacciHeap'; + FibonacciHeap.prototype.isFibonacciHeap = true; - /** - * Get HTML representation. (wrapper function) - * - * This function can get an object of the following form: - * { - * handler: //This can be a callback function of the form - * // "function callback(node, options)" or - * // a map that maps function names (used in FunctionNodes) - * // to callbacks - * parenthesis: "keep" //the parenthesis option (This is optional) - * } - * - * @param {Object} [options] - * @return {string} - */ - Node.prototype.toHTML = function (options) { - var customString; - if (options && typeof options === 'object') { - switch (typeof options.handler) { - case 'object': - case 'undefined': - break; - case 'function': - customString = options.handler(this, options); - break; - default: - throw new TypeError('Object or function expected as callback'); + /** + * Inserts a new data element into the heap. No heap consolidation is + * performed at this time, the new node is simply inserted into the root + * list of this heap. Running time: O(1) actual. + * @memberof FibonacciHeap + */ + FibonacciHeap.prototype.insert = function (key, value) { + // create node + var node = { + key: key, + value: value, + degree: 0 + }; + // check we have a node in the minimum + if (this._minimum) { + // minimum node + var minimum = this._minimum; + // update left & right of node + node.left = minimum; + node.right = minimum.right; + minimum.right = node; + node.right.left = node; + // update minimum node in heap if needed + if (smaller$$1(key, minimum.key)) { + // node has a smaller key, use it as minimum + this._minimum = node; } - } - - if (typeof customString !== 'undefined') { - return customString; - } - - return this.toHTML(options); - }; - - /** - * Internal function to generate the string output. - * This has to be implemented by every Node - * - * @throws {Error} - */ - Node.prototype._toString = function () { - //must be implemented by each of the Node implementations - throw new Error('_toString not implemented for ' + this.type); - }; - - /** - * Get LaTeX representation. (wrapper function) - * - * This function can get an object of the following form: - * { - * handler: //This can be a callback function of the form - * // "function callback(node, options)"or - * // a map that maps function names (used in FunctionNodes) - * // to callbacks - * parenthesis: "keep" //the parenthesis option (This is optional) - * } - * - * @param {Object} [options] - * @return {string} - */ - Node.prototype.toTex = function (options) { - var customTex; - if (options && typeof options == 'object') { - switch (typeof options.handler) { - case 'object': - case 'undefined': - break; - case 'function': - customTex = options.handler(this, options); - break; - default: - throw new TypeError('Object or function expected as callback'); } - } - - if (typeof customTex !== 'undefined') { - return customTex; - } - - return this._toTex(options); - }; + else { + // set left & right + node.left = node; + node.right = node; + // this is the first node + this._minimum = node; + } + // increment number of nodes in heap + this._size++; + // return node + return node; + }; - /** - * Internal function to generate the LaTeX output. - * This has to be implemented by every Node - * - * @param {Object} [options] - * @throws {Error} - */ - Node.prototype._toTex = function (options) { - //must be implemented by each of the Node implementations - throw new Error('_toTex not implemented for ' + this.type); - }; + /** + * Returns the number of nodes in heap. Running time: O(1) actual. + * @memberof FibonacciHeap + */ + FibonacciHeap.prototype.size = function () { + return this._size; + }; - /** - * Get identifier. - * @return {string} - */ - Node.prototype.getIdentifier = function () { - return this.type; - }; + /** + * Removes all elements from this heap. + * @memberof FibonacciHeap + */ + FibonacciHeap.prototype.clear = function () { + this._minimum = null; + this._size = 0; + }; - /** - * Get the content of the current Node. - * @return {Node} node - **/ - Node.prototype.getContent = function () { - return this; - }; - - /** - * Validate the symbol names of a scope. - * Throws an error when the scope contains an illegal symbol. - * @param {Object} scope - */ - function _validateScope(scope) { - for (var symbol in scope) { - if (hasOwnProperty$1(scope, symbol)) { - if (symbol in keywords) { - throw new Error('Scope contains an illegal symbol, "' + symbol + '" is a reserved keyword'); + /** + * Returns true if the heap is empty, otherwise false. + * @memberof FibonacciHeap + */ + FibonacciHeap.prototype.isEmpty = function () { + return this._size === 0; + }; + + /** + * Extracts the node with minimum key from heap. Amortized running + * time: O(log n). + * @memberof FibonacciHeap + */ + FibonacciHeap.prototype.extractMinimum = function () { + // node to remove + var node = this._minimum; + // check we have a minimum + if (node === null) + return node; + // current minimum + var minimum = this._minimum; + // get number of children + var numberOfChildren = node.degree; + // pointer to the first child + var x = node.child; + // for each child of node do... + while (numberOfChildren > 0) { + // store node in right side + var tempRight = x.right; + // remove x from child list + x.left.right = x.right; + x.right.left = x.left; + // add x to root list of heap + x.left = minimum; + x.right = minimum.right; + minimum.right = x; + x.right.left = x; + // set Parent[x] to null + x.parent = null; + x = tempRight; + numberOfChildren--; + } + // remove node from root list of heap + node.left.right = node.right; + node.right.left = node.left; + // update minimum + if (node == node.right) { + // empty + minimum = null; + } + else { + // update minimum + minimum = node.right; + // we need to update the pointer to the root with minimum key + minimum = _findMinimumNode(minimum, this._size); + } + // decrement size of heap + this._size--; + // update minimum + this._minimum = minimum; + // return node + return node; + }; + + /** + * Removes a node from the heap given the reference to the node. The trees + * in the heap will be consolidated, if necessary. This operation may fail + * to remove the correct element if there are nodes with key value -Infinity. + * Running time: O(log n) amortized. + * @memberof FibonacciHeap + */ + FibonacciHeap.prototype.remove = function (node) { + // decrease key value + this._minimum = _decreaseKey(this._minimum, node, -1); + // remove the smallest + this.extractMinimum(); + }; + + /** + * Decreases the key value for a heap node, given the new value to take on. + * The structure of the heap may be changed and will not be consolidated. + * Running time: O(1) amortized. + * @memberof FibonacciHeap + */ + var _decreaseKey = function (minimum, node, key) { + // set node key + node.key = key; + // get parent node + var parent = node.parent; + if (parent && smaller$$1(node.key, parent.key)) { + // remove node from parent + _cut(minimum, node, parent); + // remove all nodes from parent to the root parent + _cascadingCut(minimum, parent); + } + // update minimum node if needed + if (smaller$$1(node.key, minimum.key)) + minimum = node; + // return minimum + return minimum; + }; + + /** + * The reverse of the link operation: removes node from the child list of parent. + * This method assumes that min is non-null. Running time: O(1). + * @memberof FibonacciHeap + */ + var _cut = function (minimum, node, parent) { + // remove node from parent children and decrement Degree[parent] + node.left.right = node.right; + node.right.left = node.left; + parent.degree--; + // reset y.child if necessary + if (parent.child == node) + parent.child = node.right; + // remove child if degree is 0 + if (parent.degree === 0) + parent.child = null; + // add node to root list of heap + node.left = minimum; + node.right = minimum.right; + minimum.right = node; + node.right.left = node; + // set parent[node] to null + node.parent = null; + // set mark[node] to false + node.mark = false; + }; + + /** + * Performs a cascading cut operation. This cuts node from its parent and then + * does the same for its parent, and so on up the tree. + * Running time: O(log n); O(1) excluding the recursion. + * @memberof FibonacciHeap + */ + var _cascadingCut= function (minimum, node) { + // store parent node + var parent = node.parent; + // if there's a parent... + if (!parent) + return; + // if node is unmarked, set it marked + if (!node.mark) { + node.mark = true; + } + else { + // it's marked, cut it from parent + _cut(minimum, node, parent); + // cut its parent as well + _cascadingCut(parent); + } + }; + + /** + * Make the first node a child of the second one. Running time: O(1) actual. + * @memberof FibonacciHeap + */ + var _linkNodes = function (node, parent) { + // remove node from root list of heap + node.left.right = node.right; + node.right.left = node.left; + // make node a Child of parent + node.parent = parent; + if (!parent.child) { + parent.child = node; + node.right = node; + node.left = node; + } + else { + node.left = parent.child; + node.right = parent.child.right; + parent.child.right = node; + node.right.left = node; + } + // increase degree[parent] + parent.degree++; + // set mark[node] false + node.mark = false; + }; + + var _findMinimumNode = function (minimum, size) { + // to find trees of the same degree efficiently we use an array of length O(log n) in which we keep a pointer to one root of each degree + var arraySize = Math.floor(Math.log(size) * oneOverLogPhi) + 1; + // create list with initial capacity + var array = new Array(arraySize); + // find the number of root nodes. + var numRoots = 0; + var x = minimum; + if (x) { + numRoots++; + x = x.right; + while (x !== minimum) { + numRoots++; + x = x.right; + } + } + // vars + var y; + // For each node in root list do... + while (numRoots > 0) { + // access this node's degree.. + var d = x.degree; + // get next node + var next = x.right; + // check if there is a node already in array with the same degree + while (true) { + // get node with the same degree is any + y = array[d]; + if (!y) + break; + // make one node with the same degree a child of the other, do this based on the key value. + if (larger$$1(x.key, y.key)) { + var temp = y; + y = x; + x = temp; + } + // make y a child of x + _linkNodes(y, x); + // we have handled this degree, go to next one. + array[d] = null; + d++; + } + // save this node for later when we might encounter another of the same degree. + array[d] = x; + // move forward through list. + x = next; + numRoots--; + } + // Set min to null (effectively losing the root list) and reconstruct the root list from the array entries in array[]. + minimum = null; + // loop nodes in array + for (var i = 0; i < arraySize; i++) { + // get current node + y = array[i]; + if (!y) + continue; + // check if we have a linked list + if (minimum) { + // First remove node from root list. + y.left.right = y.right; + y.right.left = y.left; + // now add to root list, again. + y.left = minimum; + y.right = minimum.right; + minimum.right = y; + y.right.left = y; + // check if this is a new min. + if (smaller$$1(y.key, minimum.key)) + minimum = y; } + else + minimum = y; } - } + return minimum; + }; + + return FibonacciHeap; } - return Node; -} + var name$27 = 'FibonacciHeap'; + var path$8 = 'type'; + var factory_1$29 = factory$29; -var name$37 = 'Node'; -var path$14 = 'expression.node'; -var math$6 = true; // request access to the math namespace as 5th argument of the factory function -var factory_1$40 = factory$41; + var FibonacciHeap = { + name: name$27, + path: path$8, + factory: factory_1$29 + }; -var Node = { - name: name$37, - path: path$14, - math: math$6, - factory: factory_1$40 -}; + var string$5 = utils.string; + var object$3 = utils.object; -var map$1 = array.map; -var escape = string.escape; + var isArray$2 = Array.isArray; + var isString$4 = string$5.isString; -function factory$42 (type, config, load, typed) { - var Node$$1 = load(Node); - var Range$$1 = load(Range); + function factory$30 (type, config, load) { - var isArray = Array.isArray; + var DenseMatrix$$1 = load(DenseMatrix); - /** - * @constructor IndexNode - * @extends Node - * - * Describes a subset of a matrix or an object property. - * Cannot be used on its own, needs to be used within an AccessorNode or - * AssignmentNode. - * - * @param {Node[]} dimensions - * @param {boolean} [dotNotation=false] Optional property describing whether - * this index was written using dot - * notation like `a.b`, or using bracket - * notation like `a["b"]` (default). - * Used to stringify an IndexNode. - */ - function IndexNode(dimensions, dotNotation) { - if (!(this instanceof IndexNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + var smaller$$1 = load(smaller); - this.dimensions = dimensions; - this.dotNotation = dotNotation || false; + function ImmutableDenseMatrix(data, datatype) { + if (!(this instanceof ImmutableDenseMatrix)) + throw new SyntaxError('Constructor must be called with the new operator'); + if (datatype && !isString$4(datatype)) + throw new Error('Invalid datatype: ' + datatype); - // validate input - if (!isArray(dimensions) || !dimensions.every(type.isNode)) { - throw new TypeError('Array containing Nodes expected for parameter "dimensions"'); - } - if (this.dotNotation && !this.isObjectProperty()) { - throw new Error('dotNotation only applicable for object properties'); + if (type.isMatrix(data) || isArray$2(data)) { + // use DenseMatrix implementation + var matrix = new DenseMatrix$$1(data, datatype); + // internal structures + this._data = matrix._data; + this._size = matrix._size; + this._datatype = matrix._datatype; + this._min = null; + this._max = null; + } + else if (data && isArray$2(data.data) && isArray$2(data.size)) { + // initialize fields from JSON representation + this._data = data.data; + this._size = data.size; + this._datatype = data.datatype; + this._min = typeof data.min !== 'undefined' ? data.min : null; + this._max = typeof data.max !== 'undefined' ? data.max : null; + } + else if (data) { + // unsupported type + throw new TypeError('Unsupported type of data (' + utils.types.type(data) + ')'); + } + else { + // nothing provided + this._data = []; + this._size = [0]; + this._datatype = datatype; + this._min = null; + this._max = null; + } } - // TODO: deprecated since v3, remove some day - var deprecated = function () { - throw new Error('Property `IndexNode.object` is deprecated, use `IndexNode.fn` instead'); - }; - Object.defineProperty(this, 'object', { get: deprecated, set: deprecated }); - } + ImmutableDenseMatrix.prototype = new DenseMatrix$$1(); - IndexNode.prototype = new Node$$1(); + /** + * Attach type information + */ + ImmutableDenseMatrix.prototype.type = 'ImmutableDenseMatrix'; + ImmutableDenseMatrix.prototype.isImmutableDenseMatrix = true; - IndexNode.prototype.type = 'IndexNode'; + /** + * 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 | ImmutableDenseMatrix | *} [replacement] + * @param {*} [defaultValue=0] Default value, filled in on new entries when + * the matrix is resized. If not provided, + * new matrix elements will be filled with zeros. + */ + ImmutableDenseMatrix.prototype.subset = function (index) { + switch (arguments.length) { + case 1: + // use base implementation + var m = DenseMatrix$$1.prototype.subset.call(this, index); + // check result is a matrix + if (type.isMatrix(m)) { + // return immutable matrix + return new ImmutableDenseMatrix({ + data: m._data, + size: m._size, + datatype: m._datatype + }); + } + return m; + + // intentional fall through + case 2: + case 3: + throw new Error('Cannot invoke set subset on an Immutable Matrix instance'); - IndexNode.prototype.isIndexNode = true; + default: + throw new SyntaxError('Wrong number of arguments'); + } + }; - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - IndexNode.prototype._compile = function (math, argNames) { - // TODO: implement support for bignumber (currently bignumbers are silently - // reduced to numbers when changing the value to zero-based) - - // TODO: Optimization: when the range values are ConstantNodes, - // we can beforehand resolve the zero-based value - - // optimization for a simple object property - var evalDimensions = map$1(this.dimensions, function (range, i) { - if (type.isRangeNode(range)) { - if (range.needsEnd()) { - // create a range containing end (like '4:end') - var childArgNames = Object.create(argNames); - childArgNames['end'] = true; + /** + * 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 {ImmutableDenseMatrix} self + */ + ImmutableDenseMatrix.prototype.set = function () { + throw new Error('Cannot invoke set on an Immutable Matrix instance'); + }; - var evalStart = range.start._compile(math, childArgNames); - var evalEnd = range.end._compile(math, childArgNames); - var evalStep = range.step - ? range.step._compile(math, childArgNames) - : function () { return 1 }; + /** + * Resize the matrix to the given size. Returns a copy of the matrix when + * `copy=true`, otherwise return the matrix itself (resize in place). + * + * @param {Number[]} size The new size the matrix should have. + * @param {*} [defaultValue=0] Default value, filled in on new entries. + * If not provided, the matrix elements will + * be filled with zeros. + * @param {boolean} [copy] Return a resized copy of the matrix + * + * @return {Matrix} The resized matrix + */ + ImmutableDenseMatrix.prototype.resize = function () { + throw new Error('Cannot invoke resize on an Immutable Matrix instance'); + }; - return function evalDimension(scope, args, context) { - var size = math.size(context).valueOf(); - var childArgs = Object.create(args); - childArgs['end'] = size[i]; + /** + * Disallows reshaping in favor of immutability. + * + * @throws {Error} Operation not allowed + */ + ImmutableDenseMatrix.prototype.reshape = function () { + throw new Error('Cannot invoke reshape on an Immutable Matrix instance'); + }; - return createRange( - evalStart(scope, childArgs, context), - evalEnd(scope, childArgs, context), - evalStep(scope, childArgs, context) - ); - }; - } - else { - // create range - var evalStart = range.start._compile(math, argNames); - var evalEnd = range.end._compile(math, argNames); - var evalStep = range.step - ? range.step._compile(math, argNames) - : function () { return 1 }; + /** + * Create a clone of the matrix + * @return {ImmutableDenseMatrix} clone + */ + ImmutableDenseMatrix.prototype.clone = function () { + var m = new ImmutableDenseMatrix({ + data: object$3.clone(this._data), + size: object$3.clone(this._size), + datatype: this._datatype + }); + return m; + }; - return function evalDimension(scope, args, context) { - return createRange( - evalStart(scope, args, context), - evalEnd(scope, args, context), - evalStep(scope, args, context) - ); - }; - } - } - else if (type.isSymbolNode(range) && range.name === 'end') { - // SymbolNode 'end' - var childArgNames = Object.create(argNames); - childArgNames['end'] = true; + /** + * Get a JSON representation of the matrix + * @returns {Object} + */ + ImmutableDenseMatrix.prototype.toJSON = function () { + return { + mathjs: 'ImmutableDenseMatrix', + data: this._data, + size: this._size, + datatype: this._datatype + }; + }; - var evalRange = range._compile(math, childArgNames); - - return function evalDimension(scope, args, context) { - var size = math.size(context).valueOf(); - var childArgs = Object.create(args); - childArgs['end'] = size[i]; + /** + * Generate a matrix from a JSON object + * @param {Object} json An object structured like + * `{"mathjs": "ImmutableDenseMatrix", data: [], size: []}`, + * where mathjs is optional + * @returns {ImmutableDenseMatrix} + */ + ImmutableDenseMatrix.fromJSON = function (json) { + return new ImmutableDenseMatrix(json); + }; - return evalRange(scope, childArgs, context); - }; - } - else { - // ConstantNode - var evalRange = range._compile(math, argNames); - return function evalDimension(scope, args, context) { - return evalRange(scope, args, context); - }; + /** + * Swap rows i and j in Matrix. + * + * @param {Number} i Matrix row index 1 + * @param {Number} j Matrix row index 2 + * + * @return {Matrix} The matrix reference + */ + ImmutableDenseMatrix.prototype.swapRows = function () { + throw new Error('Cannot invoke swapRows on an Immutable Matrix instance'); + }; + + /** + * Calculate the minimum value in the set + * @return {Number | undefined} min + */ + ImmutableDenseMatrix.prototype.min = function () { + // check min has been calculated before + if (this._min === null) { + // minimum + var m = null; + // compute min + this.forEach(function (v) { + if (m === null || smaller$$1(v, m)) + m = v; + }); + this._min = m !== null ? m : undefined; } - }); + return this._min; + }; - return function evalIndexNode (scope, args, context) { - var dimensions = map$1(evalDimensions, function (evalDimension) { - return evalDimension(scope, args, context); - }); - return math.index.apply(math, dimensions); + /** + * Calculate the maximum value in the set + * @return {Number | undefined} max + */ + ImmutableDenseMatrix.prototype.max = function () { + // check max has been calculated before + if (this._max === null) { + // maximum + var m = null; + // compute max + this.forEach(function (v) { + if (m === null || smaller$$1(m, v)) + m = v; + }); + this._max = m !== null ? m : undefined; + } + return this._max; }; - }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - IndexNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.dimensions.length; i++) { - callback(this.dimensions[i], 'dimensions[' + i + ']', this); - } - }; + // exports + return ImmutableDenseMatrix; + } - /** - * Create a new IndexNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {IndexNode} Returns a transformed copy of the node - */ - IndexNode.prototype.map = function (callback) { - var dimensions = []; - for (var i = 0; i < this.dimensions.length; i++) { - dimensions[i] = this._ifNode(callback(this.dimensions[i], 'dimensions[' + i + ']', this)); - } + var name$28 = 'ImmutableDenseMatrix'; + var path$9 = 'type'; + var factory_1$30 = factory$30; - return new IndexNode(dimensions); + var ImmutableDenseMatrix = { + name: name$28, + path: path$9, + factory: factory_1$30 }; - /** - * Create a clone of this node, a shallow copy - * @return {IndexNode} - */ - IndexNode.prototype.clone = function () { - return new IndexNode(this.dimensions.slice(0)); - }; + var clone$1 = object.clone; + var isInteger$2 = number.isInteger; - /** - * Test whether this IndexNode contains a single property name - * @return {boolean} - */ - IndexNode.prototype.isObjectProperty = function () { - return this.dimensions.length === 1 && - type.isConstantNode(this.dimensions[0]) && - typeof this.dimensions[0].value === 'string'; - }; + function factory$31 (type) { + + /** + * Create an index. An Index can store ranges and sets for multiple dimensions. + * Matrix.get, Matrix.set, and math.subset accept an Index as input. + * + * Usage: + * var index = new Index(range1, range2, matrix1, array1, ...); + * + * Where each parameter can be any of: + * A number + * A string (containing a name of an object property) + * An instance of Range + * An Array with the Set values + * A Matrix with the Set values + * + * The parameters start, end, and step must be integer numbers. + * + * @class Index + * @Constructor Index + * @param {...*} ranges + */ + function Index(ranges) { + if (!(this instanceof Index)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - /** - * Returns the property name if IndexNode contains a property. - * If not, returns null. - * @return {string | null} - */ - IndexNode.prototype.getObjectProperty = function () { - return this.isObjectProperty() ? this.dimensions[0].value : null; - }; + this._dimensions = []; + this._isScalar = true; - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - IndexNode.prototype._toString = function (options) { - // format the parameters like "[1, 0:5]" - return this.dotNotation - ? ('.' + this.getObjectProperty()) - : ('[' + this.dimensions.join(', ') + ']'); - }; + for (var i = 0, ii = arguments.length; i < ii; i++) { + var arg = arguments[i]; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - IndexNode.prototype.toJSON = function () { - return { - mathjs: 'IndexNode', - dimensions: this.dimensions, - dotNotation: this.dotNotation - }; - }; + if (type.isRange(arg)) { + this._dimensions.push(arg); + this._isScalar = false; + } + else if (Array.isArray(arg) || type.isMatrix(arg)) { + // create matrix + var m = _createImmutableMatrix(arg.valueOf()); + this._dimensions.push(m); + // size + var size = m.size(); + // scalar + if (size.length !== 1 || size[0] !== 1) { + this._isScalar = false; + } + } + else if (typeof arg === 'number') { + this._dimensions.push(_createImmutableMatrix([arg])); + } + else if (typeof arg === 'string') { + // object property (arguments.count should be 1) + this._dimensions.push(arg); + } + // TODO: implement support for wildcard '*' + else { + throw new TypeError('Dimension must be an Array, Matrix, number, string, or Range'); + } + } + } - /** - * Instantiate an IndexNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "IndexNode", dimensions: [...], dotNotation: false}`, - * where mathjs is optional - * @returns {IndexNode} - */ - IndexNode.fromJSON = function (json) { - return new IndexNode(json.dimensions, json.dotNotation); - }; + /** + * Attach type information + */ + Index.prototype.type = 'Index'; + Index.prototype.isIndex = true; - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - IndexNode.prototype.toHTML = function (options) { - // format the parameters like "[1, 0:5]" - var dimensions = []; - for (var i=0; i.' + '' + escape(this.getObjectProperty()) + '';} - else { - return '[' + dimensions.join(',') + ']'} - }; + function _createImmutableMatrix(arg) { + // loop array elements + for (var i = 0, l = arg.length; i < l; i++) { + if (typeof arg[i] !== 'number' || !isInteger$2(arg[i])) { + throw new TypeError('Index parameters must be positive integer numbers'); + } + } + // create matrix + return new type.ImmutableDenseMatrix(arg); + } - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - IndexNode.prototype._toTex = function (options) { - var dimensions = this.dimensions.map(function (range) { - return range.toTex(options); - }); + /** + * Create a clone of the index + * @memberof Index + * @return {Index} clone + */ + Index.prototype.clone = function () { + var index = new Index(); + index._dimensions = clone$1(this._dimensions); + index._isScalar = this._isScalar; + return index; + }; - return this.dotNotation - ? ('.' + this.getObjectProperty() + '') - : ('_{' + dimensions.join(',') + '}'); - }; + /** + * Create an index from an array with ranges/numbers + * @memberof Index + * @param {Array.} ranges + * @return {Index} index + * @private + */ + Index.create = function (ranges) { + var index = new Index(); + Index.apply(index, ranges); + return index; + }; - // helper function to create a Range from start, step and end - function createRange(start, end, step) { - return new Range$$1( - type.isBigNumber(start) ? start.toNumber() : start, - type.isBigNumber(end) ? end.toNumber() : end, - type.isBigNumber(step) ? step.toNumber() : step - ); - } - return IndexNode; -} + /** + * Retrieve the size of the index, the number of elements for each dimension. + * @memberof Index + * @returns {number[]} size + */ + Index.prototype.size = function () { + var size = []; -var name$38 = 'IndexNode'; -var path$15 = 'expression.node'; -var factory_1$41 = factory$42; + for (var i = 0, ii = this._dimensions.length; i < ii; i++) { + var d = this._dimensions[i]; + size[i] = (typeof d === 'string') ? 1 : d.size()[0]; + } -var IndexNode = { - name: name$38, - path: path$15, - factory: factory_1$41 -}; + return size; + }; -/** - * Transform zero-based indices to one-based indices in errors - * @param {Error} err - * @returns {Error} Returns the transformed error - */ -var transform = function (err) { - if (err && err.isIndexError) { - return new IndexError_1( - err.index + 1, - err.min + 1, - err.max !== undefined ? err.max + 1 : undefined); - } + /** + * Get the maximum value for each of the indexes ranges. + * @memberof Index + * @returns {number[]} max + */ + Index.prototype.max = function () { + var values = []; - return err; -}; + for (var i = 0, ii = this._dimensions.length; i < ii; i++) { + var range = this._dimensions[i]; + values[i] = (typeof range === 'string') ? range : range.max(); + } -var error_transform = { - transform: transform -}; + return values; + }; -var clone$3 = object.clone; -var validateIndex$2 = array.validateIndex; -var getSafeProperty$1 = customs.getSafeProperty; -var setSafeProperty$1 = customs.setSafeProperty; + /** + * Get the minimum value for each of the indexes ranges. + * @memberof Index + * @returns {number[]} min + */ + Index.prototype.min = function () { + var values = []; + for (var i = 0, ii = this._dimensions.length; i < ii; i++) { + var range = this._dimensions[i]; + values[i] = (typeof range === 'string') ? range : range.min(); + } -function factory$43 (type, config, load, typed) { - var matrix$$1 = load(matrix); + return values; + }; - /** - * Get or set a subset of a matrix or string. - * - * Syntax: - * math.subset(value, index) // retrieve a subset - * math.subset(value, index, replacement [, defaultValue]) // replace a subset - * - * Examples: - * - * // get a subset - * var d = [[1, 2], [3, 4]]; - * math.subset(d, math.index(1, 0)); // returns 3 - * math.subset(d, math.index([0, 2], 1)); // returns [[2], [4]] - * - * // replace a subset - * var e = []; - * var f = math.subset(e, math.index(0, [0, 2]), [5, 6]); // f = [[5, 6]] - * var g = math.subset(f, math.index(1, 1), 7, 0); // g = [[5, 6], [0, 7]] - * - * See also: - * - * size, resize, squeeze, index - * - * @param {Array | Matrix | string} matrix An array, matrix, or string - * @param {Index} index An index containing ranges for each - * dimension - * @param {*} [replacement] An array, matrix, or scalar. - * If provided, the subset is replaced with replacement. - * If not provided, the subset is returned - * @param {*} [defaultValue=undefined] Default value, filled in on new entries when - * the matrix is resized. If not provided, - * math.matrix elements will be left undefined. - * @return {Array | Matrix | string} Either the retrieved subset or the updated matrix. - */ - var subset = typed('subset', { - // get subset - 'Array, Index': function (value, index) { - var m = matrix$$1(value); - var subset = m.subset(index); // returns a Matrix - return index.isScalar() - ? subset - : subset.valueOf(); // return an Array (like the input) - }, - - 'Matrix, Index': function (value, index) { - return value.subset(index); - }, - - 'Object, Index': _getObjectProperty, - - 'string, Index': _getSubstring, + /** + * Loop over each of the ranges of the index + * @memberof 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 (callback) { + for (var i = 0, ii = this._dimensions.length; i < ii; i++) { + callback(this._dimensions[i], i, this); + } + }; - // set subset - 'Array, Index, any': function (value, index, replacement) { - return matrix$$1(clone$3(value)) - .subset(index, replacement, undefined) - .valueOf(); - }, + /** + * Retrieve the dimension for the given index + * @memberof Index + * @param {Number} dim Number of the dimension + * @returns {Range | null} range + */ + Index.prototype.dimension = function (dim) { + return this._dimensions[dim] || null; + }; - 'Array, Index, any, any': function (value, index, replacement, defaultValue) { - return matrix$$1(clone$3(value)) - .subset(index, replacement, defaultValue) - .valueOf(); - }, + /** + * Test whether this index contains an object property + * @returns {boolean} Returns true if the index is an object property + */ + Index.prototype.isObjectProperty = function () { + return this._dimensions.length === 1 && typeof this._dimensions[0] === 'string'; + }; - 'Matrix, Index, any': function (value, index, replacement) { - return value.clone().subset(index, replacement); - }, + /** + * Returns the object property name when the Index holds a single object property, + * else returns null + * @returns {string | null} + */ + Index.prototype.getObjectProperty = function () { + return this.isObjectProperty() ? this._dimensions[0] : null; + }; - 'Matrix, Index, any, any': function (value, index, replacement, defaultValue) { - return value.clone().subset(index, replacement, defaultValue); - }, + /** + * Test whether this index contains only a single value. + * + * This is the case when the index is created with only scalar values as ranges, + * not for ranges resolving into a single value. + * @memberof Index + * @return {boolean} isScalar + */ + Index.prototype.isScalar = function () { + return this._isScalar; + }; - 'string, Index, string': _setSubstring, - 'string, Index, string, string': _setSubstring, - 'Object, Index, any': _setObjectProperty - }); + /** + * Expand the Index into an array. + * For example new Index([0,3], [2,7]) returns [[0,1,2], [2,3,4,5,6]] + * @memberof Index + * @returns {Array} array + */ + Index.prototype.toArray = function () { + var array = []; + for (var i = 0, ii = this._dimensions.length; i < ii; i++) { + var dimension = this._dimensions[i]; + array.push((typeof dimension === 'string') ? dimension : dimension.toArray()); + } + return array; + }; - subset.toTex = undefined; // use default template + /** + * Get the primitive value of the Index, a two dimensional array. + * Equivalent to Index.toArray(). + * @memberof Index + * @returns {Array} array + */ + Index.prototype.valueOf = Index.prototype.toArray; - return subset; + /** + * Get the string representation of the index, for example '[2:6]' or '[0:2:10, 4:7, [1,2,3]]' + * @memberof Index + * @returns {String} str + */ + Index.prototype.toString = function () { + var strings = []; - /** - * Retrieve a subset of a string - * @param {string} str string from which to get a substring - * @param {Index} index An index containing ranges for each dimension - * @returns {string} substring - * @private - */ - function _getSubstring(str, index) { - if (!type.isIndex(index)) { - // TODO: better error message - throw new TypeError('Index expected'); - } - if (index.size().length != 1) { - throw new DimensionError_1(index.size().length, 1); - } + for (var i = 0, ii = this._dimensions.length; i < ii; i++) { + var dimension = this._dimensions[i]; + if (typeof dimension === 'string') { + strings.push(JSON.stringify(dimension)); + } + else { + strings.push(dimension.toString()); + } + } - // validate whether the range is out of range - var strLen = str.length; - validateIndex$2(index.min()[0], strLen); - validateIndex$2(index.max()[0], strLen); + return '[' + strings.join(', ') + ']'; + }; - var range = index.dimension(0); + /** + * Get a JSON representation of the Index + * @memberof Index + * @returns {Object} Returns a JSON object structured as: + * `{"mathjs": "Index", "ranges": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}` + */ + Index.prototype.toJSON = function () { + return { + mathjs: 'Index', + dimensions: this._dimensions + }; + }; - var substr = ''; - range.forEach(function (v) { - substr += str.charAt(v); - }); + /** + * Instantiate an Index from a JSON object + * @memberof Index + * @param {Object} json A JSON object structured as: + * `{"mathjs": "Index", "dimensions": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}` + * @return {Index} + */ + Index.fromJSON = function (json) { + return Index.create(json.dimensions); + }; - return substr; + return Index; } - /** - * Replace a substring in a string - * @param {string} str string to be replaced - * @param {Index} index An index containing ranges for each dimension - * @param {string} replacement Replacement string - * @param {string} [defaultValue] Default value to be uses when resizing - * the string. is ' ' by default - * @returns {string} result - * @private - */ - function _setSubstring(str, index, replacement, defaultValue) { - if (!index || index.isIndex !== true) { - // TODO: better error message - throw new TypeError('Index expected'); - } - if (index.size().length != 1) { - throw new DimensionError_1(index.size().length, 1); - } - if (defaultValue !== undefined) { - if (typeof defaultValue !== 'string' || defaultValue.length !== 1) { - throw new TypeError('Single character expected as defaultValue'); - } - } - else { - defaultValue = ' '; - } + var name$29 = 'Index'; + var path$10 = 'type'; + var factory_1$31 = factory$31; - var range = index.dimension(0); - var len = range.size()[0]; + var MatrixIndex = { + name: name$29, + path: path$10, + factory: factory_1$31 + }; - if (len != replacement.length) { - throw new DimensionError_1(range.size()[0], replacement.length); - } + function factory$32 (type, config, load, typed) { + /** + * 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] + * + * @class Range + * @constructor Range + * @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'); + } - // validate whether the range is out of range - var strLen = str.length; - validateIndex$2(index.min()[0]); - validateIndex$2(index.max()[0]); + if (start != null) { + if (type.isBigNumber(start)) + start = start.toNumber(); + else if (typeof start !== 'number') + throw new TypeError('Parameter start must be a number'); + } + if (end != null) { + if (type.isBigNumber(end)) + end = end.toNumber(); + else if (typeof end !== 'number') + throw new TypeError('Parameter end must be a number'); + } + if (step != null) { + if (type.isBigNumber(step)) + step = step.toNumber(); + else if (typeof step !== 'number') + throw new TypeError('Parameter step must be a number'); + } - // copy the string into an array with characters - var chars = []; - for (var i = 0; i < strLen; i++) { - chars[i] = str.charAt(i); + this.start = (start != null) ? parseFloat(start) : 0; + this.end = (end != null) ? parseFloat(end) : 0; + this.step = (step != null) ? parseFloat(step) : 1; } - range.forEach(function (v, i) { - chars[v] = replacement.charAt(i[0]); - }); + /** + * Attach type information + */ + Range.prototype.type = 'Range'; + Range.prototype.isRange = true; - // initialize undefined characters with a space - if (chars.length > strLen) { - for (i = strLen - 1, len = chars.length; i < len; i++) { - if (!chars[i]) { - chars[i] = defaultValue; - } + /** + * 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'. + * @memberof Range + * @param {string} str + * @return {Range | null} range + */ + Range.parse = function (str) { + if (typeof str !== 'string') { + return null; } - } - return chars.join(''); - } -} - -/** - * Retrieve a property from an object - * @param {Object} object - * @param {Index} index - * @return {*} Returns the value of the property - * @private - */ -function _getObjectProperty (object$$1, index) { - if (index.size().length !== 1) { - throw new DimensionError_1(index.size(), 1); - } - - var key = index.dimension(0); - if (typeof key !== 'string') { - throw new TypeError('String expected as index to retrieve an object property'); - } - - return getSafeProperty$1(object$$1, key); -} - -/** - * Set a property on an object - * @param {Object} object - * @param {Index} index - * @param {*} replacement - * @return {*} Returns the updated object - * @private - */ -function _setObjectProperty (object$$1, index, replacement) { - if (index.size().length !== 1) { - throw new DimensionError_1(index.size(), 1); - } + var args = str.split(':'); + var nums = args.map(function (arg) { + return parseFloat(arg); + }); - var key = index.dimension(0); - if (typeof key !== 'string') { - throw new TypeError('String expected as index to retrieve an object property'); - } + var invalid = nums.some(function (num) { + return isNaN(num); + }); + if (invalid) { + return null; + } - // clone the object, and apply the property to the clone - var updated = clone$3(object$$1); - setSafeProperty$1(updated, key, replacement); + 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; + } + }; - return updated; -} + /** + * Create a clone of the range + * @return {Range} clone + */ + Range.prototype.clone = function () { + return new Range(this.start, this.end, this.step); + }; -var name$39 = 'subset'; -var factory_1$42 = factory$43; + /** + * Retrieve the size of the range. + * Returns an array containing one number, the number of elements in the range. + * @memberof Range + * @returns {number[]} size + */ + Range.prototype.size = function () { + var len = 0, + start = this.start, + step = this.step, + end = this.end, + diff = end - start; -var subset$1 = { - name: name$39, - factory: factory_1$42 -}; + if (number.sign(step) == number.sign(diff)) { + len = Math.ceil((diff) / step); + } + else if (diff == 0) { + len = 0; + } -var errorTransform = error_transform.transform; -var getSafeProperty$2 = customs.getSafeProperty; + if (isNaN(len)) { + len = 0; + } + return [len]; + }; -function factory$44 (type, config, load, typed) { - var subset = load(subset$1); + /** + * Calculate the minimum value in the range + * @memberof Range + * @return {number | undefined} min + */ + Range.prototype.min = function () { + var size = this.size()[0]; - /** - * Retrieve part of an object: - * - * - Retrieve a property from an object - * - Retrieve a part of a string - * - Retrieve a matrix subset - * - * @param {Object | Array | Matrix | string} object - * @param {Index} index - * @return {Object | Array | Matrix | string} Returns the subset - */ - return function access(object, index) { - try { - if (Array.isArray(object)) { - return subset(object, index); - } - else if (object && typeof object.subset === 'function') { // Matrix - return object.subset(index); + if (size > 0) { + if (this.step > 0) { + // positive step + return this.start; + } + else { + // negative step + return this.start + (size - 1) * this.step; + } } - else if (typeof object === 'string') { - // TODO: move getStringSubset into a separate util file, use that - return subset(object, index); + else { + return undefined; } - else if (typeof object === 'object') { - if (!index.isObjectProperty()) { - throw new TypeError('Cannot apply a numeric index as object property'); - } + }; - return getSafeProperty$2(object, index.getObjectProperty()); + /** + * Calculate the maximum value in the range + * @memberof Range + * @return {number | undefined} max + */ + Range.prototype.max = function () { + 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 { - throw new TypeError('Cannot apply index: unsupported type of object'); + return undefined; } - } - catch (err) { - throw errorTransform(err); - } - } -} - -var factory_1$43 = factory$44; + }; -var access = { - factory: factory_1$43 -}; -var getSafeProperty$3 = customs.getSafeProperty; + /** + * Execute a callback function for each value in the range. + * @memberof Range + * @param {function} callback The callback method is invoked with three + * parameters: the value of the element, the index + * of the element, and the Range being traversed. + */ + Range.prototype.forEach = function (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++; + } + } + }; -function factory$45 (type, config, load, typed) { - var Node$$1 = load(Node); - var IndexNode$$1 = load(IndexNode); - var access$$1 = load(access); + /** + * Execute a callback function for each value in the Range, and return the + * results as an array + * @memberof 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. + * @returns {Array} array + */ + Range.prototype.map = function (callback) { + var array = []; + this.forEach(function (value, index, obj) { + array[index[0]] = callback(value, index, obj); + }); + return array; + }; - /** - * @constructor AccessorNode - * @extends {Node} - * Access an object property or get a matrix subset - * - * @param {Node} object The object from which to retrieve - * a property or subset. - * @param {IndexNode} index IndexNode containing ranges - */ - function AccessorNode(object, index) { - if (!(this instanceof AccessorNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + /** + * Create an Array with a copy of the Ranges data + * @memberof Range + * @returns {Array} array + */ + Range.prototype.toArray = function () { + var array = []; + this.forEach(function (value, index) { + array[index[0]] = value; + }); + return array; + }; - if (!type.isNode(object)) { - throw new TypeError('Node expected for parameter "object"'); - } - if (!type.isIndexNode(index)) { - throw new TypeError('IndexNode expected for parameter "index"'); - } + /** + * Get the primitive value of the Range, a one dimensional array + * @memberof Range + * @returns {Array} array + */ + Range.prototype.valueOf = function () { + // TODO: implement a caching mechanism for range.valueOf() + return this.toArray(); + }; - this.object = object || null; - this.index = index; + /** + * 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' + * @memberof Range + * @param {Object | number | function} [options] Formatting options. See + * lib/utils/number:format for a + * description of the available + * options. + * @returns {string} str + */ + Range.prototype.format = function (options) { + var str = number.format(this.start, options); - // readonly property name - Object.defineProperty(this, 'name', { - get: function () { - if (this.index) { - return (this.index.isObjectProperty()) - ? this.index.getObjectProperty() - : ''; - } - else { - return this.object.name || ''; - } - }.bind(this), - set: function () { - throw new Error('Cannot assign a new name, name is read-only'); + if (this.step != 1) { + str += ':' + number.format(this.step, options); } - }); - } - - AccessorNode.prototype = new Node$$1(); - - AccessorNode.prototype.type = 'AccessorNode'; + str += ':' + number.format(this.end, options); + return str; + }; - AccessorNode.prototype.isAccessorNode = true; + /** + * Get a string representation of the range. + * @memberof Range + * @returns {string} + */ + Range.prototype.toString = function () { + return this.format(); + }; - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - AccessorNode.prototype._compile = function (math, argNames) { - var evalObject = this.object._compile(math, argNames); - var evalIndex = this.index._compile(math, argNames); - - if (this.index.isObjectProperty()) { - var prop = this.index.getObjectProperty(); - return function evalAccessorNode(scope, args, context) { - return getSafeProperty$3(evalObject(scope, args, context), prop); - }; - } - else { - return function evalAccessorNode (scope, args, context) { - var object = evalObject(scope, args, context); - var index = evalIndex(scope, args, object); // we pass object here instead of context - return access$$1(object, index); + /** + * Get a JSON representation of the range + * @memberof Range + * @returns {Object} Returns a JSON object structured as: + * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}` + */ + Range.prototype.toJSON = function () { + return { + mathjs: 'Range', + start: this.start, + end: this.end, + step: this.step }; - } - }; + }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - AccessorNode.prototype.forEach = function (callback) { - callback(this.object, 'object', this); - callback(this.index, 'index', this); - }; + /** + * Instantiate a Range from a JSON object + * @memberof Range + * @param {Object} json A JSON object structured as: + * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}` + * @return {Range} + */ + Range.fromJSON = function (json) { + return new Range(json.start, json.end, json.step); + }; - /** - * Create a new AccessorNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {AccessorNode} Returns a transformed copy of the node - */ - AccessorNode.prototype.map = function (callback) { - return new AccessorNode( - this._ifNode(callback(this.object, 'object', this)), - this._ifNode(callback(this.index, 'index', this)) - ); - }; + return Range; + } - /** - * Create a clone of this node, a shallow copy - * @return {AccessorNode} - */ - AccessorNode.prototype.clone = function () { - return new AccessorNode(this.object, this.index); + var name$30 = 'Range'; + var path$11 = 'type'; + var factory_1$32 = factory$32; + + var Range = { + name: name$30, + path: path$11, + factory: factory_1$32 }; - /** - * Get string representation - * @param {Object} options - * @return {string} - */ - AccessorNode.prototype._toString = function (options) { - var object = this.object.toString(options); - if (needParenthesis(this.object)) { - object = '(' + object + ')'; - } + function factory$33 (type, config, load, typed) { + /** + * 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. + * + * Syntax: + * + * math.index(range1, range2, ...) + * + * Where each range can be any of: + * + * - A number + * - A string for getting/setting an object property + * - An instance of `Range` + * - A one-dimensional Array or a Matrix with numbers + * + * Indexes must be zero-based, integer numbers. + * + * Examples: + * + * var math = math.js + * + * var b = [1, 2, 3, 4, 5]; + * math.subset(b, math.index([1, 2, 3])); // returns [2, 3, 4] + * + * var a = math.matrix([[1, 2], [3, 4]]); + * a.subset(math.index(0, 1)); // returns 2 + * + * See also: + * + * bignumber, boolean, complex, matrix, number, string, unit + * + * @param {...*} ranges Zero or more ranges or numbers. + * @return {Index} Returns the created index + */ + return typed('index', { + '...number | string | BigNumber | Range | Array | Matrix': function (args) { + var ranges = args.map(function (arg) { + if (type.isBigNumber(arg)) { + return arg.toNumber(); // convert BigNumber to Number + } + else if (Array.isArray(arg) || type.isMatrix(arg)) { + return arg.map(function (elem) { + // convert BigNumber to Number + return type.isBigNumber(elem) ? elem.toNumber() : elem; + }); + } + else { + return arg; + } + }); - return object + this.index.toString(options); - }; + var res = new type.Index(); + type.Index.apply(res, ranges); + return res; + } + }); + } - /** - * Get HTML representation - * @param {Object} options - * @return {string} - */ - AccessorNode.prototype.toHTML = function (options) { - var object = this.object.toHTML(options); - if (needParenthesis(this.object)) { - object = '(' + object + ')'; - } + var name$31 = 'index'; + var factory_1$33 = factory$33; - return object + this.index.toHTML(options); + var _function$1 = { + name: name$31, + factory: factory_1$33 }; - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} - */ - AccessorNode.prototype._toTex = function (options) { - var object = this.object.toTex(options); - if (needParenthesis(this.object)) { - object = '\\left(' + object + '\\right)'; - } + function factory$34 (type, config, load, typed) { - return object + this.index.toTex(options); - }; + var SparseMatrix = type.SparseMatrix; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - AccessorNode.prototype.toJSON = function () { - return { - mathjs: 'AccessorNode', - object: this.object, - index: this.index + /** + * Create a Sparse 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. + * + * Syntax: + * + * math.sparse() // creates an empty sparse matrix. + * math.sparse(data) // creates a sparse matrix with initial data. + * math.sparse(data, 'number') // creates a sparse matrix with initial data, number datatype. + * + * Examples: + * + * var m = math.sparse([[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, matrix + * + * @param {Array | Matrix} [data] A two dimensional array + * + * @return {Matrix} The created matrix + */ + var sparse = typed('sparse', { + '': function () { + return new SparseMatrix([]); + }, + + 'string': function (datatype) { + return new SparseMatrix([], datatype); + }, + + 'Array | Matrix': function (data) { + return new SparseMatrix(data); + }, + + 'Array | Matrix, string': function (data, datatype) { + return new SparseMatrix(data, datatype); + } + }); + + sparse.toTex = { + 0: '\\begin{bsparse}\\end{bsparse}', + 1: '\\left(${args[0]}\\right)' }; - }; - /** - * Instantiate an AccessorNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "AccessorNode", object: ..., index: ...}`, - * where mathjs is optional - * @returns {AccessorNode} - */ - AccessorNode.fromJSON = function (json) { - return new AccessorNode(json.object, json.index); + return sparse; + } + + var name$32 = 'sparse'; + var factory_1$34 = factory$34; + + var sparse = { + name: name$32, + factory: factory_1$34 }; - /** - * Are parenthesis needed? - * @private - */ - function needParenthesis(node) { - // TODO: maybe make a method on the nodes which tells whether they need parenthesis? - return !( - type.isAccessorNode(node) || - type.isArrayNode(node) || - type.isConstantNode(node) || - type.isFunctionNode(node) || - type.isObjectNode(node) || - type.isParenthesisNode(node) || - type.isSymbolNode(node)); - } + var matrix$1 = [ + // types + Matrix, + DenseMatrix, + SparseMatrix, + Spa, + FibonacciHeap, + ImmutableDenseMatrix, + MatrixIndex, + Range, + + // construction functions + _function$1, + matrix, + sparse + ]; - return AccessorNode; -} + function factory$35 (type, config, load, typed) { + /** + * Create a number or convert a string, boolean, or unit to a number. + * When value is a matrix, all elements will be converted to number. + * + * Syntax: + * + * math.number(value) + * math.number(unit, valuelessUnit) + * + * Examples: + * + * math.number(2); // returns number 2 + * math.number('7.2'); // returns number 7.2 + * math.number(true); // returns number 1 + * math.number([true, false, true, true]); // returns [1, 0, 1, 1] + * math.number(math.unit('52cm'), 'm'); // returns 0.52 + * + * See also: + * + * bignumber, boolean, complex, index, matrix, string, unit + * + * @param {string | number | BigNumber | Fraction | boolean | Array | Matrix | Unit | null} [value] Value to be converted + * @param {Unit | string} [valuelessUnit] A valueless unit, used to convert a unit to a number + * @return {number | Array | Matrix} The created number + */ + var number = typed('number', { + '': function () { + return 0; + }, -var name$40 = 'AccessorNode'; -var path$16 = 'expression.node'; -var factory_1$44 = factory$45; + 'number': function (x) { + return x; + }, -var AccessorNode = { - name: name$40, - path: path$16, - factory: factory_1$44 -}; + 'string': function (x) { + var num = Number(x); + if (isNaN(num)) { + throw new SyntaxError('String "' + x + '" is no valid number'); + } + return num; + }, -var map$2 = array.map; + 'BigNumber': function (x) { + return x.toNumber(); + }, -function factory$46 (type, config, load, typed) { - var Node$$1 = load(Node); + 'Fraction': function (x) { + return x.valueOf(); + }, - /** - * @constructor ArrayNode - * @extends {Node} - * Holds an 1-dimensional array with items - * @param {Node[]} [items] 1 dimensional array with items - */ - function ArrayNode(items) { - if (!(this instanceof ArrayNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + 'Unit': function (x) { + throw new Error('Second argument with valueless unit expected'); + }, - this.items = items || []; + 'null': function (x) { + return 0; + }, - // validate input - if (!Array.isArray(this.items) || !this.items.every(type.isNode)) { - throw new TypeError('Array containing Nodes expected'); - } + 'Unit, string | Unit': function (unit, valuelessUnit) { + return unit.toNumber(valuelessUnit); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, number); + } + }); - // TODO: deprecated since v3, remove some day - var deprecated = function () { - throw new Error('Property `ArrayNode.nodes` is deprecated, use `ArrayNode.items` instead'); + number.toTex = { + 0: '0', + 1: '\\left(${args[0]}\\right)', + 2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)' }; - Object.defineProperty(this, 'nodes', { get: deprecated, set: deprecated }); - } - ArrayNode.prototype = new Node$$1(); + return number; + } - ArrayNode.prototype.type = 'ArrayNode'; + var name$33 = 'number'; + var factory_1$35 = factory$35; - ArrayNode.prototype.isArrayNode = true; + var number$3 = { + name: name$33, + factory: factory_1$35 + }; - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ArrayNode.prototype._compile = function (math, argNames) { - var evalItems = map$2(this.items, function (item) { - return item._compile(math, argNames); - }); + function factory$36 (type, config, load, typed) { + /** + * A ResultSet contains a list or results + * @class ResultSet + * @param {Array} entries + * @constructor ResultSet + */ + function ResultSet(entries) { + if (!(this instanceof ResultSet)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - var asMatrix = (math.config().matrix !== 'Array'); - if (asMatrix) { - var matrix = math.matrix; - return function evalArrayNode (scope, args, context) { - return matrix(map$2(evalItems, function (evalItem) { - return evalItem(scope, args, context); - })); - }; + this.entries = entries || []; } - else { - return function evalArrayNode (scope, args, context) { - return map$2(evalItems, function (evalItem) { - return evalItem(scope, args, context); - }); + + /** + * Attach type information + */ + ResultSet.prototype.type = 'ResultSet'; + ResultSet.prototype.isResultSet = true; + + /** + * Returns the array with results hold by this ResultSet + * @memberof ResultSet + * @returns {Array} entries + */ + ResultSet.prototype.valueOf = function () { + return this.entries; + }; + + /** + * Returns the stringified results of the ResultSet + * @memberof ResultSet + * @returns {string} string + */ + ResultSet.prototype.toString = function () { + return '[' + this.entries.join(', ') + ']'; + }; + + /** + * Get a JSON representation of the ResultSet + * @memberof ResultSet + * @returns {Object} Returns a JSON object structured as: + * `{"mathjs": "ResultSet", "entries": [...]}` + */ + ResultSet.prototype.toJSON = function () { + return { + mathjs: 'ResultSet', + entries: this.entries }; - } - }; + }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ArrayNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.items.length; i++) { - var node = this.items[i]; - callback(node, 'items[' + i + ']', this); - } - }; + /** + * Instantiate a ResultSet from a JSON object + * @memberof ResultSet + * @param {Object} json A JSON object structured as: + * `{"mathjs": "ResultSet", "entries": [...]}` + * @return {ResultSet} + */ + ResultSet.fromJSON = function (json) { + return new ResultSet(json.entries); + }; - /** - * Create a new ArrayNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {ArrayNode} Returns a transformed copy of the node - */ - ArrayNode.prototype.map = function (callback) { - var items = []; - for (var i = 0; i < this.items.length; i++) { - items[i] = this._ifNode(callback(this.items[i], 'items[' + i + ']', this)); - } - return new ArrayNode(items); - }; + return ResultSet; + } - /** - * Create a clone of this node, a shallow copy - * @return {ArrayNode} - */ - ArrayNode.prototype.clone = function() { - return new ArrayNode(this.items.slice(0)); + var name$34 = 'ResultSet'; + var path$12 = 'type'; + var factory_1$36 = factory$36; + + var ResultSet = { + name: name$34, + path: path$12, + factory: factory_1$36 }; - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - ArrayNode.prototype._toString = function(options) { - var items = this.items.map(function (node) { - return node.toString(options); + var resultset = [ + // type + ResultSet + ]; + + function factory$37 (type, config, load, typed) { + /** + * Create a string or convert any object into a string. + * Elements of Arrays and Matrices are processed element wise. + * + * Syntax: + * + * math.string(value) + * + * Examples: + * + * math.string(4.2); // returns string '4.2' + * math.string(math.complex(3, 2); // returns string '3 + 2i' + * + * var u = math.unit(5, 'km'); + * math.string(u.to('m')); // returns string '5000 m' + * + * math.string([true, false]); // returns ['true', 'false'] + * + * See also: + * + * bignumber, boolean, complex, index, matrix, number, unit + * + * @param {* | Array | Matrix | null} [value] A value to convert to a string + * @return {string | Array | Matrix} The created string + */ + var string = typed('string', { + '': function () { + return ''; + }, + + 'number': number.format, + + 'null': function (x) { + return 'null'; + }, + + 'boolean': function (x) { + return x + ''; + }, + + 'string': function (x) { + return x; + }, + + 'Array | Matrix': function (x) { + return deepMap(x, string); + }, + + 'any': function (x) { + return String(x); + } }); - return '[' + items.join(', ') + ']'; + + string.toTex = { + 0: '\\mathtt{""}', + 1: '\\mathrm{string}\\left(${args[0]}\\right)' + }; + + return string; + } + + var name$35 = 'string'; + var factory_1$37 = factory$37; + + var string$6 = { + name: name$35, + factory: factory_1$37 }; + var type = [ + bignumber$1, + boolean_1, + chain$1, + complex$3, + fraction$3, + matrix$1, + number$3, + resultset, + string$6, + ]; + + var constants = createCommonjsModule(function (module, exports) { + var memoize = _function.memoize; + /** - * Get a JSON representation of the node - * @returns {Object} + * Calculate BigNumber e + * @param {function} BigNumber BigNumber constructor + * @returns {BigNumber} Returns e */ - ArrayNode.prototype.toJSON = function () { - return { - mathjs: 'ArrayNode', - items: this.items - }; - }; + exports.e = memoize(function (BigNumber) { + return new BigNumber(1).exp(); + }, hasher); /** - * Instantiate an ArrayNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "ArrayNode", items: [...]}`, - * where mathjs is optional - * @returns {ArrayNode} + * Calculate BigNumber golden ratio, phi = (1+sqrt(5))/2 + * @param {function} BigNumber BigNumber constructor + * @returns {BigNumber} Returns phi */ - ArrayNode.fromJSON = function (json) { - return new ArrayNode(json.items); - }; + exports.phi = memoize(function (BigNumber) { + return new BigNumber(1).plus(new BigNumber(5).sqrt()).div(2); + }, hasher); /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override + * Calculate BigNumber pi. + * @param {function} BigNumber BigNumber constructor + * @returns {BigNumber} Returns pi */ - ArrayNode.prototype.toHTML = function(options) { - var items = this.items.map(function (node) { - return node.toHTML(options); - }); - return '[' + items.join(',') + ']'; - }; + exports.pi = memoize(function (BigNumber) { + return BigNumber.acos(-1); + }, hasher); /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str + * Calculate BigNumber tau, tau = 2 * pi + * @param {function} BigNumber BigNumber constructor + * @returns {BigNumber} Returns tau */ - ArrayNode.prototype._toTex = function(options) { - var s = '\\begin{bmatrix}'; + exports.tau = memoize(function (BigNumber) { + return exports.pi(BigNumber).times(2); + }, hasher); - this.items.forEach(function(node) { - if (node.items) { - s += node.items.map(function(childNode) { - return childNode.toTex(options); - }).join('&'); - } - else { - s += node.toTex(options); + /** + * Create a hash for a BigNumber constructor function. The created has is + * the configured precision + * @param {Array} args Supposed to contain a single entry with + * a BigNumber constructor + * @return {number} precision + * @private + */ + function hasher (args) { + return args[0].precision; + } + }); + var constants_1 = constants.e; + var constants_2 = constants.phi; + var constants_3 = constants.pi; + var constants_4 = constants.tau; + + function factory$38 (type, config, load, typed, math) { + // listen for changed in the configuration, automatically reload + // constants when needed + math.on('config', function (curr, prev) { + if (curr.number !== prev.number || curr.define_pi !== prev.define_pi + || curr.define_e !== prev.define_e || curr.define_i !== prev.define_i) { + factory$38(type, config, load, typed, math); } - - // new line - s += '\\\\'; }); - s += '\\end{bmatrix}'; - return s; - }; - return ArrayNode; -} + setConstant(math, 'true', true); + setConstant(math, 'false', false); + setConstant(math, 'null', null); + setConstant(math, 'uninitialized', 'Error: Constant uninitialized is removed since v4.0.0. Use null instead'); -var name$41 = 'ArrayNode'; -var path$17 = 'expression.node'; -var factory_1$45 = factory$46; + if (config.number === 'BigNumber') { + setConstant(math, 'Infinity', new type.BigNumber(Infinity)); + setConstant(math, 'NaN', new type.BigNumber(NaN)); -var ArrayNode = { - name: name$41, - path: path$17, - factory: factory_1$45 -}; + if(config.define_pi === false) + deleteConstant(math, 'pi'); + else + setLazyConstant(math, 'pi', function () {return constants.pi(type.BigNumber)}); + if(config.define_e === false) + deleteConstant(math, 'e'); + else + setLazyConstant(math, 'e', function () {return constants.e(type.BigNumber)}); + } + else { + setConstant(math, 'Infinity', Infinity); + setConstant(math, 'NaN', NaN); -var errorTransform$1 = error_transform.transform; -var setSafeProperty$2 = customs.setSafeProperty; + if(config.define_pi === false) + deleteConstant(math, 'pi'); + else + setConstant(math, 'pi', Math.PI); + if(config.define_e === false) + deleteConstant(math, 'e'); + else + setConstant(math, 'e', Math.E); + } -function factory$47 (type, config, load, typed) { - var subset = load(subset$1); - var matrix$$1 = load(matrix); + if(config.define_i===false) + deleteConstant(math, 'i'); + else + // complex i + setConstant(math, 'i', type.Complex.I); + + } + + // delete a constant in both math and mathWithTransform + function deleteConstant(math, name) { + delete math[name]; + delete math.expression.mathWithTransform[name]; + } + + // create a constant in both math and mathWithTransform + function setConstant(math, name, value) { + math[name] = value; + math.expression.mathWithTransform[name] = value; + } + + // create a lazy constant in both math and mathWithTransform + function setLazyConstant (math, name, resolver) { + object.lazy(math, name, resolver); + object.lazy(math.expression.mathWithTransform, name, resolver); + } + + const lazy$4 = false; // no lazy loading of constants, the constants themselves are lazy when needed + const math$5 = true; // request access to the math namespace + + var constants$1 = { factory: factory$38, lazy: lazy$4, math: math$5 }; + + var bignumber$2 = { + 'name': 'bignumber', + 'category': 'Construction', + 'syntax': [ + 'bignumber(x)' + ], + 'description': + 'Create a big number from a number or string.', + 'examples': [ + '0.1 + 0.2', + 'bignumber(0.1) + bignumber(0.2)', + 'bignumber("7.2")', + 'bignumber("7.2e500")', + 'bignumber([0.1, 0.2, 0.3])' + ], + 'seealso': [ + 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' + ] + }; + + var boolean_1$2 = { + 'name': 'boolean', + 'category': 'Construction', + 'syntax': [ + 'x', + 'boolean(x)' + ], + 'description': + 'Convert a string or number into a boolean.', + 'examples': [ + 'boolean(0)', + 'boolean(1)', + 'boolean(3)', + 'boolean("true")', + 'boolean("false")', + 'boolean([1, 0, 1, 1])' + ], + 'seealso': [ + 'bignumber', 'complex', 'index', 'matrix', 'number', 'string', 'unit' + ] + }; + + var complex$4 = { + 'name': 'complex', + 'category': 'Construction', + 'syntax': [ + 'complex()', + 'complex(re, im)', + 'complex(string)' + ], + 'description': + 'Create a complex number.', + 'examples': [ + 'complex()', + 'complex(2, 3)', + 'complex("7 - 2i")' + ], + 'seealso': [ + 'bignumber', 'boolean', 'index', 'matrix', 'number', 'string', 'unit' + ] + }; + + var createUnit = { + 'name': 'createUnit', + 'category': 'Construction', + 'syntax': [ + 'createUnit(definitions)', + 'createUnit(name, definition)' + ], + 'description': + 'Create a user-defined unit and register it with the Unit type.', + 'examples': [ + 'createUnit("foo")', + 'createUnit("knot", {definition: "0.514444444 m/s", aliases: ["knots", "kt", "kts"]})', + 'createUnit("mph", "1 mile/hour")' + ], + 'seealso': [ + 'unit', 'splitUnit' + ] + }; + + var fraction$4 = { + 'name': 'fraction', + 'category': 'Construction', + 'syntax': [ + 'fraction(num)', + 'fraction(num,den)' + ], + 'description': + 'Create a fraction from a number or from a numerator and denominator.', + 'examples': [ + 'fraction(0.125)', + 'fraction(1, 3) + fraction(2, 5)' + ], + 'seealso': [ + 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'string', 'unit' + ] + }; + + var construction = { + 'name': 'index', + 'category': 'Construction', + 'syntax': [ + '[start]', + '[start:end]', + '[start:step:end]', + '[start1, start 2, ...]', + '[start1:end1, start2:end2, ...]', + '[start1:step1:end1, start2:step2:end2, ...]' + ], + 'description': + 'Create an index to get or replace a subset of a matrix', + 'examples': [ + '[]', + '[1, 2, 3]', + 'A = [1, 2, 3; 4, 5, 6]', + 'A[1, :]', + 'A[1, 2] = 50', + 'A[0:2, 0:2] = ones(2, 2)' + ], + 'seealso': [ + 'bignumber', 'boolean', 'complex', 'matrix,', 'number', 'range', 'string', 'unit' + ] + }; + + var matrix$2 = { + 'name': 'matrix', + 'category': 'Construction', + 'syntax': [ + '[]', + '[a1, b1, ...; a2, b2, ...]', + 'matrix()', + 'matrix("dense")', + 'matrix([...])' + ], + 'description': + 'Create a matrix.', + 'examples': [ + '[]', + '[1, 2, 3]', + '[1, 2, 3; 4, 5, 6]', + 'matrix()', + 'matrix([3, 4])', + 'matrix([3, 4; 5, 6], "sparse")', + 'matrix([3, 4; 5, 6], "sparse", "number")' + ], + 'seealso': [ + 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit', 'sparse' + ] + }; + + var number$4 = { + 'name': 'number', + 'category': 'Construction', + 'syntax': [ + 'x', + 'number(x)', + 'number(unit, valuelessUnit)' + ], + 'description': + 'Create a number or convert a string or boolean into a number.', + 'examples': [ + '2', + '2e3', + '4.05', + 'number(2)', + 'number("7.2")', + 'number(true)', + 'number([true, false, true, true])', + 'number(unit("52cm"), "m")' + ], + 'seealso': [ + 'bignumber', 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' + ] + }; + + var sparse$1 = { + 'name': 'sparse', + 'category': 'Construction', + 'syntax': [ + 'sparse()', + 'sparse([a1, b1, ...; a1, b2, ...])', + 'sparse([a1, b1, ...; a1, b2, ...], "number")' + ], + 'description': + 'Create a sparse matrix.', + 'examples': [ + 'sparse()', + 'sparse([3, 4; 5, 6])', + 'sparse([3, 0; 5, 0], "number")' + ], + 'seealso': [ + 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit', 'matrix' + ] + }; + + var splitUnit = { + 'name': 'splitUnit', + 'category': 'Construction', + 'syntax': [ + 'splitUnit(unit: Unit, parts: Unit[])' + ], + 'description': + 'Split a unit in an array of units whose sum is equal to the original unit.', + 'examples': [ + 'splitUnit(1 m, ["feet", "inch"])' + ], + 'seealso': [ + 'unit', 'createUnit' + ] + }; + + var string$7 = { + 'name': 'string', + 'category': 'Construction', + 'syntax': [ + '"text"', + 'string(x)' + ], + 'description': + 'Create a string or convert a value to a string', + 'examples': [ + '"Hello World!"', + 'string(4.2)', + 'string(3 + 2i)' + ], + 'seealso': [ + 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'number', 'unit' + ] + }; + + var unit = { + 'name': 'unit', + 'category': 'Construction', + 'syntax': [ + 'value unit', + 'unit(value, unit)', + 'unit(string)' + ], + 'description': + 'Create a unit.', + 'examples': [ + '5.5 mm', + '3 inch', + 'unit(7.1, "kilogram")', + 'unit("23 deg")' + ], + 'seealso': [ + 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'number', 'string' + ] + }; + + var e = { + 'name': 'e', + 'category': 'Constants', + 'syntax': [ + 'e' + ], + 'description': 'Euler\'s number, the base of the natural logarithm. Approximately equal to 2.71828', + 'examples': [ + 'e', + 'e ^ 2', + 'exp(2)', + 'log(e)' + ], + 'seealso': ['exp'] + }; + + var _false = { + 'name': 'false', + 'category': 'Constants', + 'syntax': [ + 'false' + ], + 'description': 'Boolean value false', + 'examples': [ + 'false' + ], + 'seealso': ['true'] + }; + + var i = { + 'name': 'i', + 'category': 'Constants', + 'syntax': [ + 'i' + ], + 'description': 'Imaginary unit, defined as i*i=-1. A complex number is described as a + b*i, where a is the real part, and b is the imaginary part.', + 'examples': [ + 'i', + 'i * i', + 'sqrt(-1)' + ], + 'seealso': [] + }; + + var _Infinity = { + 'name': 'Infinity', + 'category': 'Constants', + 'syntax': [ + 'Infinity' + ], + 'description': 'Infinity, a number which is larger than the maximum number that can be handled by a floating point number.', + 'examples': [ + 'Infinity', + '1 / 0' + ], + 'seealso': [] + }; + + var LN2 = { + 'name': 'LN2', + 'category': 'Constants', + 'syntax': [ + 'LN2' + ], + 'description': 'Returns the natural logarithm of 2, approximately equal to 0.693', + 'examples': [ + 'LN2', + 'log(2)' + ], + 'seealso': [] + }; + + var LN10 = { + 'name': 'LN10', + 'category': 'Constants', + 'syntax': [ + 'LN10' + ], + 'description': 'Returns the natural logarithm of 10, approximately equal to 2.302', + 'examples': [ + 'LN10', + 'log(10)' + ], + 'seealso': [] + }; + + var LOG2E = { + 'name': 'LOG2E', + 'category': 'Constants', + 'syntax': [ + 'LOG2E' + ], + 'description': 'Returns the base-2 logarithm of E, approximately equal to 1.442', + 'examples': [ + 'LOG2E', + 'log(e, 2)' + ], + 'seealso': [] + }; + + var LOG10E = { + 'name': 'LOG10E', + 'category': 'Constants', + 'syntax': [ + 'LOG10E' + ], + 'description': 'Returns the base-10 logarithm of E, approximately equal to 0.434', + 'examples': [ + 'LOG10E', + 'log(e, 10)' + ], + 'seealso': [] + }; + + var _NaN = { + 'name': 'NaN', + 'category': 'Constants', + 'syntax': [ + 'NaN' + ], + 'description': 'Not a number', + 'examples': [ + 'NaN', + '0 / 0' + ], + 'seealso': [] + }; + + var _null = { + 'name': 'null', + 'category': 'Constants', + 'syntax': [ + 'null' + ], + 'description': 'Value null', + 'examples': [ + 'null' + ], + 'seealso': ['true', 'false'] + }; + + var pi = { + 'name': 'pi', + 'category': 'Constants', + 'syntax': [ + 'pi' + ], + 'description': 'The number pi is a mathematical constant that is the ratio of a circle\'s circumference to its diameter, and is approximately equal to 3.14159', + 'examples': [ + 'pi', + 'sin(pi/2)' + ], + 'seealso': ['tau'] + }; + + var phi = { + 'name': 'phi', + 'category': 'Constants', + 'syntax': [ + 'phi' + ], + 'description': 'Phi is the golden ratio. Two quantities are in the golden ratio if their ratio is the same as the ratio of their sum to the larger of the two quantities. Phi is defined as `(1 + sqrt(5)) / 2` and is approximately 1.618034...', + 'examples': [ + 'phi' + ], + 'seealso': [] + }; + + var SQRT1_2 = { + 'name': 'SQRT1_2', + 'category': 'Constants', + 'syntax': [ + 'SQRT1_2' + ], + 'description': 'Returns the square root of 1/2, approximately equal to 0.707', + 'examples': [ + 'SQRT1_2', + 'sqrt(1/2)' + ], + 'seealso': [] + }; + + var SQRT2 = { + 'name': 'SQRT2', + 'category': 'Constants', + 'syntax': [ + 'SQRT2' + ], + 'description': 'Returns the square root of 2, approximately equal to 1.414', + 'examples': [ + 'SQRT2', + 'sqrt(2)' + ], + 'seealso': [] + }; + + var tau = { + 'name': 'tau', + 'category': 'Constants', + 'syntax': [ + 'tau' + ], + 'description': 'Tau is the ratio constant of a circle\'s circumference to radius, equal to 2 * pi, approximately 6.2832.', + 'examples': [ + 'tau', + '2 * pi' + ], + 'seealso': ['pi'] + }; + + var _true = { + 'name': 'true', + 'category': 'Constants', + 'syntax': [ + 'true' + ], + 'description': 'Boolean value true', + 'examples': [ + 'true' + ], + 'seealso': ['false'] + }; + + var version = { + 'name': 'version', + 'category': 'Constants', + 'syntax': [ + 'version' + ], + 'description': 'A string with the version number of math.js', + 'examples': [ + 'version' + ], + 'seealso': [] + }; + + var derivative = { + 'name': 'derivative', + 'category': 'Algebra', + 'syntax': [ + 'derivative(expr, variable)', + 'derivative(expr, variable, {simplify: boolean})' + ], + 'description': 'Takes the derivative of an expression expressed in parser Nodes. The derivative will be taken over the supplied variable in the second parameter. If there are multiple variables in the expression, it will return a partial derivative.', + 'examples': [ + 'derivative("2x^3", "x")', + 'derivative("2x^3", "x", {simplify: false})', + 'derivative("2x^2 + 3x + 4", "x")', + 'derivative("sin(2x)", "x")', + 'f = parse("x^2 + x")', + 'x = parse("x")', + 'df = derivative(f, x)', + 'df.eval({x: 3})' + ], + 'seealso': [ + 'simplify', 'parse', 'eval' + ] + }; + + var lsolve = { + 'name': 'lsolve', + 'category': 'Algebra', + 'syntax': [ + 'x=lsolve(L, b)' + ], + 'description': + 'Solves the linear system L * x = b where L is an [n x n] lower triangular matrix and b is a [n] column vector.', + 'examples': [ + 'a = [-2, 3; 2, 1]', + 'b = [11, 9]', + 'x = lsolve(a, b)' + ], + 'seealso': [ + 'lup', 'lusolve', 'usolve', 'matrix', 'sparse' + ] + }; + + var lup = { + 'name': 'lup', + 'category': 'Algebra', + 'syntax': [ + 'lup(m)' + ], + 'description': + 'Calculate the Matrix LU decomposition with partial pivoting. Matrix A is decomposed in three matrices (L, U, P) where P * A = L * U', + 'examples': [ + 'lup([[2, 1], [1, 4]])', + 'lup(matrix([[2, 1], [1, 4]]))', + 'lup(sparse([[2, 1], [1, 4]]))' + ], + 'seealso': [ + 'lusolve', 'lsolve', 'usolve', 'matrix', 'sparse', 'slu', 'qr' + ] + }; + + var lusolve = { + 'name': 'lusolve', + 'category': 'Algebra', + 'syntax': [ + 'x=lusolve(A, b)', + 'x=lusolve(lu, b)' + ], + 'description': 'Solves the linear system A * x = b where A is an [n x n] matrix and b is a [n] column vector.', + 'examples': [ + 'a = [-2, 3; 2, 1]', + 'b = [11, 9]', + 'x = lusolve(a, b)' + ], + 'seealso': [ + 'lup', 'slu', 'lsolve', 'usolve', 'matrix', 'sparse' + ] + }; + + var simplify = { + 'name': 'simplify', + 'category': 'Algebra', + 'syntax': [ + 'simplify(expr)', + 'simplify(expr, rules)' + ], + 'description': 'Simplify an expression tree.', + 'examples': [ + 'simplify("3 + 2 / 4")', + 'simplify("2x + x")', + 'f = parse("x * (x + 2 + x)")', + 'simplified = simplify(f)', + 'simplified.eval({x: 2})' + ], + 'seealso': [ + 'derivative', 'parse', 'eval' + ] + }; + + var rationalize = { + 'name': 'rationalize', + 'category': 'Algebra', + 'syntax': [ + 'rationalize(expr)', + 'rationalize(expr, scope)', + 'rationalize(expr, scope, detailed)' + ], + 'description': 'Transform a rationalizable expression in a rational fraction. If rational fraction is one variable polynomial then converts the numerator and denominator in canonical form, with decreasing exponents, returning the coefficients of numerator.', + 'examples': [ + 'rationalize("2x/y - y/(x+1)")', + 'rationalize("2x/y - y/(x+1)", true)', + ], + 'seealso': [ + 'simplify' + ] + }; + + var slu = { + 'name': 'slu', + 'category': 'Algebra', + 'syntax': [ + 'slu(A, order, threshold)' + ], + 'description': 'Calculate the Matrix LU decomposition with full pivoting. Matrix A is decomposed in two matrices (L, U) and two permutation vectors (pinv, q) where P * A * Q = L * U', + 'examples': [ + 'slu(sparse([4.5, 0, 3.2, 0; 3.1, 2.9, 0, 0.9; 0, 1.7, 3, 0; 3.5, 0.4, 0, 1]), 1, 0.001)' + ], + 'seealso': [ + 'lusolve', 'lsolve', 'usolve', 'matrix', 'sparse', 'lup', 'qr' + ] + }; + + var usolve = { + 'name': 'usolve', + 'category': 'Algebra', + 'syntax': [ + 'x=usolve(U, b)' + ], + 'description': + 'Solves the linear system U * x = b where U is an [n x n] upper triangular matrix and b is a [n] column vector.', + 'examples': [ + 'x=usolve(sparse([1, 1, 1, 1; 0, 1, 1, 1; 0, 0, 1, 1; 0, 0, 0, 1]), [1; 2; 3; 4])' + ], + 'seealso': [ + 'lup', 'lusolve', 'lsolve', 'matrix', 'sparse' + ] + }; + + var qr = { + 'name': 'qr', + 'category': 'Algebra', + 'syntax': [ + 'qr(A)' + ], + 'description': + 'Calculates the Matrix QR decomposition. Matrix `A` is decomposed in two matrices (`Q`, `R`) where `Q` is an orthogonal matrix and `R` is an upper triangular matrix.', + 'examples': [ + 'qr([[1, -1, 4], [1, 4, -2], [1, 4, 2], [1, -1, 0]])' + ], + 'seealso': [ + 'lup', 'slu', 'matrix' + ] + }; + + var abs = { + 'name': 'abs', + 'category': 'Arithmetic', + 'syntax': [ + 'abs(x)' + ], + 'description': 'Compute the absolute value.', + 'examples': [ + 'abs(3.5)', + 'abs(-4.2)' + ], + 'seealso': ['sign'] + }; + + var add$1 = { + 'name': 'add', + 'category': 'Operators', + 'syntax': [ + 'x + y', + 'add(x, y)' + ], + 'description': 'Add two values.', + 'examples': [ + 'a = 2.1 + 3.6', + 'a - 3.6', + '3 + 2i', + '3 cm + 2 inch', + '"2.3" + "4"' + ], + 'seealso': [ + 'subtract' + ] + }; + + var cbrt = { + 'name': 'cbrt', + 'category': 'Arithmetic', + 'syntax': [ + 'cbrt(x)', + 'cbrt(x, allRoots)' + ], + 'description': + 'Compute the cubic root value. If x = y * y * y, then y is the cubic root of x. When `x` is a number or complex number, an optional second argument `allRoots` can be provided to return all three cubic roots. If not provided, the principal root is returned', + 'examples': [ + 'cbrt(64)', + 'cube(4)', + 'cbrt(-8)', + 'cbrt(2 + 3i)', + 'cbrt(8i)', + 'cbrt(8i, true)', + 'cbrt(27 m^3)' + ], + 'seealso': [ + 'square', + 'sqrt', + 'cube', + 'multiply' + ] + }; + + var ceil = { + 'name': 'ceil', + 'category': 'Arithmetic', + 'syntax': [ + 'ceil(x)' + ], + 'description': + 'Round a value towards plus infinity. If x is complex, both real and imaginary part are rounded towards plus infinity.', + 'examples': [ + 'ceil(3.2)', + 'ceil(3.8)', + 'ceil(-4.2)' + ], + 'seealso': ['floor', 'fix', 'round'] + }; + + var cube = { + 'name': 'cube', + 'category': 'Arithmetic', + 'syntax': [ + 'cube(x)' + ], + 'description': 'Compute the cube of a value. The cube of x is x * x * x.', + 'examples': [ + 'cube(2)', + '2^3', + '2 * 2 * 2' + ], + 'seealso': [ + 'multiply', + 'square', + 'pow' + ] + }; + + var divide = { + 'name': 'divide', + 'category': 'Operators', + 'syntax': [ + 'x / y', + 'divide(x, y)' + ], + 'description': 'Divide two values.', + 'examples': [ + 'a = 2 / 3', + 'a * 3', + '4.5 / 2', + '3 + 4 / 2', + '(3 + 4) / 2', + '18 km / 4.5' + ], + 'seealso': [ + 'multiply' + ] + }; + + var dotDivide = { + 'name': 'dotDivide', + 'category': 'Operators', + 'syntax': [ + 'x ./ y', + 'dotDivide(x, y)' + ], + 'description': 'Divide two values element wise.', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'b = [2, 1, 1; 3, 2, 5]', + 'a ./ b' + ], + 'seealso': [ + 'multiply', + 'dotMultiply', + 'divide' + ] + }; + + var dotMultiply = { + 'name': 'dotMultiply', + 'category': 'Operators', + 'syntax': [ + 'x .* y', + 'dotMultiply(x, y)' + ], + 'description': 'Multiply two values element wise.', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'b = [2, 1, 1; 3, 2, 5]', + 'a .* b' + ], + 'seealso': [ + 'multiply', + 'divide', + 'dotDivide' + ] + }; + + var dotPow = { + 'name': 'dotpow', + 'category': 'Operators', + 'syntax': [ + 'x .^ y', + 'dotpow(x, y)' + ], + 'description': + 'Calculates the power of x to y element wise.', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'a .^ 2' + ], + 'seealso': [ + 'pow' + ] + }; + + var exp = { + 'name': 'exp', + 'category': 'Arithmetic', + 'syntax': [ + 'exp(x)' + ], + 'description': 'Calculate the exponent of a value.', + 'examples': [ + 'exp(1.3)', + 'e ^ 1.3', + 'log(exp(1.3))', + 'x = 2.4', + '(exp(i*x) == cos(x) + i*sin(x)) # Euler\'s formula' + ], + 'seealso': [ + 'expm', + 'expm1', + 'pow', + 'log' + ] + }; + + var expm = { + 'name': 'expm', + 'category': 'Arithmetic', + 'syntax': [ + 'exp(x)' + ], + 'description': 'Compute the matrix exponential, expm(A) = e^A. ' + + 'The matrix must be square. ' + + 'Not to be confused with exp(a), which performs element-wise exponentiation.', + 'examples': [ + 'expm([[0,2],[0,0]])' + ], + 'seealso': [ + 'exp' + ] + }; + + var expm1 = { + 'name': 'expm1', + 'category': 'Arithmetic', + 'syntax': [ + 'expm1(x)' + ], + 'description': 'Calculate the value of subtracting 1 from the exponential value.', + 'examples': [ + 'expm1(2)', + 'pow(e, 2) - 1', + 'log(expm1(2) + 1)' + ], + 'seealso': [ + 'exp', + 'pow', + 'log' + ] + }; + + var fix = { + 'name': 'fix', + 'category': 'Arithmetic', + 'syntax': [ + 'fix(x)' + ], + 'description': + 'Round a value towards zero. If x is complex, both real and imaginary part are rounded towards zero.', + 'examples': [ + 'fix(3.2)', + 'fix(3.8)', + 'fix(-4.2)', + 'fix(-4.8)' + ], + 'seealso': ['ceil', 'floor', 'round'] + }; + + var floor = { + 'name': 'floor', + 'category': 'Arithmetic', + 'syntax': [ + 'floor(x)' + ], + 'description': + 'Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.', + 'examples': [ + 'floor(3.2)', + 'floor(3.8)', + 'floor(-4.2)' + ], + 'seealso': ['ceil', 'fix', 'round'] + }; + + var gcd = { + 'name': 'gcd', + 'category': 'Arithmetic', + 'syntax': [ + 'gcd(a, b)', + 'gcd(a, b, c, ...)' + ], + 'description': 'Compute the greatest common divisor.', + 'examples': [ + 'gcd(8, 12)', + 'gcd(-4, 6)', + 'gcd(25, 15, -10)' + ], + 'seealso': [ 'lcm', 'xgcd' ] + }; + + var hypot = { + 'name': 'hypot', + 'category': 'Arithmetic', + 'syntax': [ + 'hypot(a, b, c, ...)', + 'hypot([a, b, c, ...])' + ], + 'description': 'Calculate the hypotenusa of a list with values. ', + 'examples': [ + 'hypot(3, 4)', + 'sqrt(3^2 + 4^2)', + 'hypot(-2)', + 'hypot([3, 4, 5])' + ], + 'seealso': [ 'abs', 'norm' ] + }; + + var lcm = { + 'name': 'lcm', + 'category': 'Arithmetic', + 'syntax': [ + 'lcm(x, y)' + ], + 'description': 'Compute the least common multiple.', + 'examples': [ + 'lcm(4, 6)', + 'lcm(6, 21)', + 'lcm(6, 21, 5)' + ], + 'seealso': [ 'gcd' ] + }; + + var log = { + 'name': 'log', + 'category': 'Arithmetic', + 'syntax': [ + 'log(x)', + 'log(x, base)' + ], + 'description': 'Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).', + 'examples': [ + 'log(3.5)', + 'a = log(2.4)', + 'exp(a)', + '10 ^ 4', + 'log(10000, 10)', + 'log(10000) / log(10)', + 'b = log(1024, 2)', + '2 ^ b' + ], + 'seealso': [ + 'exp', + 'log1p', + 'log2', + 'log10' + ] + }; + + var log2 = { + 'name': 'log2', + 'category': 'Arithmetic', + 'syntax': [ + 'log2(x)' + ], + 'description': 'Calculate the 2-base of a value. This is the same as calculating `log(x, 2)`.', + 'examples': [ + 'log2(0.03125)', + 'log2(16)', + 'log2(16) / log2(2)', + 'pow(2, 4)' + ], + 'seealso': [ + 'exp', + 'log1p', + 'log', + 'log10' + ] + }; + + var log1p = { + 'name': 'log1p', + 'category': 'Arithmetic', + 'syntax': [ + 'log1p(x)', + 'log1p(x, base)' + ], + 'description': 'Calculate the logarithm of a `value+1`', + 'examples': [ + 'log1p(2.5)', + 'exp(log1p(1.4))', + 'pow(10, 4)', + 'log1p(9999, 10)', + 'log1p(9999) / log(10)' + ], + 'seealso': [ + 'exp', + 'log', + 'log2', + 'log10' + ] + }; + + var log10 = { + 'name': 'log10', + 'category': 'Arithmetic', + 'syntax': [ + 'log10(x)' + ], + 'description': 'Compute the 10-base logarithm of a value.', + 'examples': [ + 'log10(0.00001)', + 'log10(10000)', + '10 ^ 4', + 'log(10000) / log(10)', + 'log(10000, 10)' + ], + 'seealso': [ + 'exp', + 'log' + ] + }; + + var mod = { + 'name': 'mod', + 'category': 'Operators', + 'syntax': [ + 'x % y', + 'x mod y', + 'mod(x, y)' + ], + 'description': + 'Calculates the modulus, the remainder of an integer division.', + 'examples': [ + '7 % 3', + '11 % 2', + '10 mod 4', + 'isOdd(x) = x % 2', + 'isOdd(2)', + 'isOdd(3)' + ], + 'seealso': ['divide'] + }; + + var multiply = { + 'name': 'multiply', + 'category': 'Operators', + 'syntax': [ + 'x * y', + 'multiply(x, y)' + ], + 'description': 'multiply two values.', + 'examples': [ + 'a = 2.1 * 3.4', + 'a / 3.4', + '2 * 3 + 4', + '2 * (3 + 4)', + '3 * 2.1 km' + ], + 'seealso': [ + 'divide' + ] + }; + + var norm = { + 'name': 'norm', + 'category': 'Arithmetic', + 'syntax': [ + 'norm(x)', + 'norm(x, p)' + ], + 'description': 'Calculate the norm of a number, vector or matrix.', + 'examples': [ + 'abs(-3.5)', + 'norm(-3.5)', + 'norm(3 - 4i)', + 'norm([1, 2, -3], Infinity)', + 'norm([1, 2, -3], -Infinity)', + 'norm([3, 4], 2)', + 'norm([[1, 2], [3, 4]], 1)', + 'norm([[1, 2], [3, 4]], "inf")', + 'norm([[1, 2], [3, 4]], "fro")' + ] + }; + + var nthRoot = { + 'name': 'nthRoot', + 'category': 'Arithmetic', + 'syntax': [ + 'nthRoot(a)', + 'nthRoot(a, root)' + ], + 'description': 'Calculate the nth root of a value. ' + + 'The principal nth root of a positive real number A, ' + + 'is the positive real solution of the equation "x^root = A".', + 'examples': [ + '4 ^ 3', + 'nthRoot(64, 3)', + 'nthRoot(9, 2)', + 'sqrt(9)' + ], + 'seealso': [ + 'sqrt', + 'pow' + ] + }; + + var pow = { + 'name': 'pow', + 'category': 'Operators', + 'syntax': [ + 'x ^ y', + 'pow(x, y)' + ], + 'description': + 'Calculates the power of x to y, x^y.', + 'examples': [ + '2^3', + '2*2*2', + '1 + e ^ (pi * i)' + ], + 'seealso': [ 'multiply' ] + }; + + var round = { + 'name': 'round', + 'category': 'Arithmetic', + 'syntax': [ + 'round(x)', + 'round(x, n)' + ], + 'description': + 'round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.', + 'examples': [ + 'round(3.2)', + 'round(3.8)', + 'round(-4.2)', + 'round(-4.8)', + 'round(pi, 3)', + 'round(123.45678, 2)' + ], + 'seealso': ['ceil', 'floor', 'fix'] + }; + + var sign = { + 'name': 'sign', + 'category': 'Arithmetic', + 'syntax': [ + 'sign(x)' + ], + 'description': + 'Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.', + 'examples': [ + 'sign(3.5)', + 'sign(-4.2)', + 'sign(0)' + ], + 'seealso': [ + 'abs' + ] + }; + + var sqrt = { + 'name': 'sqrt', + 'category': 'Arithmetic', + 'syntax': [ + 'sqrt(x)' + ], + 'description': + 'Compute the square root value. If x = y * y, then y is the square root of x.', + 'examples': [ + 'sqrt(25)', + '5 * 5', + 'sqrt(-1)' + ], + 'seealso': [ + 'square', + 'sqrtm', + 'multiply' + ] + }; + + var sqrtm = { + 'name': 'sqrtm', + 'category': 'Arithmetic', + 'syntax': [ + 'sqrtm(x)' + ], + 'description': + 'Calculate the principal square root of a square matrix. The principal square root matrix `X` of another matrix `A` is such that `X * X = A`.', + 'examples': [ + 'sqrtm([[1, 2], [3, 4]])' + ], + 'seealso': [ + 'sqrt', + 'abs', + 'square', + 'multiply' + ] + }; + + var square = { + 'name': 'square', + 'category': 'Arithmetic', + 'syntax': [ + 'square(x)' + ], + 'description': + 'Compute the square of a value. The square of x is x * x.', + 'examples': [ + 'square(3)', + 'sqrt(9)', + '3^2', + '3 * 3' + ], + 'seealso': [ + 'multiply', + 'pow', + 'sqrt', + 'cube' + ] + }; + + var subtract = { + 'name': 'subtract', + 'category': 'Operators', + 'syntax': [ + 'x - y', + 'subtract(x, y)' + ], + 'description': 'subtract two values.', + 'examples': [ + 'a = 5.3 - 2', + 'a + 2', + '2/3 - 1/6', + '2 * 3 - 3', + '2.1 km - 500m' + ], + 'seealso': [ + 'add' + ] + }; + + var unaryMinus = { + 'name': 'unaryMinus', + 'category': 'Operators', + 'syntax': [ + '-x', + 'unaryMinus(x)' + ], + 'description': + 'Inverse the sign of a value. Converts booleans and strings to numbers.', + 'examples': [ + '-4.5', + '-(-5.6)', + '-"22"' + ], + 'seealso': [ + 'add', 'subtract', 'unaryPlus' + ] + }; + + var unaryPlus = { + 'name': 'unaryPlus', + 'category': 'Operators', + 'syntax': [ + '+x', + 'unaryPlus(x)' + ], + 'description': + 'Converts booleans and strings to numbers.', + 'examples': [ + '+true', + '+"2"' + ], + 'seealso': [ + 'add', 'subtract', 'unaryMinus' + ] + }; + + var xgcd = { + 'name': 'xgcd', + 'category': 'Arithmetic', + 'syntax': [ + 'xgcd(a, b)' + ], + 'description': 'Calculate the extended greatest common divisor for two values. The result is an array [d, x, y] with 3 entries, where d is the greatest common divisor, and d = x * a + y * b.', + 'examples': [ + 'xgcd(8, 12)', + 'gcd(8, 12)', + 'xgcd(36163, 21199)' + ], + 'seealso': [ 'gcd', 'lcm' ] + }; + + var bitAnd = { + 'name': 'bitAnd', + 'category': 'Bitwise', + 'syntax': [ + 'x & y', + 'bitAnd(x, y)' + ], + 'description': 'Bitwise AND operation. Performs the logical AND operation on each pair of the corresponding bits of the two given values by multiplying them. If both bits in the compared position are 1, the bit in the resulting binary representation is 1, otherwise, the result is 0', + 'examples': [ + '5 & 3', + 'bitAnd(53, 131)', + '[1, 12, 31] & 42' + ], + 'seealso': [ + 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' + ] + }; + + var bitNot = { + 'name': 'bitNot', + 'category': 'Bitwise', + 'syntax': [ + '~x', + 'bitNot(x)' + ], + 'description': 'Bitwise NOT operation. Performs a logical negation on each bit of the given value. Bits that are 0 become 1, and those that are 1 become 0.', + 'examples': [ + '~1', + '~2', + 'bitNot([2, -3, 4])' + ], + 'seealso': [ + 'bitAnd', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' + ] + }; + + var bitOr = { + 'name': 'bitOr', + 'category': 'Bitwise', + 'syntax': [ + 'x | y', + 'bitOr(x, y)' + ], + 'description': 'Bitwise OR operation. Performs the logical inclusive OR operation on each pair of corresponding bits of the two given values. The result in each position is 1 if the first bit is 1 or the second bit is 1 or both bits are 1, otherwise, the result is 0.', + 'examples': [ + '5 | 3', + 'bitOr([1, 2, 3], 4)' + ], + 'seealso': [ + 'bitAnd', 'bitNot', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' + ] + }; + + var bitXor = { + 'name': 'bitXor', + 'category': 'Bitwise', + 'syntax': [ + 'bitXor(x, y)' + ], + 'description': 'Bitwise XOR operation, exclusive OR. Performs the logical exclusive OR operation on each pair of corresponding bits of the two given values. The result in each position is 1 if only the first bit is 1 or only the second bit is 1, but will be 0 if both are 0 or both are 1.', + 'examples': [ + 'bitOr(1, 2)', + 'bitXor([2, 3, 4], 4)' + ], + 'seealso': [ + 'bitAnd', 'bitNot', 'bitOr', 'leftShift', 'rightArithShift', 'rightLogShift' + ] + }; + + var leftShift = { + 'name': 'leftShift', + 'category': 'Bitwise', + 'syntax': [ + 'x << y', + 'leftShift(x, y)' + ], + 'description': 'Bitwise left logical shift of a value x by y number of bits.', + 'examples': [ + '4 << 1', + '8 >> 1' + ], + 'seealso': [ + 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'rightArithShift', 'rightLogShift' + ] + }; + + var rightArithShift = { + 'name': 'rightArithShift', + 'category': 'Bitwise', + 'syntax': [ + 'x >> y', + 'rightArithShift(x, y)' + ], + 'description': 'Bitwise right arithmetic shift of a value x by y number of bits.', + 'examples': [ + '8 >> 1', + '4 << 1', + '-12 >> 2' + ], + 'seealso': [ + 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightLogShift' + ] + }; + + var rightLogShift = { + 'name': 'rightLogShift', + 'category': 'Bitwise', + 'syntax': [ + 'x >>> y', + 'rightLogShift(x, y)' + ], + 'description': 'Bitwise right logical shift of a value x by y number of bits.', + 'examples': [ + '8 >>> 1', + '4 << 1', + '-12 >>> 2' + ], + 'seealso': [ + 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift' + ] + }; + + var bellNumbers = { + 'name': 'bellNumbers', + 'category': 'Combinatorics', + 'syntax': [ + 'bellNumbers(n)' + ], + 'description': 'The Bell Numbers count the number of partitions of a set. A partition is a pairwise disjoint subset of S whose union is S. `bellNumbers` only takes integer arguments. The following condition must be enforced: n >= 0.', + 'examples': [ + 'bellNumbers(3)', + 'bellNumbers(8)' + ], + 'seealso': ['stirlingS2'] + }; + + var catalan = { + 'name': 'catalan', + 'category': 'Combinatorics', + 'syntax': [ + 'catalan(n)' + ], + 'description': 'The Catalan Numbers enumerate combinatorial structures of many different types. catalan only takes integer arguments. The following condition must be enforced: n >= 0.', + 'examples': [ + 'catalan(3)', + 'catalan(8)' + ], + 'seealso': ['bellNumbers'] + }; + + var composition = { + 'name': 'composition', + 'category': 'Combinatorics', + 'syntax': [ + 'composition(n, k)' + ], + 'description': 'The composition counts of n into k parts. composition only takes integer arguments. The following condition must be enforced: k <= n.', + 'examples': [ + 'composition(5, 3)' + ], + 'seealso': ['combinations'] + }; + + var stirlingS2 = { + 'name': 'stirlingS2', + 'category': 'Combinatorics', + 'syntax': [ + 'stirlingS2(n, k)' + ], + 'description': 'he Stirling numbers of the second kind, counts the number of ways to partition a set of n labelled objects into k nonempty unlabelled subsets. `stirlingS2` only takes integer arguments. The following condition must be enforced: k <= n. If n = k or k = 1, then s(n,k) = 1.', + 'examples': [ + 'stirlingS2(5, 3)' + ], + 'seealso': ['bellNumbers'] + }; + + var config$1 = { + 'name': 'config', + 'category': 'Core', + 'syntax': [ + 'config()', + 'config(options)' + ], + 'description': 'Get configuration or change configuration.', + 'examples': [ + 'config()', + '1/3 + 1/4', + 'config({number: "Fraction"})', + '1/3 + 1/4' + ], + 'seealso': [] + }; + + var _import$1 = { + 'name': 'import', + 'category': 'Core', + 'syntax': [ + 'import(functions)', + 'import(functions, options)' + ], + 'description': 'Import functions or constants from an object.', + 'examples': [ + 'import({myFn: f(x)=x^2, myConstant: 32 })', + 'myFn(2)', + 'myConstant' + ], + 'seealso': [] + }; + + var typed$1 = { + 'name': 'typed', + 'category': 'Core', + 'syntax': [ + 'typed(signatures)', + 'typed(name, signatures)' + ], + 'description': 'Create a typed function.', + 'examples': [ + 'double = typed({ "number, number": f(x)=x+x })', + 'double(2)', + 'double("hello")' + ], + 'seealso': [] + }; + + var arg = { + 'name': 'arg', + 'category': 'Complex', + 'syntax': [ + 'arg(x)' + ], + 'description': + 'Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).', + 'examples': [ + 'arg(2 + 2i)', + 'atan2(3, 2)', + 'arg(2 + 3i)' + ], + 'seealso': [ + 're', + 'im', + 'conj', + 'abs' + ] + }; + + var conj = { + 'name': 'conj', + 'category': 'Complex', + 'syntax': [ + 'conj(x)' + ], + 'description': + 'Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.', + 'examples': [ + 'conj(2 + 3i)', + 'conj(2 - 3i)', + 'conj(-5.2i)' + ], + 'seealso': [ + 're', + 'im', + 'abs', + 'arg' + ] + }; + + var re = { + 'name': 're', + 'category': 'Complex', + 'syntax': [ + 're(x)' + ], + 'description': 'Get the real part of a complex number.', + 'examples': [ + 're(2 + 3i)', + 'im(2 + 3i)', + 're(-5.2i)', + 're(2.4)' + ], + 'seealso': [ + 'im', + 'conj', + 'abs', + 'arg' + ] + }; + + var im = { + 'name': 'im', + 'category': 'Complex', + 'syntax': [ + 'im(x)' + ], + 'description': 'Get the imaginary part of a complex number.', + 'examples': [ + 'im(2 + 3i)', + 're(2 + 3i)', + 'im(-5.2i)', + 'im(2.4)' + ], + 'seealso': [ + 're', + 'conj', + 'abs', + 'arg' + ] + }; + + var _eval = { + 'name': 'eval', + 'category': 'Expression', + 'syntax': [ + 'eval(expression)', + 'eval([expr1, expr2, expr3, ...])' + ], + 'description': 'Evaluate an expression or an array with expressions.', + 'examples': [ + 'eval("2 + 3")', + 'eval("sqrt(" + 4 + ")")' + ], + 'seealso': [] + }; + + var help = { + 'name': 'help', + 'category': 'Expression', + 'syntax': [ + 'help(object)', + 'help(string)' + ], + 'description': 'Display documentation on a function or data type.', + 'examples': [ + 'help(sqrt)', + 'help("complex")' + ], + 'seealso': [] + }; + + var distance = { + 'name': 'distance', + 'category': 'Geometry', + 'syntax': [ + 'distance([x1, y1], [x2, y2])', + 'distance([[x1, y1], [x2, y2])' + ], + 'description': 'Calculates the Euclidean distance between two points.', + 'examples': [ + 'distance([0,0], [4,4])', + 'distance([[0,0], [4,4]])' + ], + 'seealso': [] + }; + + var intersect = { + 'name': 'intersect', + 'category': 'Geometry', + 'syntax': [ + 'intersect(expr1, expr2, expr3, expr4)', + 'intersect(expr1, expr2, expr3)' + ], + 'description': 'Computes the intersection point of lines and/or planes.', + 'examples': [ + 'intersect([0, 0], [10, 10], [10, 0], [0, 10])', + 'intersect([1, 0, 1], [4, -2, 2], [1, 1, 1, 6])' + ], + 'seealso': [] + }; + + var and = { + 'name': 'and', + 'category': 'Logical', + 'syntax': [ + 'x and y', + 'and(x, y)' + ], + 'description': 'Logical and. Test whether two values are both defined with a nonzero/nonempty value.', + 'examples': [ + 'true and false', + 'true and true', + '2 and 4' + ], + 'seealso': [ + 'not', 'or', 'xor' + ] + }; + + var not = { + 'name': 'not', + 'category': 'Logical', + 'syntax': [ + 'not x', + 'not(x)' + ], + 'description': 'Logical not. Flips the boolean value of given argument.', + 'examples': [ + 'not true', + 'not false', + 'not 2', + 'not 0' + ], + 'seealso': [ + 'and', 'or', 'xor' + ] + }; + + var or = { + 'name': 'or', + 'category': 'Logical', + 'syntax': [ + 'x or y', + 'or(x, y)' + ], + 'description': 'Logical or. Test if at least one value is defined with a nonzero/nonempty value.', + 'examples': [ + 'true or false', + 'false or false', + '0 or 4' + ], + 'seealso': [ + 'not', 'and', 'xor' + ] + }; + + var xor = { + 'name': 'xor', + 'category': 'Logical', + 'syntax': [ + 'x xor y', + 'xor(x, y)' + ], + 'description': 'Logical exclusive or, xor. Test whether one and only one value is defined with a nonzero/nonempty value.', + 'examples': [ + 'true xor false', + 'false xor false', + 'true xor true', + '0 xor 4' + ], + 'seealso': [ + 'not', 'and', 'or' + ] + }; + + var concat = { + 'name': 'concat', + 'category': 'Matrix', + 'syntax': [ + 'concat(A, B, C, ...)', + 'concat(A, B, C, ..., dim)' + ], + 'description': 'Concatenate matrices. By default, the matrices are concatenated by the last dimension. The dimension on which to concatenate can be provided as last argument.', + 'examples': [ + 'A = [1, 2; 5, 6]', + 'B = [3, 4; 7, 8]', + 'concat(A, B)', + 'concat(A, B, 1)', + 'concat(A, B, 2)' + ], + 'seealso': [ + 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var cross = { + 'name': 'cross', + 'category': 'Matrix', + 'syntax': [ + 'cross(A, B)' + ], + 'description': 'Calculate the cross product for two vectors in three dimensional space.', + 'examples': [ + 'cross([1, 1, 0], [0, 1, 1])', + 'cross([3, -3, 1], [4, 9, 2])', + 'cross([2, 3, 4], [5, 6, 7])' + ], + 'seealso': [ + 'multiply', + 'dot' + ] + }; + + var det = { + 'name': 'det', + 'category': 'Matrix', + 'syntax': [ + 'det(x)' + ], + 'description': 'Calculate the determinant of a matrix', + 'examples': [ + 'det([1, 2; 3, 4])', + 'det([-2, 2, 3; -1, 1, 3; 2, 0, -1])' + ], + 'seealso': [ + 'concat', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var diag = { + 'name': 'diag', + 'category': 'Matrix', + 'syntax': [ + 'diag(x)', + 'diag(x, k)' + ], + 'description': 'Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned. When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.', + 'examples': [ + 'diag(1:3)', + 'diag(1:3, 1)', + 'a = [1, 2, 3; 4, 5, 6; 7, 8, 9]', + 'diag(a)' + ], + 'seealso': [ + 'concat', 'det', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var dot = { + 'name': 'dot', + 'category': 'Matrix', + 'syntax': [ + 'dot(A, B)', + 'A * B' + ], + 'description': 'Calculate the dot product of two vectors. ' + + 'The dot product of A = [a1, a2, a3, ..., an] and B = [b1, b2, b3, ..., bn] ' + + 'is defined as dot(A, B) = a1 * b1 + a2 * b2 + a3 * b3 + ... + an * bn', + 'examples': [ + 'dot([2, 4, 1], [2, 2, 3])', + '[2, 4, 1] * [2, 2, 3]' + ], + 'seealso': [ + 'multiply', + 'cross' + ] + }; + + var eye = { + 'name': 'eye', + 'category': 'Matrix', + 'syntax': [ + 'eye(n)', + 'eye(m, n)', + 'eye([m, n])' + ], + 'description': 'Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.', + 'examples': [ + 'eye(3)', + 'eye(3, 5)', + 'a = [1, 2, 3; 4, 5, 6]', + 'eye(size(a))' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var filter = { + 'name': 'filter', + 'category': 'Matrix', + 'syntax': [ + 'filter(x, test)' + ], + 'description': 'Filter items in a matrix.', + 'examples': [ + 'isPositive(x) = x > 0', + 'filter([6, -2, -1, 4, 3], isPositive)', + 'filter([6, -2, 0, 1, 0], x != 0)' + ], + 'seealso': ['sort', 'map', 'forEach'] + }; + + var flatten$1 = { + 'name': 'flatten', + 'category': 'Matrix', + 'syntax': [ + 'flatten(x)' + ], + 'description': 'Flatten a multi dimensional matrix into a single dimensional matrix.', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'size(a)', + 'b = flatten(a)', + 'size(b)' + ], + 'seealso': [ + 'concat', 'resize', 'size', 'squeeze' + ] + }; + + var forEach = { + 'name': 'forEach', + 'category': 'Matrix', + 'syntax': [ + 'forEach(x, callback)' + ], + 'description': 'Iterates over all elements of a matrix/array, and executes the given callback function.', + 'examples': [ + 'forEach([1, 2, 3], function(val) { console.log(val) })' + ], + 'seealso': ['map', 'sort', 'filter'] + }; + + var inv = { + 'name': 'inv', + 'category': 'Matrix', + 'syntax': [ + 'inv(x)' + ], + 'description': 'Calculate the inverse of a matrix', + 'examples': [ + 'inv([1, 2; 3, 4])', + 'inv(4)', + '1 / 4' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var kron = { + 'name': 'kron', + 'category': 'Matrix', + 'syntax': [ + 'kron(x, y)' + ], + 'description': 'Calculates the kronecker product of 2 matrices or vectors.', + 'examples': [ + 'kron([[1, 0], [0, 1]], [[1, 2], [3, 4]])', + 'kron([1,1], [2,3,4])' + ], + 'seealso': [ + 'multiply', 'dot', 'cross' + ] + }; + + var map = { + 'name': 'map', + 'category': 'Matrix', + 'syntax': [ + 'map(x, callback)' + ], + 'description': 'Create a new matrix or array with the results of the callback function executed on each entry of the matrix/array.', + 'examples': [ + 'map([1, 2, 3], square)' + ], + 'seealso': ['filter', 'forEach'] + }; + + var ones = { + 'name': 'ones', + 'category': 'Matrix', + 'syntax': [ + 'ones(m)', + 'ones(m, n)', + 'ones(m, n, p, ...)', + 'ones([m])', + 'ones([m, n])', + 'ones([m, n, p, ...])' + ], + 'description': 'Create a matrix containing ones.', + 'examples': [ + 'ones(3)', + 'ones(3, 5)', + 'ones([2,3]) * 4.5', + 'a = [1, 2, 3; 4, 5, 6]', + 'ones(size(a))' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var partitionSelect = { + 'name': 'partitionSelect', + 'category': 'Matrix', + 'syntax': [ + 'partitionSelect(x, k)', + 'partitionSelect(x, k, compare)' + ], + 'description': 'Partition-based selection of an array or 1D matrix. Will find the kth smallest value, and mutates the input array. Uses Quickselect.', + 'examples': [ + 'partitionSelect([5, 10, 1], 2)', + 'partitionSelect(["C", "B", "A", "D"], 1)' + ], + 'seealso': ['sort'] + }; + + var range = { + 'name': 'range', + 'category': 'Type', + 'syntax': [ + 'start:end', + 'start:step:end', + 'range(start, end)', + 'range(start, end, step)', + 'range(string)' + ], + 'description': + 'Create a range. Lower bound of the range is included, upper bound is excluded.', + 'examples': [ + '1:5', + '3:-1:-3', + 'range(3, 7)', + 'range(0, 12, 2)', + 'range("4:10")', + 'a = [1, 2, 3, 4; 5, 6, 7, 8]', + 'a[1:2, 1:2]' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var resize = { + 'name': 'resize', + 'category': 'Matrix', + 'syntax': [ + 'resize(x, size)', + 'resize(x, size, defaultValue)' + ], + 'description': 'Resize a matrix.', + 'examples': [ + 'resize([1,2,3,4,5], [3])', + 'resize([1,2,3], [5])', + 'resize([1,2,3], [5], -1)', + 'resize(2, [2, 3])', + 'resize("hello", [8], "!")' + ], + 'seealso': [ + 'size', 'subset', 'squeeze', 'reshape' + ] + }; + + var reshape = { + 'name': 'reshape', + 'category': 'Matrix', + 'syntax': [ + 'reshape(x, sizes)' + ], + 'description': 'Reshape a multi dimensional array to fit the specified dimensions.', + 'examples': [ + 'reshape([1, 2, 3, 4, 5, 6], [2, 3])', + 'reshape([[1, 2], [3, 4]], [1, 4])', + 'reshape([[1, 2], [3, 4]], [4])' + ], + 'seealso': [ + 'size', 'squeeze', 'resize' + ] + }; + + var size = { + 'name': 'size', + 'category': 'Matrix', + 'syntax': [ + 'size(x)' + ], + 'description': 'Calculate the size of a matrix.', + 'examples': [ + 'size(2.3)', + 'size("hello world")', + 'a = [1, 2; 3, 4; 5, 6]', + 'size(a)', + 'size(1:6)' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var sort = { + 'name': 'sort', + 'category': 'Matrix', + 'syntax': [ + 'sort(x)', + 'sort(x, compare)' + ], + 'description': 'Sort the items in a matrix. Compare can be a string "asc", "desc", "natural", or a custom sort function.', + 'examples': [ + 'sort([5, 10, 1])', + 'sort(["C", "B", "A", "D"])', + 'sortByLength(a, b) = size(a)[1] - size(b)[1]', + 'sort(["Langdon", "Tom", "Sara"], sortByLength)', + 'sort(["10", "1", "2"], "natural")' + ], + 'seealso': ['map', 'filter', 'forEach'] + }; + + var squeeze = { + 'name': 'squeeze', + 'category': 'Matrix', + 'syntax': [ + 'squeeze(x)' + ], + 'description': 'Remove inner and outer singleton dimensions from a matrix.', + 'examples': [ + 'a = zeros(3,2,1)', + 'size(squeeze(a))', + 'b = zeros(1,1,3)', + 'size(squeeze(b))' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'subset', 'trace', 'transpose', 'zeros' + ] + }; + + var subset = { + 'name': 'subset', + 'category': 'Matrix', + 'syntax': [ + 'value(index)', + 'value(index) = replacement', + 'subset(value, [index])', + 'subset(value, [index], replacement)' + ], + 'description': 'Get or set a subset of a matrix or string. ' + + 'Indexes are one-based. ' + + 'Both the ranges lower-bound and upper-bound are included.', + 'examples': [ + 'd = [1, 2; 3, 4]', + 'e = []', + 'e[1, 1:2] = [5, 6]', + 'e[2, :] = [7, 8]', + 'f = d * e', + 'f[2, 1]', + 'f[:, 1]' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'trace', 'transpose', 'zeros' + ] + }; + + var trace = { + 'name': 'trace', + 'category': 'Matrix', + 'syntax': [ + 'trace(A)' + ], + 'description': 'Calculate the trace of a matrix: the sum of the elements on the main diagonal of a square matrix.', + 'examples': [ + 'A = [1, 2, 3; -1, 2, 3; 2, 0, 3]', + 'trace(A)' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros' + ] + }; + + var transpose = { + 'name': 'transpose', + 'category': 'Matrix', + 'syntax': [ + 'x\'', + 'transpose(x)' + ], + 'description': 'Transpose a matrix', + 'examples': [ + 'a = [1, 2, 3; 4, 5, 6]', + 'a\'', + 'transpose(a)' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'zeros' + ] + }; + + var zeros = { + 'name': 'zeros', + 'category': 'Matrix', + 'syntax': [ + 'zeros(m)', + 'zeros(m, n)', + 'zeros(m, n, p, ...)', + 'zeros([m])', + 'zeros([m, n])', + 'zeros([m, n, p, ...])' + ], + 'description': 'Create a matrix containing zeros.', + 'examples': [ + 'zeros(3)', + 'zeros(3, 5)', + 'a = [1, 2, 3; 4, 5, 6]', + 'zeros(size(a))' + ], + 'seealso': [ + 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose' + ] + }; + + var combinations = { + 'name': 'combinations', + 'category': 'Probability', + 'syntax': [ + 'combinations(n, k)' + ], + 'description': 'Compute the number of combinations of n items taken k at a time', + 'examples': [ + 'combinations(7, 5)' + ], + 'seealso': ['permutations', 'factorial'] + }; + + var factorial = { + 'name': 'factorial', + 'category': 'Probability', + 'syntax': [ + 'n!', + 'factorial(n)' + ], + 'description': 'Compute the factorial of a value', + 'examples': [ + '5!', + '5 * 4 * 3 * 2 * 1', + '3!' + ], + 'seealso': ['combinations', 'permutations', 'gamma'] + }; + + var gamma = { + 'name': 'gamma', + 'category': 'Probability', + 'syntax': [ + 'gamma(n)' + ], + 'description': 'Compute the gamma function. For small values, the Lanczos approximation is used, and for large values the extended Stirling approximation.', + 'examples': [ + 'gamma(4)', + '3!', + 'gamma(1/2)', + 'sqrt(pi)' + ], + 'seealso': ['factorial'] + }; + + var kldivergence = { + 'name': 'kldivergence', + 'category': 'Probability', + 'syntax': [ + 'kldivergence(x, y)' + ], + 'description': 'Calculate the Kullback-Leibler (KL) divergence between two distributions.', + 'examples': [ + 'kldivergence([0.7,0.5,0.4], [0.2,0.9,0.5])' + ], + 'seealso': [] + }; + + var multinomial = { + 'name': 'multinomial', + 'category': 'Probability', + 'syntax': [ + 'multinomial(A)' + ], + 'description': 'Multinomial Coefficients compute the number of ways of picking a1, a2, ..., ai unordered outcomes from `n` possibilities. multinomial takes one array of integers as an argument. The following condition must be enforced: every ai > 0.', + 'examples': [ + 'multinomial([1, 2, 1])' + ], + 'seealso': ['combinations', 'factorial'] + }; + + var permutations = { + 'name': 'permutations', + 'category': 'Probability', + 'syntax': [ + 'permutations(n)', + 'permutations(n, k)' + ], + 'description': 'Compute the number of permutations of n items taken k at a time', + 'examples': [ + 'permutations(5)', + 'permutations(5, 3)' + ], + 'seealso': ['combinations', 'factorial'] + }; + + var pickRandom = { + 'name': 'pickRandom', + 'category': 'Probability', + 'syntax': [ + 'pickRandom(array)', + 'pickRandom(array, number)', + 'pickRandom(array, weights)', + 'pickRandom(array, number, weights)', + 'pickRandom(array, weights, number)' + ], + 'description': + 'Pick a random entry from a given array.', + 'examples': [ + 'pickRandom(0:10)', + 'pickRandom([1, 3, 1, 6])', + 'pickRandom([1, 3, 1, 6], 2)', + 'pickRandom([1, 3, 1, 6], [2, 3, 2, 1])', + 'pickRandom([1, 3, 1, 6], 2, [2, 3, 2, 1])', + 'pickRandom([1, 3, 1, 6], [2, 3, 2, 1], 2)' + ], + 'seealso': ['random', 'randomInt'] + }; + + var random = { + 'name': 'random', + 'category': 'Probability', + 'syntax': [ + 'random()', + 'random(max)', + 'random(min, max)', + 'random(size)', + 'random(size, max)', + 'random(size, min, max)' + ], + 'description': + 'Return a random number.', + 'examples': [ + 'random()', + 'random(10, 20)', + 'random([2, 3])' + ], + 'seealso': ['pickRandom', 'randomInt'] + }; + + var randomInt = { + 'name': 'randomInt', + 'category': 'Probability', + 'syntax': [ + 'randomInt(max)', + 'randomInt(min, max)', + 'randomInt(size)', + 'randomInt(size, max)', + 'randomInt(size, min, max)' + ], + 'description': + 'Return a random integer number', + 'examples': [ + 'randomInt(10, 20)', + 'randomInt([2, 3], 10)' + ], + 'seealso': ['pickRandom', 'random'] + }; + + var compare = { + 'name': 'compare', + 'category': 'Relational', + 'syntax': [ + 'compare(x, y)' + ], + 'description': + 'Compare two values. ' + + 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', + 'examples': [ + 'compare(2, 3)', + 'compare(3, 2)', + 'compare(2, 2)', + 'compare(5cm, 40mm)', + 'compare(2, [1, 2, 3])' + ], + 'seealso': [ + 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compareNatural', 'compareText' + ] + }; + + var compareNatural = { + 'name': 'compareNatural', + 'category': 'Relational', + 'syntax': [ + 'compareNatural(x, y)' + ], + 'description': + 'Compare two values of any type in a deterministic, natural way. ' + + 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', + 'examples': [ + 'compareNatural(2, 3)', + 'compareNatural(3, 2)', + 'compareNatural(2, 2)', + 'compareNatural(5cm, 40mm)', + 'compareNatural("2", "10")', + 'compareNatural(2 + 3i, 2 + 4i)', + 'compareNatural([1, 2, 4], [1, 2, 3])', + 'compareNatural([1, 5], [1, 2, 3])', + 'compareNatural([1, 2], [1, 2])', + 'compareNatural({a: 2}, {a: 4})' + ], + 'seealso': [ + 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compare', 'compareText' + ] + }; + + var compareText = { + 'name': 'compareText', + 'category': 'Relational', + 'syntax': [ + 'compareText(x, y)' + ], + 'description': + 'Compare two strings lexically. Comparison is case sensitive. ' + + 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', + 'examples': [ + 'compareText("B", "A")', + 'compareText("A", "B")', + 'compareText("A", "A")', + 'compareText("2", "10")', + 'compare("2", "10")', + 'compare(2, 10)', + 'compareNatural("2", "10")', + 'compareText("B", ["A", "B", "C"])' + ], + 'seealso': [ + 'compare', 'compareNatural' + ] + }; + + var deepEqual = { + 'name': 'deepEqual', + 'category': 'Relational', + 'syntax': [ + 'deepEqual(x, y)' + ], + 'description': + 'Check equality of two matrices element wise. Returns true if the size of both matrices is equal and when and each of the elements are equal.', + 'examples': [ + 'deepEqual([1,3,4], [1,3,4])', + 'deepEqual([1,3,4], [1,3])' + ], + 'seealso': [ + 'equal', 'unequal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare' + ] + }; + + var equal = { + 'name': 'equal', + 'category': 'Relational', + 'syntax': [ + 'x == y', + 'equal(x, y)' + ], + 'description': + 'Check equality of two values. Returns true if the values are equal, and false if not.', + 'examples': [ + '2+2 == 3', + '2+2 == 4', + 'a = 3.2', + 'b = 6-2.8', + 'a == b', + '50cm == 0.5m' + ], + 'seealso': [ + 'unequal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare', 'deepEqual', 'equalText' + ] + }; + + var equalText = { + 'name': 'equalText', + 'category': 'Relational', + 'syntax': [ + 'equalText(x, y)' + ], + 'description': + 'Check equality of two strings. Comparison is case sensitive. Returns true if the values are equal, and false if not.', + 'examples': [ + 'equalText("Hello", "Hello")', + 'equalText("a", "A")', + 'equal("2e3", "2000")', + 'equalText("2e3", "2000")', + 'equalText("B", ["A", "B", "C"])' + ], + 'seealso': [ + 'compare', 'compareNatural', 'compareText', 'equal' + ] + }; + + var larger$1 = { + 'name': 'larger', + 'category': 'Relational', + 'syntax': [ + 'x > y', + 'larger(x, y)' + ], + 'description': + 'Check if value x is larger than y. Returns true if x is larger than y, and false if not.', + 'examples': [ + '2 > 3', + '5 > 2*2', + 'a = 3.3', + 'b = 6-2.8', + '(a > b)', + '(b < a)', + '5 cm > 2 inch' + ], + 'seealso': [ + 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compare' + ] + }; + + var largerEq = { + 'name': 'largerEq', + 'category': 'Relational', + 'syntax': [ + 'x >= y', + 'largerEq(x, y)' + ], + 'description': + 'Check if value x is larger or equal to y. Returns true if x is larger or equal to y, and false if not.', + 'examples': [ + '2 >= 1+1', + '2 > 1+1', + 'a = 3.2', + 'b = 6-2.8', + '(a >= b)' + ], + 'seealso': [ + 'equal', 'unequal', 'smallerEq', 'smaller', 'compare' + ] + }; + + var smaller$1 = { + 'name': 'smaller', + 'category': 'Relational', + 'syntax': [ + 'x < y', + 'smaller(x, y)' + ], + 'description': + 'Check if value x is smaller than value y. Returns true if x is smaller than y, and false if not.', + 'examples': [ + '2 < 3', + '5 < 2*2', + 'a = 3.3', + 'b = 6-2.8', + '(a < b)', + '5 cm < 2 inch' + ], + 'seealso': [ + 'equal', 'unequal', 'larger', 'smallerEq', 'largerEq', 'compare' + ] + }; + + var smallerEq = { + 'name': 'smallerEq', + 'category': 'Relational', + 'syntax': [ + 'x <= y', + 'smallerEq(x, y)' + ], + 'description': + 'Check if value x is smaller or equal to value y. Returns true if x is smaller than y, and false if not.', + 'examples': [ + '2 <= 1+1', + '2 < 1+1', + 'a = 3.2', + 'b = 6-2.8', + '(a <= b)' + ], + 'seealso': [ + 'equal', 'unequal', 'larger', 'smaller', 'largerEq', 'compare' + ] + }; + + var unequal = { + 'name': 'unequal', + 'category': 'Relational', + 'syntax': [ + 'x != y', + 'unequal(x, y)' + ], + 'description': + 'Check unequality of two values. Returns true if the values are unequal, and false if they are equal.', + 'examples': [ + '2+2 != 3', + '2+2 != 4', + 'a = 3.2', + 'b = 6-2.8', + 'a != b', + '50cm != 0.5m', + '5 cm != 2 inch' + ], + 'seealso': [ + 'equal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare', 'deepEqual' + ] + }; + + var setCartesian = { + 'name': 'setCartesian', + 'category': 'Set', + 'syntax': [ + 'setCartesian(set1, set2)' + ], + 'description': + 'Create the cartesian product of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', + 'examples': [ + 'setCartesian([1, 2], [3, 4])' + ], + 'seealso': [ + 'setUnion', 'setIntersect', 'setDifference', 'setPowerset' + ] + }; + + var setDifference = { + 'name': 'setDifference', + 'category': 'Set', + 'syntax': [ + 'setDifference(set1, set2)' + ], + 'description': + 'Create the difference of two (multi)sets: every element of set1, that is not the element of set2. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', + 'examples': [ + 'setDifference([1, 2, 3, 4], [3, 4, 5, 6])', + 'setDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]])' + ], + 'seealso': [ + 'setUnion', 'setIntersect', 'setSymDifference' + ] + }; + + var setDistinct = { + 'name': 'setDistinct', + 'category': 'Set', + 'syntax': [ + 'setDistinct(set)' + ], + 'description': + 'Collect the distinct elements of a multiset. A multi-dimension array will be converted to a single-dimension array before the operation.', + 'examples': [ + 'setDistinct([1, 1, 1, 2, 2, 3])' + ], + 'seealso': [ + 'setMultiplicity' + ] + }; + + var setIntersect = { + 'name': 'setIntersect', + 'category': 'Set', + 'syntax': [ + 'setIntersect(set1, set2)' + ], + 'description': + 'Create the intersection of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', + 'examples': [ + 'setIntersect([1, 2, 3, 4], [3, 4, 5, 6])', + 'setIntersect([[1, 2], [3, 4]], [[3, 4], [5, 6]])' + ], + 'seealso': [ + 'setUnion', 'setDifference' + ] + }; + + var setIsSubset = { + 'name': 'setIsSubset', + 'category': 'Set', + 'syntax': [ + 'setIsSubset(set1, set2)' + ], + 'description': + 'Check whether a (multi)set is a subset of another (multi)set: every element of set1 is the element of set2. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', + 'examples': [ + 'setIsSubset([1, 2], [3, 4, 5, 6])', + 'setIsSubset([3, 4], [3, 4, 5, 6])' + ], + 'seealso': [ + 'setUnion', 'setIntersect', 'setDifference' + ] + }; + + var setMultiplicity = { + 'name': 'setMultiplicity', + 'category': 'Set', + 'syntax': [ + 'setMultiplicity(element, set)' + ], + 'description': + 'Count the multiplicity of an element in a multiset. A multi-dimension array will be converted to a single-dimension array before the operation.', + 'examples': [ + 'setMultiplicity(1, [1, 2, 2, 4])', + 'setMultiplicity(2, [1, 2, 2, 4])' + ], + 'seealso': [ + 'setDistinct', 'setSize' + ] + }; + + var setPowerset = { + 'name': 'setPowerset', + 'category': 'Set', + 'syntax': [ + 'setPowerset(set)' + ], + 'description': + 'Create the powerset of a (multi)set: the powerset contains very possible subsets of a (multi)set. A multi-dimension array will be converted to a single-dimension array before the operation.', + 'examples': [ + 'setPowerset([1, 2, 3])' + ], + 'seealso': [ + 'setCartesian' + ] + }; + + var setSize = { + 'name': 'setSize', + 'category': 'Set', + 'syntax': [ + 'setSize(set)', + 'setSize(set, unique)' + ], + 'description': + 'Count the number of elements of a (multi)set. When the second parameter "unique" is true, count only the unique values. A multi-dimension array will be converted to a single-dimension array before the operation.', + 'examples': [ + 'setSize([1, 2, 2, 4])', + 'setSize([1, 2, 2, 4], true)' + ], + 'seealso': [ + 'setUnion', 'setIntersect', 'setDifference' + ] + }; + + var setSymDifference = { + 'name': 'setSymDifference', + 'category': 'Set', + 'syntax': [ + 'setSymDifference(set1, set2)' + ], + 'description': + 'Create the symmetric difference of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', + 'examples': [ + 'setSymDifference([1, 2, 3, 4], [3, 4, 5, 6])', + 'setSymDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]])' + ], + 'seealso': [ + 'setUnion', 'setIntersect', 'setDifference' + ] + }; + + var setUnion = { + 'name': 'setUnion', + 'category': 'Set', + 'syntax': [ + 'setUnion(set1, set2)' + ], + 'description': + 'Create the union of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', + 'examples': [ + 'setUnion([1, 2, 3, 4], [3, 4, 5, 6])', + 'setUnion([[1, 2], [3, 4]], [[3, 4], [5, 6]])' + ], + 'seealso': [ + 'setIntersect', 'setDifference' + ] + }; + + var erf = { + 'name': 'erf', + 'category': 'Special', + 'syntax': [ + 'erf(x)' + ], + 'description': 'Compute the erf function of a value using a rational Chebyshev approximations for different intervals of x', + 'examples': [ + 'erf(0.2)', + 'erf(-0.5)', + 'erf(4)' + ], + 'seealso': [] + }; + + var mad = { + 'name': 'mad', + 'category': 'Statistics', + 'syntax': [ + 'mad(a, b, c, ...)', + 'mad(A)' + ], + 'description': 'Compute the median absolute deviation of a matrix or a list with values. The median absolute deviation is defined as the median of the absolute deviations from the median.', + 'examples': [ + 'mad(10, 20, 30)', + 'mad([1, 2, 3])' + ], + 'seealso': [ + 'mean', + 'median', + 'std', + 'abs' + ] + }; + + var max = { + 'name': 'max', + 'category': 'Statistics', + 'syntax': [ + 'max(a, b, c, ...)', + 'max(A)', + 'max(A, dim)' + ], + 'description': 'Compute the maximum value of a list of values.', + 'examples': [ + 'max(2, 3, 4, 1)', + 'max([2, 3, 4, 1])', + 'max([2, 5; 4, 3])', + 'max([2, 5; 4, 3], 1)', + 'max([2, 5; 4, 3], 2)', + 'max(2.7, 7.1, -4.5, 2.0, 4.1)', + 'min(2.7, 7.1, -4.5, 2.0, 4.1)' + ], + 'seealso': [ + 'mean', + 'median', + 'min', + 'prod', + 'std', + 'sum', + 'var' + ] + }; + + var mean = { + 'name': 'mean', + 'category': 'Statistics', + 'syntax': [ + 'mean(a, b, c, ...)', + 'mean(A)', + 'mean(A, dim)' + ], + 'description': 'Compute the arithmetic mean of a list of values.', + 'examples': [ + 'mean(2, 3, 4, 1)', + 'mean([2, 3, 4, 1])', + 'mean([2, 5; 4, 3])', + 'mean([2, 5; 4, 3], 1)', + 'mean([2, 5; 4, 3], 2)', + 'mean([1.0, 2.7, 3.2, 4.0])' + ], + 'seealso': [ + 'max', + 'median', + 'min', + 'prod', + 'std', + 'sum', + 'var' + ] + }; + + var median = { + 'name': 'median', + 'category': 'Statistics', + 'syntax': [ + 'median(a, b, c, ...)', + 'median(A)' + ], + 'description': 'Compute the median of all values. The values are sorted and the middle value is returned. In case of an even number of values, the average of the two middle values is returned.', + 'examples': [ + 'median(5, 2, 7)', + 'median([3, -1, 5, 7])' + ], + 'seealso': [ + 'max', + 'mean', + 'min', + 'prod', + 'std', + 'sum', + 'var', + 'quantileSeq' + ] + }; + + var min = { + 'name': 'min', + 'category': 'Statistics', + 'syntax': [ + 'min(a, b, c, ...)', + 'min(A)', + 'min(A, dim)' + ], + 'description': 'Compute the minimum value of a list of values.', + 'examples': [ + 'min(2, 3, 4, 1)', + 'min([2, 3, 4, 1])', + 'min([2, 5; 4, 3])', + 'min([2, 5; 4, 3], 1)', + 'min([2, 5; 4, 3], 2)', + 'min(2.7, 7.1, -4.5, 2.0, 4.1)', + 'max(2.7, 7.1, -4.5, 2.0, 4.1)' + ], + 'seealso': [ + 'max', + 'mean', + 'median', + 'prod', + 'std', + 'sum', + 'var' + ] + }; + + var mode = { + 'name': 'mode', + 'category': 'Statistics', + 'syntax': [ + 'mode(a, b, c, ...)', + 'mode(A)', + 'mode(A, a, b, B, c, ...)' + ], + 'description': 'Computes the mode of all values as an array. In case mode being more than one, multiple values are returned in an array.', + 'examples': [ + 'mode(2, 1, 4, 3, 1)', + 'mode([1, 2.7, 3.2, 4, 2.7])', + 'mode(1, 4, 6, 1, 6)' + ], + 'seealso': [ + 'max', + 'mean', + 'min', + 'median', + 'prod', + 'std', + 'sum', + 'var' + ] + }; + + var prod = { + 'name': 'prod', + 'category': 'Statistics', + 'syntax': [ + 'prod(a, b, c, ...)', + 'prod(A)' + ], + 'description': 'Compute the product of all values.', + 'examples': [ + 'prod(2, 3, 4)', + 'prod([2, 3, 4])', + 'prod([2, 5; 4, 3])' + ], + 'seealso': [ + 'max', + 'mean', + 'min', + 'median', + 'min', + 'std', + 'sum', + 'var' + ] + }; + + var quantileSeq = { + 'name': 'quantileSeq', + 'category': 'Statistics', + 'syntax': [ + 'quantileSeq(A, prob[, sorted])', + 'quantileSeq(A, [prob1, prob2, ...][, sorted])', + 'quantileSeq(A, N[, sorted])' + ], + 'description': 'Compute the prob order quantile of a matrix or a list with values. The sequence is sorted and the middle value is returned. Supported types of sequence values are: Number, BigNumber, Unit Supported types of probablity are: Number, BigNumber. \n\nIn case of a (multi dimensional) array or matrix, the prob order quantile of all elements will be calculated.', + 'examples': [ + 'quantileSeq([3, -1, 5, 7], 0.5)', + 'quantileSeq([3, -1, 5, 7], [1/3, 2/3])', + 'quantileSeq([3, -1, 5, 7], 2)', + 'quantileSeq([-1, 3, 5, 7], 0.5, true)' + ], + 'seealso': [ + 'mean', + 'median', + 'min', + 'max', + 'prod', + 'std', + 'sum', + 'var' + ] + }; + + var std = { + 'name': 'std', + 'category': 'Statistics', + 'syntax': [ + 'std(a, b, c, ...)', + 'std(A)', + 'std(A, normalization)' + ], + 'description': 'Compute the standard deviation of all values, defined as std(A) = sqrt(var(A)). Optional parameter normalization can be "unbiased" (default), "uncorrected", or "biased".', + 'examples': [ + 'std(2, 4, 6)', + 'std([2, 4, 6, 8])', + 'std([2, 4, 6, 8], "uncorrected")', + 'std([2, 4, 6, 8], "biased")', + 'std([1, 2, 3; 4, 5, 6])' + ], + 'seealso': [ + 'max', + 'mean', + 'min', + 'median', + 'min', + 'prod', + 'sum', + 'var' + ] + }; + + var sum = { + 'name': 'sum', + 'category': 'Statistics', + 'syntax': [ + 'sum(a, b, c, ...)', + 'sum(A)' + ], + 'description': 'Compute the sum of all values.', + 'examples': [ + 'sum(2, 3, 4, 1)', + 'sum([2, 3, 4, 1])', + 'sum([2, 5; 4, 3])' + ], + 'seealso': [ + 'max', + 'mean', + 'median', + 'min', + 'prod', + 'std', + 'sum', + 'var' + ] + }; + + var _var = { + 'name': 'var', + 'category': 'Statistics', + 'syntax': [ + 'var(a, b, c, ...)', + 'var(A)', + 'var(A, normalization)' + ], + 'description': 'Compute the variance of all values. Optional parameter normalization can be "unbiased" (default), "uncorrected", or "biased".', + 'examples': [ + 'var(2, 4, 6)', + 'var([2, 4, 6, 8])', + 'var([2, 4, 6, 8], "uncorrected")', + 'var([2, 4, 6, 8], "biased")', + 'var([1, 2, 3; 4, 5, 6])' + ], + 'seealso': [ + 'max', + 'mean', + 'min', + 'median', + 'min', + 'prod', + 'std', + 'sum' + ] + }; + + var acos = { + 'name': 'acos', + 'category': 'Trigonometry', + 'syntax': [ + 'acos(x)' + ], + 'description': 'Compute the inverse cosine of a value in radians.', + 'examples': [ + 'acos(0.5)', + 'acos(cos(2.3))' + ], + 'seealso': [ + 'cos', + 'atan', + 'asin' + ] + }; + + var acosh = { + 'name': 'acosh', + 'category': 'Trigonometry', + 'syntax': [ + 'acosh(x)' + ], + 'description': 'Calculate the hyperbolic arccos of a value, defined as `acosh(x) = ln(sqrt(x^2 - 1) + x)`.', + 'examples': [ + 'acosh(1.5)' + ], + 'seealso': [ + 'cosh', + 'asinh', + 'atanh' + ] + }; + + var acot = { + 'name': 'acot', + 'category': 'Trigonometry', + 'syntax': [ + 'acot(x)' + ], + 'description': 'Calculate the inverse cotangent of a value.', + 'examples': [ + 'acot(0.5)', + 'acot(cot(0.5))', + 'acot(2)' + ], + 'seealso': [ + 'cot', + 'atan' + ] + }; + + var acoth = { + 'name': 'acoth', + 'category': 'Trigonometry', + 'syntax': [ + 'acoth(x)' + ], + 'description': 'Calculate the hyperbolic arccotangent of a value, defined as `acoth(x) = (ln((x+1)/x) + ln(x/(x-1))) / 2`.', + 'examples': [ + 'acoth(2)', + 'acoth(0.5)' + ], + 'seealso': [ + 'acsch', + 'asech' + ] + }; + + var acsc = { + 'name': 'acsc', + 'category': 'Trigonometry', + 'syntax': [ + 'acsc(x)' + ], + 'description': 'Calculate the inverse cotangent of a value.', + 'examples': [ + 'acsc(2)', + 'acsc(csc(0.5))', + 'acsc(0.5)' + ], + 'seealso': [ + 'csc', + 'asin', + 'asec' + ] + }; + + var acsch = { + 'name': 'acsch', + 'category': 'Trigonometry', + 'syntax': [ + 'acsch(x)' + ], + 'description': 'Calculate the hyperbolic arccosecant of a value, defined as `acsch(x) = ln(1/x + sqrt(1/x^2 + 1))`.', + 'examples': [ + 'acsch(0.5)' + ], + 'seealso': [ + 'asech', + 'acoth' + ] + }; + + var asec = { + 'name': 'asec', + 'category': 'Trigonometry', + 'syntax': [ + 'asec(x)' + ], + 'description': 'Calculate the inverse secant of a value.', + 'examples': [ + 'asec(0.5)', + 'asec(sec(0.5))', + 'asec(2)' + ], + 'seealso': [ + 'acos', + 'acot', + 'acsc' + ] + }; + + var asech = { + 'name': 'asech', + 'category': 'Trigonometry', + 'syntax': [ + 'asech(x)' + ], + 'description': 'Calculate the inverse secant of a value.', + 'examples': [ + 'asech(0.5)' + ], + 'seealso': [ + 'acsch', + 'acoth' + ] + }; + + var asin = { + 'name': 'asin', + 'category': 'Trigonometry', + 'syntax': [ + 'asin(x)' + ], + 'description': 'Compute the inverse sine of a value in radians.', + 'examples': [ + 'asin(0.5)', + 'asin(sin(0.5))' + ], + 'seealso': [ + 'sin', + 'acos', + 'atan' + ] + }; + + var asinh = { + 'name': 'asinh', + 'category': 'Trigonometry', + 'syntax': [ + 'asinh(x)' + ], + 'description': 'Calculate the hyperbolic arcsine of a value, defined as `asinh(x) = ln(x + sqrt(x^2 + 1))`.', + 'examples': [ + 'asinh(0.5)' + ], + 'seealso': [ + 'acosh', + 'atanh' + ] + }; + + var atan = { + 'name': 'atan', + 'category': 'Trigonometry', + 'syntax': [ + 'atan(x)' + ], + 'description': 'Compute the inverse tangent of a value in radians.', + 'examples': [ + 'atan(0.5)', + 'atan(tan(0.5))' + ], + 'seealso': [ + 'tan', + 'acos', + 'asin' + ] + }; + + var atanh = { + 'name': 'atanh', + 'category': 'Trigonometry', + 'syntax': [ + 'atanh(x)' + ], + 'description': 'Calculate the hyperbolic arctangent of a value, defined as `atanh(x) = ln((1 + x)/(1 - x)) / 2`.', + 'examples': [ + 'atanh(0.5)' + ], + 'seealso': [ + 'acosh', + 'asinh' + ] + }; + + var atan2 = { + 'name': 'atan2', + 'category': 'Trigonometry', + 'syntax': [ + 'atan2(y, x)' + ], + 'description': + 'Computes the principal value of the arc tangent of y/x in radians.', + 'examples': [ + 'atan2(2, 2) / pi', + 'angle = 60 deg in rad', + 'x = cos(angle)', + 'y = sin(angle)', + 'atan2(y, x)' + ], + 'seealso': [ + 'sin', + 'cos', + 'tan' + ] + }; + + var cos = { + 'name': 'cos', + 'category': 'Trigonometry', + 'syntax': [ + 'cos(x)' + ], + 'description': 'Compute the cosine of x in radians.', + 'examples': [ + 'cos(2)', + 'cos(pi / 4) ^ 2', + 'cos(180 deg)', + 'cos(60 deg)', + 'sin(0.2)^2 + cos(0.2)^2' + ], + 'seealso': [ + 'acos', + 'sin', + 'tan' + ] + }; + + var cosh = { + 'name': 'cosh', + 'category': 'Trigonometry', + 'syntax': [ + 'cosh(x)' + ], + 'description': 'Compute the hyperbolic cosine of x in radians.', + 'examples': [ + 'cosh(0.5)' + ], + 'seealso': [ + 'sinh', + 'tanh', + 'coth' + ] + }; + + var cot = { + 'name': 'cot', + 'category': 'Trigonometry', + 'syntax': [ + 'cot(x)' + ], + 'description': 'Compute the cotangent of x in radians. Defined as 1/tan(x)', + 'examples': [ + 'cot(2)', + '1 / tan(2)' + ], + 'seealso': [ + 'sec', + 'csc', + 'tan' + ] + }; + + var coth = { + 'name': 'coth', + 'category': 'Trigonometry', + 'syntax': [ + 'coth(x)' + ], + 'description': 'Compute the hyperbolic cotangent of x in radians.', + 'examples': [ + 'coth(2)', + '1 / tanh(2)' + ], + 'seealso': [ + 'sech', + 'csch', + 'tanh' + ] + }; + + var csc = { + 'name': 'csc', + 'category': 'Trigonometry', + 'syntax': [ + 'csc(x)' + ], + 'description': 'Compute the cosecant of x in radians. Defined as 1/sin(x)', + 'examples': [ + 'csc(2)', + '1 / sin(2)' + ], + 'seealso': [ + 'sec', + 'cot', + 'sin' + ] + }; + + var csch = { + 'name': 'csch', + 'category': 'Trigonometry', + 'syntax': [ + 'csch(x)' + ], + 'description': 'Compute the hyperbolic cosecant of x in radians. Defined as 1/sinh(x)', + 'examples': [ + 'csch(2)', + '1 / sinh(2)' + ], + 'seealso': [ + 'sech', + 'coth', + 'sinh' + ] + }; + + var sec = { + 'name': 'sec', + 'category': 'Trigonometry', + 'syntax': [ + 'sec(x)' + ], + 'description': 'Compute the secant of x in radians. Defined as 1/cos(x)', + 'examples': [ + 'sec(2)', + '1 / cos(2)' + ], + 'seealso': [ + 'cot', + 'csc', + 'cos' + ] + }; + + var sech = { + 'name': 'sech', + 'category': 'Trigonometry', + 'syntax': [ + 'sech(x)' + ], + 'description': 'Compute the hyperbolic secant of x in radians. Defined as 1/cosh(x)', + 'examples': [ + 'sech(2)', + '1 / cosh(2)' + ], + 'seealso': [ + 'coth', + 'csch', + 'cosh' + ] + }; + + var sin = { + 'name': 'sin', + 'category': 'Trigonometry', + 'syntax': [ + 'sin(x)' + ], + 'description': 'Compute the sine of x in radians.', + 'examples': [ + 'sin(2)', + 'sin(pi / 4) ^ 2', + 'sin(90 deg)', + 'sin(30 deg)', + 'sin(0.2)^2 + cos(0.2)^2' + ], + 'seealso': [ + 'asin', + 'cos', + 'tan' + ] + }; + + var sinh = { + 'name': 'sinh', + 'category': 'Trigonometry', + 'syntax': [ + 'sinh(x)' + ], + 'description': 'Compute the hyperbolic sine of x in radians.', + 'examples': [ + 'sinh(0.5)' + ], + 'seealso': [ + 'cosh', + 'tanh' + ] + }; + + var tan = { + 'name': 'tan', + 'category': 'Trigonometry', + 'syntax': [ + 'tan(x)' + ], + 'description': 'Compute the tangent of x in radians.', + 'examples': [ + 'tan(0.5)', + 'sin(0.5) / cos(0.5)', + 'tan(pi / 4)', + 'tan(45 deg)' + ], + 'seealso': [ + 'atan', + 'sin', + 'cos' + ] + }; + + var tanh = { + 'name': 'tanh', + 'category': 'Trigonometry', + 'syntax': [ + 'tanh(x)' + ], + 'description': 'Compute the hyperbolic tangent of x in radians.', + 'examples': [ + 'tanh(0.5)', + 'sinh(0.5) / cosh(0.5)' + ], + 'seealso': [ + 'sinh', + 'cosh' + ] + }; + + var to = { + 'name': 'to', + 'category': 'Units', + 'syntax': [ + 'x to unit', + 'to(x, unit)' + ], + 'description': 'Change the unit of a value.', + 'examples': [ + '5 inch to cm', + '3.2kg to g', + '16 bytes in bits' + ], + 'seealso': [] + }; + + var clone$2 = { + 'name': 'clone', + 'category': 'Utils', + 'syntax': [ + 'clone(x)' + ], + 'description': 'Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices', + 'examples': [ + 'clone(3.5)', + 'clone(2 - 4i)', + 'clone(45 deg)', + 'clone([1, 2; 3, 4])', + 'clone("hello world")' + ], + 'seealso': [] + }; + + var format$2 = { + 'name': 'format', + 'category': 'Utils', + 'syntax': [ + 'format(value)', + 'format(value, precision)' + ], + 'description': 'Format a value of any type as string.', + 'examples': [ + 'format(2.3)', + 'format(3 - 4i)', + 'format([])', + 'format(pi, 3)' + ], + 'seealso': ['print'] + }; + + var _isNaN = { + 'name': 'isNaN', + 'category': 'Utils', + 'syntax': [ + 'isNaN(x)' + ], + 'description': 'Test whether a value is NaN (not a number)', + 'examples': [ + 'isNaN(2)', + 'isNaN(0 / 0)', + 'isNaN(NaN)', + 'isNaN(Infinity)' + ], + 'seealso': ['isNegative', 'isNumeric', 'isPositive', 'isZero'] + }; + + var isInteger$3 = { + 'name': 'isInteger', + 'category': 'Utils', + 'syntax': [ + 'isInteger(x)' + ], + 'description': 'Test whether a value is an integer number.', + 'examples': [ + 'isInteger(2)', + 'isInteger(3.5)', + 'isInteger([3, 0.5, -2])' + ], + 'seealso': ['isNegative', 'isNumeric', 'isPositive', 'isZero'] + }; + + var isNegative = { + 'name': 'isNegative', + 'category': 'Utils', + 'syntax': [ + 'isNegative(x)' + ], + 'description': 'Test whether a value is negative: smaller than zero.', + 'examples': [ + 'isNegative(2)', + 'isNegative(0)', + 'isNegative(-4)', + 'isNegative([3, 0.5, -2])' + ], + 'seealso': ['isInteger', 'isNumeric', 'isPositive', 'isZero'] + }; + + var isNumeric = { + 'name': 'isNumeric', + 'category': 'Utils', + 'syntax': [ + 'isNumeric(x)' + ], + 'description': 'Test whether a value is a numeric value. ' + + 'Returns true when the input is a number, BigNumber, Fraction, or boolean.', + 'examples': [ + 'isNumeric(2)', + 'isNumeric(0)', + 'isNumeric(bignumber(500))', + 'isNumeric(fraction(0.125))', + 'isNumeric("3")', + 'isNumeric(2 + 3i)', + 'isNumeric([2.3, "foo", false])' + ], + 'seealso': ['isInteger', 'isZero', 'isNegative', 'isPositive', 'isNaN'] + }; + + var isPositive = { + 'name': 'isPositive', + 'category': 'Utils', + 'syntax': [ + 'isPositive(x)' + ], + 'description': 'Test whether a value is positive: larger than zero.', + 'examples': [ + 'isPositive(2)', + 'isPositive(0)', + 'isPositive(-4)', + 'isPositive([3, 0.5, -2])' + ], + 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isZero'] + }; + + var isPrime = { + 'name': 'isPrime', + 'category': 'Utils', + 'syntax': [ + 'isPrime(x)' + ], + 'description': 'Test whether a value is prime: has no divisors other than itself and one.', + 'examples': [ + 'isPrime(3)', + 'isPrime(-2)', + 'isPrime([2, 17, 100])' + ], + 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isZero'] + }; + + var isZero = { + 'name': 'isZero', + 'category': 'Utils', + 'syntax': [ + 'isZero(x)' + ], + 'description': 'Test whether a value is zero.', + 'examples': [ + 'isZero(2)', + 'isZero(0)', + 'isZero(-4)', + 'isZero([3, 0, -2, 0])' + ], + 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isPositive'] + }; + + var _typeof = { + 'name': 'typeof', + 'category': 'Utils', + 'syntax': [ + 'typeof(x)' + ], + 'description': 'Get the type of a variable.', + 'examples': [ + 'typeof(3.5)', + 'typeof(2 - 4i)', + 'typeof(45 deg)', + 'typeof("hello world")' + ], + 'seealso': [] + }; + + function factory$39 (construction$$1, config, load, typed) { + var docs = {}; + + + // construction functions + docs.bignumber = bignumber$2; + docs['boolean'] = boolean_1$2; + docs.complex = complex$4; + docs.createUnit = createUnit; + docs.fraction = fraction$4; + docs.index = construction; + docs.matrix = matrix$2; + docs.number = number$4; + docs.sparse = sparse$1; + docs.splitUnit = splitUnit; + docs.string = string$7; + docs.unit = unit; + + // constants + docs.e = e; + docs.E = e; + docs['false'] = _false; + docs.i = i; + docs['Infinity'] = _Infinity; + docs.LN2 = LN2; + docs.LN10 = LN10; + docs.LOG2E = LOG2E; + docs.LOG10E = LOG10E; + docs.NaN = _NaN; + docs['null'] = _null; + docs.pi = pi; + docs.PI = pi; + docs.phi = phi; + docs.SQRT1_2 = SQRT1_2; + docs.SQRT2 = SQRT2; + docs.tau = tau; + docs['true'] = _true; + docs.version = version; + + // physical constants + // TODO: more detailed docs for physical constants + docs.speedOfLight = {description: 'Speed of light in vacuum', examples: ['speedOfLight']}; + docs.gravitationConstant = {description: 'Newtonian constant of gravitation', examples: ['gravitationConstant']}; + docs.planckConstant = {description: 'Planck constant', examples: ['planckConstant']}; + docs.reducedPlanckConstant = {description: 'Reduced Planck constant', examples: ['reducedPlanckConstant']}; + + docs.magneticConstant = {description: 'Magnetic constant (vacuum permeability)', examples: ['magneticConstant']}; + docs.electricConstant = {description: 'Electric constant (vacuum permeability)', examples: ['electricConstant']}; + docs.vacuumImpedance = {description: 'Characteristic impedance of vacuum', examples: ['vacuumImpedance']}; + docs.coulomb = {description: 'Coulomb\'s constant', examples: ['coulomb']}; + docs.elementaryCharge = {description: 'Elementary charge', examples: ['elementaryCharge']}; + docs.bohrMagneton = {description: 'Borh magneton', examples: ['bohrMagneton']}; + docs.conductanceQuantum = {description: 'Conductance quantum', examples: ['conductanceQuantum']}; + docs.inverseConductanceQuantum = {description: 'Inverse conductance quantum', examples: ['inverseConductanceQuantum']}; + //docs.josephson = {description: 'Josephson constant', examples: ['josephson']}; + docs.magneticFluxQuantum = {description: 'Magnetic flux quantum', examples: ['magneticFluxQuantum']}; + docs.nuclearMagneton = {description: 'Nuclear magneton', examples: ['nuclearMagneton']}; + docs.klitzing = {description: 'Von Klitzing constant', examples: ['klitzing']}; + + docs.bohrRadius = {description: 'Borh radius', examples: ['bohrRadius']}; + docs.classicalElectronRadius = {description: 'Classical electron radius', examples: ['classicalElectronRadius']}; + docs.electronMass = {description: 'Electron mass', examples: ['electronMass']}; + docs.fermiCoupling = {description: 'Fermi coupling constant', examples: ['fermiCoupling']}; + docs.fineStructure = {description: 'Fine-structure constant', examples: ['fineStructure']}; + docs.hartreeEnergy = {description: 'Hartree energy', examples: ['hartreeEnergy']}; + docs.protonMass = {description: 'Proton mass', examples: ['protonMass']}; + docs.deuteronMass = {description: 'Deuteron Mass', examples: ['deuteronMass']}; + docs.neutronMass = {description: 'Neutron mass', examples: ['neutronMass']}; + docs.quantumOfCirculation = {description: 'Quantum of circulation', examples: ['quantumOfCirculation']}; + docs.rydberg = {description: 'Rydberg constant', examples: ['rydberg']}; + docs.thomsonCrossSection = {description: 'Thomson cross section', examples: ['thomsonCrossSection']}; + docs.weakMixingAngle = {description: 'Weak mixing angle', examples: ['weakMixingAngle']}; + docs.efimovFactor = {description: 'Efimov factor', examples: ['efimovFactor']}; + + docs.atomicMass = {description: 'Atomic mass constant', examples: ['atomicMass']}; + docs.avogadro = {description: 'Avogadro\'s number', examples: ['avogadro']}; + docs.boltzmann = {description: 'Boltzmann constant', examples: ['boltzmann']}; + docs.faraday = {description: 'Faraday constant', examples: ['faraday']}; + docs.firstRadiation = {description: 'First radiation constant', examples: ['firstRadiation']}; + docs.loschmidt = {description: 'Loschmidt constant at T=273.15 K and p=101.325 kPa', examples: ['loschmidt']}; + docs.gasConstant = {description: 'Gas constant', examples: ['gasConstant']}; + docs.molarPlanckConstant = {description: 'Molar Planck constant', examples: ['molarPlanckConstant']}; + docs.molarVolume = {description: 'Molar volume of an ideal gas at T=273.15 K and p=101.325 kPa', examples: ['molarVolume']}; + docs.sackurTetrode = {description: 'Sackur-Tetrode constant at T=1 K and p=101.325 kPa', examples: ['sackurTetrode']}; + docs.secondRadiation = {description: 'Second radiation constant', examples: ['secondRadiation']}; + docs.stefanBoltzmann = {description: 'Stefan-Boltzmann constant', examples: ['stefanBoltzmann']}; + docs.wienDisplacement = {description: 'Wien displacement law constant', examples: ['wienDisplacement']}; + //docs.spectralRadiance = {description: 'First radiation constant for spectral radiance', examples: ['spectralRadiance']}; + + docs.molarMass = {description: 'Molar mass constant', examples: ['molarMass']}; + docs.molarMassC12 = {description: 'Molar mass constant of carbon-12', examples: ['molarMassC12']}; + docs.gravity = {description: 'Standard acceleration of gravity (standard acceleration of free-fall on Earth)', examples: ['gravity']}; + + docs.planckLength = {description: 'Planck length', examples: ['planckLength']}; + docs.planckMass = {description: 'Planck mass', examples: ['planckMass']}; + docs.planckTime = {description: 'Planck time', examples: ['planckTime']}; + docs.planckCharge = {description: 'Planck charge', examples: ['planckCharge']}; + docs.planckTemperature = {description: 'Planck temperature', examples: ['planckTemperature']}; + + // functions - algebra + docs.derivative = derivative; + docs.lsolve = lsolve; + docs.lup = lup; + docs.lusolve = lusolve; + docs.simplify = simplify; + docs.rationalize = rationalize; + docs.slu = slu; + docs.usolve = usolve; + docs.qr = qr; + + // functions - arithmetic + docs.abs = abs; + docs.add = add$1; + docs.cbrt = cbrt; + docs.ceil = ceil; + docs.cube = cube; + docs.divide = divide; + docs.dotDivide = dotDivide; + docs.dotMultiply = dotMultiply; + docs.dotPow = dotPow; + docs.exp = exp; + docs.expm = expm; + docs.expm1 = expm1; + docs.fix = fix; + docs.floor = floor; + docs.gcd = gcd; + docs.hypot = hypot; + docs.lcm = lcm; + docs.log = log; + docs.log2 = log2; + docs.log1p = log1p; + docs.log10 = log10; + docs.mod = mod; + docs.multiply = multiply; + docs.norm = norm; + docs.nthRoot = nthRoot; + docs.pow = pow; + docs.round = round; + docs.sign = sign; + docs.sqrt = sqrt; + docs.sqrtm = sqrtm; + docs.square = square; + docs.subtract = subtract; + docs.unaryMinus = unaryMinus; + docs.unaryPlus = unaryPlus; + docs.xgcd = xgcd; + + // functions - bitwise + docs.bitAnd = bitAnd; + docs.bitNot = bitNot; + docs.bitOr = bitOr; + docs.bitXor = bitXor; + docs.leftShift = leftShift; + docs.rightArithShift = rightArithShift; + docs.rightLogShift = rightLogShift; + + // functions - combinatorics + docs.bellNumbers = bellNumbers; + docs.catalan = catalan; + docs.composition = composition; + docs.stirlingS2 = stirlingS2; + + // functions - core + docs['config'] = config$1; + docs['import'] = _import$1; + docs['typed'] = typed$1; + + // functions - complex + docs.arg = arg; + docs.conj = conj; + docs.re = re; + docs.im = im; + + // functions - expression + docs['eval'] = _eval; + docs.help = help; + + // functions - geometry + docs.distance = distance; + docs.intersect = intersect; + + // functions - logical + docs['and'] = and; + docs['not'] = not; + docs['or'] = or; + docs['xor'] = xor; + + // functions - matrix + docs['concat'] = concat; + docs.cross = cross; + docs.det = det; + docs.diag = diag; + docs.dot = dot; + docs.eye = eye; + docs.filter = filter; + docs.flatten = flatten$1; + docs.forEach = forEach; + docs.inv = inv; + docs.kron = kron; + docs.map = map; + docs.ones = ones; + docs.partitionSelect = partitionSelect; + docs.range = range; + docs.resize = resize; + docs.reshape = reshape; + docs.size = size; + docs.sort = sort; + docs.squeeze = squeeze; + docs.subset = subset; + docs.trace = trace; + docs.transpose = transpose; + docs.zeros = zeros; + + // functions - probability + docs.combinations = combinations; + //docs.distribution = require('./function/probability/distribution'); + docs.factorial = factorial; + docs.gamma = gamma; + docs.kldivergence = kldivergence; + docs.multinomial = multinomial; + docs.permutations = permutations; + docs.pickRandom = pickRandom; + docs.random = random; + docs.randomInt = randomInt; + + // functions - relational + docs.compare = compare; + docs.compareNatural = compareNatural; + docs.compareText = compareText; + docs.deepEqual = deepEqual; + docs['equal'] = equal; + docs.equalText = equalText; + docs.larger = larger$1; + docs.largerEq = largerEq; + docs.smaller = smaller$1; + docs.smallerEq = smallerEq; + docs.unequal = unequal; + + // functions - set + docs.setCartesian = setCartesian; + docs.setDifference = setDifference; + docs.setDistinct = setDistinct; + docs.setIntersect = setIntersect; + docs.setIsSubset = setIsSubset; + docs.setMultiplicity = setMultiplicity; + docs.setPowerset = setPowerset; + docs.setSize = setSize; + docs.setSymDifference = setSymDifference; + docs.setUnion = setUnion; + + // functions - special + docs.erf = erf; + + // functions - statistics + docs.mad = mad; + docs.max = max; + docs.mean = mean; + docs.median = median; + docs.min = min; + docs.mode = mode; + docs.prod = prod; + docs.quantileSeq = quantileSeq; + docs.std = std; + docs.sum = sum; + docs['var'] = _var; + + // functions - trigonometry + docs.acos = acos; + docs.acosh = acosh; + docs.acot = acot; + docs.acoth = acoth; + docs.acsc = acsc; + docs.acsch = acsch; + docs.asec = asec; + docs.asech = asech; + docs.asin = asin; + docs.asinh = asinh; + docs.atan = atan; + docs.atanh = atanh; + docs.atan2 = atan2; + docs.cos = cos; + docs.cosh = cosh; + docs.cot = cot; + docs.coth = coth; + docs.csc = csc; + docs.csch = csch; + docs.sec = sec; + docs.sech = sech; + docs.sin = sin; + docs.sinh = sinh; + docs.tan = tan; + docs.tanh = tanh; + + // functions - units + docs.to = to; + + // functions - utils + docs.clone = clone$2; + docs.format = format$2; + docs.isNaN = _isNaN; + docs.isInteger = isInteger$3; + docs.isNegative = isNegative; + docs.isNumeric = isNumeric; + docs.isPositive = isPositive; + docs.isPrime = isPrime; + docs.isZero = isZero; + // docs.print = require('./function/utils/print'); // TODO: add documentation for print as soon as the parser supports objects. + docs['typeof'] = _typeof; + + return docs; + } + + var name$36 = 'docs'; + var path$13 = 'expression'; + var factory_1$38 = factory$39; + + var embeddedDocs = { + name: name$36, + path: path$13, + factory: factory_1$38 + }; + + function factory$40(type, config, load, typed) { + + // TODO: expose this function to mathjs, add documentation - /** - * Replace part of an object: - * - * - Assign a property to an object - * - Replace a part of a string - * - Replace a matrix subset - * - * @param {Object | Array | Matrix | string} object - * @param {Index} index - * @param {*} value - * @return {Object | Array | Matrix | string} Returns the original object - * except in case of a string - */ - // TODO: change assign to return the value instead of the object - return function assign(object, index, value) { - try { - if (Array.isArray(object)) { - return matrix$$1(object).subset(index, value).valueOf(); - } - else if (object && typeof object.subset === 'function') { // Matrix - return object.subset(index, value); - } - else if (typeof object === 'string') { - // TODO: move setStringSubset into a separate util file, use that - return subset(object, index, value); + /** + * Create a numeric value with a specific type: number, BigNumber, or Fraction + * + * @param {string | number} value + * @param {'number' | 'BigNumber' | 'Fraction'} + * @return {number | BigNumber | Fraction} Returns an instance of the + * numeric requested type + */ + return function numeric (value, valueType) { + if (valueType === 'BigNumber') { + return new type.BigNumber(value); } - else if (typeof object === 'object') { - if (!index.isObjectProperty()) { - throw TypeError('Cannot apply a numeric index as object property'); - } - setSafeProperty$2(object, index.getObjectProperty(), value); - return object; + else if (valueType === 'Fraction') { + return new type.Fraction(value); } else { - throw new TypeError('Cannot apply index: unsupported type of object'); - } - } - catch (err) { - throw errorTransform$1(err); - } - } -} - -var factory_1$46 = factory$47; - -var assign = { - factory: factory_1$46 -}; - -//list of identifiers of nodes in order of their precedence -//also contains information about left/right associativity -//and which other operator the operator is associative with -//Example: -// addition is associative with addition and subtraction, because: -// (a+b)+c=a+(b+c) -// (a+b)-c=a+(b-c) -// -// postfix operators are left associative, prefix operators -// are right associative -// -//It's also possible to set the following properties: -// latexParens: if set to false, this node doesn't need to be enclosed -// in parentheses when using LaTeX -// latexLeftParens: if set to false, this !OperatorNode's! -// left argument doesn't need to be enclosed -// in parentheses -// latexRightParens: the same for the right argument -var properties = [ - { //assignment - 'AssignmentNode': {}, - 'FunctionAssignmentNode': {} - }, - { //conditional expression - 'ConditionalNode': { - latexLeftParens: false, - latexRightParens: false, - latexParens: false - //conditionals don't need parentheses in LaTeX because - //they are 2 dimensional - } - }, - { //logical or - 'OperatorNode:or': { - associativity: 'left', - associativeWith: [] - } - - }, - { //logical xor - 'OperatorNode:xor': { - associativity: 'left', - associativeWith: [] - } - }, - { //logical and - 'OperatorNode:and': { - associativity: 'left', - associativeWith: [] - } - }, - { //bitwise or - 'OperatorNode:bitOr': { - associativity: 'left', - associativeWith: [] - } - }, - { //bitwise xor - 'OperatorNode:bitXor': { - associativity: 'left', - associativeWith: [] - } - }, - { //bitwise and - 'OperatorNode:bitAnd': { - associativity: 'left', - associativeWith: [] - } - }, - { //relational operators - 'OperatorNode:equal': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:unequal': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:smaller': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:larger': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:smallerEq': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:largerEq': { - associativity: 'left', - associativeWith: [] - } - }, - { //bitshift operators - 'OperatorNode:leftShift': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:rightArithShift': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:rightLogShift': { - associativity: 'left', - associativeWith: [] - } - }, - { //unit conversion - 'OperatorNode:to': { - associativity: 'left', - associativeWith: [] - } - }, - { //range - 'RangeNode': {} - }, - { //addition, subtraction - 'OperatorNode:add': { - associativity: 'left', - associativeWith: ['OperatorNode:add', 'OperatorNode:subtract'] - }, - 'OperatorNode:subtract': { - associativity: 'left', - associativeWith: [] - } - }, - { //multiply, divide, modulus - 'OperatorNode:multiply': { - associativity: 'left', - associativeWith: [ - 'OperatorNode:multiply', - 'OperatorNode:divide', - 'Operator:dotMultiply', - 'Operator:dotDivide' - ] - }, - 'OperatorNode:divide': { - associativity: 'left', - associativeWith: [], - latexLeftParens: false, - latexRightParens: false, - latexParens: false - //fractions don't require parentheses because - //they're 2 dimensional, so parens aren't needed - //in LaTeX - }, - 'OperatorNode:dotMultiply': { - associativity: 'left', - associativeWith: [ - 'OperatorNode:multiply', - 'OperatorNode:divide', - 'OperatorNode:dotMultiply', - 'OperatorNode:doDivide' - ] - }, - 'OperatorNode:dotDivide': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:mod': { - associativity: 'left', - associativeWith: [] - } - }, - { //unary prefix operators - 'OperatorNode:unaryPlus': { - associativity: 'right' - }, - 'OperatorNode:unaryMinus': { - associativity: 'right' - }, - 'OperatorNode:bitNot': { - associativity: 'right' - }, - 'OperatorNode:not': { - associativity: 'right' - } - }, - { //exponentiation - 'OperatorNode:pow': { - associativity: 'right', - associativeWith: [], - latexRightParens: false - //the exponent doesn't need parentheses in - //LaTeX because it's 2 dimensional - //(it's on top) - }, - 'OperatorNode:dotPow': { - associativity: 'right', - associativeWith: [] - } - }, - { //factorial - 'OperatorNode:factorial': { - associativity: 'left' - } - }, - { //matrix transpose - 'OperatorNode:transpose': { - associativity: 'left' - } - } -]; - -/** - * Get the precedence of a Node. - * Higher number for higher precedence, starting with 0. - * Returns null if the precedence is undefined. - * - * @param {Node} - * @param {string} parenthesis - * @return {number|null} - */ -function getPrecedence (_node, parenthesis) { - var node = _node; - if (parenthesis !== 'keep') { - //ParenthesisNodes are only ignored when not in 'keep' mode - node = _node.getContent(); - } - var identifier = node.getIdentifier(); - for (var i = 0; i < properties.length; i++) { - if (identifier in properties[i]) { - return i; - } - } - return null; -} - -/** - * Get the associativity of an operator (left or right). - * Returns a string containing 'left' or 'right' or null if - * the associativity is not defined. - * - * @param {Node} - * @param {string} parenthesis - * @return {string|null} - * @throws {Error} - */ -function getAssociativity (_node, parenthesis) { - var node = _node; - if (parenthesis !== 'keep') { - //ParenthesisNodes are only ignored when not in 'keep' mode - node = _node.getContent(); - } - var identifier = node.getIdentifier(); - var index = getPrecedence(node, parenthesis); - if (index === null) { - //node isn't in the list - return null; - } - var property = properties[index][identifier]; - - if (property.hasOwnProperty('associativity')) { - if (property.associativity === 'left') { - return 'left'; - } - if (property.associativity === 'right') { - return 'right'; - } - //associativity is invalid - throw Error('\'' + identifier + '\' has the invalid associativity \'' - + property.associativity + '\'.'); - } - - //associativity is undefined - return null; -} - -/** - * Check if an operator is associative with another operator. - * Returns either true or false or null if not defined. - * - * @param {Node} nodeA - * @param {Node} nodeB - * @param {string} parenthesis - * @return {bool|null} - */ -function isAssociativeWith (nodeA, nodeB, parenthesis) { - var a = nodeA; - var b = nodeB; - if (parenthesis !== 'keep') { - //ParenthesisNodes are only ignored when not in 'keep' mode - var a = nodeA.getContent(); - var b = nodeB.getContent(); - } - var identifierA = a.getIdentifier(); - var identifierB = b.getIdentifier(); - var index = getPrecedence(a, parenthesis); - if (index === null) { - //node isn't in the list - return null; - } - var property = properties[index][identifierA]; + // valueType === 'number' or undefined // TODO: check this + if (typeof value === 'number') { + return value; + } + else { + if (value === 'Infinity') { + return Infinity; + } - if (property.hasOwnProperty('associativeWith') - && (property.associativeWith instanceof Array)) { - for (var i = 0; i < property.associativeWith.length; i++) { - if (property.associativeWith[i] === identifierB) { - return true; + if (value === 'NaN') { + return NaN; + } + + // The following regexp is relatively permissive + if (!/^[\-+]?((\d+\.?\d*)|(\d*\.?\d+))([eE][+\-]?\d+)?$/.test(value)) { + throw new Error('Invalid numeric value "' + value + '"'); + } + + // remove leading zeros like '003.2' which are not allowed by JavaScript + return parseFloat(value.replace(/^(0*)[0-9]/, function (match, zeros) { + return match.substring(zeros.length); + })); + } } } - return false; } - //associativeWith is not defined - return null; -} + var factory_1$39 = factory$40; -var properties_1 = properties; -var getPrecedence_1 = getPrecedence; -var getAssociativity_1 = getAssociativity; -var isAssociativeWith_1 = isAssociativeWith; + var numeric = { + factory: factory_1$39 + }; -var operators = { - properties: properties_1, - getPrecedence: getPrecedence_1, - getAssociativity: getAssociativity_1, - isAssociativeWith: isAssociativeWith_1 -}; + var hasOwnProperty = object.hasOwnProperty; -var getSafeProperty$4 = customs.getSafeProperty; -var setSafeProperty$3 = customs.setSafeProperty; + /** + * Get a property of a plain object + * Throws an error in case the object is not a plain object or the + * property is not defined on the object itself + * @param {Object} object + * @param {string} prop + * @return {*} Returns the property value when safe + */ + function getSafeProperty (object$$1, prop) { + // only allow getting safe properties of a plain object + if (isPlainObject(object$$1) && isSafeProperty(object$$1, prop)) { + return object$$1[prop]; + } -function factory$48 (type, config, load, typed) { - var Node$$1 = load(Node); - var assign$$1 = load(assign); - var access$$1 = load(access); + if (typeof object$$1[prop] === 'function' && isSafeMethod(object$$1, prop)) { + throw new Error('Cannot access method "' + prop + '" as a property'); + } - var operators$$1 = operators; + throw new Error('No access to property "' + prop + '"'); + } /** - * @constructor AssignmentNode - * @extends {Node} - * - * Define a symbol, like `a=3.2`, update a property like `a.b=3.2`, or - * replace a subset of a matrix like `A[2,2]=42`. - * - * Syntax: - * - * new AssignmentNode(symbol, value) - * new AssignmentNode(object, index, value) - * - * Usage: - * - * new AssignmentNode(new SymbolNode('a'), new ConstantNode(2)); // a=2 - * new AssignmentNode(new SymbolNode('a'), new IndexNode('b'), new ConstantNode(2)) // a.b=2 - * new AssignmentNode(new SymbolNode('a'), new IndexNode(1, 2), new ConstantNode(3)) // a[1,2]=3 - * - * @param {SymbolNode | AccessorNode} object Object on which to assign a value - * @param {IndexNode} [index=null] Index, property name or matrix - * index. Optional. If not provided - * and `object` is a SymbolNode, - * the property is assigned to the - * global scope. - * @param {Node} value The value to be assigned + * Set a property on a plain object. + * Throws an error in case the object is not a plain object or the + * property would override an inherited property like .constructor or .toString + * @param {Object} object + * @param {string} prop + * @param {*} value + * @return {*} Returns the value */ - function AssignmentNode(object, index, value) { - if (!(this instanceof AssignmentNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); + // TODO: merge this function into access.js? + function setSafeProperty (object$$1, prop, value) { + // only allow setting safe properties of a plain object + if (isPlainObject(object$$1) && isSafeProperty(object$$1, prop)) { + return object$$1[prop] = value; } - this.object = object; - this.index = value ? index : null; - this.value = value ? value : index; + throw new Error('No access to property "' + prop + '"'); + } - // validate input - if (!type.isSymbolNode(object) && !type.isAccessorNode(object)) { - throw new TypeError('SymbolNode or AccessorNode expected as "object"'); + /** + * Test whether a property is safe to use for an object. + * For example .toString and .constructor are not safe + * @param {string} prop + * @return {boolean} Returns true when safe + */ + function isSafeProperty (object$$1, prop) { + if (!object$$1 || typeof object$$1 !== 'object') { + return false; } - if (type.isSymbolNode(object) && object.name === 'end') { - throw new Error('Cannot assign to symbol "end"'); + // SAFE: whitelisted + // e.g length + if (hasOwnProperty(safeNativeProperties, prop)) { + return true; } - if (this.index && !type.isIndexNode(this.index)) { // index is optional - throw new TypeError('IndexNode expected as "index"'); + // UNSAFE: inherited from Object prototype + // e.g constructor + if (prop in Object.prototype) { + // 'in' is used instead of hasOwnProperty for nodejs v0.10 + // which is inconsistent on root prototypes. It is safe + // here because Object.prototype is a root object + return false; } - if (!type.isNode(this.value)) { - throw new TypeError('Node expected as "value"'); + // UNSAFE: inherited from Function prototype + // e.g call, apply + if (prop in Function.prototype) { + // 'in' is used instead of hasOwnProperty for nodejs v0.10 + // which is inconsistent on root prototypes. It is safe + // here because Function.prototype is a root object + return false; } - - // readonly property name - Object.defineProperty(this, 'name', { - get: function () { - if (this.index) { - return (this.index.isObjectProperty()) - ? this.index.getObjectProperty() - : ''; - } - else { - return this.object.name || ''; - } - }.bind(this), - set: function () { - throw new Error('Cannot assign a new name, name is read-only'); - } - }); + return true; } - AssignmentNode.prototype = new Node$$1(); - - AssignmentNode.prototype.type = 'AssignmentNode'; - - AssignmentNode.prototype.isAssignmentNode = true; - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) + * Validate whether a method is safe. + * Throws an error when that's not the case. + * @param {Object} object + * @param {string} method */ - AssignmentNode.prototype._compile = function (math, argNames) { - var evalObject = this.object._compile(math, argNames); - var evalIndex = this.index ? this.index._compile(math, argNames) : null; - var evalValue = this.value._compile(math, argNames); - var name = this.object.name; - - if (!this.index) { - // apply a variable to the scope, for example `a=2` - if (!type.isSymbolNode(this.object)) { - throw new TypeError('SymbolNode expected as object'); - } - - return function evalAssignmentNode (scope, args, context) { - return setSafeProperty$3(scope, name, evalValue(scope, args, context)); - }; + // TODO: merge this function into assign.js? + function validateSafeMethod (object$$1, method) { + if (!isSafeMethod(object$$1, method)) { + throw new Error('No access to method "' + method + '"'); } - else if (this.index.isObjectProperty()) { - // apply an object property for example `a.b=2` - var prop = this.index.getObjectProperty(); + } - return function evalAssignmentNode (scope, args, context) { - var object = evalObject(scope, args, context); - var value = evalValue(scope, args, context); - return setSafeProperty$3(object, prop, value); - }; + /** + * Check whether a method is safe. + * Throws an error when that's not the case (for example for `constructor`). + * @param {Object} object + * @param {string} method + * @return {boolean} Returns true when safe, false otherwise + */ + function isSafeMethod (object$$1, method) { + if (!object$$1 || typeof object$$1[method] !== 'function') { + return false; } - else if (type.isSymbolNode(this.object)) { - // update a matrix subset, for example `a[2]=3` - return function evalAssignmentNode(scope, args, context) { - var childObject = evalObject(scope, args, context); - var value = evalValue(scope, args, context); - var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context - setSafeProperty$3(scope, name, assign$$1(childObject, index, value)); - return value; - } + // UNSAFE: ghosted + // e.g overridden toString + // Note that IE10 doesn't support __proto__ and we can't do this check there. + if (hasOwnProperty(object$$1, method) && + (object$$1.__proto__ && (method in object$$1.__proto__))) { + return false; } - else { // type.isAccessorNode(node.object) === true - // update a matrix subset, for example `a.b[2]=3` - - // we will not use the compile function of the AccessorNode, but compile it - // ourselves here as we need the parent object of the AccessorNode: - // wee need to apply the updated object to parent object - var evalParentObject = this.object.object._compile(math, argNames); - - if (this.object.index.isObjectProperty()) { - var parentProp = this.object.index.getObjectProperty(); - - return function evalAssignmentNode(scope, args, context) { - var parent = evalParentObject(scope, args, context); - var childObject = getSafeProperty$4(parent, parentProp); - var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context - var value = evalValue(scope, args, context); - setSafeProperty$3(parent, parentProp, assign$$1(childObject, index, value)); - return value; - } - } - else { - // if some parameters use the 'end' parameter, we need to calculate the size - var evalParentIndex = this.object.index._compile(math, argNames); - - return function evalAssignmentNode(scope, args, context) { - var parent = evalParentObject(scope, args, context); - var parentIndex = evalParentIndex(scope, args, parent); // Important: we pass parent instead of context - var childObject = access$$1(parent, parentIndex); - var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context - var value = evalValue(scope, args, context); - - assign$$1(parent, parentIndex, assign$$1(childObject, index, value)); - - return value; - } - } + // SAFE: whitelisted + // e.g toString + if (hasOwnProperty(safeNativeMethods, method)) { + return true; } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - AssignmentNode.prototype.forEach = function (callback) { - callback(this.object, 'object', this); - if (this.index) { - callback(this.index, 'index', this); + // UNSAFE: inherited from Object prototype + // e.g constructor + if (method in Object.prototype) { + // 'in' is used instead of hasOwnProperty for nodejs v0.10 + // which is inconsistent on root prototypes. It is safe + // here because Object.prototype is a root object + return false; } - callback(this.value, 'value', this); - }; - - /** - * Create a new AssignmentNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {AssignmentNode} Returns a transformed copy of the node - */ - AssignmentNode.prototype.map = function (callback) { - var object = this._ifNode(callback(this.object, 'object', this)); - var index = this.index - ? this._ifNode(callback(this.index, 'index', this)) - : null; - var value = this._ifNode(callback(this.value, 'value', this)); - - return new AssignmentNode(object, index, value); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {AssignmentNode} - */ - AssignmentNode.prototype.clone = function() { - return new AssignmentNode(this.object, this.index, this.value); - }; - - /* - * Is parenthesis needed? - * @param {node} node - * @param {string} [parenthesis='keep'] - * @private - */ - function needParenthesis(node, parenthesis) { - if (!parenthesis) { - parenthesis = 'keep'; + // UNSAFE: inherited from Function prototype + // e.g call, apply + if (method in Function.prototype) { + // 'in' is used instead of hasOwnProperty for nodejs v0.10 + // which is inconsistent on root prototypes. It is safe + // here because Function.prototype is a root object + return false; } + return true; + } - var precedence = operators$$1.getPrecedence(node, parenthesis); - var exprPrecedence = operators$$1.getPrecedence(node.value, parenthesis); - return (parenthesis === 'all') - || ((exprPrecedence !== null) && (exprPrecedence <= precedence)); + function isPlainObject (object$$1) { + return typeof object$$1 === 'object' && object$$1 && object$$1.constructor === Object; } - /** - * Get string representation - * @param {Object} options - * @return {string} - */ - AssignmentNode.prototype._toString = function(options) { - var object = this.object.toString(options); - var index = this.index ? this.index.toString(options) : ''; - var value = this.value.toString(options); - if (needParenthesis(this, options && options.parenthesis)) { - value = '(' + value + ')'; - } + var safeNativeProperties = { + length: true, + name: true + }; - return object + index + ' = ' + value; + var safeNativeMethods = { + toString: true, + valueOf: true, + toLocaleString: true }; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - AssignmentNode.prototype.toJSON = function () { - return { - mathjs: 'AssignmentNode', - object: this.object, - index: this.index, - value: this.value - }; + var getSafeProperty_1 = getSafeProperty; + var setSafeProperty_1 = setSafeProperty; + var isSafeProperty_1 = isSafeProperty; + var validateSafeMethod_1 = validateSafeMethod; + var isSafeMethod_1 = isSafeMethod; + var isPlainObject_1 = isPlainObject; + + var customs = { + getSafeProperty: getSafeProperty_1, + setSafeProperty: setSafeProperty_1, + isSafeProperty: isSafeProperty_1, + validateSafeMethod: validateSafeMethod_1, + isSafeMethod: isSafeMethod_1, + isPlainObject: isPlainObject_1 }; - /** - * Instantiate an AssignmentNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "AssignmentNode", object: ..., index: ..., value: ...}`, - * where mathjs is optional - * @returns {AssignmentNode} - */ - AssignmentNode.fromJSON = function (json) { - return new AssignmentNode(json.object, json.index, json.value); + // Reserved keywords not allowed to use in the parser + var keywords = { + end: true }; - /** - * Get HTML representation - * @param {Object} options - * @return {string} - */ - AssignmentNode.prototype.toHTML = function(options) { - var object = this.object.toHTML(options); - var index = this.index ? this.index.toHTML(options) : ''; - var value = this.value.toHTML(options); - if (needParenthesis(this, options && options.parenthesis)) { - value = '(' + value + ')'; - } + var deepEqual$1= object.deepEqual; + var hasOwnProperty$1 = object.hasOwnProperty; - return object + index + '=' + value; - }; + function factory$41 (type, config, load, typed, math) { - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} - */ - AssignmentNode.prototype._toTex = function(options) { - var object = this.object.toTex(options); - var index = this.index ? this.index.toTex(options) : ''; - var value = this.value.toTex(options); - if (needParenthesis(this, options && options.parenthesis)) { - value = '\\left(' + value + '\\right)'; + /** + * Node + */ + function Node() { + if (!(this instanceof Node)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } } - return object + index + ':=' + value; - }; + /** + * Evaluate the node + * @param {Object} [scope] Scope to read/write variables + * @return {*} Returns the result + */ + Node.prototype.eval = function(scope) { + return this.compile().eval(scope); + }; - return AssignmentNode; -} + Node.prototype.type = 'Node'; -var name$42 = 'AssignmentNode'; -var path$18 = 'expression.node'; -var factory_1$47 = factory$48; + Node.prototype.isNode = true; -var AssignmentNode = { - name: name$42, - path: path$18, - factory: factory_1$47 -}; + Node.prototype.comment = ''; -var forEach$1 = array.forEach; -var map$3 = array.map; + /** + * Compile the node into an optimized, evauatable JavaScript function + * @return {{eval: function([Object])}} expr Returns an object with a function 'eval', + * which can be invoked as expr.eval([scope: Object]), + * where scope is an optional object with + * variables. + */ + Node.prototype.compile = function () { + var expr = this._compile(math.expression.mathWithTransform, {}); + var args = {}; + var context = null; + return { + eval: function evalNode(scope) { + var s = scope ? scope : {}; + _validateScope(s); + return expr(s, args, context); + } + } + }; + + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + Node.prototype._compile = function (math, argNames) { + throw new Error('Method _compile should be implemented by type ' + this.type); + }; -function factory$49 (type, config, load, typed) { - var Node$$1 = load(Node); - var ResultSet$$1 = load(ResultSet); + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + Node.prototype.forEach = function (callback) { + // must be implemented by each of the Node implementations + throw new Error('Cannot run forEach on a Node interface'); + }; - /** - * @constructor BlockNode - * @extends {Node} - * Holds a set with blocks - * @param {Array.<{node: Node} | {node: Node, visible: boolean}>} blocks - * An array with blocks, where a block is constructed as an Object - * with properties block, which is a Node, and visible, which is - * a boolean. The property visible is optional and is true by default - */ - function BlockNode(blocks) { - if (!(this instanceof BlockNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + /** + * Create a new Node having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {OperatorNode} Returns a transformed copy of the node + */ + Node.prototype.map = function (callback) { + // must be implemented by each of the Node implementations + throw new Error('Cannot run map on a Node interface'); + }; - // validate input, copy blocks - if (!Array.isArray(blocks)) throw new Error('Array expected'); - this.blocks = blocks.map(function (block) { - var node = block && block.node; - var visible = block && block.visible !== undefined ? block.visible : true; + /** + * Validate whether an object is a Node, for use with map + * @param {Node} node + * @returns {Node} Returns the input if it's a node, else throws an Error + * @protected + */ + Node.prototype._ifNode = function (node) { + if (!type.isNode(node)) { + throw new TypeError('Callback function must return a Node'); + } - if (!type.isNode(node)) throw new TypeError('Property "node" must be a Node'); - if (typeof visible !== 'boolean') throw new TypeError('Property "visible" must be a boolean'); + return node; + }; - return { - node: node, - visible: visible + /** + * Recursively traverse all nodes in a node tree. Executes given callback for + * this node and each of its child nodes. + * @param {function(node: Node, path: string, parent: Node)} callback + * A callback called for every node in the node tree. + */ + Node.prototype.traverse = function (callback) { + // execute callback for itself + callback(this, null, null); + + // recursively traverse over all childs of a node + function _traverse(node, callback) { + node.forEach(function (child, path, parent) { + callback(child, path, parent); + _traverse(child, callback); + }); } - }); - } - BlockNode.prototype = new Node$$1(); - - BlockNode.prototype.type = 'BlockNode'; + _traverse(this, callback); + }; - BlockNode.prototype.isBlockNode = true; + /** + * Recursively transform a node tree via a transform function. + * + * For example, to replace all nodes of type SymbolNode having name 'x' with a + * ConstantNode with value 2: + * + * var res = Node.transform(function (node, path, parent) { + * if (node && node.isSymbolNode) && (node.name == 'x')) { + * return new ConstantNode(2); + * } + * else { + * return node; + * } + * }); + * + * @param {function(node: Node, path: string, parent: Node) : Node} callback + * A mapping function accepting a node, and returning + * a replacement for the node or the original node. + * Signature: callback(node: Node, index: string, parent: Node) : Node + * @return {Node} Returns the original node or its replacement + */ + Node.prototype.transform = function (callback) { + // traverse over all childs + function _transform (node, callback) { + return node.map(function(child, path, parent) { + var replacement = callback(child, path, parent); + return _transform(replacement, callback); + }); + } - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - BlockNode.prototype._compile = function (math, argNames) { - var evalBlocks = map$3(this.blocks, function (block) { - return { - eval: block.node._compile(math, argNames), - visible: block.visible - }; - }); + var replacement = callback(this, null, null); + return _transform(replacement, callback); + }; - return function evalBlockNodes (scope, args, context) { - var results = []; + /** + * Find any node in the node tree matching given filter function. For example, to + * find all nodes of type SymbolNode having name 'x': + * + * var results = Node.filter(function (node) { + * return (node && node.isSymbolNode) && (node.name == 'x'); + * }); + * + * @param {function(node: Node, path: string, parent: Node) : Node} callback + * A test function returning true when a node matches, and false + * otherwise. Function signature: + * callback(node: Node, index: string, parent: Node) : boolean + * @return {Node[]} nodes An array with nodes matching given filter criteria + */ + Node.prototype.filter = function (callback) { + var nodes = []; - forEach$1(evalBlocks, function evalBlockNode(block) { - var result = block.eval(scope, args, context); - if (block.visible) { - results.push(result); + this.traverse(function (node, path, parent) { + if (callback(node, path, parent)) { + nodes.push(node); } }); - return new ResultSet$$1(results); - } - }; - - /** - * Execute a callback for each of the child blocks of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - BlockNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.blocks.length; i++) { - callback(this.blocks[i].node, 'blocks[' + i + '].node', this); - } - }; - - /** - * Create a new BlockNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {BlockNode} Returns a transformed copy of the node - */ - BlockNode.prototype.map = function (callback) { - var blocks = []; - for (var i = 0; i < this.blocks.length; i++) { - var block = this.blocks[i]; - var node = this._ifNode(callback(block.node, 'blocks[' + i + '].node', this)); - blocks[i] = { - node: node, - visible: block.visible - }; - } - return new BlockNode(blocks); - }; + return nodes; + }; - /** - * Create a clone of this node, a shallow copy - * @return {BlockNode} - */ - BlockNode.prototype.clone = function () { - var blocks = this.blocks.map(function (block) { - return { - node: block.node, - visible: block.visible - }; - }); + // TODO: deprecated since version 1.1.0, remove this some day + Node.prototype.find = function () { + throw new Error('Function Node.find is deprecated. Use Node.filter instead.'); + }; - return new BlockNode(blocks); - }; + // TODO: deprecated since version 1.1.0, remove this some day + Node.prototype.match = function () { + throw new Error('Function Node.match is deprecated. See functions Node.filter, Node.transform, Node.traverse.'); + }; - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - BlockNode.prototype._toString = function (options) { - return this.blocks.map(function (param) { - return param.node.toString(options) + (param.visible ? '' : ';'); - }).join('\n'); - }; + /** + * Create a shallow clone of this node + * @return {Node} + */ + Node.prototype.clone = function () { + // must be implemented by each of the Node implementations + throw new Error('Cannot clone a Node interface'); + }; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - BlockNode.prototype.toJSON = function () { - return { - mathjs: 'BlockNode', - blocks: this.blocks + /** + * Create a deep clone of this node + * @return {Node} + */ + Node.prototype.cloneDeep = function () { + return this.map(function (node) { + return node.cloneDeep(); + }); }; - }; - /** - * Instantiate an BlockNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "BlockNode", blocks: [{node: ..., visible: false}, ...]}`, - * where mathjs is optional - * @returns {BlockNode} - */ - BlockNode.fromJSON = function (json) { - return new BlockNode(json.blocks); - }; + /** + * Deep compare this node with another node. + * @param {Node} other + * @return {boolean} Returns true when both nodes are of the same type and + * contain the same values (as do their childs) + */ + Node.prototype.equals = function (other) { + return other + ? deepEqual$1(this, other) + : false + }; - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - BlockNode.prototype.toHTML = function (options) { - return this.blocks.map(function (param) { - return param.node.toHTML(options) + (param.visible ? '' : ';'); - }).join('
'); - }; + /** + * Get string representation. (wrapper function) + * + * This function can get an object of the following form: + * { + * handler: //This can be a callback function of the form + * // "function callback(node, options)"or + * // a map that maps function names (used in FunctionNodes) + * // to callbacks + * parenthesis: "keep" //the parenthesis option (This is optional) + * } + * + * @param {Object} [options] + * @return {string} + */ + Node.prototype.toString = function (options) { + var customString; + if (options && typeof options === 'object') { + switch (typeof options.handler) { + case 'object': + case 'undefined': + break; + case 'function': + customString = options.handler(this, options); + break; + default: + throw new TypeError('Object or function expected as callback'); + } + } - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - BlockNode.prototype._toTex = function (options) { - return this.blocks.map(function (param) { - return param.node.toTex(options) + (param.visible ? '' : ';'); - }).join('\\;\\;\n'); - }; + if (typeof customString !== 'undefined') { + return customString; + } - return BlockNode; -} + return this._toString(options); + }; -var name$43 = 'BlockNode'; -var path$19 = 'expression.node'; -var factory_1$48 = factory$49; + /** + * Get a JSON representation of the node + * Both .toJSON() and the static .fromJSON(json) should be implemented by all + * implementations of Node + * @returns {Object} + */ + Node.prototype.toJSON = function () { + throw new Error('Cannot serialize object: toJSON not implemented by ' + this.type); + }; -var BlockNode = { - name: name$43, - path: path$19, - factory: factory_1$48 -}; + /** + * Get HTML representation. (wrapper function) + * + * This function can get an object of the following form: + * { + * handler: //This can be a callback function of the form + * // "function callback(node, options)" or + * // a map that maps function names (used in FunctionNodes) + * // to callbacks + * parenthesis: "keep" //the parenthesis option (This is optional) + * } + * + * @param {Object} [options] + * @return {string} + */ + Node.prototype.toHTML = function (options) { + var customString; + if (options && typeof options === 'object') { + switch (typeof options.handler) { + case 'object': + case 'undefined': + break; + case 'function': + customString = options.handler(this, options); + break; + default: + throw new TypeError('Object or function expected as callback'); + } + } -function factory$50 (type, config, load, typed) { - /** - * Determine the type of a variable. - * - * Function `typeof` recognizes the following types of objects: - * - * Object | Returns | Example - * ---------------------- | ------------- | ------------------------------------------ - * null | `'null'` | `math.typeof(null)` - * number | `'number'` | `math.typeof(3.5)` - * boolean | `'boolean'` | `math.typeof(true)` - * string | `'string'` | `math.typeof('hello world')` - * Array | `'Array'` | `math.typeof([1, 2, 3])` - * Date | `'Date'` | `math.typeof(new Date())` - * Function | `'Function'` | `math.typeof(function () {})` - * Object | `'Object'` | `math.typeof({a: 2, b: 3})` - * RegExp | `'RegExp'` | `math.typeof(/a regexp/)` - * undefined | `'undefined'` | `math.typeof(undefined)` - * math.type.BigNumber | `'BigNumber'` | `math.typeof(math.bignumber('2.3e500'))` - * math.type.Chain | `'Chain'` | `math.typeof(math.chain(2))` - * math.type.Complex | `'Complex'` | `math.typeof(math.complex(2, 3))` - * math.type.Fraction | `'Fraction'` | `math.typeof(math.fraction(1, 3))` - * math.type.Help | `'Help'` | `math.typeof(math.help('sqrt'))` - * math.type.Help | `'Help'` | `math.typeof(math.help('sqrt'))` - * math.type.Index | `'Index'` | `math.typeof(math.index(1, 3))` - * math.type.Matrix | `'Matrix'` | `math.typeof(math.matrix([[1,2], [3, 4]]))` - * math.type.Range | `'Range'` | `math.typeof(math.range(0, 10))` - * math.type.ResultSet | `'ResultSet'` | `math.typeof(math.eval('a=2\nb=3'))` - * math.type.Unit | `'Unit'` | `math.typeof(math.unit('45 deg'))` - * math.expression.node.AccessorNode | `'AccessorNode'` | `math.typeof(math.parse('A[2]'))` - * math.expression.node.ArrayNode | `'ArrayNode'` | `math.typeof(math.parse('[1,2,3]'))` - * math.expression.node.AssignmentNode | `'AssignmentNode'` | `math.typeof(math.parse('x=2'))` - * math.expression.node.BlockNode | `'BlockNode'` | `math.typeof(math.parse('a=2; b=3'))` - * math.expression.node.ConditionalNode | `'ConditionalNode'` | `math.typeof(math.parse('x<0 ? -x : x'))` - * math.expression.node.ConstantNode | `'ConstantNode'` | `math.typeof(math.parse('2.3'))` - * math.expression.node.FunctionAssignmentNode | `'FunctionAssignmentNode'` | `math.typeof(math.parse('f(x)=x^2'))` - * math.expression.node.FunctionNode | `'FunctionNode'` | `math.typeof(math.parse('sqrt(4)'))` - * math.expression.node.IndexNode | `'IndexNode'` | `math.typeof(math.parse('A[2]').index)` - * math.expression.node.ObjectNode | `'ObjectNode'` | `math.typeof(math.parse('{a:2}'))` - * math.expression.node.ParenthesisNode | `'ParenthesisNode'` | `math.typeof(math.parse('(2+3)'))` - * math.expression.node.RangeNode | `'RangeNode'` | `math.typeof(math.parse('1:10'))` - * math.expression.node.SymbolNode | `'SymbolNode'` | `math.typeof(math.parse('x'))` - * - * Syntax: - * - * math.typeof(x) - * - * Examples: - * - * math.typeof(3.5); // returns 'number' - * math.typeof(math.complex('2-4i')); // returns 'Complex' - * math.typeof(math.unit('45 deg')); // returns 'Unit' - * math.typeof('hello world'); // returns 'string' - * - * @param {*} x The variable for which to test the type. - * @return {string} Returns the name of the type. Primitive types are lower case, - * non-primitive types are upper-camel-case. - * For example 'number', 'string', 'Array', 'Date'. - */ - var _typeof = typed('_typeof', { - 'any': function (x) { - var t = typeof x; - - if (t === 'object') { - // JavaScript types - if (x === null) return 'null'; - if (Array.isArray(x)) return 'Array'; - if (x instanceof Date) return 'Date'; - if (x instanceof RegExp) return 'RegExp'; - if (x instanceof Boolean) return 'boolean'; - if (x instanceof Number) return 'number'; - if (x instanceof String) return 'string'; - - // math.js types - if (type.isBigNumber(x)) return 'BigNumber'; - if (type.isComplex(x)) return 'Complex'; - if (type.isFraction(x)) return 'Fraction'; - if (type.isMatrix(x)) return 'Matrix'; - if (type.isUnit(x)) return 'Unit'; - if (type.isIndex(x)) return 'Index'; - if (type.isRange(x)) return 'Range'; - if (type.isResultSet(x)) return 'ResultSet'; - if (type.isNode(x)) return x.type; - if (type.isChain(x)) return 'Chain'; - if (type.isHelp(x)) return 'Help'; - - return 'Object'; - } - - if (t === 'function') return 'Function'; - - return t; // can be 'string', 'number', 'boolean', ... - } - }); + if (typeof customString !== 'undefined') { + return customString; + } - _typeof.toTex = undefined; // use default template + return this.toHTML(options); + }; - return _typeof; -} + /** + * Internal function to generate the string output. + * This has to be implemented by every Node + * + * @throws {Error} + */ + Node.prototype._toString = function () { + //must be implemented by each of the Node implementations + throw new Error('_toString not implemented for ' + this.type); + }; -var name$44 = 'typeof'; -var factory_1$49 = factory$50; + /** + * Get LaTeX representation. (wrapper function) + * + * This function can get an object of the following form: + * { + * handler: //This can be a callback function of the form + * // "function callback(node, options)"or + * // a map that maps function names (used in FunctionNodes) + * // to callbacks + * parenthesis: "keep" //the parenthesis option (This is optional) + * } + * + * @param {Object} [options] + * @return {string} + */ + Node.prototype.toTex = function (options) { + var customTex; + if (options && typeof options == 'object') { + switch (typeof options.handler) { + case 'object': + case 'undefined': + break; + case 'function': + customTex = options.handler(this, options); + break; + default: + throw new TypeError('Object or function expected as callback'); + } + } -var _typeof$1 = { - name: name$44, - factory: factory_1$49 -}; + if (typeof customTex !== 'undefined') { + return customTex; + } -function factory$51 (type, config, load, typed) { - var Node$$1 = load(Node); - var mathTypeOf = load(_typeof$1); + return this._toTex(options); + }; - /** - * A lazy evaluating conditional operator: 'condition ? trueExpr : falseExpr' - * - * @param {Node} condition Condition, must result in a boolean - * @param {Node} trueExpr Expression evaluated when condition is true - * @param {Node} falseExpr Expression evaluated when condition is true - * - * @constructor ConditionalNode - * @extends {Node} - */ - function ConditionalNode(condition, trueExpr, falseExpr) { - if (!(this instanceof ConditionalNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - if (!type.isNode(condition)) throw new TypeError('Parameter condition must be a Node'); - if (!type.isNode(trueExpr)) throw new TypeError('Parameter trueExpr must be a Node'); - if (!type.isNode(falseExpr)) throw new TypeError('Parameter falseExpr must be a Node'); + /** + * Internal function to generate the LaTeX output. + * This has to be implemented by every Node + * + * @param {Object} [options] + * @throws {Error} + */ + Node.prototype._toTex = function (options) { + //must be implemented by each of the Node implementations + throw new Error('_toTex not implemented for ' + this.type); + }; - this.condition = condition; - this.trueExpr = trueExpr; - this.falseExpr = falseExpr; - } + /** + * Get identifier. + * @return {string} + */ + Node.prototype.getIdentifier = function () { + return this.type; + }; - ConditionalNode.prototype = new Node$$1(); + /** + * Get the content of the current Node. + * @return {Node} node + **/ + Node.prototype.getContent = function () { + return this; + }; - ConditionalNode.prototype.type = 'ConditionalNode'; + /** + * Validate the symbol names of a scope. + * Throws an error when the scope contains an illegal symbol. + * @param {Object} scope + */ + function _validateScope(scope) { + for (var symbol in scope) { + if (hasOwnProperty$1(scope, symbol)) { + if (symbol in keywords) { + throw new Error('Scope contains an illegal symbol, "' + symbol + '" is a reserved keyword'); + } + } + } + } - ConditionalNode.prototype.isConditionalNode = true; + return Node; + } - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ConditionalNode.prototype._compile = function (math, argNames) { - var evalCondition = this.condition._compile(math, argNames); - var evalTrueExpr = this.trueExpr._compile(math, argNames); - var evalFalseExpr = this.falseExpr._compile(math, argNames); + var name$37 = 'Node'; + var path$14 = 'expression.node'; + var math$6 = true; // request access to the math namespace as 5th argument of the factory function + var factory_1$40 = factory$41; - return function evalConditionalNode(scope, args, context) { - return testCondition(evalCondition(scope, args, context)) - ? evalTrueExpr(scope, args, context) - : evalFalseExpr(scope, args, context); - } + var Node = { + name: name$37, + path: path$14, + math: math$6, + factory: factory_1$40 }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ConditionalNode.prototype.forEach = function (callback) { - callback(this.condition, 'condition', this); - callback(this.trueExpr, 'trueExpr', this); - callback(this.falseExpr, 'falseExpr', this); - }; + var map$1 = array.map; + var escape = string.escape; - /** - * Create a new ConditionalNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {ConditionalNode} Returns a transformed copy of the node - */ - ConditionalNode.prototype.map = function (callback) { - return new ConditionalNode( - this._ifNode(callback(this.condition, 'condition', this)), - this._ifNode(callback(this.trueExpr, 'trueExpr', this)), - this._ifNode(callback(this.falseExpr, 'falseExpr', this)) - ); - }; + function factory$42 (type, config, load, typed) { + var Node$$1 = load(Node); + var Range$$1 = load(Range); - /** - * Create a clone of this node, a shallow copy - * @return {ConditionalNode} - */ - ConditionalNode.prototype.clone = function () { - return new ConditionalNode(this.condition, this.trueExpr, this.falseExpr); - }; + var isArray = Array.isArray; - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - ConditionalNode.prototype._toString = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var precedence = operators.getPrecedence(this, parenthesis); + /** + * @constructor IndexNode + * @extends Node + * + * Describes a subset of a matrix or an object property. + * Cannot be used on its own, needs to be used within an AccessorNode or + * AssignmentNode. + * + * @param {Node[]} dimensions + * @param {boolean} [dotNotation=false] Optional property describing whether + * this index was written using dot + * notation like `a.b`, or using bracket + * notation like `a["b"]` (default). + * Used to stringify an IndexNode. + */ + function IndexNode(dimensions, dotNotation) { + if (!(this instanceof IndexNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - //Enclose Arguments in parentheses if they are an OperatorNode - //or have lower or equal precedence - //NOTE: enclosing all OperatorNodes in parentheses is a decision - //purely based on aesthetics and readability - var condition = this.condition.toString(options); - var conditionPrecedence = operators.getPrecedence(this.condition, parenthesis); - if ((parenthesis === 'all') - || (this.condition.type === 'OperatorNode') - || ((conditionPrecedence !== null) && (conditionPrecedence <= precedence))) { - condition = '(' + condition + ')'; - } + this.dimensions = dimensions; + this.dotNotation = dotNotation || false; - var trueExpr = this.trueExpr.toString(options); - var truePrecedence = operators.getPrecedence(this.trueExpr, parenthesis); - if ((parenthesis === 'all') - || (this.trueExpr.type === 'OperatorNode') - || ((truePrecedence !== null) && (truePrecedence <= precedence))) { - trueExpr = '(' + trueExpr + ')'; - } + // validate input + if (!isArray(dimensions) || !dimensions.every(type.isNode)) { + throw new TypeError('Array containing Nodes expected for parameter "dimensions"'); + } + if (this.dotNotation && !this.isObjectProperty()) { + throw new Error('dotNotation only applicable for object properties'); + } - var falseExpr = this.falseExpr.toString(options); - var falsePrecedence = operators.getPrecedence(this.falseExpr, parenthesis); - if ((parenthesis === 'all') - || (this.falseExpr.type === 'OperatorNode') - || ((falsePrecedence !== null) && (falsePrecedence <= precedence))) { - falseExpr = '(' + falseExpr + ')'; + // TODO: deprecated since v3, remove some day + var deprecated = function () { + throw new Error('Property `IndexNode.object` is deprecated, use `IndexNode.fn` instead'); + }; + Object.defineProperty(this, 'object', { get: deprecated, set: deprecated }); } - return condition + ' ? ' + trueExpr + ' : ' + falseExpr; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ConditionalNode.prototype.toJSON = function () { - return { - mathjs: 'ConditionalNode', - condition: this.condition, - trueExpr: this.trueExpr, - falseExpr: this.falseExpr - }; - }; - /** - * Instantiate an ConditionalNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "ConditionalNode", "condition": ..., "trueExpr": ..., "falseExpr": ...}`, - * where mathjs is optional - * @returns {ConditionalNode} - */ - ConditionalNode.fromJSON = function (json) { - return new ConditionalNode(json.condition, json.trueExpr, json.falseExpr); - }; + IndexNode.prototype = new Node$$1(); - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - ConditionalNode.prototype.toHTML = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var precedence = operators.getPrecedence(this, parenthesis); + IndexNode.prototype.type = 'IndexNode'; - //Enclose Arguments in parentheses if they are an OperatorNode - //or have lower or equal precedence - //NOTE: enclosing all OperatorNodes in parentheses is a decision - //purely based on aesthetics and readability - var condition = this.condition.toHTML(options); - var conditionPrecedence = operators.getPrecedence(this.condition, parenthesis); - if ((parenthesis === 'all') - || (this.condition.type === 'OperatorNode') - || ((conditionPrecedence !== null) && (conditionPrecedence <= precedence))) { - condition = '(' + condition + ')'; - } + IndexNode.prototype.isIndexNode = true; - var trueExpr = this.trueExpr.toHTML(options); - var truePrecedence = operators.getPrecedence(this.trueExpr, parenthesis); - if ((parenthesis === 'all') - || (this.trueExpr.type === 'OperatorNode') - || ((truePrecedence !== null) && (truePrecedence <= precedence))) { - trueExpr = '(' + trueExpr + ')'; - } + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + IndexNode.prototype._compile = function (math, argNames) { + // TODO: implement support for bignumber (currently bignumbers are silently + // reduced to numbers when changing the value to zero-based) + + // TODO: Optimization: when the range values are ConstantNodes, + // we can beforehand resolve the zero-based value + + // optimization for a simple object property + var evalDimensions = map$1(this.dimensions, function (range, i) { + if (type.isRangeNode(range)) { + if (range.needsEnd()) { + // create a range containing end (like '4:end') + var childArgNames = Object.create(argNames); + childArgNames['end'] = true; + + var evalStart = range.start._compile(math, childArgNames); + var evalEnd = range.end._compile(math, childArgNames); + var evalStep = range.step + ? range.step._compile(math, childArgNames) + : function () { return 1 }; + + return function evalDimension(scope, args, context) { + var size = math.size(context).valueOf(); + var childArgs = Object.create(args); + childArgs['end'] = size[i]; + + return createRange( + evalStart(scope, childArgs, context), + evalEnd(scope, childArgs, context), + evalStep(scope, childArgs, context) + ); + }; + } + else { + // create range + var evalStart = range.start._compile(math, argNames); + var evalEnd = range.end._compile(math, argNames); + var evalStep = range.step + ? range.step._compile(math, argNames) + : function () { return 1 }; + + return function evalDimension(scope, args, context) { + return createRange( + evalStart(scope, args, context), + evalEnd(scope, args, context), + evalStep(scope, args, context) + ); + }; + } + } + else if (type.isSymbolNode(range) && range.name === 'end') { + // SymbolNode 'end' + var childArgNames = Object.create(argNames); + childArgNames['end'] = true; - var falseExpr = this.falseExpr.toHTML(options); - var falsePrecedence = operators.getPrecedence(this.falseExpr, parenthesis); - if ((parenthesis === 'all') - || (this.falseExpr.type === 'OperatorNode') - || ((falsePrecedence !== null) && (falsePrecedence <= precedence))) { - falseExpr = '(' + falseExpr + ')'; - } - return condition + '?' + trueExpr + ':' + falseExpr; - }; + var evalRange = range._compile(math, childArgNames); + + return function evalDimension(scope, args, context) { + var size = math.size(context).valueOf(); + var childArgs = Object.create(args); + childArgs['end'] = size[i]; - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - ConditionalNode.prototype._toTex = function (options) { - return '\\begin{cases} {' - + this.trueExpr.toTex(options) + '}, &\\quad{\\text{if }\\;' - + this.condition.toTex(options) - + '}\\\\{' + this.falseExpr.toTex(options) - + '}, &\\quad{\\text{otherwise}}\\end{cases}'; - }; + return evalRange(scope, childArgs, context); + }; + } + else { + // ConstantNode + var evalRange = range._compile(math, argNames); + return function evalDimension(scope, args, context) { + return evalRange(scope, args, context); + }; + } + }); - /** - * Test whether a condition is met - * @param {*} condition - * @returns {boolean} true if condition is true or non-zero, else false - */ - function testCondition (condition) { - if (typeof condition === 'number' - || typeof condition === 'boolean' - || typeof condition === 'string') { - return condition ? true : false; - } + return function evalIndexNode (scope, args, context) { + var dimensions = map$1(evalDimensions, function (evalDimension) { + return evalDimension(scope, args, context); + }); + return math.index.apply(math, dimensions); + }; + }; - if (condition) { - if (type.isBigNumber(condition)) { - return condition.isZero() ? false : true; + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + IndexNode.prototype.forEach = function (callback) { + for (var i = 0; i < this.dimensions.length; i++) { + callback(this.dimensions[i], 'dimensions[' + i + ']', this); } + }; - if (type.isComplex(condition)) { - return (condition.re || condition.im) ? true : false; + /** + * Create a new IndexNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {IndexNode} Returns a transformed copy of the node + */ + IndexNode.prototype.map = function (callback) { + var dimensions = []; + for (var i = 0; i < this.dimensions.length; i++) { + dimensions[i] = this._ifNode(callback(this.dimensions[i], 'dimensions[' + i + ']', this)); } - if (type.isUnit(condition)) { - return condition.value ? true : false; - } - } + return new IndexNode(dimensions); + }; - if (condition === null || condition === undefined) { - return false; - } + /** + * Create a clone of this node, a shallow copy + * @return {IndexNode} + */ + IndexNode.prototype.clone = function () { + return new IndexNode(this.dimensions.slice(0)); + }; - throw new TypeError('Unsupported type of condition "' + mathTypeOf(condition) + '"'); - } - return ConditionalNode; -} + /** + * Test whether this IndexNode contains a single property name + * @return {boolean} + */ + IndexNode.prototype.isObjectProperty = function () { + return this.dimensions.length === 1 && + type.isConstantNode(this.dimensions[0]) && + typeof this.dimensions[0].value === 'string'; + }; + + /** + * Returns the property name if IndexNode contains a property. + * If not, returns null. + * @return {string | null} + */ + IndexNode.prototype.getObjectProperty = function () { + return this.isObjectProperty() ? this.dimensions[0].value : null; + }; + + /** + * Get string representation + * @param {Object} options + * @return {string} str + */ + IndexNode.prototype._toString = function (options) { + // format the parameters like "[1, 0:5]" + return this.dotNotation + ? ('.' + this.getObjectProperty()) + : ('[' + this.dimensions.join(', ') + ']'); + }; -var name$45 = 'ConditionalNode'; -var path$20 = 'expression.node'; -var factory_1$50 = factory$51; + /** + * Get a JSON representation of the node + * @returns {Object} + */ + IndexNode.prototype.toJSON = function () { + return { + mathjs: 'IndexNode', + dimensions: this.dimensions, + dotNotation: this.dotNotation + }; + }; -var ConditionalNode = { - name: name$45, - path: path$20, - factory: factory_1$50 -}; + /** + * Instantiate an IndexNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "IndexNode", dimensions: [...], dotNotation: false}`, + * where mathjs is optional + * @returns {IndexNode} + */ + IndexNode.fromJSON = function (json) { + return new IndexNode(json.dimensions, json.dotNotation); + }; -var format$3 = string.format; -var escapeLatex = latex.escape; + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + */ + IndexNode.prototype.toHTML = function (options) { + // format the parameters like "[1, 0:5]" + var dimensions = []; + for (var i=0; i.' + '' + escape(this.getObjectProperty()) + '';} + else { + return '[' + dimensions.join(',') + ']'} + }; -function factory$52 (type, config, load, typed) { - var Node$$1 = load(Node); - var getType = load(_typeof$1); + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + */ + IndexNode.prototype._toTex = function (options) { + var dimensions = this.dimensions.map(function (range) { + return range.toTex(options); + }); - /** - * A ConstantNode holds a constant value like a number or string. - * - * Usage: - * - * new ConstantNode(2.3); - * new ConstantNode('hello'); - * - * @param {*} value Value can be any type (number, BigNumber, string, ...) - * @constructor ConstantNode - * @extends {Node} - */ - function ConstantNode(value) { - if (!(this instanceof ConstantNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + return this.dotNotation + ? ('.' + this.getObjectProperty() + '') + : ('_{' + dimensions.join(',') + '}'); + }; - if (arguments.length === 2) { - // TODO: remove deprecation error some day (created 2018-01-23) - throw new SyntaxError('new ConstantNode(valueStr, valueType) is not supported anymore since math v4.0.0. Use new ConstantNode(value) instead, where value is a non-stringified value.'); + // helper function to create a Range from start, step and end + function createRange(start, end, step) { + return new Range$$1( + type.isBigNumber(start) ? start.toNumber() : start, + type.isBigNumber(end) ? end.toNumber() : end, + type.isBigNumber(step) ? step.toNumber() : step + ); } - - this.value = value; + return IndexNode; } - ConstantNode.prototype = new Node$$1(); - - ConstantNode.prototype.type = 'ConstantNode'; + var name$38 = 'IndexNode'; + var path$15 = 'expression.node'; + var factory_1$41 = factory$42; - ConstantNode.prototype.isConstantNode = true; + var IndexNode = { + name: name$38, + path: path$15, + factory: factory_1$41 + }; /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) + * Transform zero-based indices to one-based indices in errors + * @param {Error} err + * @returns {Error} Returns the transformed error */ - ConstantNode.prototype._compile = function (math, argNames) { - var value = this.value; - - return function evalConstantNode() { - return value; + var transform = function (err) { + if (err && err.isIndexError) { + return new IndexError_1( + err.index + 1, + err.min + 1, + err.max !== undefined ? err.max + 1 : undefined); } - }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ConstantNode.prototype.forEach = function (callback) { - // nothing to do, we don't have childs + return err; }; - /** - * Create a new ConstantNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node) : Node} callback - * @returns {ConstantNode} Returns a clone of the node - */ - ConstantNode.prototype.map = function (callback) { - return this.clone(); + var error_transform = { + transform: transform }; - /** - * Create a clone of this node, a shallow copy - * @return {ConstantNode} - */ - ConstantNode.prototype.clone = function () { - return new ConstantNode(this.value); - }; + var clone$3 = object.clone; + var validateIndex$2 = array.validateIndex; + var getSafeProperty$1 = customs.getSafeProperty; + var setSafeProperty$1 = customs.setSafeProperty; - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - ConstantNode.prototype._toString = function (options) { - return format$3 (this.value, options); - }; - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - ConstantNode.prototype.toHTML = function (options) { - var value = this._toString(options); - - switch (getType(this.value)) { - case 'number': - case 'BigNumber': - case 'Fraction': - return '' + value + ''; - case 'string': - return '' + value + ''; - case 'boolean': - return '' + value + ''; - case 'null': - return '' + value + ''; - case 'undefined': - return '' + value + ''; + function factory$43 (type, config, load, typed) { + var matrix$$1 = load(matrix); - default: - return '' + value + ''; - } - }; + /** + * Get or set a subset of a matrix or string. + * + * Syntax: + * math.subset(value, index) // retrieve a subset + * math.subset(value, index, replacement [, defaultValue]) // replace a subset + * + * Examples: + * + * // get a subset + * var d = [[1, 2], [3, 4]]; + * math.subset(d, math.index(1, 0)); // returns 3 + * math.subset(d, math.index([0, 2], 1)); // returns [[2], [4]] + * + * // replace a subset + * var e = []; + * var f = math.subset(e, math.index(0, [0, 2]), [5, 6]); // f = [[5, 6]] + * var g = math.subset(f, math.index(1, 1), 7, 0); // g = [[5, 6], [0, 7]] + * + * See also: + * + * size, resize, squeeze, index + * + * @param {Array | Matrix | string} matrix An array, matrix, or string + * @param {Index} index An index containing ranges for each + * dimension + * @param {*} [replacement] An array, matrix, or scalar. + * If provided, the subset is replaced with replacement. + * If not provided, the subset is returned + * @param {*} [defaultValue=undefined] Default value, filled in on new entries when + * the matrix is resized. If not provided, + * math.matrix elements will be left undefined. + * @return {Array | Matrix | string} Either the retrieved subset or the updated matrix. + */ + var subset = typed('subset', { + // get subset + 'Array, Index': function (value, index) { + var m = matrix$$1(value); + var subset = m.subset(index); // returns a Matrix + return index.isScalar() + ? subset + : subset.valueOf(); // return an Array (like the input) + }, - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ConstantNode.prototype.toJSON = function () { - return { - mathjs: 'ConstantNode', - value: this.value - }; - }; + 'Matrix, Index': function (value, index) { + return value.subset(index); + }, - /** - * Instantiate a ConstantNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "SymbolNode", value: 2.3}`, - * where mathjs is optional - * @returns {ConstantNode} - */ - ConstantNode.fromJSON = function (json) { - return new ConstantNode(json.value); - }; + 'Object, Index': _getObjectProperty, - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - ConstantNode.prototype._toTex = function (options) { - var value = this._toString(options); + 'string, Index': _getSubstring, - switch (getType(this.value)) { - case 'string': - return '\\mathtt{' + escapeLatex(value) + '}'; + // set subset + 'Array, Index, any': function (value, index, replacement) { + return matrix$$1(clone$3(value)) + .subset(index, replacement, undefined) + .valueOf(); + }, - case 'number': - case 'BigNumber': - var index = value.toLowerCase().indexOf('e'); - if (index !== -1) { - return value.substring(0, index) + '\\cdot10^{' + - value.substring(index + 1) + '}'; - } - return value; + 'Array, Index, any, any': function (value, index, replacement, defaultValue) { + return matrix$$1(clone$3(value)) + .subset(index, replacement, defaultValue) + .valueOf(); + }, - case 'Fraction': - return this.value.toLatex(); + 'Matrix, Index, any': function (value, index, replacement) { + return value.clone().subset(index, replacement); + }, - default: - return value; - } - }; + 'Matrix, Index, any, any': function (value, index, replacement, defaultValue) { + return value.clone().subset(index, replacement, defaultValue); + }, - return ConstantNode; -} + 'string, Index, string': _setSubstring, + 'string, Index, string, string': _setSubstring, + 'Object, Index, any': _setObjectProperty + }); -var name$46 = 'ConstantNode'; -var path$21 = 'expression.node'; -var factory_1$51 = factory$52; + subset.toTex = undefined; // use default template -var ConstantNode = { - name: name$46, - path: path$21, - factory: factory_1$51 -}; + return subset; -var escape$1 = string.escape; -var forEach$2 = array.forEach; -var join = array.join; + /** + * Retrieve a subset of a string + * @param {string} str string from which to get a substring + * @param {Index} index An index containing ranges for each dimension + * @returns {string} substring + * @private + */ + function _getSubstring(str, index) { + if (!type.isIndex(index)) { + // TODO: better error message + throw new TypeError('Index expected'); + } + if (index.size().length != 1) { + throw new DimensionError_1(index.size().length, 1); + } + // validate whether the range is out of range + var strLen = str.length; + validateIndex$2(index.min()[0], strLen); + validateIndex$2(index.max()[0], strLen); -var setSafeProperty$4 = customs.setSafeProperty; + var range = index.dimension(0); -function factory$53 (type, config, load, typed) { - var Node$$1 = load(Node); + var substr = ''; + range.forEach(function (v) { + substr += str.charAt(v); + }); - /** - * @constructor FunctionAssignmentNode - * @extends {Node} - * Function assignment - * - * @param {string} name Function name - * @param {string[] | Array.<{name: string, type: string}>} params - * Array with function parameter names, or an - * array with objects containing the name - * and type of the parameter - * @param {Node} expr The function expression - */ - function FunctionAssignmentNode(name, params, expr) { - if (!(this instanceof FunctionAssignmentNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); + return substr; } - // validate input - if (typeof name !== 'string') throw new TypeError('String expected for parameter "name"'); - if (!Array.isArray(params)) throw new TypeError('Array containing strings or objects expected for parameter "params"'); - if (!type.isNode(expr)) throw new TypeError('Node expected for parameter "expr"'); - if (name in keywords) throw new Error('Illegal function name, "' + name + '" is a reserved keyword'); - - this.name = name; - this.params = params.map(function (param) { - return param && param.name || param; - }); - this.types = params.map(function (param) { - return param && param.type || 'any' - }); - this.expr = expr; - } - - FunctionAssignmentNode.prototype = new Node$$1(); + /** + * Replace a substring in a string + * @param {string} str string to be replaced + * @param {Index} index An index containing ranges for each dimension + * @param {string} replacement Replacement string + * @param {string} [defaultValue] Default value to be uses when resizing + * the string. is ' ' by default + * @returns {string} result + * @private + */ + function _setSubstring(str, index, replacement, defaultValue) { + if (!index || index.isIndex !== true) { + // TODO: better error message + throw new TypeError('Index expected'); + } + if (index.size().length != 1) { + throw new DimensionError_1(index.size().length, 1); + } + if (defaultValue !== undefined) { + if (typeof defaultValue !== 'string' || defaultValue.length !== 1) { + throw new TypeError('Single character expected as defaultValue'); + } + } + else { + defaultValue = ' '; + } - FunctionAssignmentNode.prototype.type = 'FunctionAssignmentNode'; + var range = index.dimension(0); + var len = range.size()[0]; - FunctionAssignmentNode.prototype.isFunctionAssignmentNode = true; + if (len != replacement.length) { + throw new DimensionError_1(range.size()[0], replacement.length); + } - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - FunctionAssignmentNode.prototype._compile = function (math, argNames) { - var childArgNames = Object.create(argNames); - forEach$2(this.params, function (param) { - childArgNames[param] = true; - }); + // validate whether the range is out of range + var strLen = str.length; + validateIndex$2(index.min()[0]); + validateIndex$2(index.max()[0]); - // compile the function expression with the child args - var evalExpr = this.expr._compile(math, childArgNames); - var name = this.name; - var params = this.params; - var signature = join(this.types, ','); - var syntax = name + '(' + join(this.params, ', ') + ')'; + // copy the string into an array with characters + var chars = []; + for (var i = 0; i < strLen; i++) { + chars[i] = str.charAt(i); + } - return function evalFunctionAssignmentNode(scope, args, context) { - var signatures = {}; - signatures[signature] = function () { - var childArgs = Object.create(args); + range.forEach(function (v, i) { + chars[v] = replacement.charAt(i[0]); + }); - for (var i = 0; i < params.length; i++) { - childArgs[params[i]] = arguments[i]; + // initialize undefined characters with a space + if (chars.length > strLen) { + for (i = strLen - 1, len = chars.length; i < len; i++) { + if (!chars[i]) { + chars[i] = defaultValue; + } } + } - return evalExpr(scope, childArgs, context); - }; - var fn = typed(name, signatures); - fn.syntax = syntax; - - setSafeProperty$4(scope, name, fn); - - return fn; + return chars.join(''); } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - FunctionAssignmentNode.prototype.forEach = function (callback) { - callback(this.expr, 'expr', this); - }; - - /** - * Create a new FunctionAssignmentNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {FunctionAssignmentNode} Returns a transformed copy of the node - */ - FunctionAssignmentNode.prototype.map = function (callback) { - var expr = this._ifNode(callback(this.expr, 'expr', this)); - - return new FunctionAssignmentNode(this.name, this.params.slice(0), expr); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {FunctionAssignmentNode} - */ - FunctionAssignmentNode.prototype.clone = function () { - return new FunctionAssignmentNode(this.name, this.params.slice(0), this.expr); - }; - - /** - * Is parenthesis needed? - * @param {Node} node - * @param {Object} parenthesis - * @private - */ - function needParenthesis(node, parenthesis) { - var precedence = operators.getPrecedence(node, parenthesis); - var exprPrecedence = operators.getPrecedence(node.expr, parenthesis); - - return (parenthesis === 'all') - || ((exprPrecedence !== null) && (exprPrecedence <= precedence)); } /** - * get string representation - * @param {Object} options - * @return {string} str + * Retrieve a property from an object + * @param {Object} object + * @param {Index} index + * @return {*} Returns the value of the property + * @private */ - FunctionAssignmentNode.prototype._toString = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var expr = this.expr.toString(options); - if (needParenthesis(this, parenthesis)) { - expr = '(' + expr + ')'; + function _getObjectProperty (object$$1, index) { + if (index.size().length !== 1) { + throw new DimensionError_1(index.size(), 1); } - return this.name + '(' + this.params.join(', ') + ') = ' + expr; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - FunctionAssignmentNode.prototype.toJSON = function () { - var types = this.types; - return { - mathjs: 'FunctionAssignmentNode', - name: this.name, - params: this.params.map(function(param, index) { - return { - name: param, - type: types[index] - } - }), - expr: this.expr - }; - }; + var key = index.dimension(0); + if (typeof key !== 'string') { + throw new TypeError('String expected as index to retrieve an object property'); + } - /** - * Instantiate an FunctionAssignmentNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "FunctionAssignmentNode", name: ..., params: ..., expr: ...}`, - * where mathjs is optional - * @returns {FunctionAssignmentNode} - */ - FunctionAssignmentNode.fromJSON = function (json) { - return new FunctionAssignmentNode(json.name, json.params, json.expr); - }; + return getSafeProperty$1(object$$1, key); + } /** - * get HTML representation - * @param {Object} options - * @return {string} str + * Set a property on an object + * @param {Object} object + * @param {Index} index + * @param {*} replacement + * @return {*} Returns the updated object + * @private */ - FunctionAssignmentNode.prototype.toHTML = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var params = []; - for (var i=0; i' + escape$1(this.params[i]) + ''); - } - var expr = this.expr.toHTML(options); - if (needParenthesis(this, parenthesis)) { - expr = '(' + expr + ')'; + function _setObjectProperty (object$$1, index, replacement) { + if (index.size().length !== 1) { + throw new DimensionError_1(index.size(), 1); } - return '' + escape$1(this.name) + '' + '(' + params.join(',') + ')=' + expr; - }; - /** - * get LaTeX representation - * @param {Object} options - * @return {string} str - */ - FunctionAssignmentNode.prototype._toTex = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var expr = this.expr.toTex(options); - if (needParenthesis(this, parenthesis)) { - expr = '\\left(' + expr + '\\right)'; + var key = index.dimension(0); + if (typeof key !== 'string') { + throw new TypeError('String expected as index to retrieve an object property'); } - return '\\mathrm{' + this.name - + '}\\left(' + this.params.map(latex.toSymbol).join(',') + '\\right):=' + expr; - }; + // clone the object, and apply the property to the clone + var updated = clone$3(object$$1); + setSafeProperty$1(updated, key, replacement); - return FunctionAssignmentNode; -} -var name$47 = 'FunctionAssignmentNode'; -var path$22 = 'expression.node'; -var factory_1$52 = factory$53; + return updated; + } -var FunctionAssignmentNode = { - name: name$47, - path: path$22, - factory: factory_1$52 -}; + var name$39 = 'subset'; + var factory_1$42 = factory$43; -var stringify = string.stringify; -var escape$2 = string.escape; -var isSafeProperty$1 = customs.isSafeProperty; -var hasOwnProperty$2 = object.hasOwnProperty; + var subset$1 = { + name: name$39, + factory: factory_1$42 + }; -function factory$54 (type, config, load, typed) { - var Node$$1 = load(Node); + var errorTransform = error_transform.transform; + var getSafeProperty$2 = customs.getSafeProperty; - /** - * @constructor ObjectNode - * @extends {Node} - * Holds an object with keys/values - * @param {Object.} [properties] object with key/value pairs - */ - function ObjectNode(properties) { - if (!(this instanceof ObjectNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + function factory$44 (type, config, load, typed) { + var subset = load(subset$1); - this.properties = properties || {}; + /** + * Retrieve part of an object: + * + * - Retrieve a property from an object + * - Retrieve a part of a string + * - Retrieve a matrix subset + * + * @param {Object | Array | Matrix | string} object + * @param {Index} index + * @return {Object | Array | Matrix | string} Returns the subset + */ + return function access(object, index) { + try { + if (Array.isArray(object)) { + return subset(object, index); + } + else if (object && typeof object.subset === 'function') { // Matrix + return object.subset(index); + } + else if (typeof object === 'string') { + // TODO: move getStringSubset into a separate util file, use that + return subset(object, index); + } + else if (typeof object === 'object') { + if (!index.isObjectProperty()) { + throw new TypeError('Cannot apply a numeric index as object property'); + } - // validate input - if (properties) { - if (!(typeof properties === 'object') || !Object.keys(properties).every(function (key) { - return type.isNode(properties[key]); - })) { - throw new TypeError('Object containing Nodes expected'); + return getSafeProperty$2(object, index.getObjectProperty()); + } + else { + throw new TypeError('Cannot apply index: unsupported type of object'); + } + } + catch (err) { + throw errorTransform(err); } } } - ObjectNode.prototype = new Node$$1(); + var factory_1$43 = factory$44; - ObjectNode.prototype.type = 'ObjectNode'; + var access = { + factory: factory_1$43 + }; - ObjectNode.prototype.isObjectNode = true; + var getSafeProperty$3 = customs.getSafeProperty; - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ObjectNode.prototype._compile = function (math, argNames) { - var evalEntries = {}; + function factory$45 (type, config, load, typed) { + var Node$$1 = load(Node); + var IndexNode$$1 = load(IndexNode); + var access$$1 = load(access); - for (var key in this.properties) { - if (hasOwnProperty$2(this.properties, key)) { - // we stringify/parse the key here to resolve unicode characters, - // so you cannot create a key like {"co\\u006Estructor": null} - var stringifiedKey = stringify(key); - var parsedKey = JSON.parse(stringifiedKey); - if (!isSafeProperty$1(this.properties, parsedKey)) { - throw new Error('No access to property "' + parsedKey + '"'); - } + /** + * @constructor AccessorNode + * @extends {Node} + * Access an object property or get a matrix subset + * + * @param {Node} object The object from which to retrieve + * a property or subset. + * @param {IndexNode} index IndexNode containing ranges + */ + function AccessorNode(object, index) { + if (!(this instanceof AccessorNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - evalEntries[parsedKey]= this.properties[key]._compile(math, argNames); + if (!type.isNode(object)) { + throw new TypeError('Node expected for parameter "object"'); + } + if (!type.isIndexNode(index)) { + throw new TypeError('IndexNode expected for parameter "index"'); } - } - return function evalObjectNode (scope, args, context) { - var obj = {}; + this.object = object || null; + this.index = index; - for (var key in evalEntries) { - if (hasOwnProperty$2(evalEntries, key)) { - obj[key] = evalEntries[key](scope, args, context); + // readonly property name + Object.defineProperty(this, 'name', { + get: function () { + if (this.index) { + return (this.index.isObjectProperty()) + ? this.index.getObjectProperty() + : ''; + } + else { + return this.object.name || ''; + } + }.bind(this), + set: function () { + throw new Error('Cannot assign a new name, name is read-only'); } - } - - return obj; + }); } - }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ObjectNode.prototype.forEach = function (callback) { - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - callback(this.properties[key], 'properties[' + stringify(key) + ']', this); - } - } - }; + AccessorNode.prototype = new Node$$1(); - /** - * Create a new ObjectNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {ObjectNode} Returns a transformed copy of the node - */ - ObjectNode.prototype.map = function (callback) { - var properties = {}; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - properties[key] = this._ifNode(callback(this.properties[key], - 'properties[' + stringify(key) + ']', this)); - } - } - return new ObjectNode(properties); - }; + AccessorNode.prototype.type = 'AccessorNode'; - /** - * Create a clone of this node, a shallow copy - * @return {ObjectNode} - */ - ObjectNode.prototype.clone = function() { - var properties = {}; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - properties[key] = this.properties[key]; - } - } - return new ObjectNode(properties); - }; + AccessorNode.prototype.isAccessorNode = true; - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - ObjectNode.prototype._toString = function(options) { - var entries = []; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - entries.push(stringify(key) + ': ' + this.properties[key].toString(options)); + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + AccessorNode.prototype._compile = function (math, argNames) { + var evalObject = this.object._compile(math, argNames); + var evalIndex = this.index._compile(math, argNames); + + if (this.index.isObjectProperty()) { + var prop = this.index.getObjectProperty(); + return function evalAccessorNode(scope, args, context) { + return getSafeProperty$3(evalObject(scope, args, context), prop); + }; } - } - return '{' + entries.join(', ') + '}'; - }; + else { + return function evalAccessorNode (scope, args, context) { + var object = evalObject(scope, args, context); + var index = evalIndex(scope, args, object); // we pass object here instead of context + return access$$1(object, index); + }; + } + }; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ObjectNode.prototype.toJSON = function () { - return { - mathjs: 'ObjectNode', - properties: this.properties + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + AccessorNode.prototype.forEach = function (callback) { + callback(this.object, 'object', this); + callback(this.index, 'index', this); }; - }; - /** - * Instantiate an OperatorNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "ObjectNode", "properties": {...}}`, - * where mathjs is optional - * @returns {ObjectNode} - */ - ObjectNode.fromJSON = function (json) { - return new ObjectNode(json.properties); - }; + /** + * Create a new AccessorNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {AccessorNode} Returns a transformed copy of the node + */ + AccessorNode.prototype.map = function (callback) { + return new AccessorNode( + this._ifNode(callback(this.object, 'object', this)), + this._ifNode(callback(this.index, 'index', this)) + ); + }; - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - ObjectNode.prototype.toHTML = function(options) { - var entries = []; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - entries.push('' + escape$2(key) + '' + ':' + this.properties[key].toHTML(options)); - } - } - return '{' + entries.join(',') + '}'; - }; + /** + * Create a clone of this node, a shallow copy + * @return {AccessorNode} + */ + AccessorNode.prototype.clone = function () { + return new AccessorNode(this.object, this.index); + }; - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - ObjectNode.prototype._toTex = function(options) { - var entries = []; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - entries.push("\\mathbf{" + key + ':} & ' + this.properties[key].toTex(options) + "\\\\"); + /** + * Get string representation + * @param {Object} options + * @return {string} + */ + AccessorNode.prototype._toString = function (options) { + var object = this.object.toString(options); + if (needParenthesis(this.object)) { + object = '(' + object + ')'; } - } - return '\\left\\{\\begin{array}{ll}' + entries.join('\n') + '\\end{array}\\right\\}'; - }; - return ObjectNode; -} + return object + this.index.toString(options); + }; -var name$48 = 'ObjectNode'; -var path$23 = 'expression.node'; -var factory_1$53 = factory$54; + /** + * Get HTML representation + * @param {Object} options + * @return {string} + */ + AccessorNode.prototype.toHTML = function (options) { + var object = this.object.toHTML(options); + if (needParenthesis(this.object)) { + object = '(' + object + ')'; + } -var ObjectNode = { - name: name$48, - path: path$23, - factory: factory_1$53 -}; + return object + this.index.toHTML(options); + }; -var map$4 = array.map; -var escape$3 = string.escape; -var isSafeMethod$1 = customs.isSafeMethod; -var getSafeProperty$5 = customs.getSafeProperty; + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} + */ + AccessorNode.prototype._toTex = function (options) { + var object = this.object.toTex(options); + if (needParenthesis(this.object)) { + object = '\\left(' + object + '\\right)'; + } + return object + this.index.toTex(options); + }; -function factory$55 (type, config, load, typed) { - var Node$$1 = load(Node); + /** + * Get a JSON representation of the node + * @returns {Object} + */ + AccessorNode.prototype.toJSON = function () { + return { + mathjs: 'AccessorNode', + object: this.object, + index: this.index + }; + }; - /** - * @constructor OperatorNode - * @extends {Node} - * An operator with two arguments, like 2+3 - * - * @param {string} op Operator name, for example '+' - * @param {string} fn Function name, for example 'add' - * @param {Node[]} args Operator arguments - * @param {boolean} [implicit] Is this an implicit multiplication? - */ - function OperatorNode(op, fn, args, implicit) { - if (!(this instanceof OperatorNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + /** + * Instantiate an AccessorNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "AccessorNode", object: ..., index: ...}`, + * where mathjs is optional + * @returns {AccessorNode} + */ + AccessorNode.fromJSON = function (json) { + return new AccessorNode(json.object, json.index); + }; - //validate input - if (typeof op !== 'string') { - throw new TypeError('string expected for parameter "op"'); - } - if (typeof fn !== 'string') { - throw new TypeError('string expected for parameter "fn"'); - } - if (!Array.isArray(args) || !args.every(type.isNode)) { - throw new TypeError('Array containing Nodes expected for parameter "args"'); + /** + * Are parenthesis needed? + * @private + */ + function needParenthesis(node) { + // TODO: maybe make a method on the nodes which tells whether they need parenthesis? + return !( + type.isAccessorNode(node) || + type.isArrayNode(node) || + type.isConstantNode(node) || + type.isFunctionNode(node) || + type.isObjectNode(node) || + type.isParenthesisNode(node) || + type.isSymbolNode(node)); } - this.implicit = (implicit === true); - this.op = op; - this.fn = fn; - this.args = args || []; + return AccessorNode; } - OperatorNode.prototype = new Node$$1(); + var name$40 = 'AccessorNode'; + var path$16 = 'expression.node'; + var factory_1$44 = factory$45; - OperatorNode.prototype.type = 'OperatorNode'; + var AccessorNode = { + name: name$40, + path: path$16, + factory: factory_1$44 + }; - OperatorNode.prototype.isOperatorNode = true; + var map$2 = array.map; - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - OperatorNode.prototype._compile = function (math, argNames) { - // validate fn - if (typeof this.fn !== 'string' || !isSafeMethod$1(math, this.fn)) { - if (!math[this.fn]) { - throw new Error('Function ' + this.fn + ' missing in provided namespace "math"'); - } - else { - throw new Error('No access to function "' + this.fn + '"'); - } - } + function factory$46 (type, config, load, typed) { + var Node$$1 = load(Node); - var fn = getSafeProperty$5(math, this.fn); - var evalArgs = map$4(this.args, function (arg) { - return arg._compile(math, argNames); - }); + /** + * @constructor ArrayNode + * @extends {Node} + * Holds an 1-dimensional array with items + * @param {Node[]} [items] 1 dimensional array with items + */ + function ArrayNode(items) { + if (!(this instanceof ArrayNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - if (evalArgs.length === 1) { - var evalArg0 = evalArgs[0]; - return function evalOperatorNode(scope, args, context) { - return fn(evalArg0(scope, args, context)); - }; - } - else if (evalArgs.length === 2) { - var evalArg0 = evalArgs[0]; - var evalArg1 = evalArgs[1]; - return function evalOperatorNode(scope, args, context) { - return fn(evalArg0(scope, args, context), evalArg1(scope, args, context)) - }; - } - else { - return function evalOperatorNode(scope, args, context) { - return fn.apply(null, map$4(evalArgs, function (evalArg) { - return evalArg(scope, args, context) - })); - }; - } - }; + this.items = items || []; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - OperatorNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.args.length; i++) { - callback(this.args[i], 'args[' + i + ']', this); - } - }; + // validate input + if (!Array.isArray(this.items) || !this.items.every(type.isNode)) { + throw new TypeError('Array containing Nodes expected'); + } - /** - * Create a new OperatorNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {OperatorNode} Returns a transformed copy of the node - */ - OperatorNode.prototype.map = function (callback) { - var args = []; - for (var i = 0; i < this.args.length; i++) { - args[i] = this._ifNode(callback(this.args[i], 'args[' + i + ']', this)); + // TODO: deprecated since v3, remove some day + var deprecated = function () { + throw new Error('Property `ArrayNode.nodes` is deprecated, use `ArrayNode.items` instead'); + }; + Object.defineProperty(this, 'nodes', { get: deprecated, set: deprecated }); } - return new OperatorNode(this.op, this.fn, args, this.implicit); - }; - /** - * Create a clone of this node, a shallow copy - * @return {OperatorNode} - */ - OperatorNode.prototype.clone = function () { - return new OperatorNode(this.op, this.fn, this.args.slice(0), this.implicit); - }; + ArrayNode.prototype = new Node$$1(); - /** - * Check whether this is an unary OperatorNode: - * has exactly one argument, like `-a`. - * @return {boolean} Returns true when an unary operator node, false otherwise. - */ - OperatorNode.prototype.isUnary = function () { - return this.args.length === 1; - }; + ArrayNode.prototype.type = 'ArrayNode'; - /** - * Check whether this is a binary OperatorNode: - * has exactly two arguments, like `a + b`. - * @return {boolean} Returns true when a binary operator node, false otherwise. - */ - OperatorNode.prototype.isBinary = function () { - return this.args.length === 2; - }; + ArrayNode.prototype.isArrayNode = true; - /** - * Calculate which parentheses are necessary. Gets an OperatorNode - * (which is the root of the tree) and an Array of Nodes - * (this.args) and returns an array where 'true' means that an argument - * has to be enclosed in parentheses whereas 'false' means the opposite. - * - * @param {OperatorNode} root - * @param {string} parenthesis - * @param {Node[]} args - * @param {boolean} latex - * @return {boolean[]} - * @private - */ - function calculateNecessaryParentheses(root, parenthesis, implicit, args, latex$$1) { - //precedence of the root OperatorNode - var precedence = operators.getPrecedence(root, parenthesis); - var associativity = operators.getAssociativity(root, parenthesis); - - if ((parenthesis === 'all') || ((args.length > 2) && (root.getIdentifier() !== 'OperatorNode:add') && (root.getIdentifier() !== 'OperatorNode:multiply'))) { - var parens = args.map(function (arg) { - switch (arg.getContent().type) { //Nodes that don't need extra parentheses - case 'ArrayNode': - case 'ConstantNode': - case 'SymbolNode': - case 'ParenthesisNode': - return false; - break; - default: - return true; - } + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + ArrayNode.prototype._compile = function (math, argNames) { + var evalItems = map$2(this.items, function (item) { + return item._compile(math, argNames); }); - return parens; - } - - var result = undefined; - switch (args.length) { - case 0: - result = []; - break; - case 1: //unary operators - //precedence of the operand - var operandPrecedence = operators.getPrecedence(args[0], parenthesis); + var asMatrix = (math.config().matrix !== 'Array'); + if (asMatrix) { + var matrix = math.matrix; + return function evalArrayNode (scope, args, context) { + return matrix(map$2(evalItems, function (evalItem) { + return evalItem(scope, args, context); + })); + }; + } + else { + return function evalArrayNode (scope, args, context) { + return map$2(evalItems, function (evalItem) { + return evalItem(scope, args, context); + }); + }; + } + }; - //handle special cases for LaTeX, where some of the parentheses aren't needed - if (latex$$1 && (operandPrecedence !== null)) { - var operandIdentifier; - var rootIdentifier; - if (parenthesis === 'keep') { - operandIdentifier = args[0].getIdentifier(); - rootIdentifier = root.getIdentifier(); - } - else { - //Ignore Parenthesis Nodes when not in 'keep' mode - operandIdentifier = args[0].getContent().getIdentifier(); - rootIdentifier = root.getContent().getIdentifier(); - } - if (operators.properties[precedence][rootIdentifier].latexLeftParens === false) { - result = [false]; - break; - } + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + ArrayNode.prototype.forEach = function (callback) { + for (var i = 0; i < this.items.length; i++) { + var node = this.items[i]; + callback(node, 'items[' + i + ']', this); + } + }; - if (operators.properties[operandPrecedence][operandIdentifier].latexParens === false) { - result = [false]; - break; - } - } + /** + * Create a new ArrayNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {ArrayNode} Returns a transformed copy of the node + */ + ArrayNode.prototype.map = function (callback) { + var items = []; + for (var i = 0; i < this.items.length; i++) { + items[i] = this._ifNode(callback(this.items[i], 'items[' + i + ']', this)); + } + return new ArrayNode(items); + }; - if (operandPrecedence === null) { - //if the operand has no defined precedence, no parens are needed - result = [false]; - break; - } + /** + * Create a clone of this node, a shallow copy + * @return {ArrayNode} + */ + ArrayNode.prototype.clone = function() { + return new ArrayNode(this.items.slice(0)); + }; - if (operandPrecedence <= precedence) { - //if the operands precedence is lower, parens are needed - result = [true]; - break; - } + /** + * Get string representation + * @param {Object} options + * @return {string} str + * @override + */ + ArrayNode.prototype._toString = function(options) { + var items = this.items.map(function (node) { + return node.toString(options); + }); + return '[' + items.join(', ') + ']'; + }; - //otherwise, no parens needed - result = [false]; - break; + /** + * Get a JSON representation of the node + * @returns {Object} + */ + ArrayNode.prototype.toJSON = function () { + return { + mathjs: 'ArrayNode', + items: this.items + }; + }; - case 2: //binary operators - var lhsParens; //left hand side needs parenthesis? - //precedence of the left hand side - var lhsPrecedence = operators.getPrecedence(args[0], parenthesis); - //is the root node associative with the left hand side - var assocWithLhs = operators.isAssociativeWith(root, args[0], parenthesis); + /** + * Instantiate an ArrayNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "ArrayNode", items: [...]}`, + * where mathjs is optional + * @returns {ArrayNode} + */ + ArrayNode.fromJSON = function (json) { + return new ArrayNode(json.items); + }; - if (lhsPrecedence === null) { - //if the left hand side has no defined precedence, no parens are needed - //FunctionNode for example - lhsParens = false; - } - else if ((lhsPrecedence === precedence) && (associativity === 'right') && !assocWithLhs) { - //In case of equal precedence, if the root node is left associative - // parens are **never** necessary for the left hand side. - //If it is right associative however, parens are necessary - //if the root node isn't associative with the left hand side - lhsParens = true; - } - else if (lhsPrecedence < precedence) { - lhsParens = true; - } - else { - lhsParens = false; - } + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + * @override + */ + ArrayNode.prototype.toHTML = function(options) { + var items = this.items.map(function (node) { + return node.toHTML(options); + }); + return '[' + items.join(',') + ']'; + }; - var rhsParens; //right hand side needs parenthesis? - //precedence of the right hand side - var rhsPrecedence = operators.getPrecedence(args[1], parenthesis); - //is the root node associative with the right hand side? - var assocWithRhs = operators.isAssociativeWith(root, args[1], parenthesis); + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + */ + ArrayNode.prototype._toTex = function(options) { + var s = '\\begin{bmatrix}'; - if (rhsPrecedence === null) { - //if the right hand side has no defined precedence, no parens are needed - //FunctionNode for example - rhsParens = false; - } - else if ((rhsPrecedence === precedence) && (associativity === 'left') && !assocWithRhs) { - //In case of equal precedence, if the root node is right associative - // parens are **never** necessary for the right hand side. - //If it is left associative however, parens are necessary - //if the root node isn't associative with the right hand side - rhsParens = true; - } - else if (rhsPrecedence < precedence) { - rhsParens = true; + this.items.forEach(function(node) { + if (node.items) { + s += node.items.map(function(childNode) { + return childNode.toTex(options); + }).join('&'); } else { - rhsParens = false; + s += node.toTex(options); } - //handle special cases for LaTeX, where some of the parentheses aren't needed - if (latex$$1) { - var rootIdentifier; - var lhsIdentifier; - var rhsIdentifier; - if (parenthesis === 'keep') { - rootIdentifier = root.getIdentifier(); - lhsIdentifier = root.args[0].getIdentifier(); - rhsIdentifier = root.args[1].getIdentifier(); - } - else { - //Ignore ParenthesisNodes when not in 'keep' mode - rootIdentifier = root.getContent().getIdentifier(); - lhsIdentifier = root.args[0].getContent().getIdentifier(); - rhsIdentifier = root.args[1].getContent().getIdentifier(); - } - - if (lhsPrecedence !== null) { - if (operators.properties[precedence][rootIdentifier].latexLeftParens === false) { - lhsParens = false; - } + // new line + s += '\\\\'; + }); + s += '\\end{bmatrix}'; + return s; + }; - if (operators.properties[lhsPrecedence][lhsIdentifier].latexParens === false) { - lhsParens = false; - } - } + return ArrayNode; + } - if (rhsPrecedence !== null) { - if (operators.properties[precedence][rootIdentifier].latexRightParens === false) { - rhsParens = false; - } + var name$41 = 'ArrayNode'; + var path$17 = 'expression.node'; + var factory_1$45 = factory$46; - if (operators.properties[rhsPrecedence][rhsIdentifier].latexParens === false) { - rhsParens = false; - } - } - } + var ArrayNode = { + name: name$41, + path: path$17, + factory: factory_1$45 + }; - result = [lhsParens, rhsParens]; - break; + var errorTransform$1 = error_transform.transform; + var setSafeProperty$2 = customs.setSafeProperty; - default: - if ((root.getIdentifier() === 'OperatorNode:add') || (root.getIdentifier() === 'OperatorNode:multiply')) { - var result = args.map(function (arg) { - var argPrecedence = operators.getPrecedence(arg, parenthesis); - var assocWithArg = operators.isAssociativeWith(root, arg, parenthesis); - var argAssociativity = operators.getAssociativity(arg, parenthesis); - if (argPrecedence === null) { - //if the argument has no defined precedence, no parens are needed - return false; - } else if ((precedence === argPrecedence) && (associativity === argAssociativity) && !assocWithArg) { - return true; - } else if (argPrecedence < precedence) { - return true; - } + function factory$47 (type, config, load, typed) { + var subset = load(subset$1); + var matrix$$1 = load(matrix); - return false; - }); + /** + * Replace part of an object: + * + * - Assign a property to an object + * - Replace a part of a string + * - Replace a matrix subset + * + * @param {Object | Array | Matrix | string} object + * @param {Index} index + * @param {*} value + * @return {Object | Array | Matrix | string} Returns the original object + * except in case of a string + */ + // TODO: change assign to return the value instead of the object + return function assign(object, index, value) { + try { + if (Array.isArray(object)) { + return matrix$$1(object).subset(index, value).valueOf(); } - break; - } - - //handles an edge case of 'auto' parentheses with implicit multiplication of ConstantNode - //In that case print parentheses for ParenthesisNodes even though they normally wouldn't be - //printed. - if ((args.length >= 2) && (root.getIdentifier() === 'OperatorNode:multiply') && root.implicit && (parenthesis === 'auto') && (implicit === 'hide')) { - result = args.map(function (arg, index) { - var isParenthesisNode = (arg.getIdentifier() === 'ParenthesisNode'); - if (result[index] || isParenthesisNode) { //put in parenthesis? - return true; + else if (object && typeof object.subset === 'function') { // Matrix + return object.subset(index, value); } - - return false; - }); + else if (typeof object === 'string') { + // TODO: move setStringSubset into a separate util file, use that + return subset(object, index, value); + } + else if (typeof object === 'object') { + if (!index.isObjectProperty()) { + throw TypeError('Cannot apply a numeric index as object property'); + } + setSafeProperty$2(object, index.getObjectProperty(), value); + return object; + } + else { + throw new TypeError('Cannot apply index: unsupported type of object'); + } + } + catch (err) { + throw errorTransform$1(err); + } } - - return result; } - /** - * Get string representation. - * @param {Object} options - * @return {string} str - */ - OperatorNode.prototype._toString = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var implicit = (options && options.implicit) ? options.implicit : 'hide'; - var args = this.args; - var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, false); + var factory_1$46 = factory$47; - if (args.length === 1) { //unary operators - var assoc = operators.getAssociativity(this, parenthesis); + var assign = { + factory: factory_1$46 + }; - var operand = args[0].toString(options); - if (parens[0]) { - operand = '(' + operand + ')'; + //list of identifiers of nodes in order of their precedence + //also contains information about left/right associativity + //and which other operator the operator is associative with + //Example: + // addition is associative with addition and subtraction, because: + // (a+b)+c=a+(b+c) + // (a+b)-c=a+(b-c) + // + // postfix operators are left associative, prefix operators + // are right associative + // + //It's also possible to set the following properties: + // latexParens: if set to false, this node doesn't need to be enclosed + // in parentheses when using LaTeX + // latexLeftParens: if set to false, this !OperatorNode's! + // left argument doesn't need to be enclosed + // in parentheses + // latexRightParens: the same for the right argument + var properties = [ + { //assignment + 'AssignmentNode': {}, + 'FunctionAssignmentNode': {} + }, + { //conditional expression + 'ConditionalNode': { + latexLeftParens: false, + latexRightParens: false, + latexParens: false + //conditionals don't need parentheses in LaTeX because + //they are 2 dimensional + } + }, + { //logical or + 'OperatorNode:or': { + associativity: 'left', + associativeWith: [] } - if (assoc === 'right') { //prefix operator - return this.op + operand; + }, + { //logical xor + 'OperatorNode:xor': { + associativity: 'left', + associativeWith: [] } - else if (assoc === 'left') { //postfix - return operand + this.op; + }, + { //logical and + 'OperatorNode:and': { + associativity: 'left', + associativeWith: [] } - - //fall back to postfix - return operand + this.op; - } else if (args.length == 2) { - var lhs = args[0].toString(options); //left hand side - var rhs = args[1].toString(options); //right hand side - if (parens[0]) { //left hand side in parenthesis? - lhs = '(' + lhs + ')'; + }, + { //bitwise or + 'OperatorNode:bitOr': { + associativity: 'left', + associativeWith: [] } - if (parens[1]) { //right hand side in parenthesis? - rhs = '(' + rhs + ')'; + }, + { //bitwise xor + 'OperatorNode:bitXor': { + associativity: 'left', + associativeWith: [] } - - if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit == 'hide')) { - return lhs + ' ' + rhs; + }, + { //bitwise and + 'OperatorNode:bitAnd': { + associativity: 'left', + associativeWith: [] } - - return lhs + ' ' + this.op + ' ' + rhs; - } else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { - var stringifiedArgs = args.map(function (arg, index) { - arg = arg.toString(options); - if (parens[index]) { //put in parenthesis? - arg = '(' + arg + ')'; - } - - return arg; - }); - - if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit === 'hide')) { - return stringifiedArgs.join(' '); + }, + { //relational operators + 'OperatorNode:equal': { + associativity: 'left', + associativeWith: [] + }, + 'OperatorNode:unequal': { + associativity: 'left', + associativeWith: [] + }, + 'OperatorNode:smaller': { + associativity: 'left', + associativeWith: [] + }, + 'OperatorNode:larger': { + associativity: 'left', + associativeWith: [] + }, + 'OperatorNode:smallerEq': { + associativity: 'left', + associativeWith: [] + }, + 'OperatorNode:largerEq': { + associativity: 'left', + associativeWith: [] + } + }, + { //bitshift operators + 'OperatorNode:leftShift': { + associativity: 'left', + associativeWith: [] + }, + 'OperatorNode:rightArithShift': { + associativity: 'left', + associativeWith: [] + }, + 'OperatorNode:rightLogShift': { + associativity: 'left', + associativeWith: [] + } + }, + { //unit conversion + 'OperatorNode:to': { + associativity: 'left', + associativeWith: [] + } + }, + { //range + 'RangeNode': {} + }, + { //addition, subtraction + 'OperatorNode:add': { + associativity: 'left', + associativeWith: ['OperatorNode:add', 'OperatorNode:subtract'] + }, + 'OperatorNode:subtract': { + associativity: 'left', + associativeWith: [] + } + }, + { //multiply, divide, modulus + 'OperatorNode:multiply': { + associativity: 'left', + associativeWith: [ + 'OperatorNode:multiply', + 'OperatorNode:divide', + 'Operator:dotMultiply', + 'Operator:dotDivide' + ] + }, + 'OperatorNode:divide': { + associativity: 'left', + associativeWith: [], + latexLeftParens: false, + latexRightParens: false, + latexParens: false + //fractions don't require parentheses because + //they're 2 dimensional, so parens aren't needed + //in LaTeX + }, + 'OperatorNode:dotMultiply': { + associativity: 'left', + associativeWith: [ + 'OperatorNode:multiply', + 'OperatorNode:divide', + 'OperatorNode:dotMultiply', + 'OperatorNode:doDivide' + ] + }, + 'OperatorNode:dotDivide': { + associativity: 'left', + associativeWith: [] + }, + 'OperatorNode:mod': { + associativity: 'left', + associativeWith: [] + } + }, + { //unary prefix operators + 'OperatorNode:unaryPlus': { + associativity: 'right' + }, + 'OperatorNode:unaryMinus': { + associativity: 'right' + }, + 'OperatorNode:bitNot': { + associativity: 'right' + }, + 'OperatorNode:not': { + associativity: 'right' + } + }, + { //exponentiation + 'OperatorNode:pow': { + associativity: 'right', + associativeWith: [], + latexRightParens: false + //the exponent doesn't need parentheses in + //LaTeX because it's 2 dimensional + //(it's on top) + }, + 'OperatorNode:dotPow': { + associativity: 'right', + associativeWith: [] + } + }, + { //factorial + 'OperatorNode:factorial': { + associativity: 'left' + } + }, + { //matrix transpose + 'OperatorNode:transpose': { + associativity: 'left' } - - return stringifiedArgs.join(' ' + this.op + ' '); - } else { - //fallback to formatting as a function call - return this.fn + '(' + this.args.join(', ') + ')'; } - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - OperatorNode.prototype.toJSON = function () { - return { - mathjs: 'OperatorNode', - op: this.op, - fn: this.fn, - args: this.args, - implicit: this.implicit - }; - }; + ]; /** - * Instantiate an OperatorNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "OperatorNode", "op": "+", "fn": "add", "args": [...], "implicit": false}`, - * where mathjs is optional - * @returns {OperatorNode} + * Get the precedence of a Node. + * Higher number for higher precedence, starting with 0. + * Returns null if the precedence is undefined. + * + * @param {Node} + * @param {string} parenthesis + * @return {number|null} */ - OperatorNode.fromJSON = function (json) { - return new OperatorNode(json.op, json.fn, json.args, json.implicit); - }; + function getPrecedence (_node, parenthesis) { + var node = _node; + if (parenthesis !== 'keep') { + //ParenthesisNodes are only ignored when not in 'keep' mode + node = _node.getContent(); + } + var identifier = node.getIdentifier(); + for (var i = 0; i < properties.length; i++) { + if (identifier in properties[i]) { + return i; + } + } + return null; + } /** - * Get HTML representation. - * @param {Object} options - * @return {string} str + * Get the associativity of an operator (left or right). + * Returns a string containing 'left' or 'right' or null if + * the associativity is not defined. + * + * @param {Node} + * @param {string} parenthesis + * @return {string|null} + * @throws {Error} */ - OperatorNode.prototype.toHTML = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var implicit = (options && options.implicit) ? options.implicit : 'hide'; - var args = this.args; - var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, false); - - if (args.length === 1) { //unary operators - var assoc = operators.getAssociativity(this, parenthesis); - - var operand = args[0].toHTML(options); - if (parens[0]) { - operand = '(' + operand + ')'; - } + function getAssociativity (_node, parenthesis) { + var node = _node; + if (parenthesis !== 'keep') { + //ParenthesisNodes are only ignored when not in 'keep' mode + node = _node.getContent(); + } + var identifier = node.getIdentifier(); + var index = getPrecedence(node, parenthesis); + if (index === null) { + //node isn't in the list + return null; + } + var property = properties[index][identifier]; - if (assoc === 'right') { //prefix operator - return '' + escape$3(this.op) + '' + operand; + if (property.hasOwnProperty('associativity')) { + if (property.associativity === 'left') { + return 'left'; } - else if (assoc === 'left') { //postfix - return '' + escape$3(this.op) + '' + operand; + if (property.associativity === 'right') { + return 'right'; } + //associativity is invalid + throw Error('\'' + identifier + '\' has the invalid associativity \'' + + property.associativity + '\'.'); + } + + //associativity is undefined + return null; + } - //fall back to postfix - return '' + escape$3(this.op) + '' + operand; + /** + * Check if an operator is associative with another operator. + * Returns either true or false or null if not defined. + * + * @param {Node} nodeA + * @param {Node} nodeB + * @param {string} parenthesis + * @return {bool|null} + */ + function isAssociativeWith (nodeA, nodeB, parenthesis) { + var a = nodeA; + var b = nodeB; + if (parenthesis !== 'keep') { + //ParenthesisNodes are only ignored when not in 'keep' mode + var a = nodeA.getContent(); + var b = nodeB.getContent(); + } + var identifierA = a.getIdentifier(); + var identifierB = b.getIdentifier(); + var index = getPrecedence(a, parenthesis); + if (index === null) { + //node isn't in the list + return null; } - else if (args.length == 2) { // binary operatoes - var lhs = args[0].toHTML(options); //left hand side - var rhs = args[1].toHTML(options); //right hand side - if (parens[0]) { //left hand side in parenthesis? - lhs = '(' + lhs + ')'; - } - if (parens[1]) { //right hand side in parenthesis? - rhs = '(' + rhs + ')'; + var property = properties[index][identifierA]; + + if (property.hasOwnProperty('associativeWith') + && (property.associativeWith instanceof Array)) { + for (var i = 0; i < property.associativeWith.length; i++) { + if (property.associativeWith[i] === identifierB) { + return true; + } } - - if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit == 'hide')) { - return lhs + '' + rhs; - } - - return lhs + '' + escape$3(this.op) + '' + rhs; + return false; } - else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { - var stringifiedArgs = args.map(function (arg, index) { - arg = arg.toHTML(options); - if (parens[index]) { //put in parenthesis? - arg = '(' + arg + ')'; - } - return arg; - }); + //associativeWith is not defined + return null; + } - if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit === 'hide')) { - return stringifiedArgs.join(''); - } + var properties_1 = properties; + var getPrecedence_1 = getPrecedence; + var getAssociativity_1 = getAssociativity; + var isAssociativeWith_1 = isAssociativeWith; - return stringifiedArgs.join('' + escape$3(this.op) + ''); - } else { - //fallback to formatting as a function call - return '' + escape$3(this.fn) + '(' + stringifiedArgs.join(',') + ')'; - } + var operators = { + properties: properties_1, + getPrecedence: getPrecedence_1, + getAssociativity: getAssociativity_1, + isAssociativeWith: isAssociativeWith_1 }; - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - OperatorNode.prototype._toTex = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var implicit = (options && options.implicit) ? options.implicit : 'hide'; - var args = this.args; - var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, true); - var op = latex.operators[this.fn]; - op = typeof op === 'undefined' ? this.op : op; //fall back to using this.op + var getSafeProperty$4 = customs.getSafeProperty; + var setSafeProperty$3 = customs.setSafeProperty; - if (args.length === 1) { //unary operators - var assoc = operators.getAssociativity(this, parenthesis); + function factory$48 (type, config, load, typed) { + var Node$$1 = load(Node); + var assign$$1 = load(assign); + var access$$1 = load(access); - var operand = args[0].toTex(options); - if (parens[0]) { - operand = '\\left(' + operand + '\\right)'; - } + var operators$$1 = operators; - if (assoc === 'right') { //prefix operator - return op + operand; - } - else if (assoc === 'left') { //postfix operator - return operand + op; + /** + * @constructor AssignmentNode + * @extends {Node} + * + * Define a symbol, like `a=3.2`, update a property like `a.b=3.2`, or + * replace a subset of a matrix like `A[2,2]=42`. + * + * Syntax: + * + * new AssignmentNode(symbol, value) + * new AssignmentNode(object, index, value) + * + * Usage: + * + * new AssignmentNode(new SymbolNode('a'), new ConstantNode(2)); // a=2 + * new AssignmentNode(new SymbolNode('a'), new IndexNode('b'), new ConstantNode(2)) // a.b=2 + * new AssignmentNode(new SymbolNode('a'), new IndexNode(1, 2), new ConstantNode(3)) // a[1,2]=3 + * + * @param {SymbolNode | AccessorNode} object Object on which to assign a value + * @param {IndexNode} [index=null] Index, property name or matrix + * index. Optional. If not provided + * and `object` is a SymbolNode, + * the property is assigned to the + * global scope. + * @param {Node} value The value to be assigned + */ + function AssignmentNode(object, index, value) { + if (!(this instanceof AssignmentNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); } - //fall back to postfix - return operand + op; - } else if (args.length === 2) { //binary operators - var lhs = args[0]; //left hand side - var lhsTex = lhs.toTex(options); - if (parens[0]) { - lhsTex = '\\left(' + lhsTex + '\\right)'; - } + this.object = object; + this.index = value ? index : null; + this.value = value ? value : index; - var rhs = args[1]; //right hand side - var rhsTex = rhs.toTex(options); - if (parens[1]) { - rhsTex = '\\left(' + rhsTex + '\\right)'; + // validate input + if (!type.isSymbolNode(object) && !type.isAccessorNode(object)) { + throw new TypeError('SymbolNode or AccessorNode expected as "object"'); } - - //handle some exceptions (due to the way LaTeX works) - var lhsIdentifier; - if (parenthesis === 'keep') { - lhsIdentifier = lhs.getIdentifier(); + if (type.isSymbolNode(object) && object.name === 'end') { + throw new Error('Cannot assign to symbol "end"'); } - else { - //Ignore ParenthesisNodes if in 'keep' mode - lhsIdentifier = lhs.getContent().getIdentifier(); - } - switch (this.getIdentifier()) { - case 'OperatorNode:divide': - //op contains '\\frac' at this point - return op + '{' + lhsTex + '}' + '{' + rhsTex + '}'; - case 'OperatorNode:pow': - lhsTex = '{' + lhsTex + '}'; - rhsTex = '{' + rhsTex + '}'; - switch (lhsIdentifier) { - case 'ConditionalNode': // - case 'OperatorNode:divide': - lhsTex = '\\left(' + lhsTex + '\\right)'; - } - case 'OperatorNode:multiply': - if (this.implicit && (implicit === 'hide')) { - return lhsTex + '~' + rhsTex; - } - } - return lhsTex + op + rhsTex; - } else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { - var texifiedArgs = args.map(function (arg, index) { - arg = arg.toTex(options); - if (parens[index]) { - arg = '\\left(' + arg + '\\right)'; - } - return arg; - }); - - if ((this.getIdentifier() === 'OperatorNode:multiply') && this.implicit) { - return texifiedArgs.join('~'); + if (this.index && !type.isIndexNode(this.index)) { // index is optional + throw new TypeError('IndexNode expected as "index"'); + } + if (!type.isNode(this.value)) { + throw new TypeError('Node expected as "value"'); } - return texifiedArgs.join(op) - } else { - //fall back to formatting as a function call - //as this is a fallback, it doesn't use - //fancy function names - return '\\mathrm{' + this.fn + '}\\left(' - + args.map(function (arg) { - return arg.toTex(options); - }).join(',') + '\\right)'; + // readonly property name + Object.defineProperty(this, 'name', { + get: function () { + if (this.index) { + return (this.index.isObjectProperty()) + ? this.index.getObjectProperty() + : ''; + } + else { + return this.object.name || ''; + } + }.bind(this), + set: function () { + throw new Error('Cannot assign a new name, name is read-only'); + } + }); } - }; - /** - * Get identifier. - * @return {string} - */ - OperatorNode.prototype.getIdentifier = function () { - return this.type + ':' + this.fn; - }; + AssignmentNode.prototype = new Node$$1(); - return OperatorNode; -} + AssignmentNode.prototype.type = 'AssignmentNode'; -var name$49 = 'OperatorNode'; -var path$24 = 'expression.node'; -var factory_1$54 = factory$55; + AssignmentNode.prototype.isAssignmentNode = true; -var OperatorNode = { - name: name$49, - path: path$24, - factory: factory_1$54 -}; + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + AssignmentNode.prototype._compile = function (math, argNames) { + var evalObject = this.object._compile(math, argNames); + var evalIndex = this.index ? this.index._compile(math, argNames) : null; + var evalValue = this.value._compile(math, argNames); + var name = this.object.name; + + if (!this.index) { + // apply a variable to the scope, for example `a=2` + if (!type.isSymbolNode(this.object)) { + throw new TypeError('SymbolNode expected as object'); + } -function factory$56 (type, config, load, typed) { - var Node$$1 = load(Node); + return function evalAssignmentNode (scope, args, context) { + return setSafeProperty$3(scope, name, evalValue(scope, args, context)); + }; + } + else if (this.index.isObjectProperty()) { + // apply an object property for example `a.b=2` + var prop = this.index.getObjectProperty(); - /** - * @constructor ParenthesisNode - * @extends {Node} - * A parenthesis node describes manual parenthesis from the user input - * @param {Node} content - * @extends {Node} - */ - function ParenthesisNode(content) { - if (!(this instanceof ParenthesisNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + return function evalAssignmentNode (scope, args, context) { + var object = evalObject(scope, args, context); + var value = evalValue(scope, args, context); + return setSafeProperty$3(object, prop, value); + }; + } + else if (type.isSymbolNode(this.object)) { + // update a matrix subset, for example `a[2]=3` + return function evalAssignmentNode(scope, args, context) { + var childObject = evalObject(scope, args, context); + var value = evalValue(scope, args, context); + var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context + setSafeProperty$3(scope, name, assign$$1(childObject, index, value)); + return value; + } + } + else { // type.isAccessorNode(node.object) === true + // update a matrix subset, for example `a.b[2]=3` - // validate input - if (!type.isNode(content)) { - throw new TypeError('Node expected for parameter "content"'); - } + // we will not use the compile function of the AccessorNode, but compile it + // ourselves here as we need the parent object of the AccessorNode: + // wee need to apply the updated object to parent object + var evalParentObject = this.object.object._compile(math, argNames); - this.content = content; - } + if (this.object.index.isObjectProperty()) { + var parentProp = this.object.index.getObjectProperty(); - ParenthesisNode.prototype = new Node$$1(); + return function evalAssignmentNode(scope, args, context) { + var parent = evalParentObject(scope, args, context); + var childObject = getSafeProperty$4(parent, parentProp); + var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context + var value = evalValue(scope, args, context); + setSafeProperty$3(parent, parentProp, assign$$1(childObject, index, value)); + return value; + } + } + else { + // if some parameters use the 'end' parameter, we need to calculate the size + var evalParentIndex = this.object.index._compile(math, argNames); - ParenthesisNode.prototype.type = 'ParenthesisNode'; + return function evalAssignmentNode(scope, args, context) { + var parent = evalParentObject(scope, args, context); + var parentIndex = evalParentIndex(scope, args, parent); // Important: we pass parent instead of context + var childObject = access$$1(parent, parentIndex); + var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context + var value = evalValue(scope, args, context); - ParenthesisNode.prototype.isParenthesisNode = true; + assign$$1(parent, parentIndex, assign$$1(childObject, index, value)); - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ParenthesisNode.prototype._compile = function (math, argNames) { - return this.content._compile(math, argNames); - }; + return value; + } + } + } + }; - /** - * Get the content of the current Node. - * @return {Node} content - * @override - **/ - ParenthesisNode.prototype.getContent = function () { - return this.content.getContent(); - }; + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + AssignmentNode.prototype.forEach = function (callback) { + callback(this.object, 'object', this); + if (this.index) { + callback(this.index, 'index', this); + } + callback(this.value, 'value', this); + }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ParenthesisNode.prototype.forEach = function (callback) { - callback(this.content, 'content', this); - }; + /** + * Create a new AssignmentNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {AssignmentNode} Returns a transformed copy of the node + */ + AssignmentNode.prototype.map = function (callback) { + var object = this._ifNode(callback(this.object, 'object', this)); + var index = this.index + ? this._ifNode(callback(this.index, 'index', this)) + : null; + var value = this._ifNode(callback(this.value, 'value', this)); + + return new AssignmentNode(object, index, value); + }; - /** - * Create a new ParenthesisNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node) : Node} callback - * @returns {ParenthesisNode} Returns a clone of the node - */ - ParenthesisNode.prototype.map = function (callback) { - var content = callback(this.content, 'content', this); - return new ParenthesisNode(content); - }; + /** + * Create a clone of this node, a shallow copy + * @return {AssignmentNode} + */ + AssignmentNode.prototype.clone = function() { + return new AssignmentNode(this.object, this.index, this.value); + }; - /** - * Create a clone of this node, a shallow copy - * @return {ParenthesisNode} - */ - ParenthesisNode.prototype.clone = function() { - return new ParenthesisNode(this.content); - }; + /* + * Is parenthesis needed? + * @param {node} node + * @param {string} [parenthesis='keep'] + * @private + */ + function needParenthesis(node, parenthesis) { + if (!parenthesis) { + parenthesis = 'keep'; + } - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - ParenthesisNode.prototype._toString = function(options) { - if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { - return '(' + this.content.toString(options) + ')'; + var precedence = operators$$1.getPrecedence(node, parenthesis); + var exprPrecedence = operators$$1.getPrecedence(node.value, parenthesis); + return (parenthesis === 'all') + || ((exprPrecedence !== null) && (exprPrecedence <= precedence)); } - return this.content.toString(options); - }; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ParenthesisNode.prototype.toJSON = function () { - return { - mathjs: 'ParenthesisNode', - content: this.content + /** + * Get string representation + * @param {Object} options + * @return {string} + */ + AssignmentNode.prototype._toString = function(options) { + var object = this.object.toString(options); + var index = this.index ? this.index.toString(options) : ''; + var value = this.value.toString(options); + if (needParenthesis(this, options && options.parenthesis)) { + value = '(' + value + ')'; + } + + return object + index + ' = ' + value; }; - }; - /** - * Instantiate an ParenthesisNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "ParenthesisNode", "content": ...}`, - * where mathjs is optional - * @returns {ParenthesisNode} - */ - ParenthesisNode.fromJSON = function (json) { - return new ParenthesisNode(json.content); - }; + /** + * Get a JSON representation of the node + * @returns {Object} + */ + AssignmentNode.prototype.toJSON = function () { + return { + mathjs: 'AssignmentNode', + object: this.object, + index: this.index, + value: this.value + }; + }; - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - ParenthesisNode.prototype.toHTML = function(options) { - if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { - return '(' + this.content.toHTML(options) + ')'; - } - return this.content.toHTML(options); - }; + /** + * Instantiate an AssignmentNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "AssignmentNode", object: ..., index: ..., value: ...}`, + * where mathjs is optional + * @returns {AssignmentNode} + */ + AssignmentNode.fromJSON = function (json) { + return new AssignmentNode(json.object, json.index, json.value); + }; - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - * @override - */ - ParenthesisNode.prototype._toTex = function(options) { - if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { - return '\\left(' + this.content.toTex(options) + '\\right)'; - } - return this.content.toTex(options); - }; + /** + * Get HTML representation + * @param {Object} options + * @return {string} + */ + AssignmentNode.prototype.toHTML = function(options) { + var object = this.object.toHTML(options); + var index = this.index ? this.index.toHTML(options) : ''; + var value = this.value.toHTML(options); + if (needParenthesis(this, options && options.parenthesis)) { + value = '(' + value + ')'; + } - return ParenthesisNode; -} + return object + index + '=' + value; + }; -var name$50 = 'ParenthesisNode'; -var path$25 = 'expression.node'; -var factory_1$55 = factory$56; + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} + */ + AssignmentNode.prototype._toTex = function(options) { + var object = this.object.toTex(options); + var index = this.index ? this.index.toTex(options) : ''; + var value = this.value.toTex(options); + if (needParenthesis(this, options && options.parenthesis)) { + value = '\\left(' + value + '\\right)'; + } -var ParenthesisNode = { - name: name$50, - path: path$25, - factory: factory_1$55 -}; + return object + index + ':=' + value; + }; -var escape$4 = string.escape; -var hasOwnProperty$3 = object.hasOwnProperty; -var getSafeProperty$6 = customs.getSafeProperty; + return AssignmentNode; + } -function factory$57 (type, config, load, typed, math) { - var Node$$1 = load(Node); + var name$42 = 'AssignmentNode'; + var path$18 = 'expression.node'; + var factory_1$47 = factory$48; - /** - * Check whether some name is a valueless unit like "inch". - * @param {string} name - * @return {boolean} - */ - function isValuelessUnit (name) { - return type.Unit ? type.Unit.isValuelessUnit(name) : false; - } + var AssignmentNode = { + name: name$42, + path: path$18, + factory: factory_1$47 + }; - /** - * @constructor SymbolNode - * @extends {Node} - * A symbol node can hold and resolve a symbol - * @param {string} name - * @extends {Node} - */ - function SymbolNode(name) { - if (!(this instanceof SymbolNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); + var forEach$1 = array.forEach; + var map$3 = array.map; + + function factory$49 (type, config, load, typed) { + var Node$$1 = load(Node); + var ResultSet$$1 = load(ResultSet); + + /** + * @constructor BlockNode + * @extends {Node} + * Holds a set with blocks + * @param {Array.<{node: Node} | {node: Node, visible: boolean}>} blocks + * An array with blocks, where a block is constructed as an Object + * with properties block, which is a Node, and visible, which is + * a boolean. The property visible is optional and is true by default + */ + function BlockNode(blocks) { + if (!(this instanceof BlockNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } + + // validate input, copy blocks + if (!Array.isArray(blocks)) throw new Error('Array expected'); + this.blocks = blocks.map(function (block) { + var node = block && block.node; + var visible = block && block.visible !== undefined ? block.visible : true; + + if (!type.isNode(node)) throw new TypeError('Property "node" must be a Node'); + if (typeof visible !== 'boolean') throw new TypeError('Property "visible" must be a boolean'); + + return { + node: node, + visible: visible + } + }); } - // validate input - if (typeof name !== 'string') throw new TypeError('String expected for parameter "name"'); + BlockNode.prototype = new Node$$1(); - this.name = name; - } + BlockNode.prototype.type = 'BlockNode'; - SymbolNode.prototype = new Node$$1(); + BlockNode.prototype.isBlockNode = true; - SymbolNode.prototype.type = 'SymbolNode'; + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + BlockNode.prototype._compile = function (math, argNames) { + var evalBlocks = map$3(this.blocks, function (block) { + return { + eval: block.node._compile(math, argNames), + visible: block.visible + }; + }); - SymbolNode.prototype.isSymbolNode = true; + return function evalBlockNodes (scope, args, context) { + var results = []; - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - SymbolNode.prototype._compile = function (math, argNames) { - var name = this.name; + forEach$1(evalBlocks, function evalBlockNode(block) { + var result = block.eval(scope, args, context); + if (block.visible) { + results.push(result); + } + }); - if (hasOwnProperty$3(argNames, name)) { - // this is a FunctionAssignment argument - // (like an x when inside the expression of a function assignment `f(x) = ...`) - return function (scope, args, context) { - return args[name]; + return new ResultSet$$1(results); } - } - else if (name in math) { - return function (scope, args, context) { - return name in scope - ? getSafeProperty$6(scope, name) - : getSafeProperty$6(math, name); + }; + + /** + * Execute a callback for each of the child blocks of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + BlockNode.prototype.forEach = function (callback) { + for (var i = 0; i < this.blocks.length; i++) { + callback(this.blocks[i].node, 'blocks[' + i + '].node', this); } - } - else { - var isUnit = isValuelessUnit(name); + }; - return function (scope, args, context) { - return name in scope - ? getSafeProperty$6(scope, name) - : isUnit - ? new type.Unit(null, name) - : undef(name); + /** + * Create a new BlockNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {BlockNode} Returns a transformed copy of the node + */ + BlockNode.prototype.map = function (callback) { + var blocks = []; + for (var i = 0; i < this.blocks.length; i++) { + var block = this.blocks[i]; + var node = this._ifNode(callback(block.node, 'blocks[' + i + '].node', this)); + blocks[i] = { + node: node, + visible: block.visible + }; } - } - }; + return new BlockNode(blocks); + }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - SymbolNode.prototype.forEach = function (callback) { - // nothing to do, we don't have childs - }; + /** + * Create a clone of this node, a shallow copy + * @return {BlockNode} + */ + BlockNode.prototype.clone = function () { + var blocks = this.blocks.map(function (block) { + return { + node: block.node, + visible: block.visible + }; + }); - /** - * Create a new SymbolNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node) : Node} callback - * @returns {SymbolNode} Returns a clone of the node - */ - SymbolNode.prototype.map = function (callback) { - return this.clone(); - }; + return new BlockNode(blocks); + }; - /** - * Throws an error 'Undefined symbol {name}' - * @param {string} name - */ - function undef (name) { - throw new Error('Undefined symbol ' + name); - } + /** + * Get string representation + * @param {Object} options + * @return {string} str + * @override + */ + BlockNode.prototype._toString = function (options) { + return this.blocks.map(function (param) { + return param.node.toString(options) + (param.visible ? '' : ';'); + }).join('\n'); + }; - /** - * Create a clone of this node, a shallow copy - * @return {SymbolNode} - */ - SymbolNode.prototype.clone = function() { - return new SymbolNode(this.name); - }; + /** + * Get a JSON representation of the node + * @returns {Object} + */ + BlockNode.prototype.toJSON = function () { + return { + mathjs: 'BlockNode', + blocks: this.blocks + }; + }; - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - SymbolNode.prototype._toString = function(options) { - return this.name; - }; + /** + * Instantiate an BlockNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "BlockNode", blocks: [{node: ..., visible: false}, ...]}`, + * where mathjs is optional + * @returns {BlockNode} + */ + BlockNode.fromJSON = function (json) { + return new BlockNode(json.blocks); + }; - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - SymbolNode.prototype.toHTML = function(options) { - var name = escape$4(this.name); - - if (name == "true" || name == "false") { - return '' + name + ''; - } - else if (name == "i") { - return '' + name + ''; - } - else if (name == "Infinity") { - return '' + name + ''; - } - else if (name == "NaN") { - return '' + name + ''; - } - else if (name == "null") { - return '' + name + ''; - } - else if (name == "undefined") { - return '' + name + ''; - } - - return '' + name + ''; - }; + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + * @override + */ + BlockNode.prototype.toHTML = function (options) { + return this.blocks.map(function (param) { + return param.node.toHTML(options) + (param.visible ? '' : ';'); + }).join('
'); + }; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - SymbolNode.prototype.toJSON = function () { - return { - mathjs: 'SymbolNode', - name: this.name + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + */ + BlockNode.prototype._toTex = function (options) { + return this.blocks.map(function (param) { + return param.node.toTex(options) + (param.visible ? '' : ';'); + }).join('\\;\\;\n'); }; + + return BlockNode; + } + + var name$43 = 'BlockNode'; + var path$19 = 'expression.node'; + var factory_1$48 = factory$49; + + var BlockNode = { + name: name$43, + path: path$19, + factory: factory_1$48 }; - /** - * Instantiate a SymbolNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "SymbolNode", name: "x"}`, - * where mathjs is optional - * @returns {SymbolNode} - */ - SymbolNode.fromJSON = function (json) { - return new SymbolNode(json.name); + function factory$50 (type, config, load, typed) { + /** + * Determine the type of a variable. + * + * Function `typeof` recognizes the following types of objects: + * + * Object | Returns | Example + * ---------------------- | ------------- | ------------------------------------------ + * null | `'null'` | `math.typeof(null)` + * number | `'number'` | `math.typeof(3.5)` + * boolean | `'boolean'` | `math.typeof(true)` + * string | `'string'` | `math.typeof('hello world')` + * Array | `'Array'` | `math.typeof([1, 2, 3])` + * Date | `'Date'` | `math.typeof(new Date())` + * Function | `'Function'` | `math.typeof(function () {})` + * Object | `'Object'` | `math.typeof({a: 2, b: 3})` + * RegExp | `'RegExp'` | `math.typeof(/a regexp/)` + * undefined | `'undefined'` | `math.typeof(undefined)` + * math.type.BigNumber | `'BigNumber'` | `math.typeof(math.bignumber('2.3e500'))` + * math.type.Chain | `'Chain'` | `math.typeof(math.chain(2))` + * math.type.Complex | `'Complex'` | `math.typeof(math.complex(2, 3))` + * math.type.Fraction | `'Fraction'` | `math.typeof(math.fraction(1, 3))` + * math.type.Help | `'Help'` | `math.typeof(math.help('sqrt'))` + * math.type.Help | `'Help'` | `math.typeof(math.help('sqrt'))` + * math.type.Index | `'Index'` | `math.typeof(math.index(1, 3))` + * math.type.Matrix | `'Matrix'` | `math.typeof(math.matrix([[1,2], [3, 4]]))` + * math.type.Range | `'Range'` | `math.typeof(math.range(0, 10))` + * math.type.ResultSet | `'ResultSet'` | `math.typeof(math.eval('a=2\nb=3'))` + * math.type.Unit | `'Unit'` | `math.typeof(math.unit('45 deg'))` + * math.expression.node.AccessorNode | `'AccessorNode'` | `math.typeof(math.parse('A[2]'))` + * math.expression.node.ArrayNode | `'ArrayNode'` | `math.typeof(math.parse('[1,2,3]'))` + * math.expression.node.AssignmentNode | `'AssignmentNode'` | `math.typeof(math.parse('x=2'))` + * math.expression.node.BlockNode | `'BlockNode'` | `math.typeof(math.parse('a=2; b=3'))` + * math.expression.node.ConditionalNode | `'ConditionalNode'` | `math.typeof(math.parse('x<0 ? -x : x'))` + * math.expression.node.ConstantNode | `'ConstantNode'` | `math.typeof(math.parse('2.3'))` + * math.expression.node.FunctionAssignmentNode | `'FunctionAssignmentNode'` | `math.typeof(math.parse('f(x)=x^2'))` + * math.expression.node.FunctionNode | `'FunctionNode'` | `math.typeof(math.parse('sqrt(4)'))` + * math.expression.node.IndexNode | `'IndexNode'` | `math.typeof(math.parse('A[2]').index)` + * math.expression.node.ObjectNode | `'ObjectNode'` | `math.typeof(math.parse('{a:2}'))` + * math.expression.node.ParenthesisNode | `'ParenthesisNode'` | `math.typeof(math.parse('(2+3)'))` + * math.expression.node.RangeNode | `'RangeNode'` | `math.typeof(math.parse('1:10'))` + * math.expression.node.SymbolNode | `'SymbolNode'` | `math.typeof(math.parse('x'))` + * + * Syntax: + * + * math.typeof(x) + * + * Examples: + * + * math.typeof(3.5); // returns 'number' + * math.typeof(math.complex('2-4i')); // returns 'Complex' + * math.typeof(math.unit('45 deg')); // returns 'Unit' + * math.typeof('hello world'); // returns 'string' + * + * @param {*} x The variable for which to test the type. + * @return {string} Returns the name of the type. Primitive types are lower case, + * non-primitive types are upper-camel-case. + * For example 'number', 'string', 'Array', 'Date'. + */ + var _typeof = typed('_typeof', { + 'any': function (x) { + var t = typeof x; + + if (t === 'object') { + // JavaScript types + if (x === null) return 'null'; + if (Array.isArray(x)) return 'Array'; + if (x instanceof Date) return 'Date'; + if (x instanceof RegExp) return 'RegExp'; + if (x instanceof Boolean) return 'boolean'; + if (x instanceof Number) return 'number'; + if (x instanceof String) return 'string'; + + // math.js types + if (type.isBigNumber(x)) return 'BigNumber'; + if (type.isComplex(x)) return 'Complex'; + if (type.isFraction(x)) return 'Fraction'; + if (type.isMatrix(x)) return 'Matrix'; + if (type.isUnit(x)) return 'Unit'; + if (type.isIndex(x)) return 'Index'; + if (type.isRange(x)) return 'Range'; + if (type.isResultSet(x)) return 'ResultSet'; + if (type.isNode(x)) return x.type; + if (type.isChain(x)) return 'Chain'; + if (type.isHelp(x)) return 'Help'; + + return 'Object'; + } + + if (t === 'function') return 'Function'; + + return t; // can be 'string', 'number', 'boolean', ... + } + }); + + _typeof.toTex = undefined; // use default template + + return _typeof; + } + + var name$44 = 'typeof'; + var factory_1$49 = factory$50; + + var _typeof$1 = { + name: name$44, + factory: factory_1$49 }; - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - * @override - */ - SymbolNode.prototype._toTex = function(options) { - var isUnit = false; - if ((typeof math[this.name] === 'undefined') && isValuelessUnit(this.name)) { - isUnit = true; - } - var symbol = latex.toSymbol(this.name, isUnit); - if (symbol[0] === '\\') { - //no space needed if the symbol starts with '\' - return symbol; - } - //the space prevents symbols from breaking stuff like '\cdot' if it's written right before the symbol - return ' ' + symbol; - }; - - return SymbolNode; -} - -var name$51 = 'SymbolNode'; -var path$26 = 'expression.node'; -var math$7 = true; // request access to the math namespace as 5th argument of the factory function -var factory_1$56 = factory$57; - -var SymbolNode = { - name: name$51, - path: path$26, - math: math$7, - factory: factory_1$56 -}; - -var latex$1 = latex; -var escape$5 = string.escape; -var hasOwnProperty$4 = object.hasOwnProperty; -var map$5 = array.map; -var validateSafeMethod$1 = customs.validateSafeMethod; -var getSafeProperty$7 = customs.getSafeProperty; - -function factory$58 (type, config, load, typed, math) { - var Node$$1 = load(Node); - var SymbolNode$$1 = load(SymbolNode); + function factory$51 (type, config, load, typed) { + var Node$$1 = load(Node); + var mathTypeOf = load(_typeof$1); - /** - * @constructor FunctionNode - * @extends {./Node} - * invoke a list with arguments on a node - * @param {./Node | string} fn Node resolving with a function on which to invoke - * the arguments, typically a SymboNode or AccessorNode - * @param {./Node[]} args - */ - function FunctionNode(fn, args) { - if (!(this instanceof FunctionNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } + /** + * A lazy evaluating conditional operator: 'condition ? trueExpr : falseExpr' + * + * @param {Node} condition Condition, must result in a boolean + * @param {Node} trueExpr Expression evaluated when condition is true + * @param {Node} falseExpr Expression evaluated when condition is true + * + * @constructor ConditionalNode + * @extends {Node} + */ + function ConditionalNode(condition, trueExpr, falseExpr) { + if (!(this instanceof ConditionalNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } + if (!type.isNode(condition)) throw new TypeError('Parameter condition must be a Node'); + if (!type.isNode(trueExpr)) throw new TypeError('Parameter trueExpr must be a Node'); + if (!type.isNode(falseExpr)) throw new TypeError('Parameter falseExpr must be a Node'); - if (typeof fn === 'string') { - fn = new SymbolNode$$1(fn); + this.condition = condition; + this.trueExpr = trueExpr; + this.falseExpr = falseExpr; } - // validate input - if (!type.isNode(fn)) throw new TypeError('Node expected as parameter "fn"'); - if (!Array.isArray(args) || !args.every(type.isNode)) { - throw new TypeError('Array containing Nodes expected for parameter "args"'); - } + ConditionalNode.prototype = new Node$$1(); - this.fn = fn; - this.args = args || []; + ConditionalNode.prototype.type = 'ConditionalNode'; + + ConditionalNode.prototype.isConditionalNode = true; + + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + ConditionalNode.prototype._compile = function (math, argNames) { + var evalCondition = this.condition._compile(math, argNames); + var evalTrueExpr = this.trueExpr._compile(math, argNames); + var evalFalseExpr = this.falseExpr._compile(math, argNames); - // readonly property name - Object.defineProperty(this, 'name', { - get: function () { - return this.fn.name || ''; - }.bind(this), - set: function () { - throw new Error('Cannot assign a new name, name is read-only'); + return function evalConditionalNode(scope, args, context) { + return testCondition(evalCondition(scope, args, context)) + ? evalTrueExpr(scope, args, context) + : evalFalseExpr(scope, args, context); } - }); + }; - // TODO: deprecated since v3, remove some day - var deprecated = function () { - throw new Error('Property `FunctionNode.object` is deprecated, use `FunctionNode.fn` instead'); + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + ConditionalNode.prototype.forEach = function (callback) { + callback(this.condition, 'condition', this); + callback(this.trueExpr, 'trueExpr', this); + callback(this.falseExpr, 'falseExpr', this); }; - Object.defineProperty(this, 'object', { get: deprecated, set: deprecated }); - } - FunctionNode.prototype = new Node$$1(); + /** + * Create a new ConditionalNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {ConditionalNode} Returns a transformed copy of the node + */ + ConditionalNode.prototype.map = function (callback) { + return new ConditionalNode( + this._ifNode(callback(this.condition, 'condition', this)), + this._ifNode(callback(this.trueExpr, 'trueExpr', this)), + this._ifNode(callback(this.falseExpr, 'falseExpr', this)) + ); + }; - FunctionNode.prototype.type = 'FunctionNode'; + /** + * Create a clone of this node, a shallow copy + * @return {ConditionalNode} + */ + ConditionalNode.prototype.clone = function () { + return new ConditionalNode(this.condition, this.trueExpr, this.falseExpr); + }; - FunctionNode.prototype.isFunctionNode = true; + /** + * Get string representation + * @param {Object} options + * @return {string} str + */ + ConditionalNode.prototype._toString = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var precedence = operators.getPrecedence(this, parenthesis); + + //Enclose Arguments in parentheses if they are an OperatorNode + //or have lower or equal precedence + //NOTE: enclosing all OperatorNodes in parentheses is a decision + //purely based on aesthetics and readability + var condition = this.condition.toString(options); + var conditionPrecedence = operators.getPrecedence(this.condition, parenthesis); + if ((parenthesis === 'all') + || (this.condition.type === 'OperatorNode') + || ((conditionPrecedence !== null) && (conditionPrecedence <= precedence))) { + condition = '(' + condition + ')'; + } + + var trueExpr = this.trueExpr.toString(options); + var truePrecedence = operators.getPrecedence(this.trueExpr, parenthesis); + if ((parenthesis === 'all') + || (this.trueExpr.type === 'OperatorNode') + || ((truePrecedence !== null) && (truePrecedence <= precedence))) { + trueExpr = '(' + trueExpr + ')'; + } + + var falseExpr = this.falseExpr.toString(options); + var falsePrecedence = operators.getPrecedence(this.falseExpr, parenthesis); + if ((parenthesis === 'all') + || (this.falseExpr.type === 'OperatorNode') + || ((falsePrecedence !== null) && (falsePrecedence <= precedence))) { + falseExpr = '(' + falseExpr + ')'; + } + return condition + ' ? ' + trueExpr + ' : ' + falseExpr; + }; - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - FunctionNode.prototype._compile = function (math, argNames) { - if (!(this instanceof FunctionNode)) { - throw new TypeError('No valid FunctionNode') - } + /** + * Get a JSON representation of the node + * @returns {Object} + */ + ConditionalNode.prototype.toJSON = function () { + return { + mathjs: 'ConditionalNode', + condition: this.condition, + trueExpr: this.trueExpr, + falseExpr: this.falseExpr + }; + }; - // compile arguments - var evalArgs = map$5(this.args, function (arg) { - return arg._compile(math, argNames); - }); + /** + * Instantiate an ConditionalNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "ConditionalNode", "condition": ..., "trueExpr": ..., "falseExpr": ...}`, + * where mathjs is optional + * @returns {ConditionalNode} + */ + ConditionalNode.fromJSON = function (json) { + return new ConditionalNode(json.condition, json.trueExpr, json.falseExpr); + }; - if (type.isSymbolNode(this.fn)) { - // we can statically determine whether the function has an rawArgs property - var name = this.fn.name; - var fn = name in math ? getSafeProperty$7(math, name) : undefined; - var isRaw = (typeof fn === 'function') && (fn.rawArgs == true); + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + */ + ConditionalNode.prototype.toHTML = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var precedence = operators.getPrecedence(this, parenthesis); + + //Enclose Arguments in parentheses if they are an OperatorNode + //or have lower or equal precedence + //NOTE: enclosing all OperatorNodes in parentheses is a decision + //purely based on aesthetics and readability + var condition = this.condition.toHTML(options); + var conditionPrecedence = operators.getPrecedence(this.condition, parenthesis); + if ((parenthesis === 'all') + || (this.condition.type === 'OperatorNode') + || ((conditionPrecedence !== null) && (conditionPrecedence <= precedence))) { + condition = '(' + condition + ')'; + } + + var trueExpr = this.trueExpr.toHTML(options); + var truePrecedence = operators.getPrecedence(this.trueExpr, parenthesis); + if ((parenthesis === 'all') + || (this.trueExpr.type === 'OperatorNode') + || ((truePrecedence !== null) && (truePrecedence <= precedence))) { + trueExpr = '(' + trueExpr + ')'; + } + + var falseExpr = this.falseExpr.toHTML(options); + var falsePrecedence = operators.getPrecedence(this.falseExpr, parenthesis); + if ((parenthesis === 'all') + || (this.falseExpr.type === 'OperatorNode') + || ((falsePrecedence !== null) && (falsePrecedence <= precedence))) { + falseExpr = '(' + falseExpr + ')'; + } + return condition + '?' + trueExpr + ':' + falseExpr; + }; - if (isRaw) { - // pass unevaluated parameters (nodes) to the function - // "raw" evaluation - var rawArgs = this.args; - return function evalFunctionNode(scope, args, context) { - return (name in scope ? getSafeProperty$7(scope, name) : fn)(rawArgs, math, scope); - }; + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + */ + ConditionalNode.prototype._toTex = function (options) { + return '\\begin{cases} {' + + this.trueExpr.toTex(options) + '}, &\\quad{\\text{if }\\;' + + this.condition.toTex(options) + + '}\\\\{' + this.falseExpr.toTex(options) + + '}, &\\quad{\\text{otherwise}}\\end{cases}'; + }; + + /** + * Test whether a condition is met + * @param {*} condition + * @returns {boolean} true if condition is true or non-zero, else false + */ + function testCondition (condition) { + if (typeof condition === 'number' + || typeof condition === 'boolean' + || typeof condition === 'string') { + return condition ? true : false; } - else { - // "regular" evaluation - if (evalArgs.length === 1) { - var evalArg0 = evalArgs[0]; - return function evalFunctionNode(scope, args, context) { - return (name in scope ? getSafeProperty$7(scope, name) : fn)(evalArg0(scope, args, context)); - }; + + if (condition) { + if (type.isBigNumber(condition)) { + return condition.isZero() ? false : true; } - else if (evalArgs.length === 2) { - var evalArg0 = evalArgs[0]; - var evalArg1 = evalArgs[1]; - return function evalFunctionNode(scope, args, context) { - return (name in scope ? getSafeProperty$7(scope, name) : fn)(evalArg0(scope, args, context), evalArg1(scope, args, context)); - }; + + if (type.isComplex(condition)) { + return (condition.re || condition.im) ? true : false; } - else { - return function evalFunctionNode(scope, args, context) { - return (name in scope ? getSafeProperty$7(scope, name) : fn).apply(null, map$5(evalArgs, function (evalArg) { - return evalArg(scope, args, context); - })); - } + + if (type.isUnit(condition)) { + return condition.value ? true : false; } } + + if (condition === null || condition === undefined) { + return false; + } + + throw new TypeError('Unsupported type of condition "' + mathTypeOf(condition) + '"'); } - else if (type.isAccessorNode(this.fn) && - type.isIndexNode(this.fn.index) && this.fn.index.isObjectProperty()) { - // execute the function with the right context: the object of the AccessorNode + return ConditionalNode; + } - var evalObject = this.fn.object._compile(math, argNames); - var prop = this.fn.index.getObjectProperty(); - var rawArgs = this.args; + var name$45 = 'ConditionalNode'; + var path$20 = 'expression.node'; + var factory_1$50 = factory$51; - return function evalFunctionNode (scope, args, context) { - var object$$1 = evalObject(scope, args, context); - validateSafeMethod$1(object$$1, prop); - var isRaw = object$$1[prop] && object$$1[prop].rawArgs; + var ConditionalNode = { + name: name$45, + path: path$20, + factory: factory_1$50 + }; - return isRaw - ? object$$1[prop](rawArgs, math, scope) // "raw" evaluation - : object$$1[prop].apply(object$$1, map$5(evalArgs, function (evalArg) { // "regular" evaluation - return evalArg(scope, args, context); - })); - } - } - else { // node.fn.isAccessorNode && !node.fn.index.isObjectProperty() - // we have to dynamically determine whether the function has a rawArgs property - var evalFn = this.fn._compile(math, argNames); + var format$3 = string.format; + var escapeLatex = latex.escape; - return function evalFunctionNode (scope, args, context) { - var fn = evalFn(scope, args, context); - var isRaw = fn && fn.rawArgs; + function factory$52 (type, config, load, typed) { + var Node$$1 = load(Node); + var getType = load(_typeof$1); - return isRaw - ? fn(rawArgs, math, scope) // "raw" evaluation - : fn.apply(fn, map$5(evalArgs, function (evalArg) { // "regular" evaluation - return evalArg(scope, args, context); - })); - }; - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - FunctionNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.args.length; i++) { - callback(this.args[i], 'args[' + i + ']', this); - } - }; - - /** - * Create a new FunctionNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {FunctionNode} Returns a transformed copy of the node - */ - FunctionNode.prototype.map = function (callback) { - var fn = this.fn.map(callback); - var args = []; - for (var i = 0; i < this.args.length; i++) { - args[i] = this._ifNode(callback(this.args[i], 'args[' + i + ']', this)); - } - return new FunctionNode(fn, args); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {FunctionNode} - */ - FunctionNode.prototype.clone = function () { - return new FunctionNode(this.fn, this.args.slice(0)); - }; + /** + * A ConstantNode holds a constant value like a number or string. + * + * Usage: + * + * new ConstantNode(2.3); + * new ConstantNode('hello'); + * + * @param {*} value Value can be any type (number, BigNumber, string, ...) + * @constructor ConstantNode + * @extends {Node} + */ + function ConstantNode(value) { + if (!(this instanceof ConstantNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - //backup Node's toString function - //@private - var nodeToString = FunctionNode.prototype.toString; + if (arguments.length === 2) { + // TODO: remove deprecation error some day (created 2018-01-23) + throw new SyntaxError('new ConstantNode(valueStr, valueType) is not supported anymore since math v4.0.0. Use new ConstantNode(value) instead, where value is a non-stringified value.'); + } - /** - * Get string representation. (wrapper function) - * This overrides parts of Node's toString function. - * If callback is an object containing callbacks, it - * calls the correct callback for the current node, - * otherwise it falls back to calling Node's toString - * function. - * - * @param {Object} options - * @return {string} str - * @override - */ - FunctionNode.prototype.toString = function (options) { - var customString; - var name = this.fn.toString(options); - if (options && (typeof options.handler === 'object') && hasOwnProperty$4(options.handler, name)) { - //callback is a map of callback functions - customString = options.handler[name](this, options); + this.value = value; } - if (typeof customString !== 'undefined') { - return customString; - } + ConstantNode.prototype = new Node$$1(); - //fall back to Node's toString - return nodeToString.call(this, options); - }; + ConstantNode.prototype.type = 'ConstantNode'; - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - FunctionNode.prototype._toString = function (options) { - var args = this.args.map(function (arg) { - return arg.toString(options); - }); + ConstantNode.prototype.isConstantNode = true; - var fn = type.isFunctionAssignmentNode(this.fn) - ? ('(' + this.fn.toString(options) + ')') - : this.fn.toString(options); + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + ConstantNode.prototype._compile = function (math, argNames) { + var value = this.value; - // format the arguments like "add(2, 4.2)" - return fn + '(' + args.join(', ') + ')'; - }; + return function evalConstantNode() { + return value; + } + }; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - FunctionNode.prototype.toJSON = function () { - return { - mathjs: 'FunctionNode', - fn: this.fn, - args: this.args + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + ConstantNode.prototype.forEach = function (callback) { + // nothing to do, we don't have childs }; - }; - /** - * Instantiate an AssignmentNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "FunctionNode", fn: ..., args: ...}`, - * where mathjs is optional - * @returns {FunctionNode} - */ - FunctionNode.fromJSON = function (json) { - return new FunctionNode(json.fn, json.args); - }; + /** + * Create a new ConstantNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node) : Node} callback + * @returns {ConstantNode} Returns a clone of the node + */ + ConstantNode.prototype.map = function (callback) { + return this.clone(); + }; - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - FunctionNode.prototype.toHTML = function (options) { - var args = this.args.map(function (arg) { - return arg.toHTML(options); - }); + /** + * Create a clone of this node, a shallow copy + * @return {ConstantNode} + */ + ConstantNode.prototype.clone = function () { + return new ConstantNode(this.value); + }; - // format the arguments like "add(2, 4.2)" - return '' + escape$5(this.fn) + '(' + args.join(',') + ')'; - }; + /** + * Get string representation + * @param {Object} options + * @return {string} str + */ + ConstantNode.prototype._toString = function (options) { + return format$3 (this.value, options); + }; - /* - * Expand a LaTeX template - * - * @param {string} template - * @param {Node} node - * @param {Object} options - * @private - **/ - function expandTemplate(template, node, options) { - var latex$$1 = ''; - - // Match everything of the form ${identifier} or ${identifier[2]} or $$ - // while submatching identifier and 2 (in the second case) - var regex = new RegExp('\\$(?:\\{([a-z_][a-z_0-9]*)(?:\\[([0-9]+)\\])?\\}|\\$)', 'ig'); - - var inputPos = 0; //position in the input string - var match; - while ((match = regex.exec(template)) !== null) { //go through all matches - // add everything in front of the match to the LaTeX string - latex$$1 += template.substring(inputPos, match.index); - inputPos = match.index; - - if (match[0] === '$$') { // escaped dollar sign - latex$$1 += '$'; - inputPos++; - } - else { // template parameter - inputPos += match[0].length; - var property = node[match[1]]; - if (!property) { - throw new ReferenceError('Template: Property ' + match[1] + ' does not exist.'); - } - if (match[2] === undefined) { //no square brackets - switch (typeof property) { - case 'string': - latex$$1 += property; - break; - case 'object': - if (type.isNode(property)) { - latex$$1 += property.toTex(options); - } - else if (Array.isArray(property)) { - //make array of Nodes into comma separated list - latex$$1 += property.map(function (arg, index) { - if (type.isNode(arg)) { - return arg.toTex(options); - } - throw new TypeError('Template: ' + match[1] + '[' + index + '] is not a Node.'); - }).join(','); - } - else { - throw new TypeError('Template: ' + match[1] + ' has to be a Node, String or array of Nodes'); - } - break; - default: - throw new TypeError('Template: ' + match[1] + ' has to be a Node, String or array of Nodes'); - } - } - else { //with square brackets - if (type.isNode(property[match[2]] && property[match[2]])) { - latex$$1 += property[match[2]].toTex(options); - } - else { - throw new TypeError('Template: ' + match[1] + '[' + match[2] + '] is not a Node.'); - } - } - } - } - latex$$1 += template.slice(inputPos); //append rest of the template + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + */ + ConstantNode.prototype.toHTML = function (options) { + var value = this._toString(options); + + switch (getType(this.value)) { + case 'number': + case 'BigNumber': + case 'Fraction': + return '' + value + ''; + case 'string': + return '' + value + ''; + case 'boolean': + return '' + value + ''; + case 'null': + return '' + value + ''; + case 'undefined': + return '' + value + ''; - return latex$$1; - } + default: + return '' + value + ''; + } + }; - //backup Node's toTex function - //@private - var nodeToTex = FunctionNode.prototype.toTex; + /** + * Get a JSON representation of the node + * @returns {Object} + */ + ConstantNode.prototype.toJSON = function () { + return { + mathjs: 'ConstantNode', + value: this.value + }; + }; - /** - * Get LaTeX representation. (wrapper function) - * This overrides parts of Node's toTex function. - * If callback is an object containing callbacks, it - * calls the correct callback for the current node, - * otherwise it falls back to calling Node's toTex - * function. - * - * @param {Object} options - * @return {string} - */ - FunctionNode.prototype.toTex = function (options) { - var customTex; - if (options && (typeof options.handler === 'object') && hasOwnProperty$4(options.handler, this.name)) { - //callback is a map of callback functions - customTex = options.handler[this.name](this, options); - } + /** + * Instantiate a ConstantNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "SymbolNode", value: 2.3}`, + * where mathjs is optional + * @returns {ConstantNode} + */ + ConstantNode.fromJSON = function (json) { + return new ConstantNode(json.value); + }; - if (typeof customTex !== 'undefined') { - return customTex; - } + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + */ + ConstantNode.prototype._toTex = function (options) { + var value = this._toString(options); - //fall back to Node's toTex - return nodeToTex.call(this, options); - }; + switch (getType(this.value)) { + case 'string': + return '\\mathtt{' + escapeLatex(value) + '}'; - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - FunctionNode.prototype._toTex = function (options) { - var args = this.args.map(function (arg) { //get LaTeX of the arguments - return arg.toTex(options); - }); + case 'number': + case 'BigNumber': + var index = value.toLowerCase().indexOf('e'); + if (index !== -1) { + return value.substring(0, index) + '\\cdot10^{' + + value.substring(index + 1) + '}'; + } + return value; - var latexConverter; + case 'Fraction': + return this.value.toLatex(); - if (math[this.name] && ((typeof math[this.name].toTex === 'function') || (typeof math[this.name].toTex === 'object') || (typeof math[this.name].toTex === 'string'))) { - //.toTex is a callback function - latexConverter = math[this.name].toTex; - } + default: + return value; + } + }; - var customToTex; - switch (typeof latexConverter) { - case 'function': //a callback function - customToTex = latexConverter(this, options); - break; - case 'string': //a template string - customToTex = expandTemplate(latexConverter, this, options); - break; - case 'object': //an object with different "converters" for different numbers of arguments - switch (typeof latexConverter[args.length]) { - case 'function': - customToTex = latexConverter[args.length](this, options); - break; - case 'string': - customToTex = expandTemplate(latexConverter[args.length], this, options); - break; - } - } + return ConstantNode; + } - if (typeof customToTex !== 'undefined') { - return customToTex; - } + var name$46 = 'ConstantNode'; + var path$21 = 'expression.node'; + var factory_1$51 = factory$52; - return expandTemplate(latex$1.defaultTemplate, this, options); + var ConstantNode = { + name: name$46, + path: path$21, + factory: factory_1$51 }; - /** - * Get identifier. - * @return {string} - */ - FunctionNode.prototype.getIdentifier = function () { - return this.type + ':' + this.name; - }; + var escape$1 = string.escape; + var forEach$2 = array.forEach; + var join = array.join; + - return FunctionNode; -} + var setSafeProperty$4 = customs.setSafeProperty; -var name$52 = 'FunctionNode'; -var path$27 = 'expression.node'; -var math$8 = true; // request access to the math namespace as 5th argument of the factory function -var factory_1$57 = factory$58; + function factory$53 (type, config, load, typed) { + var Node$$1 = load(Node); -var FunctionNode = { - name: name$52, - path: path$27, - math: math$8, - factory: factory_1$57 -}; + /** + * @constructor FunctionAssignmentNode + * @extends {Node} + * Function assignment + * + * @param {string} name Function name + * @param {string[] | Array.<{name: string, type: string}>} params + * Array with function parameter names, or an + * array with objects containing the name + * and type of the parameter + * @param {Node} expr The function expression + */ + function FunctionAssignmentNode(name, params, expr) { + if (!(this instanceof FunctionAssignmentNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } -function factory$59 (type, config, load, typed) { - var Node$$1 = load(Node); + // validate input + if (typeof name !== 'string') throw new TypeError('String expected for parameter "name"'); + if (!Array.isArray(params)) throw new TypeError('Array containing strings or objects expected for parameter "params"'); + if (!type.isNode(expr)) throw new TypeError('Node expected for parameter "expr"'); + if (name in keywords) throw new Error('Illegal function name, "' + name + '" is a reserved keyword'); - /** - * @constructor RangeNode - * @extends {Node} - * create a range - * @param {Node} start included lower-bound - * @param {Node} end included upper-bound - * @param {Node} [step] optional step - */ - function RangeNode(start, end, step) { - if (!(this instanceof RangeNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); + this.name = name; + this.params = params.map(function (param) { + return param && param.name || param; + }); + this.types = params.map(function (param) { + return param && param.type || 'any' + }); + this.expr = expr; } - // validate inputs - if (!type.isNode(start)) throw new TypeError('Node expected'); - if (!type.isNode(end)) throw new TypeError('Node expected'); - if (step && !type.isNode(step)) throw new TypeError('Node expected'); - if (arguments.length > 3) throw new Error('Too many arguments'); + FunctionAssignmentNode.prototype = new Node$$1(); - this.start = start; // included lower-bound - this.end = end; // included upper-bound - this.step = step || null; // optional step - } + FunctionAssignmentNode.prototype.type = 'FunctionAssignmentNode'; - RangeNode.prototype = new Node$$1(); + FunctionAssignmentNode.prototype.isFunctionAssignmentNode = true; - RangeNode.prototype.type = 'RangeNode'; + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + FunctionAssignmentNode.prototype._compile = function (math, argNames) { + var childArgNames = Object.create(argNames); + forEach$2(this.params, function (param) { + childArgNames[param] = true; + }); - RangeNode.prototype.isRangeNode = true; + // compile the function expression with the child args + var evalExpr = this.expr._compile(math, childArgNames); + var name = this.name; + var params = this.params; + var signature = join(this.types, ','); + var syntax = name + '(' + join(this.params, ', ') + ')'; - /** - * Check whether the RangeNode needs the `end` symbol to be defined. - * This end is the size of the Matrix in current dimension. - * @return {boolean} - */ - RangeNode.prototype.needsEnd = function () { - // find all `end` symbols in this RangeNode - var endSymbols = this.filter(function (node) { - return type.isSymbolNode(node) && (node.name === 'end'); - }); + return function evalFunctionAssignmentNode(scope, args, context) { + var signatures = {}; + signatures[signature] = function () { + var childArgs = Object.create(args); - return endSymbols.length > 0; - }; + for (var i = 0; i < params.length; i++) { + childArgs[params[i]] = arguments[i]; + } - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - RangeNode.prototype._compile = function (math, argNames) { - var range = math.range; - var evalStart = this.start._compile(math, argNames); - var evalEnd = this.end._compile(math, argNames); + return evalExpr(scope, childArgs, context); + }; + var fn = typed(name, signatures); + fn.syntax = syntax; - if (this.step) { - var evalStep = this.step._compile(math, argNames); - - return function evalRangeNode(scope, args, context) { - return range( - evalStart(scope, args, context), - evalEnd(scope, args, context), - evalStep(scope, args, context) - ); - } - } - else { - return function evalRangeNode(scope, args, context) { - return range( - evalStart(scope, args, context), - evalEnd(scope, args, context) - ); + setSafeProperty$4(scope, name, fn); + + return fn; } - } - }; + }; - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - RangeNode.prototype.forEach = function (callback) { - callback(this.start, 'start', this); - callback(this.end, 'end', this); - if (this.step) { - callback(this.step, 'step', this); - } - }; + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + FunctionAssignmentNode.prototype.forEach = function (callback) { + callback(this.expr, 'expr', this); + }; - /** - * Create a new RangeNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {RangeNode} Returns a transformed copy of the node - */ - RangeNode.prototype.map = function (callback) { - return new RangeNode( - this._ifNode(callback(this.start, 'start', this)), - this._ifNode(callback(this.end, 'end', this)), - this.step && this._ifNode(callback(this.step, 'step', this)) - ); - }; + /** + * Create a new FunctionAssignmentNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {FunctionAssignmentNode} Returns a transformed copy of the node + */ + FunctionAssignmentNode.prototype.map = function (callback) { + var expr = this._ifNode(callback(this.expr, 'expr', this)); - /** - * Create a clone of this node, a shallow copy - * @return {RangeNode} - */ - RangeNode.prototype.clone = function () { - return new RangeNode(this.start, this.end, this.step && this.step); - }; + return new FunctionAssignmentNode(this.name, this.params.slice(0), expr); + }; - /** - * Calculate the necessary parentheses - * @param {Node} node - * @param {string} parenthesis - * @return {Object} parentheses - * @private - */ - function calculateNecessaryParentheses(node, parenthesis) { - var precedence = operators.getPrecedence(node, parenthesis); - var parens = {}; + /** + * Create a clone of this node, a shallow copy + * @return {FunctionAssignmentNode} + */ + FunctionAssignmentNode.prototype.clone = function () { + return new FunctionAssignmentNode(this.name, this.params.slice(0), this.expr); + }; - var startPrecedence = operators.getPrecedence(node.start, parenthesis); - parens.start = ((startPrecedence !== null) && (startPrecedence <= precedence)) - || (parenthesis === 'all'); + /** + * Is parenthesis needed? + * @param {Node} node + * @param {Object} parenthesis + * @private + */ + function needParenthesis(node, parenthesis) { + var precedence = operators.getPrecedence(node, parenthesis); + var exprPrecedence = operators.getPrecedence(node.expr, parenthesis); - if (node.step) { - var stepPrecedence = operators.getPrecedence(node.step, parenthesis); - parens.step = ((stepPrecedence !== null) && (stepPrecedence <= precedence)) - || (parenthesis === 'all'); + return (parenthesis === 'all') + || ((exprPrecedence !== null) && (exprPrecedence <= precedence)); } - var endPrecedence = operators.getPrecedence(node.end, parenthesis); - parens.end = ((endPrecedence !== null) && (endPrecedence <= precedence)) - || (parenthesis === 'all'); + /** + * get string representation + * @param {Object} options + * @return {string} str + */ + FunctionAssignmentNode.prototype._toString = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var expr = this.expr.toString(options); + if (needParenthesis(this, parenthesis)) { + expr = '(' + expr + ')'; + } + return this.name + '(' + this.params.join(', ') + ') = ' + expr; + }; - return parens; - } + /** + * Get a JSON representation of the node + * @returns {Object} + */ + FunctionAssignmentNode.prototype.toJSON = function () { + var types = this.types; - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - RangeNode.prototype._toString = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var parens = calculateNecessaryParentheses(this, parenthesis); + return { + mathjs: 'FunctionAssignmentNode', + name: this.name, + params: this.params.map(function(param, index) { + return { + name: param, + type: types[index] + } + }), + expr: this.expr + }; + }; - //format string as start:step:stop - var str; + /** + * Instantiate an FunctionAssignmentNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "FunctionAssignmentNode", name: ..., params: ..., expr: ...}`, + * where mathjs is optional + * @returns {FunctionAssignmentNode} + */ + FunctionAssignmentNode.fromJSON = function (json) { + return new FunctionAssignmentNode(json.name, json.params, json.expr); + }; - var start = this.start.toString(options); - if (parens.start) { - start = '(' + start + ')'; - } - str = start; + /** + * get HTML representation + * @param {Object} options + * @return {string} str + */ + FunctionAssignmentNode.prototype.toHTML = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var params = []; + for (var i=0; i' + escape$1(this.params[i]) + ''); + } + var expr = this.expr.toHTML(options); + if (needParenthesis(this, parenthesis)) { + expr = '(' + expr + ')'; + } + return '' + escape$1(this.name) + '' + '(' + params.join(',') + ')=' + expr; + }; - if (this.step) { - var step = this.step.toString(options); - if (parens.step) { - step = '(' + step + ')'; + /** + * get LaTeX representation + * @param {Object} options + * @return {string} str + */ + FunctionAssignmentNode.prototype._toTex = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var expr = this.expr.toTex(options); + if (needParenthesis(this, parenthesis)) { + expr = '\\left(' + expr + '\\right)'; } - str += ':' + step; - } - var end = this.end.toString(options); - if (parens.end) { - end = '(' + end + ')'; - } - str += ':' + end; + return '\\mathrm{' + this.name + + '}\\left(' + this.params.map(latex.toSymbol).join(',') + '\\right):=' + expr; + }; - return str; - }; + return FunctionAssignmentNode; + } + var name$47 = 'FunctionAssignmentNode'; + var path$22 = 'expression.node'; + var factory_1$52 = factory$53; - /** - * Get a JSON representation of the node - * @returns {Object} - */ - RangeNode.prototype.toJSON = function () { - return { - mathjs: 'RangeNode', - start: this.start, - end: this.end, - step: this.step - }; + var FunctionAssignmentNode = { + name: name$47, + path: path$22, + factory: factory_1$52 }; - /** - * Instantiate an RangeNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "RangeNode", "start": ..., "end": ..., "step": ...}`, - * where mathjs is optional - * @returns {RangeNode} - */ - RangeNode.fromJSON = function (json) { - return new RangeNode(json.start, json.end, json.step); - }; + var stringify = string.stringify; + var escape$2 = string.escape; + var isSafeProperty$1 = customs.isSafeProperty; + var hasOwnProperty$2 = object.hasOwnProperty; - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - RangeNode.prototype.toHTML = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var parens = calculateNecessaryParentheses(this, parenthesis); + function factory$54 (type, config, load, typed) { + var Node$$1 = load(Node); - //format string as start:step:stop - var str; + /** + * @constructor ObjectNode + * @extends {Node} + * Holds an object with keys/values + * @param {Object.} [properties] object with key/value pairs + */ + function ObjectNode(properties) { + if (!(this instanceof ObjectNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - var start = this.start.toHTML(options); - if (parens.start) { - start = '(' + start + ')'; - } - str = start; + this.properties = properties || {}; - if (this.step) { - var step = this.step.toHTML(options); - if (parens.step) { - step = '(' + step + ')'; + // validate input + if (properties) { + if (!(typeof properties === 'object') || !Object.keys(properties).every(function (key) { + return type.isNode(properties[key]); + })) { + throw new TypeError('Object containing Nodes expected'); + } } - str += ':' + step; } - var end = this.end.toHTML(options); - if (parens.end) { - end = '(' + end + ')'; - } - str += ':' + end; + ObjectNode.prototype = new Node$$1(); - return str; - }; + ObjectNode.prototype.type = 'ObjectNode'; - /** - * Get LaTeX representation - * @params {Object} options - * @return {string} str - */ - RangeNode.prototype._toTex = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var parens = calculateNecessaryParentheses(this, parenthesis); + ObjectNode.prototype.isObjectNode = true; - var str = this.start.toTex(options); - if (parens.start) { - str = '\\left(' + str + '\\right)'; - } + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + ObjectNode.prototype._compile = function (math, argNames) { + var evalEntries = {}; + + for (var key in this.properties) { + if (hasOwnProperty$2(this.properties, key)) { + // we stringify/parse the key here to resolve unicode characters, + // so you cannot create a key like {"co\\u006Estructor": null} + var stringifiedKey = stringify(key); + var parsedKey = JSON.parse(stringifiedKey); + if (!isSafeProperty$1(this.properties, parsedKey)) { + throw new Error('No access to property "' + parsedKey + '"'); + } - if (this.step) { - var step = this.step.toTex(options); - if (parens.step) { - step = '\\left(' + step + '\\right)'; + evalEntries[parsedKey]= this.properties[key]._compile(math, argNames); + } } - str += ':' + step; - } - var end = this.end.toTex(options); - if (parens.end) { - end = '\\left(' + end + '\\right)'; - } - str += ':' + end; + return function evalObjectNode (scope, args, context) { + var obj = {}; - return str; - }; + for (var key in evalEntries) { + if (hasOwnProperty$2(evalEntries, key)) { + obj[key] = evalEntries[key](scope, args, context); + } + } - return RangeNode; -} - -var name$53 = 'RangeNode'; -var path$28 = 'expression.node'; -var factory_1$58 = factory$59; - -var RangeNode = { - name: name$53, - path: path$28, - factory: factory_1$58 -}; - -function factory$60 (type, config, load, typed) { - var numeric$$1 = load(numeric); - - var AccessorNode$$1 = load(AccessorNode); - var ArrayNode$$1 = load(ArrayNode); - var AssignmentNode$$1 = load(AssignmentNode); - var BlockNode$$1 = load(BlockNode); - var ConditionalNode$$1 = load(ConditionalNode); - var ConstantNode$$1 = load(ConstantNode); - var FunctionAssignmentNode$$1 = load(FunctionAssignmentNode); - var IndexNode$$1 = load(IndexNode); - var ObjectNode$$1 = load(ObjectNode); - var OperatorNode$$1 = load(OperatorNode); - var ParenthesisNode$$1 = load(ParenthesisNode); - var FunctionNode$$1 = load(FunctionNode); - var RangeNode$$1 = load(RangeNode); - var SymbolNode$$1 = load(SymbolNode); + return obj; + } + }; - /** - * Parse an expression. Returns a node tree, which can be evaluated by - * invoking node.eval(); - * - * Syntax: - * - * parse(expr) - * parse(expr, options) - * parse([expr1, expr2, expr3, ...]) - * parse([expr1, expr2, expr3, ...], options) - * - * Example: - * - * var node = parse('sqrt(3^2 + 4^2)'); - * node.compile(math).eval(); // 5 - * - * var scope = {a:3, b:4} - * var node = parse('a * b'); // 12 - * var code = node.compile(math); - * code.eval(scope); // 12 - * scope.a = 5; - * code.eval(scope); // 20 - * - * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); - * nodes[2].compile(math).eval(); // 12 - * - * @param {string | string[] | Matrix} expr - * @param {{nodes: Object}} [options] Available options: - * - `nodes` a set of custom nodes - * @return {Node | Node[]} node - * @throws {Error} - */ - function parse (expr, options) { - if (arguments.length !== 1 && arguments.length !== 2) { - throw new ArgumentsError_1('parse', arguments.length, 1, 2); - } + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + ObjectNode.prototype.forEach = function (callback) { + for (var key in this.properties) { + if (this.properties.hasOwnProperty(key)) { + callback(this.properties[key], 'properties[' + stringify(key) + ']', this); + } + } + }; - // pass extra nodes - extra_nodes = (options && options.nodes) ? options.nodes : {}; + /** + * Create a new ObjectNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {ObjectNode} Returns a transformed copy of the node + */ + ObjectNode.prototype.map = function (callback) { + var properties = {}; + for (var key in this.properties) { + if (this.properties.hasOwnProperty(key)) { + properties[key] = this._ifNode(callback(this.properties[key], + 'properties[' + stringify(key) + ']', this)); + } + } + return new ObjectNode(properties); + }; - if (typeof expr === 'string') { - // parse a single expression - expression = expr; - return parseStart(); - } - else if (Array.isArray(expr) || expr instanceof type.Matrix) { - // parse an array or matrix with expressions - return deepMap(expr, function (elem) { - if (typeof elem !== 'string') throw new TypeError('String expected'); + /** + * Create a clone of this node, a shallow copy + * @return {ObjectNode} + */ + ObjectNode.prototype.clone = function() { + var properties = {}; + for (var key in this.properties) { + if (this.properties.hasOwnProperty(key)) { + properties[key] = this.properties[key]; + } + } + return new ObjectNode(properties); + }; - expression = elem; - return parseStart(); - }); - } - else { - // oops - throw new TypeError('String or matrix expected'); - } - } - - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - NUMBER : 2, - SYMBOL : 3, - UNKNOWN : 4 - }; - - // map with all delimiters - var DELIMITERS = { - ',': true, - '(': true, - ')': true, - '[': true, - ']': true, - '{': true, - '}': true, - '\"': true, - ';': true, - - '+': true, - '-': true, - '*': true, - '.*': true, - '/': true, - './': true, - '%': true, - '^': true, - '.^': true, - '~': true, - '!': true, - '&': true, - '|': true, - '^|': true, - '\'': true, - '=': true, - ':': true, - '?': true, - - '==': true, - '!=': true, - '<': true, - '>': true, - '<=': true, - '>=': true, - - '<<': true, - '>>': true, - '>>>': true - }; - - // map with all named delimiters - var NAMED_DELIMITERS = { - 'mod': true, - 'to': true, - 'in': true, - 'and': true, - 'xor': true, - 'or': true, - 'not': true - }; - - var CONSTANTS = { - 'true': true, - 'false': false, - 'null': null, - 'undefined': undefined - }; - - var NUMERIC_CONSTANTS = [ - 'NaN', - 'Infinity' - ]; + /** + * Get string representation + * @param {Object} options + * @return {string} str + * @override + */ + ObjectNode.prototype._toString = function(options) { + var entries = []; + for (var key in this.properties) { + if (this.properties.hasOwnProperty(key)) { + entries.push(stringify(key) + ': ' + this.properties[key].toString(options)); + } + } + return '{' + entries.join(', ') + '}'; + }; - var extra_nodes = {}; // current extra nodes - var expression = ''; // current expression - var comment = ''; // last parsed comment - var index = 0; // current index in expr - var c = ''; // current token character in expr - var token = ''; // current token - var token_type = TOKENTYPE.NULL; // type of the token - var nesting_level = 0; // level of nesting inside parameters, used to ignore newline characters - var conditional_level = null; // when a conditional is being parsed, the level of the conditional is stored here - var tokenStates = []; // holds saved token states + /** + * Get a JSON representation of the node + * @returns {Object} + */ + ObjectNode.prototype.toJSON = function () { + return { + mathjs: 'ObjectNode', + properties: this.properties + }; + }; - /** - * Get the first character from the expression. - * The character is stored into the char c. If the end of the expression is - * reached, the function puts an empty string in c. - * @private - */ - function first() { - index = 0; - c = expression.charAt(0); - nesting_level = 0; - conditional_level = null; - } + /** + * Instantiate an OperatorNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "ObjectNode", "properties": {...}}`, + * where mathjs is optional + * @returns {ObjectNode} + */ + ObjectNode.fromJSON = function (json) { + return new ObjectNode(json.properties); + }; - /** - * Get the next character from the expression. - * The character is stored into the char c. If the end of the expression is - * reached, the function puts an empty string in c. - * @private - */ - function next() { - index++; - c = expression.charAt(index); - } + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + * @override + */ + ObjectNode.prototype.toHTML = function(options) { + var entries = []; + for (var key in this.properties) { + if (this.properties.hasOwnProperty(key)) { + entries.push('' + escape$2(key) + '' + ':' + this.properties[key].toHTML(options)); + } + } + return '{' + entries.join(',') + '}'; + }; - /** - * Preview the previous character from the expression. - * @return {string} cNext - * @private - */ - function prevPreview() { - return expression.charAt(index - 1); - } + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + */ + ObjectNode.prototype._toTex = function(options) { + var entries = []; + for (var key in this.properties) { + if (this.properties.hasOwnProperty(key)) { + entries.push("\\mathbf{" + key + ':} & ' + this.properties[key].toTex(options) + "\\\\"); + } + } + return '\\left\\{\\begin{array}{ll}' + entries.join('\n') + '\\end{array}\\right\\}'; + }; - /** - * Preview the next character from the expression. - * @return {string} cNext - * @private - */ - function nextPreview() { - return expression.charAt(index + 1); + return ObjectNode; } - /** - * Preview the second next character from the expression. - * @return {string} cNext - * @private - */ - function nextNextPreview() { - return expression.charAt(index + 2); - } + var name$48 = 'ObjectNode'; + var path$23 = 'expression.node'; + var factory_1$53 = factory$54; - /** - * Save the current token state so we can rewind later if necessary. - * @private - */ - function pushTokenState() { - tokenStates.push({ - token_type: token_type, - token: token, - comment: comment, - index: index, - c: c - }); - } + var ObjectNode = { + name: name$48, + path: path$23, + factory: factory_1$53 + }; - /** - * Rewind the parser by one token by restoring the last saved token state - * @private - */ - function popTokenState() { - var restoredState = tokenStates.pop(); - token_type = restoredState.token_type; - token = restoredState.token; - comment = restoredState.comment; - index = restoredState.index; - c = restoredState.c; - } + var map$4 = array.map; + var escape$3 = string.escape; + var isSafeMethod$1 = customs.isSafeMethod; + var getSafeProperty$5 = customs.getSafeProperty; - /** - * Discard the most recent token state without restoring it - * @private - */ - function discardTokenState() { - tokenStates.pop(); - } - /** - * Get next token in the current string expr. - * The token and token type are available as token and token_type - * @private - */ - function getToken() { - token_type = TOKENTYPE.NULL; - token = ''; - comment = ''; - - // skip over whitespaces - // space, tab, and newline when inside parameters - while (parse.isWhitespace(c, nesting_level)) { - next(); - } + function factory$55 (type, config, load, typed) { + var Node$$1 = load(Node); - // skip comment - if (c === '#') { - while (c !== '\n' && c !== '') { - comment += c; - next(); + /** + * @constructor OperatorNode + * @extends {Node} + * An operator with two arguments, like 2+3 + * + * @param {string} op Operator name, for example '+' + * @param {string} fn Function name, for example 'add' + * @param {Node[]} args Operator arguments + * @param {boolean} [implicit] Is this an implicit multiplication? + */ + function OperatorNode(op, fn, args, implicit) { + if (!(this instanceof OperatorNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); } - } - // check for end of expression - if (c === '') { - // token is still empty - token_type = TOKENTYPE.DELIMITER; - return; - } + //validate input + if (typeof op !== 'string') { + throw new TypeError('string expected for parameter "op"'); + } + if (typeof fn !== 'string') { + throw new TypeError('string expected for parameter "fn"'); + } + if (!Array.isArray(args) || !args.every(type.isNode)) { + throw new TypeError('Array containing Nodes expected for parameter "args"'); + } - // check for new line character - if (c === '\n' && !nesting_level) { - token_type = TOKENTYPE.DELIMITER; - token = c; - next(); - return; + this.implicit = (implicit === true); + this.op = op; + this.fn = fn; + this.args = args || []; } - // check for delimiters consisting of 3 characters - var c2 = c + nextPreview(); - var c3 = c2 + nextNextPreview(); - if (c3.length === 3 && DELIMITERS[c3]) { - token_type = TOKENTYPE.DELIMITER; - token = c3; - next(); - next(); - next(); - return; - } + OperatorNode.prototype = new Node$$1(); - // check for delimiters consisting of 2 characters - if (c2.length === 2 && DELIMITERS[c2]) { - token_type = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } + OperatorNode.prototype.type = 'OperatorNode'; - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - token_type = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } + OperatorNode.prototype.isOperatorNode = true; - // check for a number - if (parse.isDigitDot(c)) { - token_type = TOKENTYPE.NUMBER; + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + OperatorNode.prototype._compile = function (math, argNames) { + // validate fn + if (typeof this.fn !== 'string' || !isSafeMethod$1(math, this.fn)) { + if (!math[this.fn]) { + throw new Error('Function ' + this.fn + ' missing in provided namespace "math"'); + } + else { + throw new Error('No access to function "' + this.fn + '"'); + } + } - // get number, can have a single dot - if (c === '.') { - token += c; - next(); + var fn = getSafeProperty$5(math, this.fn); + var evalArgs = map$4(this.args, function (arg) { + return arg._compile(math, argNames); + }); - if (!parse.isDigit(c)) { - // this is no number, it is just a dot (can be dot notation) - token_type = TOKENTYPE.DELIMITER; - } + if (evalArgs.length === 1) { + var evalArg0 = evalArgs[0]; + return function evalOperatorNode(scope, args, context) { + return fn(evalArg0(scope, args, context)); + }; + } + else if (evalArgs.length === 2) { + var evalArg0 = evalArgs[0]; + var evalArg1 = evalArgs[1]; + return function evalOperatorNode(scope, args, context) { + return fn(evalArg0(scope, args, context), evalArg1(scope, args, context)) + }; } else { - while (parse.isDigit(c)) { - token += c; - next(); - } - if (parse.isDecimalMark(c, nextPreview())) { - token += c; - next(); - } + return function evalOperatorNode(scope, args, context) { + return fn.apply(null, map$4(evalArgs, function (evalArg) { + return evalArg(scope, args, context) + })); + }; } - while (parse.isDigit(c)) { - token += c; - next(); + }; + + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + OperatorNode.prototype.forEach = function (callback) { + for (var i = 0; i < this.args.length; i++) { + callback(this.args[i], 'args[' + i + ']', this); } + }; - // check for exponential notation like "2.3e-4", "1.23e50" or "2e+4" - c2 = nextPreview(); - if (c === 'E' || c === 'e') { - if (parse.isDigit(c2) || c2 === '-' || c2 === '+') { - token += c; - next(); + /** + * Create a new OperatorNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {OperatorNode} Returns a transformed copy of the node + */ + OperatorNode.prototype.map = function (callback) { + var args = []; + for (var i = 0; i < this.args.length; i++) { + args[i] = this._ifNode(callback(this.args[i], 'args[' + i + ']', this)); + } + return new OperatorNode(this.op, this.fn, args, this.implicit); + }; - if (c === '+' || c === '-') { - token += c; - next(); - } + /** + * Create a clone of this node, a shallow copy + * @return {OperatorNode} + */ + OperatorNode.prototype.clone = function () { + return new OperatorNode(this.op, this.fn, this.args.slice(0), this.implicit); + }; - // Scientific notation MUST be followed by an exponent - if (!parse.isDigit(c)) { - throw createSyntaxError('Digit expected, got "' + c + '"'); - } + /** + * Check whether this is an unary OperatorNode: + * has exactly one argument, like `-a`. + * @return {boolean} Returns true when an unary operator node, false otherwise. + */ + OperatorNode.prototype.isUnary = function () { + return this.args.length === 1; + }; - while (parse.isDigit(c)) { - token += c; - next(); - } + /** + * Check whether this is a binary OperatorNode: + * has exactly two arguments, like `a + b`. + * @return {boolean} Returns true when a binary operator node, false otherwise. + */ + OperatorNode.prototype.isBinary = function () { + return this.args.length === 2; + }; - if (parse.isDecimalMark(c, nextPreview())) { - throw createSyntaxError('Digit expected, got "' + c + '"'); + /** + * Calculate which parentheses are necessary. Gets an OperatorNode + * (which is the root of the tree) and an Array of Nodes + * (this.args) and returns an array where 'true' means that an argument + * has to be enclosed in parentheses whereas 'false' means the opposite. + * + * @param {OperatorNode} root + * @param {string} parenthesis + * @param {Node[]} args + * @param {boolean} latex + * @return {boolean[]} + * @private + */ + function calculateNecessaryParentheses(root, parenthesis, implicit, args, latex$$1) { + //precedence of the root OperatorNode + var precedence = operators.getPrecedence(root, parenthesis); + var associativity = operators.getAssociativity(root, parenthesis); + + if ((parenthesis === 'all') || ((args.length > 2) && (root.getIdentifier() !== 'OperatorNode:add') && (root.getIdentifier() !== 'OperatorNode:multiply'))) { + var parens = args.map(function (arg) { + switch (arg.getContent().type) { //Nodes that don't need extra parentheses + case 'ArrayNode': + case 'ConstantNode': + case 'SymbolNode': + case 'ParenthesisNode': + return false; + break; + default: + return true; } - } - else if (c2 === '.') { - next(); - throw createSyntaxError('Digit expected, got "' + c + '"'); - } + }); + return parens; } - return; - } - - // check for variables, functions, named operators - if (parse.isAlpha(c, prevPreview(), nextPreview())) { - while (parse.isAlpha(c, prevPreview(), nextPreview()) || parse.isDigit(c)) { - token += c; - next(); - } + var result = undefined; + switch (args.length) { + case 0: + result = []; + break; - if (NAMED_DELIMITERS.hasOwnProperty(token)) { - token_type = TOKENTYPE.DELIMITER; - } - else { - token_type = TOKENTYPE.SYMBOL; - } + case 1: //unary operators + //precedence of the operand + var operandPrecedence = operators.getPrecedence(args[0], parenthesis); + + //handle special cases for LaTeX, where some of the parentheses aren't needed + if (latex$$1 && (operandPrecedence !== null)) { + var operandIdentifier; + var rootIdentifier; + if (parenthesis === 'keep') { + operandIdentifier = args[0].getIdentifier(); + rootIdentifier = root.getIdentifier(); + } + else { + //Ignore Parenthesis Nodes when not in 'keep' mode + operandIdentifier = args[0].getContent().getIdentifier(); + rootIdentifier = root.getContent().getIdentifier(); + } + if (operators.properties[precedence][rootIdentifier].latexLeftParens === false) { + result = [false]; + break; + } - return; - } + if (operators.properties[operandPrecedence][operandIdentifier].latexParens === false) { + result = [false]; + break; + } + } - // something unknown is found, wrong characters -> a syntax error - token_type = TOKENTYPE.UNKNOWN; - while (c !== '') { - token += c; - next(); - } - throw createSyntaxError('Syntax error in part "' + token + '"'); - } + if (operandPrecedence === null) { + //if the operand has no defined precedence, no parens are needed + result = [false]; + break; + } - /** - * Get next token and skip newline tokens - */ - function getTokenSkipNewline () { - do { - getToken(); - } - while (token === '\n'); - } + if (operandPrecedence <= precedence) { + //if the operands precedence is lower, parens are needed + result = [true]; + break; + } - /** - * Open parameters. - * New line characters will be ignored until closeParams() is called - */ - function openParams() { - nesting_level++; - } + //otherwise, no parens needed + result = [false]; + break; - /** - * Close parameters. - * New line characters will no longer be ignored - */ - function closeParams() { - nesting_level--; - } - - /** - * Checks whether the current character `c` is a valid alpha character: - * - * - A latin letter (upper or lower case) Ascii: a-z, A-Z - * - An underscore Ascii: _ - * - A dollar sign Ascii: $ - * - A latin letter with accents Unicode: \u00C0 - \u02AF - * - A greek letter Unicode: \u0370 - \u03FF - * - A mathematical alphanumeric symbol Unicode: \u{1D400} - \u{1D7FF} excluding invalid code points - * - * The previous and next characters are needed to determine whether - * this character is part of a unicode surrogate pair. - * - * @param {string} c Current character in the expression - * @param {string} cPrev Previous character - * @param {string} cNext Next character - * @return {boolean} - */ - parse.isAlpha = function isAlpha (c, cPrev, cNext) { - return parse.isValidLatinOrGreek(c) - || parse.isValidMathSymbol(c, cNext) - || parse.isValidMathSymbol(cPrev, c); - }; - - /** - * Test whether a character is a valid latin, greek, or letter-like character - * @param {string} c - * @return {boolean} - */ - parse.isValidLatinOrGreek = function isValidLatinOrGreek (c) { - return /^[a-zA-Z_$\u00C0-\u02AF\u0370-\u03FF\u2100-\u214F]$/.test(c); - }; + case 2: //binary operators + var lhsParens; //left hand side needs parenthesis? + //precedence of the left hand side + var lhsPrecedence = operators.getPrecedence(args[0], parenthesis); + //is the root node associative with the left hand side + var assocWithLhs = operators.isAssociativeWith(root, args[0], parenthesis); + + if (lhsPrecedence === null) { + //if the left hand side has no defined precedence, no parens are needed + //FunctionNode for example + lhsParens = false; + } + else if ((lhsPrecedence === precedence) && (associativity === 'right') && !assocWithLhs) { + //In case of equal precedence, if the root node is left associative + // parens are **never** necessary for the left hand side. + //If it is right associative however, parens are necessary + //if the root node isn't associative with the left hand side + lhsParens = true; + } + else if (lhsPrecedence < precedence) { + lhsParens = true; + } + else { + lhsParens = false; + } - /** - * Test whether two given 16 bit characters form a surrogate pair of a - * unicode math symbol. - * - * http://unicode-table.com/en/ - * http://www.wikiwand.com/en/Mathematical_operators_and_symbols_in_Unicode - * - * Note: In ES6 will be unicode aware: - * http://stackoverflow.com/questions/280712/javascript-unicode-regexes - * https://mathiasbynens.be/notes/es6-unicode-regex - * - * @param {string} high - * @param {string} low - * @return {boolean} - */ - parse.isValidMathSymbol = function isValidMathSymbol (high, low) { - return /^[\uD835]$/.test(high) && - /^[\uDC00-\uDFFF]$/.test(low) && - /^[^\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]$/.test(low); - }; + var rhsParens; //right hand side needs parenthesis? + //precedence of the right hand side + var rhsPrecedence = operators.getPrecedence(args[1], parenthesis); + //is the root node associative with the right hand side? + var assocWithRhs = operators.isAssociativeWith(root, args[1], parenthesis); - /** - * Check whether given character c is a white space character: space, tab, or enter - * @param {string} c - * @param {number} nestingLevel - * @return {boolean} - */ - parse.isWhitespace = function isWhitespace (c, nestingLevel) { - // TODO: also take '\r' carriage return as newline? Or does that give problems on mac? - return c === ' ' || c === '\t' || (c === '\n' && nestingLevel > 0); - }; + if (rhsPrecedence === null) { + //if the right hand side has no defined precedence, no parens are needed + //FunctionNode for example + rhsParens = false; + } + else if ((rhsPrecedence === precedence) && (associativity === 'left') && !assocWithRhs) { + //In case of equal precedence, if the root node is right associative + // parens are **never** necessary for the right hand side. + //If it is left associative however, parens are necessary + //if the root node isn't associative with the right hand side + rhsParens = true; + } + else if (rhsPrecedence < precedence) { + rhsParens = true; + } + else { + rhsParens = false; + } - /** - * Test whether the character c is a decimal mark (dot). - * This is the case when it's not the start of a delimiter '.*', './', or '.^' - * @param {string} c - * @param {string} cNext - * @return {boolean} - */ - parse.isDecimalMark = function isDecimalMark (c, cNext) { - return c === '.' && cNext !== '/' && cNext !== '*' && cNext !== '^'; - }; + //handle special cases for LaTeX, where some of the parentheses aren't needed + if (latex$$1) { + var rootIdentifier; + var lhsIdentifier; + var rhsIdentifier; + if (parenthesis === 'keep') { + rootIdentifier = root.getIdentifier(); + lhsIdentifier = root.args[0].getIdentifier(); + rhsIdentifier = root.args[1].getIdentifier(); + } + else { + //Ignore ParenthesisNodes when not in 'keep' mode + rootIdentifier = root.getContent().getIdentifier(); + lhsIdentifier = root.args[0].getContent().getIdentifier(); + rhsIdentifier = root.args[1].getContent().getIdentifier(); + } - /** - * checks if the given char c is a digit or dot - * @param {string} c a string with one character - * @return {boolean} - */ - parse.isDigitDot = function isDigitDot (c) { - return ((c >= '0' && c <= '9') || c === '.'); - }; + if (lhsPrecedence !== null) { + if (operators.properties[precedence][rootIdentifier].latexLeftParens === false) { + lhsParens = false; + } - /** - * checks if the given char c is a digit - * @param {string} c a string with one character - * @return {boolean} - */ - parse.isDigit = function isDigit (c) { - return (c >= '0' && c <= '9'); - }; + if (operators.properties[lhsPrecedence][lhsIdentifier].latexParens === false) { + lhsParens = false; + } + } - /** - * Start of the parse levels below, in order of precedence - * @return {Node} node - * @private - */ - function parseStart () { - // get the first character in expression - first(); + if (rhsPrecedence !== null) { + if (operators.properties[precedence][rootIdentifier].latexRightParens === false) { + rhsParens = false; + } - getToken(); + if (operators.properties[rhsPrecedence][rhsIdentifier].latexParens === false) { + rhsParens = false; + } + } + } - var node = parseBlock(); + result = [lhsParens, rhsParens]; + break; - // check for garbage at the end of the expression - // an expression ends with a empty character '' and token_type DELIMITER - if (token !== '') { - if (token_type === TOKENTYPE.DELIMITER) { - // user entered a not existing operator like "//" + default: + if ((root.getIdentifier() === 'OperatorNode:add') || (root.getIdentifier() === 'OperatorNode:multiply')) { + var result = args.map(function (arg) { + var argPrecedence = operators.getPrecedence(arg, parenthesis); + var assocWithArg = operators.isAssociativeWith(root, arg, parenthesis); + var argAssociativity = operators.getAssociativity(arg, parenthesis); + if (argPrecedence === null) { + //if the argument has no defined precedence, no parens are needed + return false; + } else if ((precedence === argPrecedence) && (associativity === argAssociativity) && !assocWithArg) { + return true; + } else if (argPrecedence < precedence) { + return true; + } - // TODO: give hints for aliases, for example with "<>" give as hint " did you mean !== ?" - throw createError('Unexpected operator ' + token); - } - else { - throw createSyntaxError('Unexpected part "' + token + '"'); + return false; + }); + } + break; } - } - - return node; - } - - /** - * Parse a block with expressions. Expressions can be separated by a newline - * character '\n', or by a semicolon ';'. In case of a semicolon, no output - * of the preceding line is returned. - * @return {Node} node - * @private - */ - function parseBlock () { - var node; - var blocks = []; - var visible; - if (token !== '' && token !== '\n' && token !== ';') { - node = parseAssignment(); - node.comment = comment; - } + //handles an edge case of 'auto' parentheses with implicit multiplication of ConstantNode + //In that case print parentheses for ParenthesisNodes even though they normally wouldn't be + //printed. + if ((args.length >= 2) && (root.getIdentifier() === 'OperatorNode:multiply') && root.implicit && (parenthesis === 'auto') && (implicit === 'hide')) { + result = args.map(function (arg, index) { + var isParenthesisNode = (arg.getIdentifier() === 'ParenthesisNode'); + if (result[index] || isParenthesisNode) { //put in parenthesis? + return true; + } - // TODO: simplify this loop - while (token === '\n' || token === ';') { - if (blocks.length === 0 && node) { - visible = (token !== ';'); - blocks.push({ - node: node, - visible: visible + return false; }); } - getToken(); - if (token !== '\n' && token !== ';' && token !== '') { - node = parseAssignment(); - node.comment = comment; - - visible = (token !== ';'); - blocks.push({ - node: node, - visible: visible - }); - } + return result; } - if (blocks.length > 0) { - return new BlockNode$$1(blocks); - } - else { - if (!node) { - node = new ConstantNode$$1(undefined); - node.comment = comment; - } + /** + * Get string representation. + * @param {Object} options + * @return {string} str + */ + OperatorNode.prototype._toString = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var implicit = (options && options.implicit) ? options.implicit : 'hide'; + var args = this.args; + var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, false); - return node - } - } + if (args.length === 1) { //unary operators + var assoc = operators.getAssociativity(this, parenthesis); - /** - * Assignment of a function or variable, - * - can be a variable like 'a=2.3' - * - or a updating an existing variable like 'matrix(2,3:5)=[6,7,8]' - * - defining a function like 'f(x) = x^2' - * @return {Node} node - * @private - */ - function parseAssignment () { - var name, args, value, valid; + var operand = args[0].toString(options); + if (parens[0]) { + operand = '(' + operand + ')'; + } - var node = parseConditional(); + if (assoc === 'right') { //prefix operator + return this.op + operand; + } + else if (assoc === 'left') { //postfix + return operand + this.op; + } - if (token === '=') { - if (type.isSymbolNode(node)) { - // parse a variable assignment like 'a = 2/3' - name = node.name; - getTokenSkipNewline(); - value = parseAssignment(); - return new AssignmentNode$$1(new SymbolNode$$1(name), value); - } - else if (type.isAccessorNode(node)) { - // parse a matrix subset assignment like 'A[1,2] = 4' - getTokenSkipNewline(); - value = parseAssignment(); - return new AssignmentNode$$1(node.object, node.index, value); - } - else if (type.isFunctionNode(node) && type.isSymbolNode(node.fn)) { - // parse function assignment like 'f(x) = x^2' - valid = true; - args = []; + //fall back to postfix + return operand + this.op; + } else if (args.length == 2) { + var lhs = args[0].toString(options); //left hand side + var rhs = args[1].toString(options); //right hand side + if (parens[0]) { //left hand side in parenthesis? + lhs = '(' + lhs + ')'; + } + if (parens[1]) { //right hand side in parenthesis? + rhs = '(' + rhs + ')'; + } - name = node.name; - node.args.forEach(function (arg, index) { - if (type.isSymbolNode(arg)) { - args[index] = arg.name; - } - else { - valid = false; + if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit == 'hide')) { + return lhs + ' ' + rhs; + } + + return lhs + ' ' + this.op + ' ' + rhs; + } else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { + var stringifiedArgs = args.map(function (arg, index) { + arg = arg.toString(options); + if (parens[index]) { //put in parenthesis? + arg = '(' + arg + ')'; } + + return arg; }); - if (valid) { - getTokenSkipNewline(); - value = parseAssignment(); - return new FunctionAssignmentNode$$1(name, args, value); + if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit === 'hide')) { + return stringifiedArgs.join(' '); } - } - - throw createSyntaxError('Invalid left hand side of assignment operator ='); - } - return node; - } + return stringifiedArgs.join(' ' + this.op + ' '); + } else { + //fallback to formatting as a function call + return this.fn + '(' + this.args.join(', ') + ')'; + } + }; - /** - * conditional operation - * - * condition ? truePart : falsePart - * - * Note: conditional operator is right-associative - * - * @return {Node} node - * @private - */ - function parseConditional () { - var node = parseLogicalOr(); + /** + * Get a JSON representation of the node + * @returns {Object} + */ + OperatorNode.prototype.toJSON = function () { + return { + mathjs: 'OperatorNode', + op: this.op, + fn: this.fn, + args: this.args, + implicit: this.implicit + }; + }; - while (token === '?') { - // set a conditional level, the range operator will be ignored as long - // as conditional_level === nesting_level. - var prev = conditional_level; - conditional_level = nesting_level; - getTokenSkipNewline(); + /** + * Instantiate an OperatorNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "OperatorNode", "op": "+", "fn": "add", "args": [...], "implicit": false}`, + * where mathjs is optional + * @returns {OperatorNode} + */ + OperatorNode.fromJSON = function (json) { + return new OperatorNode(json.op, json.fn, json.args, json.implicit); + }; - var condition = node; - var trueExpr = parseAssignment(); + /** + * Get HTML representation. + * @param {Object} options + * @return {string} str + */ + OperatorNode.prototype.toHTML = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var implicit = (options && options.implicit) ? options.implicit : 'hide'; + var args = this.args; + var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, false); - if (token !== ':') throw createSyntaxError('False part of conditional expression expected'); + if (args.length === 1) { //unary operators + var assoc = operators.getAssociativity(this, parenthesis); - conditional_level = null; - getTokenSkipNewline(); + var operand = args[0].toHTML(options); + if (parens[0]) { + operand = '(' + operand + ')'; + } - var falseExpr = parseAssignment(); // Note: check for conditional operator again, right associativity + if (assoc === 'right') { //prefix operator + return '' + escape$3(this.op) + '' + operand; + } + else if (assoc === 'left') { //postfix + return '' + escape$3(this.op) + '' + operand; + } - node = new ConditionalNode$$1(condition, trueExpr, falseExpr); + //fall back to postfix + return '' + escape$3(this.op) + '' + operand; + } + else if (args.length == 2) { // binary operatoes + var lhs = args[0].toHTML(options); //left hand side + var rhs = args[1].toHTML(options); //right hand side + if (parens[0]) { //left hand side in parenthesis? + lhs = '(' + lhs + ')'; + } + if (parens[1]) { //right hand side in parenthesis? + rhs = '(' + rhs + ')'; + } + + if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit == 'hide')) { + return lhs + '' + rhs; + } + + return lhs + '' + escape$3(this.op) + '' + rhs; + } + else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { + var stringifiedArgs = args.map(function (arg, index) { + arg = arg.toHTML(options); + if (parens[index]) { //put in parenthesis? + arg = '(' + arg + ')'; + } - // restore the previous conditional level - conditional_level = prev; - } + return arg; + }); - return node; - } + if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit === 'hide')) { + return stringifiedArgs.join(''); + } - /** - * logical or, 'x or y' - * @return {Node} node - * @private - */ - function parseLogicalOr() { - var node = parseLogicalXor(); + return stringifiedArgs.join('' + escape$3(this.op) + ''); + } else { + //fallback to formatting as a function call + return '' + escape$3(this.fn) + '(' + stringifiedArgs.join(',') + ')'; + } + }; - while (token === 'or') { - getTokenSkipNewline(); - node = new OperatorNode$$1('or', 'or', [node, parseLogicalXor()]); - } + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + */ + OperatorNode.prototype._toTex = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var implicit = (options && options.implicit) ? options.implicit : 'hide'; + var args = this.args; + var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, true); + var op = latex.operators[this.fn]; + op = typeof op === 'undefined' ? this.op : op; //fall back to using this.op - return node; - } + if (args.length === 1) { //unary operators + var assoc = operators.getAssociativity(this, parenthesis); - /** - * logical exclusive or, 'x xor y' - * @return {Node} node - * @private - */ - function parseLogicalXor() { - var node = parseLogicalAnd(); + var operand = args[0].toTex(options); + if (parens[0]) { + operand = '\\left(' + operand + '\\right)'; + } - while (token === 'xor') { - getTokenSkipNewline(); - node = new OperatorNode$$1('xor', 'xor', [node, parseLogicalAnd()]); - } + if (assoc === 'right') { //prefix operator + return op + operand; + } + else if (assoc === 'left') { //postfix operator + return operand + op; + } - return node; - } + //fall back to postfix + return operand + op; + } else if (args.length === 2) { //binary operators + var lhs = args[0]; //left hand side + var lhsTex = lhs.toTex(options); + if (parens[0]) { + lhsTex = '\\left(' + lhsTex + '\\right)'; + } - /** - * logical and, 'x and y' - * @return {Node} node - * @private - */ - function parseLogicalAnd() { - var node = parseBitwiseOr(); + var rhs = args[1]; //right hand side + var rhsTex = rhs.toTex(options); + if (parens[1]) { + rhsTex = '\\left(' + rhsTex + '\\right)'; + } - while (token === 'and') { - getTokenSkipNewline(); - node = new OperatorNode$$1('and', 'and', [node, parseBitwiseOr()]); - } + //handle some exceptions (due to the way LaTeX works) + var lhsIdentifier; + if (parenthesis === 'keep') { + lhsIdentifier = lhs.getIdentifier(); + } + else { + //Ignore ParenthesisNodes if in 'keep' mode + lhsIdentifier = lhs.getContent().getIdentifier(); + } + switch (this.getIdentifier()) { + case 'OperatorNode:divide': + //op contains '\\frac' at this point + return op + '{' + lhsTex + '}' + '{' + rhsTex + '}'; + case 'OperatorNode:pow': + lhsTex = '{' + lhsTex + '}'; + rhsTex = '{' + rhsTex + '}'; + switch (lhsIdentifier) { + case 'ConditionalNode': // + case 'OperatorNode:divide': + lhsTex = '\\left(' + lhsTex + '\\right)'; + } + case 'OperatorNode:multiply': + if (this.implicit && (implicit === 'hide')) { + return lhsTex + '~' + rhsTex; + } + } + return lhsTex + op + rhsTex; + } else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { + var texifiedArgs = args.map(function (arg, index) { + arg = arg.toTex(options); + if (parens[index]) { + arg = '\\left(' + arg + '\\right)'; + } + return arg; + }); - return node; - } + if ((this.getIdentifier() === 'OperatorNode:multiply') && this.implicit) { + return texifiedArgs.join('~'); + } - /** - * bitwise or, 'x | y' - * @return {Node} node - * @private - */ - function parseBitwiseOr() { - var node = parseBitwiseXor(); + return texifiedArgs.join(op) + } else { + //fall back to formatting as a function call + //as this is a fallback, it doesn't use + //fancy function names + return '\\mathrm{' + this.fn + '}\\left(' + + args.map(function (arg) { + return arg.toTex(options); + }).join(',') + '\\right)'; + } + }; - while (token === '|') { - getTokenSkipNewline(); - node = new OperatorNode$$1('|', 'bitOr', [node, parseBitwiseXor()]); - } + /** + * Get identifier. + * @return {string} + */ + OperatorNode.prototype.getIdentifier = function () { + return this.type + ':' + this.fn; + }; - return node; + return OperatorNode; } - /** - * bitwise exclusive or (xor), 'x ^| y' - * @return {Node} node - * @private - */ - function parseBitwiseXor() { - var node = parseBitwiseAnd(); + var name$49 = 'OperatorNode'; + var path$24 = 'expression.node'; + var factory_1$54 = factory$55; - while (token === '^|') { - getTokenSkipNewline(); - node = new OperatorNode$$1('^|', 'bitXor', [node, parseBitwiseAnd()]); - } + var OperatorNode = { + name: name$49, + path: path$24, + factory: factory_1$54 + }; - return node; - } + function factory$56 (type, config, load, typed) { + var Node$$1 = load(Node); - /** - * bitwise and, 'x & y' - * @return {Node} node - * @private - */ - function parseBitwiseAnd () { - var node = parseRelational(); + /** + * @constructor ParenthesisNode + * @extends {Node} + * A parenthesis node describes manual parenthesis from the user input + * @param {Node} content + * @extends {Node} + */ + function ParenthesisNode(content) { + if (!(this instanceof ParenthesisNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } + + // validate input + if (!type.isNode(content)) { + throw new TypeError('Node expected for parameter "content"'); + } - while (token === '&') { - getTokenSkipNewline(); - node = new OperatorNode$$1('&', 'bitAnd', [node, parseRelational()]); + this.content = content; } - return node; - } + ParenthesisNode.prototype = new Node$$1(); - /** - * relational operators - * @return {Node} node - * @private - */ - function parseRelational () { - var node, operators, name, fn, params; + ParenthesisNode.prototype.type = 'ParenthesisNode'; - node = parseShift(); + ParenthesisNode.prototype.isParenthesisNode = true; - operators = { - '==': 'equal', - '!=': 'unequal', - '<': 'smaller', - '>': 'larger', - '<=': 'smallerEq', - '>=': 'largerEq' + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + ParenthesisNode.prototype._compile = function (math, argNames) { + return this.content._compile(math, argNames); }; - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; - getTokenSkipNewline(); - params = [node, parseShift()]; - node = new OperatorNode$$1(name, fn, params); - } + /** + * Get the content of the current Node. + * @return {Node} content + * @override + **/ + ParenthesisNode.prototype.getContent = function () { + return this.content.getContent(); + }; - return node; - } + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + ParenthesisNode.prototype.forEach = function (callback) { + callback(this.content, 'content', this); + }; - /** - * Bitwise left shift, bitwise right arithmetic shift, bitwise right logical shift - * @return {Node} node - * @private - */ - function parseShift () { - var node, operators, name, fn, params; + /** + * Create a new ParenthesisNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node) : Node} callback + * @returns {ParenthesisNode} Returns a clone of the node + */ + ParenthesisNode.prototype.map = function (callback) { + var content = callback(this.content, 'content', this); + return new ParenthesisNode(content); + }; - node = parseConversion(); + /** + * Create a clone of this node, a shallow copy + * @return {ParenthesisNode} + */ + ParenthesisNode.prototype.clone = function() { + return new ParenthesisNode(this.content); + }; - operators = { - '<<' : 'leftShift', - '>>' : 'rightArithShift', - '>>>' : 'rightLogShift' + /** + * Get string representation + * @param {Object} options + * @return {string} str + * @override + */ + ParenthesisNode.prototype._toString = function(options) { + if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { + return '(' + this.content.toString(options) + ')'; + } + return this.content.toString(options); }; - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; + /** + * Get a JSON representation of the node + * @returns {Object} + */ + ParenthesisNode.prototype.toJSON = function () { + return { + mathjs: 'ParenthesisNode', + content: this.content + }; + }; - getTokenSkipNewline(); - params = [node, parseConversion()]; - node = new OperatorNode$$1(name, fn, params); - } - - return node; - } - - /** - * conversion operators 'to' and 'in' - * @return {Node} node - * @private - */ - function parseConversion () { - var node, operators, name, fn, params; - - node = parseRange(); - - operators = { - 'to' : 'to', - 'in' : 'to' // alias of 'to' + /** + * Instantiate an ParenthesisNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "ParenthesisNode", "content": ...}`, + * where mathjs is optional + * @returns {ParenthesisNode} + */ + ParenthesisNode.fromJSON = function (json) { + return new ParenthesisNode(json.content); }; - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; - - getTokenSkipNewline(); - - if (name === 'in' && token === '') { - // end of expression -> this is the unit 'in' ('inch') - node = new OperatorNode$$1('*', 'multiply', [node, new SymbolNode$$1('in')], true); + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + * @override + */ + ParenthesisNode.prototype.toHTML = function(options) { + if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { + return '(' + this.content.toHTML(options) + ')'; } - else { - // operator 'a to b' or 'a in b' - params = [node, parseRange()]; - node = new OperatorNode$$1(name, fn, params); + return this.content.toHTML(options); + }; + + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + * @override + */ + ParenthesisNode.prototype._toTex = function(options) { + if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { + return '\\left(' + this.content.toTex(options) + '\\right)'; } - } + return this.content.toTex(options); + }; - return node; + return ParenthesisNode; } - /** - * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc - * @return {Node} node - * @private - */ - function parseRange () { - var node, params = []; - - if (token === ':') { - // implicit start=1 (one-based) - node = new ConstantNode$$1(1); - } - else { - // explicit start - node = parseAddSubtract(); - } + var name$50 = 'ParenthesisNode'; + var path$25 = 'expression.node'; + var factory_1$55 = factory$56; - if (token === ':' && (conditional_level !== nesting_level)) { - // we ignore the range operator when a conditional operator is being processed on the same level - params.push(node); + var ParenthesisNode = { + name: name$50, + path: path$25, + factory: factory_1$55 + }; - // parse step and end - while (token === ':' && params.length < 3) { - getTokenSkipNewline(); + var escape$4 = string.escape; + var hasOwnProperty$3 = object.hasOwnProperty; + var getSafeProperty$6 = customs.getSafeProperty; - if (token === ')' || token === ']' || token === ',' || token === '') { - // implicit end - params.push(new SymbolNode$$1('end')); - } - else { - // explicit end - params.push(parseAddSubtract()); - } - } + function factory$57 (type, config, load, typed, math) { + var Node$$1 = load(Node); - if (params.length === 3) { - // params = [start, step, end] - node = new RangeNode$$1(params[0], params[2], params[1]); // start, end, step - } - else { // length === 2 - // params = [start, end] - node = new RangeNode$$1(params[0], params[1]); // start, end - } + /** + * Check whether some name is a valueless unit like "inch". + * @param {string} name + * @return {boolean} + */ + function isValuelessUnit (name) { + return type.Unit ? type.Unit.isValuelessUnit(name) : false; } - return node; - } - - /** - * add or subtract - * @return {Node} node - * @private - */ - function parseAddSubtract () { - var node, operators, name, fn, params; - - node = parseMultiplyDivide(); + /** + * @constructor SymbolNode + * @extends {Node} + * A symbol node can hold and resolve a symbol + * @param {string} name + * @extends {Node} + */ + function SymbolNode(name) { + if (!(this instanceof SymbolNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - operators = { - '+': 'add', - '-': 'subtract' - }; - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; + // validate input + if (typeof name !== 'string') throw new TypeError('String expected for parameter "name"'); - getTokenSkipNewline(); - params = [node, parseMultiplyDivide()]; - node = new OperatorNode$$1(name, fn, params); + this.name = name; } - return node; - } - - /** - * multiply, divide, modulus - * @return {Node} node - * @private - */ - function parseMultiplyDivide () { - var node, last, operators, name, fn; - - node = parseImplicitMultiplication(); - last = node; + SymbolNode.prototype = new Node$$1(); - operators = { - '*': 'multiply', - '.*': 'dotMultiply', - '/': 'divide', - './': 'dotDivide', - '%': 'mod', - 'mod': 'mod' - }; + SymbolNode.prototype.type = 'SymbolNode'; - while (true) { - if (operators.hasOwnProperty(token)) { - // explicit operators - name = token; - fn = operators[name]; + SymbolNode.prototype.isSymbolNode = true; - getTokenSkipNewline(); + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + SymbolNode.prototype._compile = function (math, argNames) { + var name = this.name; - last = parseImplicitMultiplication(); - node = new OperatorNode$$1(name, fn, [node, last]); - } - else { - break; + if (hasOwnProperty$3(argNames, name)) { + // this is a FunctionAssignment argument + // (like an x when inside the expression of a function assignment `f(x) = ...`) + return function (scope, args, context) { + return args[name]; + } } - } - - return node; - } - - /** - * implicit multiplication - * @return {Node} node - * @private - */ - function parseImplicitMultiplication () { - var node, last; - - node = parseRule2(); - last = node; - - while (true) { - if ((token_type === TOKENTYPE.SYMBOL) || - (token === 'in' && type.isConstantNode(node)) || - (token_type === TOKENTYPE.NUMBER && - !type.isConstantNode(last) && - (!type.isOperatorNode(last) || last.op === '!')) || - (token === '(')) { - // parse implicit multiplication - // - // symbol: implicit multiplication like '2a', '(2+3)a', 'a b' - // number: implicit multiplication like '(2+3)2' - // parenthesis: implicit multiplication like '2(3+4)', '(3+4)(1+2)' - last = parseRule2(); - node = new OperatorNode$$1('*', 'multiply', [node, last], true /*implicit*/); + else if (name in math) { + return function (scope, args, context) { + return name in scope + ? getSafeProperty$6(scope, name) + : getSafeProperty$6(math, name); + } } else { - break; - } - } + var isUnit = isValuelessUnit(name); - return node; - } - - /** - * Infamous "rule 2" as described in https://github.com/josdejong/mathjs/issues/792#issuecomment-361065370 - * Explicit division gets higher precedence than implicit multiplication - * when the division matches this pattern: [number] / [number] [symbol] - * @return {Node} node - * @private - */ - function parseRule2 () { - var node, last; - - node = parseUnary(); - last = node; - - - while(true) { - - // Match the "number /" part of the pattern "number / number symbol" - if(token === '/' && type.isConstantNode(last)) { - - // Look ahead to see if the next token is a number - pushTokenState(); - getTokenSkipNewline(); - - // Match the "number / number" part of the pattern - if(token_type === TOKENTYPE.NUMBER) { - - // Look ahead again - pushTokenState(); - getTokenSkipNewline(); - - // Match the "symbol" part of the pattern, or a left parenthesis - if(token_type === TOKENTYPE.SYMBOL || token === '(') { - // We've matched the pattern "number / number symbol". - // Rewind once and build the "number / number" node; the symbol will be consumed later - popTokenState(); - discardTokenState(); - last = parseUnary(); - node = new OperatorNode$$1('/', 'divide', [node, last]); - } - else { - // Not a match, so rewind - popTokenState(); - popTokenState(); - break; - } - } - else { - // Not a match, so rewind - popTokenState(); - break; + return function (scope, args, context) { + return name in scope + ? getSafeProperty$6(scope, name) + : isUnit + ? new type.Unit(null, name) + : undef(name); } } - else { - break; - } - } - - return node; - } - - /** - * Unary plus and minus, and logical and bitwise not - * @return {Node} node - * @private - */ - function parseUnary () { - var name, params, fn; - var operators = { - '-': 'unaryMinus', - '+': 'unaryPlus', - '~': 'bitNot', - 'not': 'not' }; - if (operators.hasOwnProperty(token)) { - fn = operators[token]; - name = token; + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + SymbolNode.prototype.forEach = function (callback) { + // nothing to do, we don't have childs + }; - getTokenSkipNewline(); - params = [parseUnary()]; + /** + * Create a new SymbolNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node) : Node} callback + * @returns {SymbolNode} Returns a clone of the node + */ + SymbolNode.prototype.map = function (callback) { + return this.clone(); + }; - return new OperatorNode$$1(name, fn, params); + /** + * Throws an error 'Undefined symbol {name}' + * @param {string} name + */ + function undef (name) { + throw new Error('Undefined symbol ' + name); } - return parsePow(); - } + /** + * Create a clone of this node, a shallow copy + * @return {SymbolNode} + */ + SymbolNode.prototype.clone = function() { + return new SymbolNode(this.name); + }; - /** - * power - * Note: power operator is right associative - * @return {Node} node - * @private - */ - function parsePow () { - var node, name, fn, params; + /** + * Get string representation + * @param {Object} options + * @return {string} str + * @override + */ + SymbolNode.prototype._toString = function(options) { + return this.name; + }; + + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + * @override + */ + SymbolNode.prototype.toHTML = function(options) { + var name = escape$4(this.name); + + if (name == "true" || name == "false") { + return '' + name + ''; + } + else if (name == "i") { + return '' + name + ''; + } + else if (name == "Infinity") { + return '' + name + ''; + } + else if (name == "NaN") { + return '' + name + ''; + } + else if (name == "null") { + return '' + name + ''; + } + else if (name == "undefined") { + return '' + name + ''; + } + + return '' + name + ''; + }; - node = parseLeftHandOperators(); + /** + * Get a JSON representation of the node + * @returns {Object} + */ + SymbolNode.prototype.toJSON = function () { + return { + mathjs: 'SymbolNode', + name: this.name + }; + }; - if (token === '^' || token === '.^') { - name = token; - fn = (name === '^') ? 'pow' : 'dotPow'; + /** + * Instantiate a SymbolNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "SymbolNode", name: "x"}`, + * where mathjs is optional + * @returns {SymbolNode} + */ + SymbolNode.fromJSON = function (json) { + return new SymbolNode(json.name); + }; - getTokenSkipNewline(); - params = [node, parseUnary()]; // Go back to unary, we can have '2^-3' - node = new OperatorNode$$1(name, fn, params); - } + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + * @override + */ + SymbolNode.prototype._toTex = function(options) { + var isUnit = false; + if ((typeof math[this.name] === 'undefined') && isValuelessUnit(this.name)) { + isUnit = true; + } + var symbol = latex.toSymbol(this.name, isUnit); + if (symbol[0] === '\\') { + //no space needed if the symbol starts with '\' + return symbol; + } + //the space prevents symbols from breaking stuff like '\cdot' if it's written right before the symbol + return ' ' + symbol; + }; - return node; + return SymbolNode; } - /** - * Left hand operators: factorial x!, transpose x' - * @return {Node} node - * @private - */ - function parseLeftHandOperators () { - var node, operators, name, fn, params; + var name$51 = 'SymbolNode'; + var path$26 = 'expression.node'; + var math$7 = true; // request access to the math namespace as 5th argument of the factory function + var factory_1$56 = factory$57; - node = parseCustomNodes(); + var SymbolNode = { + name: name$51, + path: path$26, + math: math$7, + factory: factory_1$56 + }; - operators = { - '!': 'factorial', - '\'': 'transpose' - }; + var latex$1 = latex; + var escape$5 = string.escape; + var hasOwnProperty$4 = object.hasOwnProperty; + var map$5 = array.map; + var validateSafeMethod$1 = customs.validateSafeMethod; + var getSafeProperty$7 = customs.getSafeProperty; - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; + function factory$58 (type, config, load, typed, math) { + var Node$$1 = load(Node); + var SymbolNode$$1 = load(SymbolNode); - getToken(); - params = [node]; + /** + * @constructor FunctionNode + * @extends {./Node} + * invoke a list with arguments on a node + * @param {./Node | string} fn Node resolving with a function on which to invoke + * the arguments, typically a SymboNode or AccessorNode + * @param {./Node[]} args + */ + function FunctionNode(fn, args) { + if (!(this instanceof FunctionNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - node = new OperatorNode$$1(name, fn, params); - node = parseAccessors(node); - } + if (typeof fn === 'string') { + fn = new SymbolNode$$1(fn); + } - return node; - } + // validate input + if (!type.isNode(fn)) throw new TypeError('Node expected as parameter "fn"'); + if (!Array.isArray(args) || !args.every(type.isNode)) { + throw new TypeError('Array containing Nodes expected for parameter "args"'); + } - /** - * Parse a custom node handler. A node handler can be used to process - * nodes in a custom way, for example for handling a plot. - * - * A handler must be passed as second argument of the parse function. - * - must extend math.expression.node.Node - * - must contain a function _compile(defs: Object) : string - * - must contain a function find(filter: Object) : Node[] - * - must contain a function toString() : string - * - the constructor is called with a single argument containing all parameters - * - * For example: - * - * nodes = { - * 'plot': PlotHandler - * }; - * - * The constructor of the handler is called as: - * - * node = new PlotHandler(params); - * - * The handler will be invoked when evaluating an expression like: - * - * node = math.parse('plot(sin(x), x)', nodes); - * - * @return {Node} node - * @private - */ - function parseCustomNodes () { - var params = []; + this.fn = fn; + this.args = args || []; - if (token_type === TOKENTYPE.SYMBOL && extra_nodes.hasOwnProperty(token)) { - var CustomNode = extra_nodes[token]; + // readonly property name + Object.defineProperty(this, 'name', { + get: function () { + return this.fn.name || ''; + }.bind(this), + set: function () { + throw new Error('Cannot assign a new name, name is read-only'); + } + }); - getToken(); + // TODO: deprecated since v3, remove some day + var deprecated = function () { + throw new Error('Property `FunctionNode.object` is deprecated, use `FunctionNode.fn` instead'); + }; + Object.defineProperty(this, 'object', { get: deprecated, set: deprecated }); + } - // parse parameters - if (token === '(') { - params = []; + FunctionNode.prototype = new Node$$1(); - openParams(); - getToken(); + FunctionNode.prototype.type = 'FunctionNode'; - if (token !== ')') { - params.push(parseAssignment()); + FunctionNode.prototype.isFunctionNode = true; - // parse a list with parameters - while (token === ',') { - getToken(); - params.push(parseAssignment()); - } - } + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + FunctionNode.prototype._compile = function (math, argNames) { + if (!(this instanceof FunctionNode)) { + throw new TypeError('No valid FunctionNode') + } - if (token !== ')') { - throw createSyntaxError('Parenthesis ) expected'); + // compile arguments + var evalArgs = map$5(this.args, function (arg) { + return arg._compile(math, argNames); + }); + + if (type.isSymbolNode(this.fn)) { + // we can statically determine whether the function has an rawArgs property + var name = this.fn.name; + var fn = name in math ? getSafeProperty$7(math, name) : undefined; + var isRaw = (typeof fn === 'function') && (fn.rawArgs == true); + + if (isRaw) { + // pass unevaluated parameters (nodes) to the function + // "raw" evaluation + var rawArgs = this.args; + return function evalFunctionNode(scope, args, context) { + return (name in scope ? getSafeProperty$7(scope, name) : fn)(rawArgs, math, scope); + }; + } + else { + // "regular" evaluation + if (evalArgs.length === 1) { + var evalArg0 = evalArgs[0]; + return function evalFunctionNode(scope, args, context) { + return (name in scope ? getSafeProperty$7(scope, name) : fn)(evalArg0(scope, args, context)); + }; + } + else if (evalArgs.length === 2) { + var evalArg0 = evalArgs[0]; + var evalArg1 = evalArgs[1]; + return function evalFunctionNode(scope, args, context) { + return (name in scope ? getSafeProperty$7(scope, name) : fn)(evalArg0(scope, args, context), evalArg1(scope, args, context)); + }; + } + else { + return function evalFunctionNode(scope, args, context) { + return (name in scope ? getSafeProperty$7(scope, name) : fn).apply(null, map$5(evalArgs, function (evalArg) { + return evalArg(scope, args, context); + })); + } + } } - closeParams(); - getToken(); } + else if (type.isAccessorNode(this.fn) && + type.isIndexNode(this.fn.index) && this.fn.index.isObjectProperty()) { + // execute the function with the right context: the object of the AccessorNode - // create a new custom node - //noinspection JSValidateTypes - return new CustomNode(params); - } - - return parseSymbol(); - } + var evalObject = this.fn.object._compile(math, argNames); + var prop = this.fn.index.getObjectProperty(); + var rawArgs = this.args; - /** - * parse symbols: functions, variables, constants, units - * @return {Node} node - * @private - */ - function parseSymbol () { - var node, name; + return function evalFunctionNode (scope, args, context) { + var object$$1 = evalObject(scope, args, context); + validateSafeMethod$1(object$$1, prop); + var isRaw = object$$1[prop] && object$$1[prop].rawArgs; - if (token_type === TOKENTYPE.SYMBOL || - (token_type === TOKENTYPE.DELIMITER && token in NAMED_DELIMITERS)) { - name = token; + return isRaw + ? object$$1[prop](rawArgs, math, scope) // "raw" evaluation + : object$$1[prop].apply(object$$1, map$5(evalArgs, function (evalArg) { // "regular" evaluation + return evalArg(scope, args, context); + })); + } + } + else { // node.fn.isAccessorNode && !node.fn.index.isObjectProperty() + // we have to dynamically determine whether the function has a rawArgs property + var evalFn = this.fn._compile(math, argNames); - getToken(); + return function evalFunctionNode (scope, args, context) { + var fn = evalFn(scope, args, context); + var isRaw = fn && fn.rawArgs; - if (CONSTANTS.hasOwnProperty(name)) { // true, false, null, ... - node = new ConstantNode$$1(CONSTANTS[name]); + return isRaw + ? fn(rawArgs, math, scope) // "raw" evaluation + : fn.apply(fn, map$5(evalArgs, function (evalArg) { // "regular" evaluation + return evalArg(scope, args, context); + })); + }; } - else if (NUMERIC_CONSTANTS.indexOf(name) !== -1) { // NaN, Infinity - node = new ConstantNode$$1(numeric$$1(name)); + }; + + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + FunctionNode.prototype.forEach = function (callback) { + for (var i = 0; i < this.args.length; i++) { + callback(this.args[i], 'args[' + i + ']', this); } - else { - node = new SymbolNode$$1(name); + }; + + /** + * Create a new FunctionNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {FunctionNode} Returns a transformed copy of the node + */ + FunctionNode.prototype.map = function (callback) { + var fn = this.fn.map(callback); + var args = []; + for (var i = 0; i < this.args.length; i++) { + args[i] = this._ifNode(callback(this.args[i], 'args[' + i + ']', this)); } + return new FunctionNode(fn, args); + }; - // parse function parameters and matrix index - node = parseAccessors(node); - return node; - } + /** + * Create a clone of this node, a shallow copy + * @return {FunctionNode} + */ + FunctionNode.prototype.clone = function () { + return new FunctionNode(this.fn, this.args.slice(0)); + }; - return parseString(); - } + //backup Node's toString function + //@private + var nodeToString = FunctionNode.prototype.toString; - /** - * parse accessors: - * - function invocation in round brackets (...), for example sqrt(2) - * - index enclosed in square brackets [...], for example A[2,3] - * - dot notation for properties, like foo.bar - * @param {Node} node Node on which to apply the parameters. If there - * are no parameters in the expression, the node - * itself is returned - * @param {string[]} [types] Filter the types of notations - * can be ['(', '[', '.'] - * @return {Node} node - * @private - */ - function parseAccessors (node, types) { - var params; + /** + * Get string representation. (wrapper function) + * This overrides parts of Node's toString function. + * If callback is an object containing callbacks, it + * calls the correct callback for the current node, + * otherwise it falls back to calling Node's toString + * function. + * + * @param {Object} options + * @return {string} str + * @override + */ + FunctionNode.prototype.toString = function (options) { + var customString; + var name = this.fn.toString(options); + if (options && (typeof options.handler === 'object') && hasOwnProperty$4(options.handler, name)) { + //callback is a map of callback functions + customString = options.handler[name](this, options); + } - while ((token === '(' || token === '[' || token === '.') && - (!types || types.indexOf(token) !== -1)) { - params = []; + if (typeof customString !== 'undefined') { + return customString; + } - if (token === '(') { - if (type.isSymbolNode(node) || type.isAccessorNode(node)) { - // function invocation like fn(2, 3) or obj.fn(2, 3) - openParams(); - getToken(); - - if (token !== ')') { - params.push(parseAssignment()); + //fall back to Node's toString + return nodeToString.call(this, options); + }; - // parse a list with parameters - while (token === ',') { - getToken(); - params.push(parseAssignment()); - } - } + /** + * Get string representation + * @param {Object} options + * @return {string} str + */ + FunctionNode.prototype._toString = function (options) { + var args = this.args.map(function (arg) { + return arg.toString(options); + }); - if (token !== ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - closeParams(); - getToken(); + var fn = type.isFunctionAssignmentNode(this.fn) + ? ('(' + this.fn.toString(options) + ')') + : this.fn.toString(options); - node = new FunctionNode$$1(node, params); - } - else { - // implicit multiplication like (2+3)(4+5) or sqrt(2)(1+2) - // don't parse it here but let it be handled by parseImplicitMultiplication - // with correct precedence - return node; - } - } - else if (token === '[') { - // index notation like variable[2, 3] - openParams(); - getToken(); + // format the arguments like "add(2, 4.2)" + return fn + '(' + args.join(', ') + ')'; + }; - if (token !== ']') { - params.push(parseAssignment()); + /** + * Get a JSON representation of the node + * @returns {Object} + */ + FunctionNode.prototype.toJSON = function () { + return { + mathjs: 'FunctionNode', + fn: this.fn, + args: this.args + }; + }; - // parse a list with parameters - while (token === ',') { - getToken(); - params.push(parseAssignment()); - } - } + /** + * Instantiate an AssignmentNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "FunctionNode", fn: ..., args: ...}`, + * where mathjs is optional + * @returns {FunctionNode} + */ + FunctionNode.fromJSON = function (json) { + return new FunctionNode(json.fn, json.args); + }; - if (token !== ']') { - throw createSyntaxError('Parenthesis ] expected'); - } - closeParams(); - getToken(); + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + */ + FunctionNode.prototype.toHTML = function (options) { + var args = this.args.map(function (arg) { + return arg.toHTML(options); + }); - node = new AccessorNode$$1(node, new IndexNode$$1(params)); - } - else { - // dot notation like variable.prop - getToken(); + // format the arguments like "add(2, 4.2)" + return '' + escape$5(this.fn) + '(' + args.join(',') + ')'; + }; - if (token_type !== TOKENTYPE.SYMBOL) { - throw createSyntaxError('Property name expected after dot'); + /* + * Expand a LaTeX template + * + * @param {string} template + * @param {Node} node + * @param {Object} options + * @private + **/ + function expandTemplate(template, node, options) { + var latex$$1 = ''; + + // Match everything of the form ${identifier} or ${identifier[2]} or $$ + // while submatching identifier and 2 (in the second case) + var regex = new RegExp('\\$(?:\\{([a-z_][a-z_0-9]*)(?:\\[([0-9]+)\\])?\\}|\\$)', 'ig'); + + var inputPos = 0; //position in the input string + var match; + while ((match = regex.exec(template)) !== null) { //go through all matches + // add everything in front of the match to the LaTeX string + latex$$1 += template.substring(inputPos, match.index); + inputPos = match.index; + + if (match[0] === '$$') { // escaped dollar sign + latex$$1 += '$'; + inputPos++; + } + else { // template parameter + inputPos += match[0].length; + var property = node[match[1]]; + if (!property) { + throw new ReferenceError('Template: Property ' + match[1] + ' does not exist.'); + } + if (match[2] === undefined) { //no square brackets + switch (typeof property) { + case 'string': + latex$$1 += property; + break; + case 'object': + if (type.isNode(property)) { + latex$$1 += property.toTex(options); + } + else if (Array.isArray(property)) { + //make array of Nodes into comma separated list + latex$$1 += property.map(function (arg, index) { + if (type.isNode(arg)) { + return arg.toTex(options); + } + throw new TypeError('Template: ' + match[1] + '[' + index + '] is not a Node.'); + }).join(','); + } + else { + throw new TypeError('Template: ' + match[1] + ' has to be a Node, String or array of Nodes'); + } + break; + default: + throw new TypeError('Template: ' + match[1] + ' has to be a Node, String or array of Nodes'); + } + } + else { //with square brackets + if (type.isNode(property[match[2]] && property[match[2]])) { + latex$$1 += property[match[2]].toTex(options); + } + else { + throw new TypeError('Template: ' + match[1] + '[' + match[2] + '] is not a Node.'); + } + } } - params.push(new ConstantNode$$1(token)); - getToken(); - - var dotNotation = true; - node = new AccessorNode$$1(node, new IndexNode$$1(params, dotNotation)); } + latex$$1 += template.slice(inputPos); //append rest of the template + + return latex$$1; } - return node; - } + //backup Node's toTex function + //@private + var nodeToTex = FunctionNode.prototype.toTex; - /** - * parse a string. - * A string is enclosed by double quotes - * @return {Node} node - * @private - */ - function parseString () { - var node, str; + /** + * Get LaTeX representation. (wrapper function) + * This overrides parts of Node's toTex function. + * If callback is an object containing callbacks, it + * calls the correct callback for the current node, + * otherwise it falls back to calling Node's toTex + * function. + * + * @param {Object} options + * @return {string} + */ + FunctionNode.prototype.toTex = function (options) { + var customTex; + if (options && (typeof options.handler === 'object') && hasOwnProperty$4(options.handler, this.name)) { + //callback is a map of callback functions + customTex = options.handler[this.name](this, options); + } - if (token === '"') { - str = parseStringToken(); + if (typeof customTex !== 'undefined') { + return customTex; + } - // create constant - node = new ConstantNode$$1(str); + //fall back to Node's toTex + return nodeToTex.call(this, options); + }; - // parse index parameters - node = parseAccessors(node); + /** + * Get LaTeX representation + * @param {Object} options + * @return {string} str + */ + FunctionNode.prototype._toTex = function (options) { + var args = this.args.map(function (arg) { //get LaTeX of the arguments + return arg.toTex(options); + }); - return node; - } + var latexConverter; - return parseMatrix(); - } + if (math[this.name] && ((typeof math[this.name].toTex === 'function') || (typeof math[this.name].toTex === 'object') || (typeof math[this.name].toTex === 'string'))) { + //.toTex is a callback function + latexConverter = math[this.name].toTex; + } - /** - * Parse a string surrounded by double quotes "..." - * @return {string} - */ - function parseStringToken () { - var str = ''; + var customToTex; + switch (typeof latexConverter) { + case 'function': //a callback function + customToTex = latexConverter(this, options); + break; + case 'string': //a template string + customToTex = expandTemplate(latexConverter, this, options); + break; + case 'object': //an object with different "converters" for different numbers of arguments + switch (typeof latexConverter[args.length]) { + case 'function': + customToTex = latexConverter[args.length](this, options); + break; + case 'string': + customToTex = expandTemplate(latexConverter[args.length], this, options); + break; + } + } - while (c !== '' && c !== '\"') { - if (c === '\\') { - // escape character, immediately process the next - // character to prevent stopping at a next '\"' - str += c; - next(); + if (typeof customToTex !== 'undefined') { + return customToTex; } - str += c; - next(); - } + return expandTemplate(latex$1.defaultTemplate, this, options); + }; - getToken(); - if (token !== '"') { - throw createSyntaxError('End of string " expected'); - } - getToken(); + /** + * Get identifier. + * @return {string} + */ + FunctionNode.prototype.getIdentifier = function () { + return this.type + ':' + this.name; + }; - return JSON.parse('"' + str + '"'); // unescape escaped characters + return FunctionNode; } - /** - * parse the matrix - * @return {Node} node - * @private - */ - function parseMatrix () { - var array, params, rows, cols; + var name$52 = 'FunctionNode'; + var path$27 = 'expression.node'; + var math$8 = true; // request access to the math namespace as 5th argument of the factory function + var factory_1$57 = factory$58; - if (token === '[') { - // matrix [...] - openParams(); - getToken(); + var FunctionNode = { + name: name$52, + path: path$27, + math: math$8, + factory: factory_1$57 + }; - if (token !== ']') { - // this is a non-empty matrix - var row = parseRow(); + function factory$59 (type, config, load, typed) { + var Node$$1 = load(Node); - if (token === ';') { - // 2 dimensional array - rows = 1; - params = [row]; + /** + * @constructor RangeNode + * @extends {Node} + * create a range + * @param {Node} start included lower-bound + * @param {Node} end included upper-bound + * @param {Node} [step] optional step + */ + function RangeNode(start, end, step) { + if (!(this instanceof RangeNode)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - // the rows of the matrix are separated by dot-comma's - while (token === ';') { - getToken(); + // validate inputs + if (!type.isNode(start)) throw new TypeError('Node expected'); + if (!type.isNode(end)) throw new TypeError('Node expected'); + if (step && !type.isNode(step)) throw new TypeError('Node expected'); + if (arguments.length > 3) throw new Error('Too many arguments'); - params[rows] = parseRow(); - rows++; - } + this.start = start; // included lower-bound + this.end = end; // included upper-bound + this.step = step || null; // optional step + } - if (token !== ']') { - throw createSyntaxError('End of matrix ] expected'); - } - closeParams(); - getToken(); + RangeNode.prototype = new Node$$1(); - // check if the number of columns matches in all rows - cols = params[0].items.length; - for (var r = 1; r < rows; r++) { - if (params[r].items.length !== cols) { - throw createError('Column dimensions mismatch ' + - '(' + params[r].items.length + ' !== ' + cols + ')'); - } - } + RangeNode.prototype.type = 'RangeNode'; - array = new ArrayNode$$1(params); - } - else { - // 1 dimensional vector - if (token !== ']') { - throw createSyntaxError('End of matrix ] expected'); - } - closeParams(); - getToken(); + RangeNode.prototype.isRangeNode = true; + + /** + * Check whether the RangeNode needs the `end` symbol to be defined. + * This end is the size of the Matrix in current dimension. + * @return {boolean} + */ + RangeNode.prototype.needsEnd = function () { + // find all `end` symbols in this RangeNode + var endSymbols = this.filter(function (node) { + return type.isSymbolNode(node) && (node.name === 'end'); + }); + + return endSymbols.length > 0; + }; + + /** + * Compile a node into a JavaScript function. + * This basically pre-calculates as much as possible and only leaves open + * calculations which depend on a dynamic scope with variables. + * @param {Object} math Math.js namespace with functions and constants. + * @param {Object} argNames An object with argument names as key and `true` + * as value. Used in the SymbolNode to optimize + * for arguments from user assigned functions + * (see FunctionAssignmentNode) or special symbols + * like `end` (see IndexNode). + * @return {function} Returns a function which can be called like: + * evalNode(scope: Object, args: Object, context: *) + */ + RangeNode.prototype._compile = function (math, argNames) { + var range = math.range; + var evalStart = this.start._compile(math, argNames); + var evalEnd = this.end._compile(math, argNames); - array = row; + if (this.step) { + var evalStep = this.step._compile(math, argNames); + + return function evalRangeNode(scope, args, context) { + return range( + evalStart(scope, args, context), + evalEnd(scope, args, context), + evalStep(scope, args, context) + ); } } else { - // this is an empty matrix "[ ]" - closeParams(); - getToken(); - array = new ArrayNode$$1([]); + return function evalRangeNode(scope, args, context) { + return range( + evalStart(scope, args, context), + evalEnd(scope, args, context) + ); + } } + }; - return parseAccessors(array); - } + /** + * Execute a callback for each of the child nodes of this node + * @param {function(child: Node, path: string, parent: Node)} callback + */ + RangeNode.prototype.forEach = function (callback) { + callback(this.start, 'start', this); + callback(this.end, 'end', this); + if (this.step) { + callback(this.step, 'step', this); + } + }; - return parseObject(); - } + /** + * Create a new RangeNode having it's childs be the results of calling + * the provided callback function for each of the childs of the original node. + * @param {function(child: Node, path: string, parent: Node): Node} callback + * @returns {RangeNode} Returns a transformed copy of the node + */ + RangeNode.prototype.map = function (callback) { + return new RangeNode( + this._ifNode(callback(this.start, 'start', this)), + this._ifNode(callback(this.end, 'end', this)), + this.step && this._ifNode(callback(this.step, 'step', this)) + ); + }; - /** - * Parse a single comma-separated row from a matrix, like 'a, b, c' - * @return {ArrayNode} node - */ - function parseRow () { - var params = [parseAssignment()]; - var len = 1; + /** + * Create a clone of this node, a shallow copy + * @return {RangeNode} + */ + RangeNode.prototype.clone = function () { + return new RangeNode(this.start, this.end, this.step && this.step); + }; - while (token === ',') { - getToken(); + /** + * Calculate the necessary parentheses + * @param {Node} node + * @param {string} parenthesis + * @return {Object} parentheses + * @private + */ + function calculateNecessaryParentheses(node, parenthesis) { + var precedence = operators.getPrecedence(node, parenthesis); + var parens = {}; - // parse expression - params[len] = parseAssignment(); - len++; - } + var startPrecedence = operators.getPrecedence(node.start, parenthesis); + parens.start = ((startPrecedence !== null) && (startPrecedence <= precedence)) + || (parenthesis === 'all'); - return new ArrayNode$$1(params); - } + if (node.step) { + var stepPrecedence = operators.getPrecedence(node.step, parenthesis); + parens.step = ((stepPrecedence !== null) && (stepPrecedence <= precedence)) + || (parenthesis === 'all'); + } - /** - * parse an object, enclosed in angle brackets{...}, for example {value: 2} - * @return {Node} node - * @private - */ - function parseObject () { - if (token === '{') { - var key; + var endPrecedence = operators.getPrecedence(node.end, parenthesis); + parens.end = ((endPrecedence !== null) && (endPrecedence <= precedence)) + || (parenthesis === 'all'); - var properties = {}; - do { - getToken(); + return parens; + } - if (token !== '}') { - // parse key - if (token === '"') { - key = parseStringToken(); - } - else if (token_type === TOKENTYPE.SYMBOL) { - key = token; - getToken(); - } - else { - throw createSyntaxError('Symbol or string expected as object key'); - } + /** + * Get string representation + * @param {Object} options + * @return {string} str + */ + RangeNode.prototype._toString = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var parens = calculateNecessaryParentheses(this, parenthesis); - // parse key/value separator - if (token !== ':') { - throw createSyntaxError('Colon : expected after object key'); - } - getToken(); + //format string as start:step:stop + var str; - // parse key - properties[key] = parseAssignment(); + var start = this.start.toString(options); + if (parens.start) { + start = '(' + start + ')'; + } + str = start; + + if (this.step) { + var step = this.step.toString(options); + if (parens.step) { + step = '(' + step + ')'; } + str += ':' + step; } - while (token === ','); - if (token !== '}') { - throw createSyntaxError('Comma , or bracket } expected after object value'); + var end = this.end.toString(options); + if (parens.end) { + end = '(' + end + ')'; } - getToken(); + str += ':' + end; - var node = new ObjectNode$$1(properties); + return str; + }; - // parse index parameters - node = parseAccessors(node); + /** + * Get a JSON representation of the node + * @returns {Object} + */ + RangeNode.prototype.toJSON = function () { + return { + mathjs: 'RangeNode', + start: this.start, + end: this.end, + step: this.step + }; + }; - return node; - } + /** + * Instantiate an RangeNode from its JSON representation + * @param {Object} json An object structured like + * `{"mathjs": "RangeNode", "start": ..., "end": ..., "step": ...}`, + * where mathjs is optional + * @returns {RangeNode} + */ + RangeNode.fromJSON = function (json) { + return new RangeNode(json.start, json.end, json.step); + }; - return parseNumber(); - } + /** + * Get HTML representation + * @param {Object} options + * @return {string} str + */ + RangeNode.prototype.toHTML = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var parens = calculateNecessaryParentheses(this, parenthesis); - /** - * parse a number - * @return {Node} node - * @private - */ - function parseNumber () { - var numberStr; + //format string as start:step:stop + var str; - if (token_type === TOKENTYPE.NUMBER) { - // this is a number - numberStr = token; - getToken(); + var start = this.start.toHTML(options); + if (parens.start) { + start = '(' + start + ')'; + } + str = start; - return new ConstantNode$$1(numeric$$1(numberStr, config.number)); - } + if (this.step) { + var step = this.step.toHTML(options); + if (parens.step) { + step = '(' + step + ')'; + } + str += ':' + step; + } - return parseParentheses(); - } + var end = this.end.toHTML(options); + if (parens.end) { + end = '(' + end + ')'; + } + str += ':' + end; - /** - * parentheses - * @return {Node} node - * @private - */ - function parseParentheses () { - var node; + return str; + }; - // check if it is a parenthesized expression - if (token === '(') { - // parentheses (...) - openParams(); - getToken(); + /** + * Get LaTeX representation + * @params {Object} options + * @return {string} str + */ + RangeNode.prototype._toTex = function (options) { + var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; + var parens = calculateNecessaryParentheses(this, parenthesis); - node = parseAssignment(); // start again + var str = this.start.toTex(options); + if (parens.start) { + str = '\\left(' + str + '\\right)'; + } - if (token !== ')') { - throw createSyntaxError('Parenthesis ) expected'); + if (this.step) { + var step = this.step.toTex(options); + if (parens.step) { + step = '\\left(' + step + '\\right)'; + } + str += ':' + step; } - closeParams(); - getToken(); - node = new ParenthesisNode$$1(node); - node = parseAccessors(node); - return node; - } + var end = this.end.toTex(options); + if (parens.end) { + end = '\\left(' + end + '\\right)'; + } + str += ':' + end; - return parseEnd(); - } + return str; + }; - /** - * Evaluated when the expression is not yet ended but expected to end - * @return {Node} res - * @private - */ - function parseEnd () { - if (token === '') { - // syntax error or unexpected end of expression - throw createSyntaxError('Unexpected end of expression'); - } else if (token === "'") { - throw createSyntaxError('Value expected. Note: strings must be enclosed by double quotes'); - } else { - throw createSyntaxError('Value expected'); - } + return RangeNode; } - /** - * Shortcut for getting the current row value (one based) - * Returns the line of the currently handled expression - * @private - */ - /* TODO: implement keeping track on the row number - function row () { - return null; - } - */ + var name$53 = 'RangeNode'; + var path$28 = 'expression.node'; + var factory_1$58 = factory$59; - /** - * Shortcut for getting the current col value (one based) - * Returns the column (position) where the last token starts - * @private - */ - function col () { - return index - token.length + 1; - } + var RangeNode = { + name: name$53, + path: path$28, + factory: factory_1$58 + }; - /** - * Create an error - * @param {string} message - * @return {SyntaxError} instantiated error - * @private - */ - function createSyntaxError (message) { - var c = col(); - var error = new SyntaxError(message + ' (char ' + c + ')'); - error['char'] = c; + function factory$60 (type, config, load, typed) { + var numeric$$1 = load(numeric); - return error; - } + var AccessorNode$$1 = load(AccessorNode); + var ArrayNode$$1 = load(ArrayNode); + var AssignmentNode$$1 = load(AssignmentNode); + var BlockNode$$1 = load(BlockNode); + var ConditionalNode$$1 = load(ConditionalNode); + var ConstantNode$$1 = load(ConstantNode); + var FunctionAssignmentNode$$1 = load(FunctionAssignmentNode); + var IndexNode$$1 = load(IndexNode); + var ObjectNode$$1 = load(ObjectNode); + var OperatorNode$$1 = load(OperatorNode); + var ParenthesisNode$$1 = load(ParenthesisNode); + var FunctionNode$$1 = load(FunctionNode); + var RangeNode$$1 = load(RangeNode); + var SymbolNode$$1 = load(SymbolNode); - /** - * Create an error - * @param {string} message - * @return {Error} instantiated error - * @private - */ - function createError (message) { - var c = col(); - var error = new SyntaxError(message + ' (char ' + c + ')'); - error['char'] = c; + /** + * Parse an expression. Returns a node tree, which can be evaluated by + * invoking node.eval(); + * + * Syntax: + * + * parse(expr) + * parse(expr, options) + * parse([expr1, expr2, expr3, ...]) + * parse([expr1, expr2, expr3, ...], options) + * + * Example: + * + * var node = parse('sqrt(3^2 + 4^2)'); + * node.compile(math).eval(); // 5 + * + * var scope = {a:3, b:4} + * var node = parse('a * b'); // 12 + * var code = node.compile(math); + * code.eval(scope); // 12 + * scope.a = 5; + * code.eval(scope); // 20 + * + * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); + * nodes[2].compile(math).eval(); // 12 + * + * @param {string | string[] | Matrix} expr + * @param {{nodes: Object}} [options] Available options: + * - `nodes` a set of custom nodes + * @return {Node | Node[]} node + * @throws {Error} + */ + function parse (expr, options) { + if (arguments.length !== 1 && arguments.length !== 2) { + throw new ArgumentsError_1('parse', arguments.length, 1, 2); + } - return error; - } + // pass extra nodes + extra_nodes = (options && options.nodes) ? options.nodes : {}; - return parse; -} + if (typeof expr === 'string') { + // parse a single expression + expression = expr; + return parseStart(); + } + else if (Array.isArray(expr) || expr instanceof type.Matrix) { + // parse an array or matrix with expressions + return deepMap(expr, function (elem) { + if (typeof elem !== 'string') throw new TypeError('String expected'); -var name$54 = 'parse'; -var path$29 = 'expression'; -var factory_1$59 = factory$60; + expression = elem; + return parseStart(); + }); + } + else { + // oops + throw new TypeError('String or matrix expected'); + } + } -var parse = { - name: name$54, - path: path$29, - factory: factory_1$59 -}; + // token types enumeration + var TOKENTYPE = { + NULL : 0, + DELIMITER : 1, + NUMBER : 2, + SYMBOL : 3, + UNKNOWN : 4 + }; -function factory$61 (type, config, load, typed) { - var parse$$1 = load(parse); + // map with all delimiters + var DELIMITERS = { + ',': true, + '(': true, + ')': true, + '[': true, + ']': true, + '{': true, + '}': true, + '\"': true, + ';': true, + + '+': true, + '-': true, + '*': true, + '.*': true, + '/': true, + './': true, + '%': true, + '^': true, + '.^': true, + '~': true, + '!': true, + '&': true, + '|': true, + '^|': true, + '\'': true, + '=': true, + ':': true, + '?': true, + + '==': true, + '!=': true, + '<': true, + '>': true, + '<=': true, + '>=': true, + + '<<': true, + '>>': true, + '>>>': true + }; - /** - * Parse and compile an expression. - * Returns a an object with a function `eval([scope])` to evaluate the - * compiled expression. - * - * Syntax: - * - * math.compile(expr) // returns one node - * math.compile([expr1, expr2, expr3, ...]) // returns an array with nodes - * - * Examples: - * - * var code = math.compile('sqrt(3^2 + 4^2)'); - * code.eval(); // 5 - * - * var scope = {a: 3, b: 4} - * var code = math.compile('a * b'); // 12 - * code.eval(scope); // 12 - * scope.a = 5; - * code.eval(scope); // 20 - * - * var nodes = math.compile(['a = 3', 'b = 4', 'a * b']); - * nodes[2].eval(); // 12 - * - * See also: - * - * parse, eval - * - * @param {string | string[] | Array | Matrix} expr - * The expression to be compiled - * @return {{eval: Function} | Array.<{eval: Function}>} code - * An object with the compiled expression - * @throws {Error} - */ - return typed('compile', { - 'string': function (expr) { - return parse$$1(expr).compile(); - }, + // map with all named delimiters + var NAMED_DELIMITERS = { + 'mod': true, + 'to': true, + 'in': true, + 'and': true, + 'xor': true, + 'or': true, + 'not': true + }; - 'Array | Matrix': function (expr) { - return deepMap(expr, function (entry) { - return parse$$1(entry).compile(); - }); - } - }); -} + var CONSTANTS = { + 'true': true, + 'false': false, + 'null': null, + 'undefined': undefined + }; -var name$55 = 'compile'; -var factory_1$60 = factory$61; + var NUMERIC_CONSTANTS = [ + 'NaN', + 'Infinity' + ]; -var compile = { - name: name$55, - factory: factory_1$60 -}; + var extra_nodes = {}; // current extra nodes + var expression = ''; // current expression + var comment = ''; // last parsed comment + var index = 0; // current index in expr + var c = ''; // current token character in expr + var token = ''; // current token + var token_type = TOKENTYPE.NULL; // type of the token + var nesting_level = 0; // level of nesting inside parameters, used to ignore newline characters + var conditional_level = null; // when a conditional is being parsed, the level of the conditional is stored here + var tokenStates = []; // holds saved token states -function factory$62 (type, config, load, typed) { - var parse$$1 = load(parse); + /** + * Get the first character from the expression. + * The character is stored into the char c. If the end of the expression is + * reached, the function puts an empty string in c. + * @private + */ + function first() { + index = 0; + c = expression.charAt(0); + nesting_level = 0; + conditional_level = null; + } - /** - * Evaluate an expression. - * - * Note the evaluating arbitrary expressions may involve security risks, - * see [http://mathjs.org/docs/expressions/security.html](http://mathjs.org/docs/expressions/security.html) for more information. - * - * Syntax: - * - * math.eval(expr) - * math.eval(expr, scope) - * math.eval([expr1, expr2, expr3, ...]) - * math.eval([expr1, expr2, expr3, ...], scope) - * - * Example: - * - * math.eval('(2+3)/4'); // 1.25 - * math.eval('sqrt(3^2 + 4^2)'); // 5 - * math.eval('sqrt(-4)'); // 2i - * math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12] - * - * var scope = {a:3, b:4}; - * math.eval('a * b', scope); // 12 - * - * See also: - * - * parse, compile - * - * @param {string | string[] | Matrix} expr The expression to be evaluated - * @param {Object} [scope] Scope to read/write variables - * @return {*} The result of the expression - * @throws {Error} - */ - return typed('compile', { - 'string': function (expr) { - var scope = {}; - return parse$$1(expr).compile().eval(scope); - }, + /** + * Get the next character from the expression. + * The character is stored into the char c. If the end of the expression is + * reached, the function puts an empty string in c. + * @private + */ + function next() { + index++; + c = expression.charAt(index); + } - 'string, Object': function (expr, scope) { - return parse$$1(expr).compile().eval(scope); - }, + /** + * Preview the previous character from the expression. + * @return {string} cNext + * @private + */ + function prevPreview() { + return expression.charAt(index - 1); + } - 'Array | Matrix': function (expr) { - var scope = {}; - return deepMap(expr, function (entry) { - return parse$$1(entry).compile().eval(scope); - }); - }, + /** + * Preview the next character from the expression. + * @return {string} cNext + * @private + */ + function nextPreview() { + return expression.charAt(index + 1); + } - 'Array | Matrix, Object': function (expr, scope) { - return deepMap(expr, function (entry) { - return parse$$1(entry).compile().eval(scope); - }); + /** + * Preview the second next character from the expression. + * @return {string} cNext + * @private + */ + function nextNextPreview() { + return expression.charAt(index + 2); } - }); -} -var name$56 = 'eval'; -var factory_1$61 = factory$62; + /** + * Save the current token state so we can rewind later if necessary. + * @private + */ + function pushTokenState() { + tokenStates.push({ + token_type: token_type, + token: token, + comment: comment, + index: index, + c: c + }); + } -var _eval$1 = { - name: name$56, - factory: factory_1$61 -}; + /** + * Rewind the parser by one token by restoring the last saved token state + * @private + */ + function popTokenState() { + var restoredState = tokenStates.pop(); + token_type = restoredState.token_type; + token = restoredState.token; + comment = restoredState.comment; + index = restoredState.index; + c = restoredState.c; + } -var getSafeProperty$8 = customs.getSafeProperty; + /** + * Discard the most recent token state without restoring it + * @private + */ + function discardTokenState() { + tokenStates.pop(); + } -function factory$63 (type, config, load, typed, math) { - var docs = load(embeddedDocs); + /** + * Get next token in the current string expr. + * The token and token type are available as token and token_type + * @private + */ + function getToken() { + token_type = TOKENTYPE.NULL; + token = ''; + comment = ''; + + // skip over whitespaces + // space, tab, and newline when inside parameters + while (parse.isWhitespace(c, nesting_level)) { + next(); + } - /** - * Retrieve help on a function or data type. - * Help files are retrieved from the documentation in math.expression.docs. - * - * Syntax: - * - * math.help(search) - * - * Examples: - * - * console.log(math.help('sin').toString()); - * console.log(math.help(math.add).toString()); - * console.log(math.help(math.add).toJSON()); - * - * @param {Function | string | Object} search A function or function name - * for which to get help - * @return {Help} A help object - */ - return typed('help', { - 'any': function (search) { - var prop; - var name = search; - - if (typeof search !== 'string') { - for (prop in math) { - // search in functions and constants - if (math.hasOwnProperty(prop) && (search === math[prop])) { - name = prop; - break; - } + // skip comment + if (c === '#') { + while (c !== '\n' && c !== '') { + comment += c; + next(); } - - /* TODO: implement help for data types - if (!text) { - // search data type - for (prop in math.type) { - if (math.type.hasOwnProperty(prop)) { - if (search === math.type[prop]) { - text = prop; - break; - } - } - } - } - */ } - var doc = getSafeProperty$8(docs, name); - if (!doc) { - throw new Error('No documentation found on "' + name + '"'); + // check for end of expression + if (c === '') { + // token is still empty + token_type = TOKENTYPE.DELIMITER; + return; } - return new type.Help(doc); - } - }); -} - -var math$9 = true; // request access to the math namespace as 5th argument of the factory function -var name$57 = 'help'; -var factory_1$62 = factory$63; -var help$1 = { - math: math$9, - name: name$57, - factory: factory_1$62 -}; - -function factory$64 (type, config, load, typed) { - var parse$$1 = load(parse); + // check for new line character + if (c === '\n' && !nesting_level) { + token_type = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } - /** - * Parse an expression. Returns a node tree, which can be evaluated by - * invoking node.eval(); - * - * Note the evaluating arbitrary expressions may involve security risks, - * see [http://mathjs.org/docs/expressions/security.html](http://mathjs.org/docs/expressions/security.html) for more information. - * - * Syntax: - * - * math.parse(expr) - * math.parse(expr, options) - * math.parse([expr1, expr2, expr3, ...]) - * math.parse([expr1, expr2, expr3, ...], options) - * - * Example: - * - * var node = math.parse('sqrt(3^2 + 4^2)'); - * node.compile().eval(); // 5 - * - * var scope = {a:3, b:4} - * var node = math.parse('a * b'); // 12 - * var code = node.compile(); - * code.eval(scope); // 12 - * scope.a = 5; - * code.eval(scope); // 20 - * - * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); - * nodes[2].compile().eval(); // 12 - * - * See also: - * - * eval, compile - * - * @param {string | string[] | Matrix} expr Expression to be parsed - * @param {{nodes: Object}} [options] Available options: - * - `nodes` a set of custom nodes - * @return {Node | Node[]} node - * @throws {Error} - */ - return typed('parse', { - 'string | Array | Matrix': parse$$1, - 'string | Array | Matrix, Object': parse$$1 - }); -} + // check for delimiters consisting of 3 characters + var c2 = c + nextPreview(); + var c3 = c2 + nextNextPreview(); + if (c3.length === 3 && DELIMITERS[c3]) { + token_type = TOKENTYPE.DELIMITER; + token = c3; + next(); + next(); + next(); + return; + } -var name$58 = 'parse'; -var factory_1$63 = factory$64; + // check for delimiters consisting of 2 characters + if (c2.length === 2 && DELIMITERS[c2]) { + token_type = TOKENTYPE.DELIMITER; + token = c2; + next(); + next(); + return; + } -var parse$1 = { - name: name$58, - factory: factory_1$63 -}; + // check for delimiters consisting of 1 character + if (DELIMITERS[c]) { + token_type = TOKENTYPE.DELIMITER; + token = c; + next(); + return; + } -var extend$1 = object.extend; + // check for a number + if (parse.isDigitDot(c)) { + token_type = TOKENTYPE.NUMBER; + // get number, can have a single dot + if (c === '.') { + token += c; + next(); -function factory$65 (type, config, load, typed, math) { - var _parse = load(parse); + if (!parse.isDigit(c)) { + // this is no number, it is just a dot (can be dot notation) + token_type = TOKENTYPE.DELIMITER; + } + } + else { + while (parse.isDigit(c)) { + token += c; + next(); + } + if (parse.isDecimalMark(c, nextPreview())) { + token += c; + next(); + } + } + while (parse.isDigit(c)) { + token += c; + next(); + } - /** - * @constructor Parser - * Parser contains methods to evaluate or parse expressions, and has a number - * of convenience methods to get, set, and remove variables from memory. Parser - * keeps a scope containing variables in memory, which is used for all - * evaluations. - * - * Methods: - * var result = parser.eval(expr); // evaluate an expression - * var value = parser.get(name); // retrieve a variable from the parser - * var values = parser.getAll(); // retrieve all defined variables - * parser.set(name, value); // set a variable in the parser - * parser.remove(name); // clear a variable from the - * // parsers scope - * parser.clear(); // clear the parsers scope - * - * Example usage: - * var parser = new Parser(); - * // Note: there is a convenience method which can be used instead: - * // var parser = new math.parser(); - * - * // evaluate expressions - * parser.eval('sqrt(3^2 + 4^2)'); // 5 - * parser.eval('sqrt(-4)'); // 2i - * parser.eval('2 inch in cm'); // 5.08 cm - * parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { - * return 'hello, ' + name + '!'; - * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - * - */ - function Parser() { - if (!(this instanceof Parser)) { - throw new SyntaxError( - 'Constructor must be called with the new operator'); - } - this.scope = {}; - } + // check for exponential notation like "2.3e-4", "1.23e50" or "2e+4" + c2 = nextPreview(); + if (c === 'E' || c === 'e') { + if (parse.isDigit(c2) || c2 === '-' || c2 === '+') { + token += c; + next(); - /** - * Attach type information - */ - Parser.prototype.type = 'Parser'; - Parser.prototype.isParser = true; + if (c === '+' || c === '-') { + token += c; + next(); + } - /** - * Parse an expression and return the parsed function node. - * The node tree can be compiled via `code = node.compile(math)`, - * and the compiled code can be executed as `code.eval([scope])` - * @param {string} expr - * @return {Node} node - * @throws {Error} - */ - Parser.prototype.parse = function (expr) { - throw new Error('Parser.parse is deprecated. Use math.parse instead.'); - }; + // Scientific notation MUST be followed by an exponent + if (!parse.isDigit(c)) { + throw createSyntaxError('Digit expected, got "' + c + '"'); + } - /** - * Parse and compile an expression, return the compiled javascript code. - * The node can be evaluated via code.eval([scope]) - * @param {string} expr - * @return {{eval: function}} code - * @throws {Error} - */ - Parser.prototype.compile = function (expr) { - throw new Error('Parser.compile is deprecated. Use math.compile instead.'); - }; + while (parse.isDigit(c)) { + token += c; + next(); + } - /** - * Parse and evaluate the given expression - * @param {string} expr A string containing an expression, for example "2+3" - * @return {*} result The result, or undefined when the expression was empty - * @throws {Error} - */ - Parser.prototype.eval = function (expr) { - // TODO: validate arguments - return _parse(expr) - .compile() - .eval(this.scope); - }; + if (parse.isDecimalMark(c, nextPreview())) { + throw createSyntaxError('Digit expected, got "' + c + '"'); + } + } + else if (c2 === '.') { + next(); + throw createSyntaxError('Digit expected, got "' + c + '"'); + } + } - /** - * Get a variable (a function or variable) by name from the parsers scope. - * Returns undefined when not found - * @param {string} name - * @return {* | undefined} value - */ - Parser.prototype.get = function (name) { - // TODO: validate arguments - return name in this.scope - ? customs.getSafeProperty(this.scope, name) - : undefined; - }; + return; + } - /** - * Get a map with all defined variables - * @return {Object} values - */ - Parser.prototype.getAll = function () { - return extend$1({}, this.scope); - }; + // check for variables, functions, named operators + if (parse.isAlpha(c, prevPreview(), nextPreview())) { + while (parse.isAlpha(c, prevPreview(), nextPreview()) || parse.isDigit(c)) { + token += c; + next(); + } - /** - * Set a symbol (a function or variable) by name from the parsers scope. - * @param {string} name - * @param {* | undefined} value - */ - Parser.prototype.set = function (name, value) { - // TODO: validate arguments - return customs.setSafeProperty(this.scope, name, value); - }; + if (NAMED_DELIMITERS.hasOwnProperty(token)) { + token_type = TOKENTYPE.DELIMITER; + } + else { + token_type = TOKENTYPE.SYMBOL; + } - /** - * Remove a variable from the parsers scope - * @param {string} name - */ - Parser.prototype.remove = function (name) { - // TODO: validate arguments - delete this.scope[name]; - }; + return; + } - /** - * Clear the scope with variables and functions - */ - Parser.prototype.clear = function () { - for (var name in this.scope) { - if (this.scope.hasOwnProperty(name)) { - delete this.scope[name]; + // something unknown is found, wrong characters -> a syntax error + token_type = TOKENTYPE.UNKNOWN; + while (c !== '') { + token += c; + next(); } + throw createSyntaxError('Syntax error in part "' + token + '"'); } - }; - - return Parser; -} -var name$59 = 'Parser'; -var path$30 = 'expression'; -var factory_1$64 = factory$65; -var math$10 = true; // requires the math namespace as 5th argument - -var Parser = { - name: name$59, - path: path$30, - factory: factory_1$64, - math: math$10 -}; + /** + * Get next token and skip newline tokens + */ + function getTokenSkipNewline () { + do { + getToken(); + } + while (token === '\n'); + } -function factory$66 (type, config, load, typed, math) { - var Parser$$1 = load(Parser); + /** + * Open parameters. + * New line characters will be ignored until closeParams() is called + */ + function openParams() { + nesting_level++; + } - /** - * Create a parser. The function creates a new `math.expression.Parser` object. - * - * Syntax: - * - * math.parser() - * - * Examples: - * - * var parser = new math.parser(); - * - * // evaluate expressions - * var a = parser.eval('sqrt(3^2 + 4^2)'); // 5 - * var b = parser.eval('sqrt(-4)'); // 2i - * var c = parser.eval('2 inch in cm'); // 5.08 cm - * var d = parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { - * return 'hello, ' + name + '!'; - * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - * - * See also: - * - * eval, compile, parse - * - * @return {Parser} Parser - */ - return typed('parser', { - '': function () { - return new Parser$$1(math); + /** + * Close parameters. + * New line characters will no longer be ignored + */ + function closeParams() { + nesting_level--; } - }); -} - -var name$60 = 'parser'; -var factory_1$65 = factory$66; -var math$11 = true; // requires the math namespace as 5th argument - -var parser = { - name: name$60, - factory: factory_1$65, - math: math$11 -}; - -var _function$2 = [ - compile, - _eval$1, - help$1, - parse$1, - parser -]; - -function factory$67 (type, config, load, typed) { - /** - * @constructor UpdateNode - */ - function UpdateNode() { - // TODO: deprecated since v3. Cleanup some day - throw new Error('UpdateNode is deprecated. Use AssignmentNode instead.'); - } - return UpdateNode; -} + /** + * Checks whether the current character `c` is a valid alpha character: + * + * - A latin letter (upper or lower case) Ascii: a-z, A-Z + * - An underscore Ascii: _ + * - A dollar sign Ascii: $ + * - A latin letter with accents Unicode: \u00C0 - \u02AF + * - A greek letter Unicode: \u0370 - \u03FF + * - A mathematical alphanumeric symbol Unicode: \u{1D400} - \u{1D7FF} excluding invalid code points + * + * The previous and next characters are needed to determine whether + * this character is part of a unicode surrogate pair. + * + * @param {string} c Current character in the expression + * @param {string} cPrev Previous character + * @param {string} cNext Next character + * @return {boolean} + */ + parse.isAlpha = function isAlpha (c, cPrev, cNext) { + return parse.isValidLatinOrGreek(c) + || parse.isValidMathSymbol(c, cNext) + || parse.isValidMathSymbol(cPrev, c); + }; -var name$61 = 'UpdateNode'; -var path$31 = 'expression.node'; -var factory_1$66 = factory$67; + /** + * Test whether a character is a valid latin, greek, or letter-like character + * @param {string} c + * @return {boolean} + */ + parse.isValidLatinOrGreek = function isValidLatinOrGreek (c) { + return /^[a-zA-Z_$\u00C0-\u02AF\u0370-\u03FF\u2100-\u214F]$/.test(c); + }; -var UpdateNode = { - name: name$61, - path: path$31, - factory: factory_1$66 -}; + /** + * Test whether two given 16 bit characters form a surrogate pair of a + * unicode math symbol. + * + * http://unicode-table.com/en/ + * http://www.wikiwand.com/en/Mathematical_operators_and_symbols_in_Unicode + * + * Note: In ES6 will be unicode aware: + * http://stackoverflow.com/questions/280712/javascript-unicode-regexes + * https://mathiasbynens.be/notes/es6-unicode-regex + * + * @param {string} high + * @param {string} low + * @return {boolean} + */ + parse.isValidMathSymbol = function isValidMathSymbol (high, low) { + return /^[\uD835]$/.test(high) && + /^[\uDC00-\uDFFF]$/.test(low) && + /^[^\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]$/.test(low); + }; -var node = [ - AccessorNode, - ArrayNode, - AssignmentNode, - BlockNode, - ConditionalNode, - ConstantNode, - IndexNode, - FunctionAssignmentNode, - FunctionNode, - Node, - ObjectNode, - OperatorNode, - ParenthesisNode, - RangeNode, - SymbolNode, - UpdateNode -]; + /** + * Check whether given character c is a white space character: space, tab, or enter + * @param {string} c + * @param {number} nestingLevel + * @return {boolean} + */ + parse.isWhitespace = function isWhitespace (c, nestingLevel) { + // TODO: also take '\r' carriage return as newline? Or does that give problems on mac? + return c === ' ' || c === '\t' || (c === '\n' && nestingLevel > 0); + }; -var clone$4 = object.clone; -var isInteger$4 = number.isInteger; + /** + * Test whether the character c is a decimal mark (dot). + * This is the case when it's not the start of a delimiter '.*', './', or '.^' + * @param {string} c + * @param {string} cNext + * @return {boolean} + */ + parse.isDecimalMark = function isDecimalMark (c, cNext) { + return c === '.' && cNext !== '/' && cNext !== '*' && cNext !== '^'; + }; + /** + * checks if the given char c is a digit or dot + * @param {string} c a string with one character + * @return {boolean} + */ + parse.isDigitDot = function isDigitDot (c) { + return ((c >= '0' && c <= '9') || c === '.'); + }; + /** + * checks if the given char c is a digit + * @param {string} c a string with one character + * @return {boolean} + */ + parse.isDigit = function isDigit (c) { + return (c >= '0' && c <= '9'); + }; + /** + * Start of the parse levels below, in order of precedence + * @return {Node} node + * @private + */ + function parseStart () { + // get the first character in expression + first(); -function factory$68 (type, config, load, typed) { - var matrix$$1 = load(matrix); + getToken(); - /** - * Concatenate two or more matrices. - * - * Syntax: - * - * math.concat(A, B, C, ...) - * math.concat(A, B, C, ..., dim) - * - * Where: - * - * - `dim: number` is a zero-based dimension over which to concatenate the matrices. - * By default the last dimension of the matrices. - * - * Examples: - * - * var A = [[1, 2], [5, 6]]; - * var B = [[3, 4], [7, 8]]; - * - * math.concat(A, B); // returns [[1, 2, 3, 4], [5, 6, 7, 8]] - * math.concat(A, B, 0); // returns [[1, 2], [5, 6], [3, 4], [7, 8]] - * math.concat('hello', ' ', 'world'); // returns 'hello world' - * - * See also: - * - * size, squeeze, subset, transpose - * - * @param {... Array | Matrix} args Two or more matrices - * @return {Array | Matrix} Concatenated matrix - */ - var concat = typed('concat', { - // TODO: change signature to '...Array | Matrix, dim?' when supported - '...Array | Matrix | number | BigNumber': function (args) { - var i; - var len = args.length; - var dim = -1; // zero-based dimension - var prevDim; - var asMatrix = false; - var matrices = []; // contains multi dimensional arrays + var node = parseBlock(); - for (i = 0; i < len; i++) { - var arg = args[i]; + // check for garbage at the end of the expression + // an expression ends with a empty character '' and token_type DELIMITER + if (token !== '') { + if (token_type === TOKENTYPE.DELIMITER) { + // user entered a not existing operator like "//" - // test whether we need to return a Matrix (if not we return an Array) - if (type.isMatrix(arg)) { - asMatrix = true; + // TODO: give hints for aliases, for example with "<>" give as hint " did you mean !== ?" + throw createError('Unexpected operator ' + token); + } + else { + throw createSyntaxError('Unexpected part "' + token + '"'); } + } - if (type.isNumber(arg) || type.isBigNumber(arg)) { - if (i !== len - 1) { - throw new Error('Dimension must be specified as last argument'); - } + return node; + } - // last argument contains the dimension on which to concatenate - prevDim = dim; - dim = arg.valueOf(); // change BigNumber to number + /** + * Parse a block with expressions. Expressions can be separated by a newline + * character '\n', or by a semicolon ';'. In case of a semicolon, no output + * of the preceding line is returned. + * @return {Node} node + * @private + */ + function parseBlock () { + var node; + var blocks = []; + var visible; - if (!isInteger$4(dim)) { - throw new TypeError('Integer number expected for dimension'); - } + if (token !== '' && token !== '\n' && token !== ';') { + node = parseAssignment(); + node.comment = comment; + } - if (dim < 0 || (i > 0 && dim > prevDim)) { - // TODO: would be more clear when throwing a DimensionError here - throw new IndexError_1(dim, prevDim + 1); - } + // TODO: simplify this loop + while (token === '\n' || token === ';') { + if (blocks.length === 0 && node) { + visible = (token !== ';'); + blocks.push({ + node: node, + visible: visible + }); } - else { - // this is a matrix or array - var m = clone$4(arg).valueOf(); - var size = array.size(m); - matrices[i] = m; - prevDim = dim; - dim = size.length - 1; - // verify whether each of the matrices has the same number of dimensions - if (i > 0 && dim != prevDim) { - throw new DimensionError_1(prevDim + 1, dim + 1); - } + getToken(); + if (token !== '\n' && token !== ';' && token !== '') { + node = parseAssignment(); + node.comment = comment; + + visible = (token !== ';'); + blocks.push({ + node: node, + visible: visible + }); } } - if (matrices.length == 0) { - throw new SyntaxError('At least one matrix expected'); + if (blocks.length > 0) { + return new BlockNode$$1(blocks); } + else { + if (!node) { + node = new ConstantNode$$1(undefined); + node.comment = comment; + } - var res = matrices.shift(); - while (matrices.length) { - res = _concat(res, matrices.shift(), dim, 0); + return node } - - return asMatrix ? matrix$$1(res) : res; - }, - - '...string': function (args) { - return args.join(''); } - }); - concat.toTex = undefined; // use default template - - return concat; -} - -/** - * Recursively concatenate two matrices. - * The contents of the matrices is not cloned. - * @param {Array} a Multi dimensional array - * @param {Array} b Multi dimensional array - * @param {number} concatDim The dimension on which to concatenate (zero-based) - * @param {number} dim The current dim (zero-based) - * @return {Array} c The concatenated matrix - * @private - */ -function _concat(a, b, concatDim, dim) { - if (dim < concatDim) { - // recurse into next dimension - if (a.length != b.length) { - throw new DimensionError_1(a.length, b.length); - } - - var c = []; - for (var i = 0; i < a.length; i++) { - c[i] = _concat(a[i], b[i], concatDim, dim + 1); - } - return c; - } - else { - // concatenate this dimension - return a.concat(b); - } -} - -var name$62 = 'concat'; -var factory_1$67 = factory$68; - -var concat$1 = { - name: name$62, - factory: factory_1$67 -}; - -var errorTransform$2 = error_transform.transform; - -/** - * Attach a transform function to math.range - * Adds a property transform containing the transform function. - * - * This transform changed the last `dim` parameter of function concat - * from one-based to zero based - */ -function factory$69 (type, config, load, typed) { - var concat = load(concat$1); - - // @see: comment of concat itself - return typed('concat', { - '...any': function (args) { - // change last argument from one-based to zero-based - var lastIndex = args.length - 1; - var last = args[lastIndex]; - if (type.isNumber(last)) { - args[lastIndex] = last - 1; - } - else if (type.isBigNumber(last)) { - args[lastIndex] = last.minus(1); - } + /** + * Assignment of a function or variable, + * - can be a variable like 'a=2.3' + * - or a updating an existing variable like 'matrix(2,3:5)=[6,7,8]' + * - defining a function like 'f(x) = x^2' + * @return {Node} node + * @private + */ + function parseAssignment () { + var name, args, value, valid; - try { - return concat.apply(null, args); - } - catch (err) { - throw errorTransform$2(err); - } - } - }); -} + var node = parseConditional(); -var name$63 = 'concat'; -var path$32 = 'expression.transform'; -var factory_1$68 = factory$69; + if (token === '=') { + if (type.isSymbolNode(node)) { + // parse a variable assignment like 'a = 2/3' + name = node.name; + getTokenSkipNewline(); + value = parseAssignment(); + return new AssignmentNode$$1(new SymbolNode$$1(name), value); + } + else if (type.isAccessorNode(node)) { + // parse a matrix subset assignment like 'A[1,2] = 4' + getTokenSkipNewline(); + value = parseAssignment(); + return new AssignmentNode$$1(node.object, node.index, value); + } + else if (type.isFunctionNode(node) && type.isSymbolNode(node.fn)) { + // parse function assignment like 'f(x) = x^2' + valid = true; + args = []; -var concat_transform = { - name: name$63, - path: path$32, - factory: factory_1$68 -}; + name = node.name; + node.args.forEach(function (arg, index) { + if (type.isSymbolNode(arg)) { + args[index] = arg.name; + } + else { + valid = false; + } + }); -function factory$70 (type, config, load, typed) { - /** - * Compile an inline expression like "x > 0" - * @param {Node} expression - * @param {Object} math - * @param {Object} scope - * @return {function} Returns a function with one argument which fills in the - * undefined variable (like "x") and evaluates the expression - */ - return function compileInlineExpression(expression, math, scope) { - // find an undefined symbol - var symbol = expression.filter(function (node) { - return type.isSymbolNode(node) && - !(node.name in math) && - !(node.name in scope); - })[0]; + if (valid) { + getTokenSkipNewline(); + value = parseAssignment(); + return new FunctionAssignmentNode$$1(name, args, value); + } + } - if (!symbol) { - throw new Error('No undefined variable found in inline expression "' + expression + '"'); - } + throw createSyntaxError('Invalid left hand side of assignment operator ='); + } - // create a test function for this equation - var name = symbol.name; // variable name - var subScope = Object.create(scope); - var eq = expression.compile(); - return function inlineExpression(x) { - subScope[name] = x; - return eq.eval(subScope); + return node; } - }; -} -var factory_1$69 = factory$70; + /** + * conditional operation + * + * condition ? truePart : falsePart + * + * Note: conditional operator is right-associative + * + * @return {Node} node + * @private + */ + function parseConditional () { + var node = parseLogicalOr(); + + while (token === '?') { + // set a conditional level, the range operator will be ignored as long + // as conditional_level === nesting_level. + var prev = conditional_level; + conditional_level = nesting_level; + getTokenSkipNewline(); -var compileInlineExpression = { - factory: factory_1$69 -}; + var condition = node; + var trueExpr = parseAssignment(); -var filter$1 = array.filter; -var filterRegExp = array.filterRegExp; -var maxArgumentCount$1 = _function.maxArgumentCount; + if (token !== ':') throw createSyntaxError('False part of conditional expression expected'); -/** - * Attach a transform function to math.filter - * Adds a property transform containing the transform function. - * - * This transform adds support for equations as test function for math.filter, - * so you can do something like 'filter([3, -2, 5], x > 0)'. - */ -function factory$71 (type, config, load, typed) { - var compileInlineExpression$$1 = load(compileInlineExpression); - var matrix$$1 = load(matrix); + conditional_level = null; + getTokenSkipNewline(); - function filterTransform(args, math, scope) { - var x, callback; + var falseExpr = parseAssignment(); // Note: check for conditional operator again, right associativity - if (args[0]) { - x = args[0].compile().eval(scope); - } + node = new ConditionalNode$$1(condition, trueExpr, falseExpr); - if (args[1]) { - if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { - // a function pointer, like filter([3, -2, 5], myTestFunction); - callback = args[1].compile().eval(scope); - } - else { - // an expression like filter([3, -2, 5], x > 0) - callback = compileInlineExpression$$1(args[1], math, scope); + // restore the previous conditional level + conditional_level = prev; } + + return node; } - return filter(x, callback); - } - filterTransform.rawArgs = true; + /** + * logical or, 'x or y' + * @return {Node} node + * @private + */ + function parseLogicalOr() { + var node = parseLogicalXor(); - // one based version of function filter - var filter = typed('filter', { - 'Array, function': _filter, + while (token === 'or') { + getTokenSkipNewline(); + node = new OperatorNode$$1('or', 'or', [node, parseLogicalXor()]); + } - 'Matrix, function': function (x, test) { - return matrix$$1(_filter(x.toArray(), test)); - }, + return node; + } - 'Array, RegExp': filterRegExp, + /** + * logical exclusive or, 'x xor y' + * @return {Node} node + * @private + */ + function parseLogicalXor() { + var node = parseLogicalAnd(); - 'Matrix, RegExp': function (x, test) { - return matrix$$1(filterRegExp(x.toArray(), test)); - } - }); + while (token === 'xor') { + getTokenSkipNewline(); + node = new OperatorNode$$1('xor', 'xor', [node, parseLogicalAnd()]); + } - filter.toTex = undefined; // use default template + return node; + } - return filterTransform; -} + /** + * logical and, 'x and y' + * @return {Node} node + * @private + */ + function parseLogicalAnd() { + var node = parseBitwiseOr(); -/** - * Filter values in a callback given a callback function - * - * !!! Passes a one-based index !!! - * - * @param {Array} x - * @param {Function} callback - * @return {Array} Returns the filtered array - * @private - */ -function _filter (x, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$1(callback); + while (token === 'and') { + getTokenSkipNewline(); + node = new OperatorNode$$1('and', 'and', [node, parseBitwiseOr()]); + } - return filter$1(x, function (value, index, array$$1) { - // invoke the callback function with the right number of arguments - if (args === 1) { - return callback(value); - } - else if (args === 2) { - return callback(value, [index + 1]); - } - else { // 3 or -1 - return callback(value, [index + 1], array$$1); + return node; } - }); -} -var name$64 = 'filter'; -var path$33 = 'expression.transform'; -var factory_1$70 = factory$71; + /** + * bitwise or, 'x | y' + * @return {Node} node + * @private + */ + function parseBitwiseOr() { + var node = parseBitwiseXor(); -var filter_transform = { - name: name$64, - path: path$33, - factory: factory_1$70 -}; + while (token === '|') { + getTokenSkipNewline(); + node = new OperatorNode$$1('|', 'bitOr', [node, parseBitwiseXor()]); + } -var maxArgumentCount$2 = _function.maxArgumentCount; -var forEach$3 = array.forEach; + return node; + } -/** - * Attach a transform function to math.forEach - * Adds a property transform containing the transform function. - * - * This transform creates a one-based index instead of a zero-based index - */ -function factory$72 (type, config, load, typed) { - var compileInlineExpression$$1 = load(compileInlineExpression); + /** + * bitwise exclusive or (xor), 'x ^| y' + * @return {Node} node + * @private + */ + function parseBitwiseXor() { + var node = parseBitwiseAnd(); - function forEachTransform(args, math, scope) { - var x, callback; + while (token === '^|') { + getTokenSkipNewline(); + node = new OperatorNode$$1('^|', 'bitXor', [node, parseBitwiseAnd()]); + } - if (args[0]) { - x = args[0].compile().eval(scope); + return node; } - if (args[1]) { - if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { - // a function pointer, like forEach([3, -2, 5], myTestFunction); - callback = args[1].compile().eval(scope); - } - else { - // an expression like forEach([3, -2, 5], x > 0 ? callback1(x) : callback2(x) ) - callback = compileInlineExpression$$1(args[1], math, scope); + /** + * bitwise and, 'x & y' + * @return {Node} node + * @private + */ + function parseBitwiseAnd () { + var node = parseRelational(); + + while (token === '&') { + getTokenSkipNewline(); + node = new OperatorNode$$1('&', 'bitAnd', [node, parseRelational()]); } + + return node; } - return _forEach(x, callback); - } - forEachTransform.rawArgs = true; + /** + * relational operators + * @return {Node} node + * @private + */ + function parseRelational () { + var node, operators, name, fn, params; + + node = parseShift(); + + operators = { + '==': 'equal', + '!=': 'unequal', + '<': 'smaller', + '>': 'larger', + '<=': 'smallerEq', + '>=': 'largerEq' + }; + while (operators.hasOwnProperty(token)) { + name = token; + fn = operators[name]; - // one-based version of forEach - var _forEach = typed('forEach', { - 'Array | Matrix, function': function (array$$1, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$2(callback); + getTokenSkipNewline(); + params = [node, parseShift()]; + node = new OperatorNode$$1(name, fn, params); + } - var recurse = function (value, index) { - if (Array.isArray(value)) { - forEach$3(value, function (child, i) { - // we create a copy of the index array and append the new index value - recurse(child, index.concat(i + 1)); // one based index, hence i+1 - }); - } - else { - // invoke the callback function with the right number of arguments - if (args === 1) { - callback(value); - } - else if (args === 2) { - callback(value, index); - } - else { // 3 or -1 - callback(value, index, array$$1); - } - } - }; - recurse(array$$1.valueOf(), []); // pass Array + return node; } - }); - - return forEachTransform; -} -var name$65 = 'forEach'; -var path$34 = 'expression.transform'; -var factory_1$71 = factory$72; + /** + * Bitwise left shift, bitwise right arithmetic shift, bitwise right logical shift + * @return {Node} node + * @private + */ + function parseShift () { + var node, operators, name, fn, params; -var forEach_transform = { - name: name$65, - path: path$34, - factory: factory_1$71 -}; + node = parseConversion(); -/** - * Attach a transform function to math.index - * Adds a property transform containing the transform function. - * - * This transform creates a one-based index instead of a zero-based index - */ -function factory$73 (type, config, load) { + operators = { + '<<' : 'leftShift', + '>>' : 'rightArithShift', + '>>>' : 'rightLogShift' + }; - return function indexTransform() { - var args = []; - for (var i = 0, ii = arguments.length; i < ii; i++) { - var arg = arguments[i]; + while (operators.hasOwnProperty(token)) { + name = token; + fn = operators[name]; - // change from one-based to zero based, and convert BigNumber to number - if (type.isRange(arg)) { - arg.start--; - arg.end -= (arg.step > 0 ? 0 : 2); - } - else if (arg && arg.isSet === true) { - arg = arg.map(function (v) { return v - 1; }); - } - else if (type.isArray(arg) || type.isMatrix(arg)) { - arg = arg.map(function (v) { return v - 1; }); - } - else if (type.isNumber(arg)) { - arg--; - } - else if (type.isBigNumber(arg)) { - arg = arg.toNumber() - 1; - } - else if (typeof arg === 'string') { - // leave as is - } - else { - throw new TypeError('Dimension must be an Array, Matrix, number, string, or Range'); + getTokenSkipNewline(); + params = [node, parseConversion()]; + node = new OperatorNode$$1(name, fn, params); } - args[i] = arg; + return node; } - var res = new type.Index(); - type.Index.apply(res, args); - return res; - }; -} - -var name$66 = 'index'; -var path$35 = 'expression.transform'; -var factory_1$72 = factory$73; + /** + * conversion operators 'to' and 'in' + * @return {Node} node + * @private + */ + function parseConversion () { + var node, operators, name, fn, params; -var index_transform = { - name: name$66, - path: path$35, - factory: factory_1$72 -}; + node = parseRange(); -var maxArgumentCount$3 = _function.maxArgumentCount; -var map$6 = array.map; + operators = { + 'to' : 'to', + 'in' : 'to' // alias of 'to' + }; -/** - * Attach a transform function to math.map - * Adds a property transform containing the transform function. - * - * This transform creates a one-based index instead of a zero-based index - */ -function factory$74 (type, config, load, typed) { - var compileInlineExpression$$1 = load(compileInlineExpression); - var matrix$$1 = load(matrix); + while (operators.hasOwnProperty(token)) { + name = token; + fn = operators[name]; - function mapTransform(args, math, scope) { - var x, callback; + getTokenSkipNewline(); + + if (name === 'in' && token === '') { + // end of expression -> this is the unit 'in' ('inch') + node = new OperatorNode$$1('*', 'multiply', [node, new SymbolNode$$1('in')], true); + } + else { + // operator 'a to b' or 'a in b' + params = [node, parseRange()]; + node = new OperatorNode$$1(name, fn, params); + } + } - if (args[0]) { - x = args[0].compile().eval(scope); + return node; } - if (args[1]) { - if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { - // a function pointer, like filter([3, -2, 5], myTestFunction); - callback = args[1].compile().eval(scope); - } + /** + * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc + * @return {Node} node + * @private + */ + function parseRange () { + var node, params = []; + + if (token === ':') { + // implicit start=1 (one-based) + node = new ConstantNode$$1(1); + } else { - // an expression like filter([3, -2, 5], x > 0) - callback = compileInlineExpression$$1(args[1], math, scope); + // explicit start + node = parseAddSubtract(); } - } - return map(x, callback); - } - mapTransform.rawArgs = true; + if (token === ':' && (conditional_level !== nesting_level)) { + // we ignore the range operator when a conditional operator is being processed on the same level + params.push(node); - // one-based version of map function - var map = typed('map', { - 'Array, function': function (x, callback) { - return _map(x, callback, x); - }, + // parse step and end + while (token === ':' && params.length < 3) { + getTokenSkipNewline(); - 'Matrix, function': function (x, callback) { - return matrix$$1(_map(x.valueOf(), callback, x)); - } - }); + if (token === ')' || token === ']' || token === ',' || token === '') { + // implicit end + params.push(new SymbolNode$$1('end')); + } + else { + // explicit end + params.push(parseAddSubtract()); + } + } - return mapTransform; -} - -/** - * Map for a multi dimensional array. One-based indexes - * @param {Array} array - * @param {function} callback - * @param {Array} orig - * @return {Array} - * @private - */ -function _map (array$$1, callback, orig) { - // figure out what number of arguments the callback function expects - var argsCount = maxArgumentCount$3(callback); - - function recurse(value, index) { - if (Array.isArray(value)) { - return map$6(value, function (child, i) { - // we create a copy of the index array and append the new index value - return recurse(child, index.concat(i + 1)); // one based index, hence i + 1 - }); - } - else { - // invoke the (typed) callback function with the right number of arguments - if (argsCount === 1) { - return callback(value); - } - else if (argsCount === 2) { - return callback(value, index); - } - else { // 3 or -1 - return callback(value, index, orig); + if (params.length === 3) { + // params = [start, step, end] + node = new RangeNode$$1(params[0], params[2], params[1]); // start, end, step + } + else { // length === 2 + // params = [start, end] + node = new RangeNode$$1(params[0], params[1]); // start, end + } } - } - } - - return recurse(array$$1, []); -} -var name$67 = 'map'; -var path$36 = 'expression.transform'; -var factory_1$73 = factory$74; + return node; + } -var map_transform = { - name: name$67, - path: path$36, - factory: factory_1$73 -}; + /** + * add or subtract + * @return {Node} node + * @private + */ + function parseAddSubtract () { + var node, operators, name, fn, params; -/** - * Test whether a value is a collection: an Array or Matrix - * @param {*} x - * @returns {boolean} isCollection - */ -var isCollection = function isCollection (x) { - return Array.isArray(x) || isMatrix(x); -}; + node = parseMultiplyDivide(); -/** - * Recursively loop over all elements in a given multi dimensional array - * and invoke the callback on each of the elements. - * @param {Array | Matrix} array - * @param {Function} callback The callback method is invoked with one - * parameter: the current element in the array - */ -var deepForEach = function deepForEach (array, callback) { - if (isMatrix(array)) { - array = array.valueOf(); - } + operators = { + '+': 'add', + '-': 'subtract' + }; + while (operators.hasOwnProperty(token)) { + name = token; + fn = operators[name]; - for (var i = 0, ii = array.length; i < ii; i++) { - var value = array[i]; + getTokenSkipNewline(); + params = [node, parseMultiplyDivide()]; + node = new OperatorNode$$1(name, fn, params); + } - if (Array.isArray(value)) { - deepForEach(value, callback); - } - else { - callback(value); + return node; } - } -}; -var arraySize = array.size; + /** + * multiply, divide, modulus + * @return {Node} node + * @private + */ + function parseMultiplyDivide () { + var node, last, operators, name, fn; + + node = parseImplicitMultiplication(); + last = node; + + operators = { + '*': 'multiply', + '.*': 'dotMultiply', + '/': 'divide', + './': 'dotDivide', + '%': 'mod', + 'mod': 'mod' + }; + while (true) { + if (operators.hasOwnProperty(token)) { + // explicit operators + name = token; + fn = operators[name]; + getTokenSkipNewline(); -/** - * Reduce a given matrix or array to a new matrix or - * array with one less dimension, applying the given - * callback in the selected dimension. - * @param {Array | Matrix} mat - * @param {number} dim - * @param {Function} callback - * @return {Array | Matrix} res - */ -var reduce = function(mat, dim, callback) { - var size = Array.isArray(mat) ? arraySize(mat) : mat.size(); - if (dim < 0 || (dim >= size.length)) { - // TODO: would be more clear when throwing a DimensionError here - throw new IndexError_1(dim, size.length); - } + last = parseImplicitMultiplication(); + node = new OperatorNode$$1(name, fn, [node, last]); + } + else { + break; + } + } - if (isMatrix(mat)) { - return mat.create(_reduce(mat.valueOf(), dim, callback)); - }else { - return _reduce(mat, dim, callback); - } -}; + return node; + } + + /** + * implicit multiplication + * @return {Node} node + * @private + */ + function parseImplicitMultiplication () { + var node, last; -/** - * Recursively reduce a matrix - * @param {Array} mat - * @param {number} dim - * @param {Function} callback - * @returns {Array} ret - * @private - */ -function _reduce(mat, dim, callback){ - var i, ret, val, tran; + node = parseRule2(); + last = node; - if(dim<=0){ - if( !Array.isArray(mat[0]) ){ - val = mat[0]; - for(i=1; i 2 - ? ' (type: ' + getType(value) + ', value: ' + JSON.stringify(value) + ')' - : ' (type: ' + err.data.actual + ')'; + if (operators.hasOwnProperty(token)) { + fn = operators[token]; + name = token; - return new TypeError('Cannot calculate ' + fnName + ', unexpected type of argument' + details); - } + getTokenSkipNewline(); + params = [parseUnary()]; - if (String(err).indexOf('complex numbers') !== -1) { - details = arguments.length > 2 - ? ' (type: ' + getType(value) + ', value: ' + JSON.stringify(value) + ')' - : ''; + return new OperatorNode$$1(name, fn, params); + } - return new TypeError('Cannot calculate ' + fnName + ', no ordering relation is defined for complex numbers' + details); + return parsePow(); } - return err; - } -} - -var factory_1$74 = factory$75; - -var improveErrorMessage = { - factory: factory_1$74 -}; - -function factory$76 (type, config, load, typed) { - var larger$$1 = load(larger); - var improveErrorMessage$$1 = load(improveErrorMessage); + /** + * power + * Note: power operator is right associative + * @return {Node} node + * @private + */ + function parsePow () { + var node, name, fn, params; - /** - * Compute the maximum value of a matrix or a list with values. - * In case of a multi dimensional array, the maximum of the flattened array - * will be calculated. When `dim` is provided, the maximum over the selected - * dimension will be calculated. Parameter `dim` is zero-based. - * - * Syntax: - * - * math.max(a, b, c, ...) - * math.max(A) - * math.max(A, dim) - * - * Examples: - * - * math.max(2, 1, 4, 3); // returns 4 - * math.max([2, 1, 4, 3]); // returns 4 - * - * // maximum over a specified dimension (zero-based) - * math.max([[2, 5], [4, 3], [1, 7]], 0); // returns [4, 7] - * math.max([[2, 5], [4, 3]], [1, 7], 1); // returns [5, 4, 7] - * - * math.max(2.7, 7.1, -4.5, 2.0, 4.1); // returns 7.1 - * math.min(2.7, 7.1, -4.5, 2.0, 4.1); // returns -4.5 - * - * See also: - * - * mean, median, min, prod, std, sum, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The maximum value - */ - var max = typed('max', { - // max([a, b, c, d, ...]) - 'Array | Matrix': _max, + node = parseLeftHandOperators(); - // max([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': function (array, dim) { - return reduce(array, dim.valueOf(), _largest); - }, + if (token === '^' || token === '.^') { + name = token; + fn = (name === '^') ? 'pow' : 'dotPow'; - // max(a, b, c, d, ...) - '...': function (args) { - if (containsCollections(args)) { - throw new TypeError('Scalar values expected in function max'); + getTokenSkipNewline(); + params = [node, parseUnary()]; // Go back to unary, we can have '2^-3' + node = new OperatorNode$$1(name, fn, params); } - return _max(args); + return node; } - }); - max.toTex = '\\max\\left(${args}\\right)'; + /** + * Left hand operators: factorial x!, transpose x' + * @return {Node} node + * @private + */ + function parseLeftHandOperators () { + var node, operators, name, fn, params; - return max; + node = parseCustomNodes(); - /** - * Return the largest of two values - * @param {*} x - * @param {*} y - * @returns {*} Returns x when x is largest, or y when y is largest - * @private - */ - function _largest(x, y) { - try { - return larger$$1(x, y) ? x : y; - } - catch (err) { - throw improveErrorMessage$$1(err, 'max', y); - } - } + operators = { + '!': 'factorial', + '\'': 'transpose' + }; - /** - * Recursively calculate the maximum value in an n-dimensional array - * @param {Array} array - * @return {number} max - * @private - */ - function _max(array) { - var max = undefined; + while (operators.hasOwnProperty(token)) { + name = token; + fn = operators[name]; - deepForEach(array, function (value) { - try { - if (max === undefined || larger$$1(value, max)) { - max = value; - } - } - catch (err) { - throw improveErrorMessage$$1(err, 'max', value); + getToken(); + params = [node]; + + node = new OperatorNode$$1(name, fn, params); + node = parseAccessors(node); } - }); - if (max === undefined) { - throw new Error('Cannot calculate max of an empty array'); + return node; } - return max; - } + /** + * Parse a custom node handler. A node handler can be used to process + * nodes in a custom way, for example for handling a plot. + * + * A handler must be passed as second argument of the parse function. + * - must extend math.expression.node.Node + * - must contain a function _compile(defs: Object) : string + * - must contain a function find(filter: Object) : Node[] + * - must contain a function toString() : string + * - the constructor is called with a single argument containing all parameters + * + * For example: + * + * nodes = { + * 'plot': PlotHandler + * }; + * + * The constructor of the handler is called as: + * + * node = new PlotHandler(params); + * + * The handler will be invoked when evaluating an expression like: + * + * node = math.parse('plot(sin(x), x)', nodes); + * + * @return {Node} node + * @private + */ + function parseCustomNodes () { + var params = []; -} + if (token_type === TOKENTYPE.SYMBOL && extra_nodes.hasOwnProperty(token)) { + var CustomNode = extra_nodes[token]; -var name$68 = 'max'; -var factory_1$75 = factory$76; + getToken(); -var max$1 = { - name: name$68, - factory: factory_1$75 -}; + // parse parameters + if (token === '(') { + params = []; -var errorTransform$3 = error_transform.transform; + openParams(); + getToken(); + if (token !== ')') { + params.push(parseAssignment()); -/** - * Attach a transform function to math.max - * Adds a property transform containing the transform function. - * - * This transform changed the last `dim` parameter of function max - * from one-based to zero based - */ -function factory$77 (type, config, load, typed) { - var max = load(max$1); + // parse a list with parameters + while (token === ',') { + getToken(); + params.push(parseAssignment()); + } + } - return typed('max', { - '...any': function (args) { - // change last argument dim from one-based to zero-based - if (args.length == 2 && isCollection(args[0])) { - var dim = args[1]; - if (type.isNumber(dim)) { - args[1] = dim - 1; - } - else if (type.isBigNumber(dim)) { - args[1] = dim.minus(1); + if (token !== ')') { + throw createSyntaxError('Parenthesis ) expected'); + } + closeParams(); + getToken(); } - } - try { - return max.apply(null, args); + // create a new custom node + //noinspection JSValidateTypes + return new CustomNode(params); } - catch (err) { - throw errorTransform$3(err); - } - } - }); -} - -var name$69 = 'max'; -var path$37 = 'expression.transform'; -var factory_1$76 = factory$77; - -var max_transform = { - name: name$69, - path: path$37, - factory: factory_1$76 -}; - -function factory$78(type, config, load, typed) { - - /** - * Multiply two scalar values, `x * y`. - * This function is meant for internal use: it is used by the public function - * `multiply` - * - * This function does not support collections (Array or Matrix), and does - * not validate the number of of inputs. - * - * @param {number | BigNumber | Fraction | Complex | Unit} x First value to multiply - * @param {number | BigNumber | Fraction | Complex} y Second value to multiply - * @return {number | BigNumber | Fraction | Complex | Unit} Multiplication of `x` and `y` - * @private - */ - var multiplyScalar = typed('multiplyScalar', { - 'number, number': function (x, y) { - return x * y; - }, + return parseSymbol(); + } - 'Complex, Complex': function (x, y) { - return x.mul(y); - }, + /** + * parse symbols: functions, variables, constants, units + * @return {Node} node + * @private + */ + function parseSymbol () { + var node, name; - 'BigNumber, BigNumber': function (x, y) { - return x.times(y); - }, + if (token_type === TOKENTYPE.SYMBOL || + (token_type === TOKENTYPE.DELIMITER && token in NAMED_DELIMITERS)) { + name = token; - 'Fraction, Fraction': function (x, y) { - return x.mul(y); - }, + getToken(); - 'number | Fraction | BigNumber | Complex, Unit': function (x, y) { - var res = y.clone(); - res.value = (res.value === null) ? res._normalize(x) : multiplyScalar(res.value, x); - return res; - }, + if (CONSTANTS.hasOwnProperty(name)) { // true, false, null, ... + node = new ConstantNode$$1(CONSTANTS[name]); + } + else if (NUMERIC_CONSTANTS.indexOf(name) !== -1) { // NaN, Infinity + node = new ConstantNode$$1(numeric$$1(name)); + } + else { + node = new SymbolNode$$1(name); + } - 'Unit, number | Fraction | BigNumber | Complex': function (x, y) { - var res = x.clone(); - res.value = (res.value === null) ? res._normalize(y) : multiplyScalar(res.value, y); - return res; - }, + // parse function parameters and matrix index + node = parseAccessors(node); + return node; + } - 'Unit, Unit': function (x, y) { - return x.multiply(y); + return parseString(); } - }); - - return multiplyScalar; -} + /** + * parse accessors: + * - function invocation in round brackets (...), for example sqrt(2) + * - index enclosed in square brackets [...], for example A[2,3] + * - dot notation for properties, like foo.bar + * @param {Node} node Node on which to apply the parameters. If there + * are no parameters in the expression, the node + * itself is returned + * @param {string[]} [types] Filter the types of notations + * can be ['(', '[', '.'] + * @return {Node} node + * @private + */ + function parseAccessors (node, types) { + var params; -var factory_1$77 = factory$78; + while ((token === '(' || token === '[' || token === '.') && + (!types || types.indexOf(token) !== -1)) { + params = []; -var multiplyScalar = { - factory: factory_1$77 -}; + if (token === '(') { + if (type.isSymbolNode(node) || type.isAccessorNode(node)) { + // function invocation like fn(2, 3) or obj.fn(2, 3) + openParams(); + getToken(); -function factory$79(type, config, load, typed) { - var multiplyScalar$$1 = load(multiplyScalar); + if (token !== ')') { + params.push(parseAssignment()); - /** - * Divide two scalar values, `x / y`. - * This function is meant for internal use: it is used by the public functions - * `divide` and `inv`. - * - * This function does not support collections (Array or Matrix), and does - * not validate the number of of inputs. - * - * @param {number | BigNumber | Fraction | Complex | Unit} x Numerator - * @param {number | BigNumber | Fraction | Complex} y Denominator - * @return {number | BigNumber | Fraction | Complex | Unit} Quotient, `x / y` - * @private - */ - var divideScalar = typed('divide', { - 'number, number': function (x, y) { - return x / y; - }, + // parse a list with parameters + while (token === ',') { + getToken(); + params.push(parseAssignment()); + } + } - 'Complex, Complex': function (x, y) { - return x.div(y); - }, + if (token !== ')') { + throw createSyntaxError('Parenthesis ) expected'); + } + closeParams(); + getToken(); - 'BigNumber, BigNumber': function (x, y) { - return x.div(y); - }, + node = new FunctionNode$$1(node, params); + } + else { + // implicit multiplication like (2+3)(4+5) or sqrt(2)(1+2) + // don't parse it here but let it be handled by parseImplicitMultiplication + // with correct precedence + return node; + } + } + else if (token === '[') { + // index notation like variable[2, 3] + openParams(); + getToken(); - 'Fraction, Fraction': function (x, y) { - return x.div(y); - }, + if (token !== ']') { + params.push(parseAssignment()); - 'Unit, number | Fraction | BigNumber': function (x, y) { - var res = x.clone(); - // TODO: move the divide function to Unit.js, it uses internals of Unit - res.value = divideScalar(((res.value === null) ? res._normalize(1) : res.value), y); - return res; - }, + // parse a list with parameters + while (token === ',') { + getToken(); + params.push(parseAssignment()); + } + } - 'number | Fraction | BigNumber, Unit': function (x, y) { - var res = y.pow(-1); - // TODO: move the divide function to Unit.js, it uses internals of Unit - res.value = multiplyScalar$$1(((res.value === null) ? res._normalize(1) : res.value), x); - return res; - }, + if (token !== ']') { + throw createSyntaxError('Parenthesis ] expected'); + } + closeParams(); + getToken(); - 'Unit, Unit': function (x, y) { - return x.divide(y); - } + node = new AccessorNode$$1(node, new IndexNode$$1(params)); + } + else { + // dot notation like variable.prop + getToken(); - }); + if (token_type !== TOKENTYPE.SYMBOL) { + throw createSyntaxError('Property name expected after dot'); + } + params.push(new ConstantNode$$1(token)); + getToken(); - return divideScalar; -} + var dotNotation = true; + node = new AccessorNode$$1(node, new IndexNode$$1(params, dotNotation)); + } + } -var factory_1$78 = factory$79; + return node; + } -var divideScalar = { - factory: factory_1$78 -}; + /** + * parse a string. + * A string is enclosed by double quotes + * @return {Node} node + * @private + */ + function parseString () { + var node, str; -function factory$80 (type, config, load, typed) { + if (token === '"') { + str = parseStringToken(); - var equalScalar$$1 = load(equalScalar); + // create constant + node = new ConstantNode$$1(str); - var SparseMatrix = type.SparseMatrix; + // parse index parameters + node = parseAccessors(node); - /** - * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). - * Callback function invoked NZ times (number of nonzero items in S). - * - * - * ┌ f(Sij, b) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} s The SparseMatrix instance (S) - * @param {Scalar} b The Scalar value - * @param {Function} callback The f(Aij,b) operation to invoke - * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) - * - * @return {Matrix} SparseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 - */ - var algorithm11 = function (s, b, callback, inverse) { - // sparse matrix arrays - var avalues = s._values; - var aindex = s._index; - var aptr = s._ptr; - var asize = s._size; - var adt = s._datatype; - - // sparse matrix cannot be a Pattern matrix - if (!avalues) - throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string') { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = []; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); + return node; + } - // loop columns - for (var j = 0; j < columns; j++) { - // initialize ptr - cptr[j] = cindex.length; - // values in j - for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - var i = aindex[k]; - // invoke callback - var v = inverse ? cf(b, avalues[k]) : cf(avalues[k], b); - // check value is zero - if (!eq(v, zero)) { - // push index & value - cindex.push(i); - cvalues.push(v); + return parseMatrix(); + } + + /** + * Parse a string surrounded by double quotes "..." + * @return {string} + */ + function parseStringToken () { + var str = ''; + + while (c !== '' && c !== '\"') { + if (c === '\\') { + // escape character, immediately process the next + // character to prevent stopping at a next '\"' + str += c; + next(); } + + str += c; + next(); + } + + getToken(); + if (token !== '"') { + throw createSyntaxError('End of string " expected'); } + getToken(); + + return JSON.parse('"' + str + '"'); // unescape escaped characters } - // update ptr - cptr[columns] = cindex.length; - // return sparse matrix - return c; - }; + /** + * parse the matrix + * @return {Node} node + * @private + */ + function parseMatrix () { + var array, params, rows, cols; - return algorithm11; -} + if (token === '[') { + // matrix [...] + openParams(); + getToken(); -var name$70 = 'algorithm11'; -var factory_1$79 = factory$80; + if (token !== ']') { + // this is a non-empty matrix + var row = parseRow(); -var algorithm11 = { - name: name$70, - factory: factory_1$79 -}; + if (token === ';') { + // 2 dimensional array + rows = 1; + params = [row]; -var extend$2 = object.extend; + // the rows of the matrix are separated by dot-comma's + while (token === ';') { + getToken(); + params[rows] = parseRow(); + rows++; + } -function factory$81 (type, config, load, typed) { - var latex$$1 = latex; + if (token !== ']') { + throw createSyntaxError('End of matrix ] expected'); + } + closeParams(); + getToken(); - var matrix$$1 = load(matrix); - var addScalar$$1 = load(addScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var equalScalar$$1 = load(equalScalar); + // check if the number of columns matches in all rows + cols = params[0].items.length; + for (var r = 1; r < rows; r++) { + if (params[r].items.length !== cols) { + throw createError('Column dimensions mismatch ' + + '(' + params[r].items.length + ' !== ' + cols + ')'); + } + } - var algorithm11$$1 = load(algorithm11); - var algorithm14$$1 = load(algorithm14); - - var DenseMatrix = type.DenseMatrix; - var SparseMatrix = type.SparseMatrix; + array = new ArrayNode$$1(params); + } + else { + // 1 dimensional vector + if (token !== ']') { + throw createSyntaxError('End of matrix ] expected'); + } + closeParams(); + getToken(); - /** - * Multiply two or more values, `x * y`. - * For matrices, the matrix product is calculated. - * - * Syntax: - * - * math.multiply(x, y) - * math.multiply(x, y, z, ...) - * - * Examples: - * - * math.multiply(4, 5.2); // returns number 20.8 - * math.multiply(2, 3, 4); // returns number 24 - * - * var a = math.complex(2, 3); - * var b = math.complex(4, 1); - * math.multiply(a, b); // returns Complex 5 + 14i - * - * var c = [[1, 2], [4, 3]]; - * var d = [[1, 2, 3], [3, -4, 7]]; - * math.multiply(c, d); // returns Array [[7, -6, 17], [13, -4, 33]] - * - * var e = math.unit('2.1 km'); - * math.multiply(3, e); // returns Unit 6.3 km - * - * See also: - * - * divide, prod, cross, dot - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to multiply - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to multiply - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` - */ - var multiply = typed('multiply', extend$2({ - // we extend the signatures of multiplyScalar with signatures dealing with matrices + array = row; + } + } + else { + // this is an empty matrix "[ ]" + closeParams(); + getToken(); + array = new ArrayNode$$1([]); + } - 'Array, Array': function (x, y) { - // check dimensions - _validateMatrixDimensions(array.size(x), array.size(y)); + return parseAccessors(array); + } - // use dense matrix implementation - var m = multiply(matrix$$1(x), matrix$$1(y)); - // return array or scalar - return type.isMatrix(m) ? m.valueOf() : m; - }, + return parseObject(); + } - 'Matrix, Matrix': function (x, y) { - // dimensions - var xsize = x.size(); - var ysize = y.size(); + /** + * Parse a single comma-separated row from a matrix, like 'a, b, c' + * @return {ArrayNode} node + */ + function parseRow () { + var params = [parseAssignment()]; + var len = 1; - // check dimensions - _validateMatrixDimensions(xsize, ysize); + while (token === ',') { + getToken(); - // process dimensions - if (xsize.length === 1) { - // process y dimensions - if (ysize.length === 1) { - // Vector * Vector - return _multiplyVectorVector(x, y, xsize[0]); - } - // Vector * Matrix - return _multiplyVectorMatrix(x, y); - } - // process y dimensions - if (ysize.length === 1) { - // Matrix * Vector - return _multiplyMatrixVector(x, y); + // parse expression + params[len] = parseAssignment(); + len++; } - // Matrix * Matrix - return _multiplyMatrixMatrix(x, y); - }, - 'Matrix, Array': function (x, y) { - // use Matrix * Matrix implementation - return multiply(x, matrix$$1(y)); - }, + return new ArrayNode$$1(params); + } - 'Array, Matrix': function (x, y) { - // use Matrix * Matrix implementation - return multiply(matrix$$1(x, y.storage()), y); - }, + /** + * parse an object, enclosed in angle brackets{...}, for example {value: 2} + * @return {Node} node + * @private + */ + function parseObject () { + if (token === '{') { + var key; - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, multiplyScalar$$1, false); - }, + var properties = {}; + do { + getToken(); - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, multiplyScalar$$1, false); - }, + if (token !== '}') { + // parse key + if (token === '"') { + key = parseStringToken(); + } + else if (token_type === TOKENTYPE.SYMBOL) { + key = token; + getToken(); + } + else { + throw createSyntaxError('Symbol or string expected as object key'); + } - 'any, SparseMatrix': function (x, y) { - return algorithm11$$1(y, x, multiplyScalar$$1, true); - }, + // parse key/value separator + if (token !== ':') { + throw createSyntaxError('Colon : expected after object key'); + } + getToken(); - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, multiplyScalar$$1, true); - }, + // parse key + properties[key] = parseAssignment(); + } + } + while (token === ','); - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, multiplyScalar$$1, false).valueOf(); - }, + if (token !== '}') { + throw createSyntaxError('Comma , or bracket } expected after object value'); + } + getToken(); - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, multiplyScalar$$1, true).valueOf(); - }, + var node = new ObjectNode$$1(properties); + + // parse index parameters + node = parseAccessors(node); + + return node; + } - 'any, any': multiplyScalar$$1, + return parseNumber(); + } + + /** + * parse a number + * @return {Node} node + * @private + */ + function parseNumber () { + var numberStr; - 'any, any, ...any': function (x, y, rest) { - var result = multiply(x, y); + if (token_type === TOKENTYPE.NUMBER) { + // this is a number + numberStr = token; + getToken(); - for (var i = 0; i < rest.length; i++) { - result = multiply(result, rest[i]); + return new ConstantNode$$1(numeric$$1(numberStr, config.number)); } - - return result; + + return parseParentheses(); } - }, multiplyScalar$$1.signatures)); - var _validateMatrixDimensions = function (size1, size2) { - // check left operand dimensions - switch (size1.length) { - case 1: - // check size2 - switch (size2.length) { - case 1: - // Vector x Vector - if (size1[0] !== size2[0]) { - // throw error - throw new RangeError('Dimension mismatch in multiplication. Vectors must have the same length'); - } - break; - case 2: - // Vector x Matrix - if (size1[0] !== size2[0]) { - // throw error - throw new RangeError('Dimension mismatch in multiplication. Vector length (' + size1[0] + ') must match Matrix rows (' + size2[0] + ')'); - } - break; - default: - throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)'); - } - break; - case 2: - // check size2 - switch (size2.length) { - case 1: - // Matrix x Vector - if (size1[1] !== size2[0]) { - // throw error - throw new RangeError('Dimension mismatch in multiplication. Matrix columns (' + size1[1] + ') must match Vector length (' + size2[0] + ')'); - } - break; - case 2: - // Matrix x Matrix - if (size1[1] !== size2[0]) { - // throw error - throw new RangeError('Dimension mismatch in multiplication. Matrix A columns (' + size1[1] + ') must match Matrix B rows (' + size2[0] + ')'); - } - break; - default: - throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)'); + /** + * parentheses + * @return {Node} node + * @private + */ + function parseParentheses () { + var node; + + // check if it is a parenthesized expression + if (token === '(') { + // parentheses (...) + openParams(); + getToken(); + + node = parseAssignment(); // start again + + if (token !== ')') { + throw createSyntaxError('Parenthesis ) expected'); } - break; - default: - throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix A has ' + size1.length + ' dimensions)'); + closeParams(); + getToken(); + + node = new ParenthesisNode$$1(node); + node = parseAccessors(node); + return node; + } + + return parseEnd(); } - }; - /** - * C = A * B - * - * @param {Matrix} a Dense Vector (N) - * @param {Matrix} b Dense Vector (N) - * - * @return {number} Scalar value - */ - var _multiplyVectorVector = function (a, b, n) { - // check empty vector - if (n === 0) - throw new Error('Cannot multiply two empty vectors'); - - // a dense - var adata = a._data; - var adt = a._datatype; - // b dense - var bdata = b._data; - var bdt = b._datatype; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); + /** + * Evaluated when the expression is not yet ended but expected to end + * @return {Node} res + * @private + */ + function parseEnd () { + if (token === '') { + // syntax error or unexpected end of expression + throw createSyntaxError('Unexpected end of expression'); + } else if (token === "'") { + throw createSyntaxError('Value expected. Note: strings must be enclosed by double quotes'); + } else { + throw createSyntaxError('Value expected'); + } } - - // result (do not initialize it with zero) - var c = mf(adata[0], bdata[0]); - // loop data - for (var i = 1; i < n; i++) { - // multiply and accumulate - c = af(c, mf(adata[i], bdata[i])); + + /** + * Shortcut for getting the current row value (one based) + * Returns the line of the currently handled expression + * @private + */ + /* TODO: implement keeping track on the row number + function row () { + return null; } - return c; - }; + */ - /** - * C = A * B - * - * @param {Matrix} a Dense Vector (M) - * @param {Matrix} b Matrix (MxN) - * - * @return {Matrix} Dense Vector (N) - */ - var _multiplyVectorMatrix = function (a, b) { - // process storage - if (b.storage() !== 'dense') { - throw new Error('Support for SparseMatrix not implemented'); + /** + * Shortcut for getting the current col value (one based) + * Returns the column (position) where the last token starts + * @private + */ + function col () { + return index - token.length + 1; } - return _multiplyVectorDenseMatrix(a, b); - }; - /** - * C = A * B - * - * @param {Matrix} a Dense Vector (M) - * @param {Matrix} b Dense Matrix (MxN) - * - * @return {Matrix} Dense Vector (N) - */ - var _multiplyVectorDenseMatrix = function (a, b) { - // a dense - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b dense - var bdata = b._data; - var bsize = b._size; - var bdt = b._datatype; - // rows & columns - var alength = asize[0]; - var bcolumns = bsize[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); + /** + * Create an error + * @param {string} message + * @return {SyntaxError} instantiated error + * @private + */ + function createSyntaxError (message) { + var c = col(); + var error = new SyntaxError(message + ' (char ' + c + ')'); + error['char'] = c; + + return error; } - // result - var c = []; + /** + * Create an error + * @param {string} message + * @return {Error} instantiated error + * @private + */ + function createError (message) { + var c = col(); + var error = new SyntaxError(message + ' (char ' + c + ')'); + error['char'] = c; - // loop matrix columns - for (var j = 0; j < bcolumns; j++) { - // sum (do not initialize it with zero) - var sum = mf(adata[0], bdata[0][j]); - // loop vector - for (var i = 1; i < alength; i++) { - // multiply & accumulate - sum = af(sum, mf(adata[i], bdata[i][j])); - } - c[j] = sum; + return error; } - // return matrix - return new DenseMatrix({ - data: c, - size: [bcolumns], - datatype: dt - }); + return parse; + } + + var name$54 = 'parse'; + var path$29 = 'expression'; + var factory_1$59 = factory$60; + + var parse = { + name: name$54, + path: path$29, + factory: factory_1$59 }; - /** - * C = A * B - * - * @param {Matrix} a Matrix (MxN) - * @param {Matrix} b Dense Vector (N) - * - * @return {Matrix} Dense Vector (M) - */ - var _multiplyMatrixVector = typed('_multiplyMatrixVector', { - 'DenseMatrix, any': _multiplyDenseMatrixVector, - 'SparseMatrix, any': _multiplySparseMatrixVector - }); + function factory$61 (type, config, load, typed) { + var parse$$1 = load(parse); - /** - * C = A * B - * - * @param {Matrix} a Matrix (MxN) - * @param {Matrix} b Matrix (NxC) - * - * @return {Matrix} Matrix (MxC) - */ - var _multiplyMatrixMatrix = typed('_multiplyMatrixMatrix', { - 'DenseMatrix, DenseMatrix': _multiplyDenseMatrixDenseMatrix, - 'DenseMatrix, SparseMatrix': _multiplyDenseMatrixSparseMatrix, - 'SparseMatrix, DenseMatrix': _multiplySparseMatrixDenseMatrix, - 'SparseMatrix, SparseMatrix': _multiplySparseMatrixSparseMatrix - }); + /** + * Parse and compile an expression. + * Returns a an object with a function `eval([scope])` to evaluate the + * compiled expression. + * + * Syntax: + * + * math.compile(expr) // returns one node + * math.compile([expr1, expr2, expr3, ...]) // returns an array with nodes + * + * Examples: + * + * var code = math.compile('sqrt(3^2 + 4^2)'); + * code.eval(); // 5 + * + * var scope = {a: 3, b: 4} + * var code = math.compile('a * b'); // 12 + * code.eval(scope); // 12 + * scope.a = 5; + * code.eval(scope); // 20 + * + * var nodes = math.compile(['a = 3', 'b = 4', 'a * b']); + * nodes[2].eval(); // 12 + * + * See also: + * + * parse, eval + * + * @param {string | string[] | Array | Matrix} expr + * The expression to be compiled + * @return {{eval: Function} | Array.<{eval: Function}>} code + * An object with the compiled expression + * @throws {Error} + */ + return typed('compile', { + 'string': function (expr) { + return parse$$1(expr).compile(); + }, - /** - * C = A * B - * - * @param {Matrix} a DenseMatrix (MxN) - * @param {Matrix} b Dense Vector (N) - * - * @return {Matrix} Dense Vector (M) - */ - function _multiplyDenseMatrixVector(a, b) { - // a dense - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b dense - var bdata = b._data; - var bdt = b._datatype; - // rows & columns - var arows = asize[0]; - var acolumns = asize[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - } - - // result - var c = []; - - // loop matrix a rows - for (var i = 0; i < arows; i++) { - // current row - var row = adata[i]; - // sum (do not initialize it with zero) - var sum = mf(row[0], bdata[0]); - // loop matrix a columns - for (var j = 1; j < acolumns; j++) { - // multiply & accumulate - sum = af(sum, mf(row[j], bdata[j])); - } - c[i] = sum; - } - - // return matrix - return new DenseMatrix({ - data: c, - size: [arows], - datatype: dt + 'Array | Matrix': function (expr) { + return deepMap(expr, function (entry) { + return parse$$1(entry).compile(); + }); + } }); } - /** - * C = A * B - * - * @param {Matrix} a DenseMatrix (MxN) - * @param {Matrix} b DenseMatrix (NxC) - * - * @return {Matrix} DenseMatrix (MxC) - */ - function _multiplyDenseMatrixDenseMatrix (a, b) { - // a dense - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b dense - var bdata = b._data; - var bsize = b._size; - var bdt = b._datatype; - // rows & columns - var arows = asize[0]; - var acolumns = asize[1]; - var bcolumns = bsize[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - } - - // result - var c = []; - - // loop matrix a rows - for (var i = 0; i < arows; i++) { - // current row - var row = adata[i]; - // initialize row array - c[i] = []; - // loop matrix b columns - for (var j = 0; j < bcolumns; j++) { - // sum (avoid initializing sum to zero) - var sum = mf(row[0], bdata[0][j]); - // loop matrix a columns - for (var x = 1; x < acolumns; x++) { - // multiply & accumulate - sum = af(sum, mf(row[x], bdata[x][j])); - } - c[i][j] = sum; - } - } + var name$55 = 'compile'; + var factory_1$60 = factory$61; - // return matrix - return new DenseMatrix({ - data: c, - size: [arows, bcolumns], - datatype: dt - }); - } + var compile = { + name: name$55, + factory: factory_1$60 + }; - /** - * C = A * B - * - * @param {Matrix} a DenseMatrix (MxN) - * @param {Matrix} b SparseMatrix (NxC) - * - * @return {Matrix} SparseMatrix (MxC) - */ - function _multiplyDenseMatrixSparseMatrix (a, b) { - // a dense - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b sparse - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - // validate b matrix - if (!bvalues) - throw new Error('Cannot multiply Dense Matrix times Pattern only Matrix'); - // rows & columns - var arows = asize[0]; - var bcolumns = bsize[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - // equalScalar signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - } - - // result - var cvalues = []; - var cindex = []; - var cptr = []; - // c matrix - var c = new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, bcolumns], - datatype: dt - }); + function factory$62 (type, config, load, typed) { + var parse$$1 = load(parse); - // loop b columns - for (var jb = 0; jb < bcolumns; jb++) { - // update ptr - cptr[jb] = cindex.length; - // indeces in column jb - var kb0 = bptr[jb]; - var kb1 = bptr[jb + 1]; - // do not process column jb if no data exists - if (kb1 > kb0) { - // last row mark processed - var last = 0; - // loop a rows - for (var i = 0; i < arows; i++) { - // column mark - var mark = i + 1; - // C[i, jb] - var cij; - // values in b column j - for (var kb = kb0; kb < kb1; kb++) { - // row - var ib = bindex[kb]; - // check value has been initialized - if (last !== mark) { - // first value in column jb - cij = mf(adata[i][ib], bvalues[kb]); - // update mark - last = mark; - } - else { - // accumulate value - cij = af(cij, mf(adata[i][ib], bvalues[kb])); - } - } - // check column has been processed and value != 0 - if (last === mark && !eq(cij, zero)) { - // push row & value - cindex.push(i); - cvalues.push(cij); - } - } - } - } - // update ptr - cptr[bcolumns] = cindex.length; + /** + * Evaluate an expression. + * + * Note the evaluating arbitrary expressions may involve security risks, + * see [http://mathjs.org/docs/expressions/security.html](http://mathjs.org/docs/expressions/security.html) for more information. + * + * Syntax: + * + * math.eval(expr) + * math.eval(expr, scope) + * math.eval([expr1, expr2, expr3, ...]) + * math.eval([expr1, expr2, expr3, ...], scope) + * + * Example: + * + * math.eval('(2+3)/4'); // 1.25 + * math.eval('sqrt(3^2 + 4^2)'); // 5 + * math.eval('sqrt(-4)'); // 2i + * math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12] + * + * var scope = {a:3, b:4}; + * math.eval('a * b', scope); // 12 + * + * See also: + * + * parse, compile + * + * @param {string | string[] | Matrix} expr The expression to be evaluated + * @param {Object} [scope] Scope to read/write variables + * @return {*} The result of the expression + * @throws {Error} + */ + return typed('compile', { + 'string': function (expr) { + var scope = {}; + return parse$$1(expr).compile().eval(scope); + }, - // return sparse matrix - return c; - } + 'string, Object': function (expr, scope) { + return parse$$1(expr).compile().eval(scope); + }, - /** - * C = A * B - * - * @param {Matrix} a SparseMatrix (MxN) - * @param {Matrix} b Dense Vector (N) - * - * @return {Matrix} SparseMatrix (M, 1) - */ - function _multiplySparseMatrixVector(a, b) { - // a sparse - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var adt = a._datatype; - // validate a matrix - if (!avalues) - throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix'); - // b dense - var bdata = b._data; - var bdt = b._datatype; - // rows & columns - var arows = a._size[0]; - var brows = b._size[0]; - // result - var cvalues = []; - var cindex = []; - var cptr = []; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - // equalScalar signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - } - - // workspace - var x = []; - // vector with marks indicating a value x[i] exists in a given column - var w = []; - - // update ptr - cptr[0] = 0; - // rows in b - for (var ib = 0; ib < brows; ib++) { - // b[ib] - var vbi = bdata[ib]; - // check b[ib] != 0, avoid loops - if (!eq(vbi, zero)) { - // A values & index in ib column - for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // a row - var ia = aindex[ka]; - // check value exists in current j - if (!w[ia]) { - // ia is new entry in j - w[ia] = true; - // add i to pattern of C - cindex.push(ia); - // x(ia) = A - x[ia] = mf(vbi, avalues[ka]); - } - else { - // i exists in C already - x[ia] = af(x[ia], mf(vbi, avalues[ka])); - } - } - } - } - // copy values from x to column jb of c - for (var p1 = cindex.length, p = 0; p < p1; p++) { - // row - var ic = cindex[p]; - // copy value - cvalues[p] = x[ic]; - } - // update ptr - cptr[1] = cindex.length; + 'Array | Matrix': function (expr) { + var scope = {}; + return deepMap(expr, function (entry) { + return parse$$1(entry).compile().eval(scope); + }); + }, - // return sparse matrix - return new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, 1], - datatype: dt + 'Array | Matrix, Object': function (expr, scope) { + return deepMap(expr, function (entry) { + return parse$$1(entry).compile().eval(scope); + }); + } }); } - /** - * C = A * B - * - * @param {Matrix} a SparseMatrix (MxN) - * @param {Matrix} b DenseMatrix (NxC) - * - * @return {Matrix} SparseMatrix (MxC) - */ - function _multiplySparseMatrixDenseMatrix(a, b) { - // a sparse - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var adt = a._datatype; - // validate a matrix - if (!avalues) - throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix'); - // b dense - var bdata = b._data; - var bdt = b._datatype; - // rows & columns - var arows = a._size[0]; - var brows = b._size[0]; - var bcolumns = b._size[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - // equalScalar signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - } - - // result - var cvalues = []; - var cindex = []; - var cptr = []; - // c matrix - var c = new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, bcolumns], - datatype: dt - }); - - // workspace - var x = []; - // vector with marks indicating a value x[i] exists in a given column - var w = []; + var name$56 = 'eval'; + var factory_1$61 = factory$62; - // loop b columns - for (var jb = 0; jb < bcolumns; jb++) { - // update ptr - cptr[jb] = cindex.length; - // mark in workspace for current column - var mark = jb + 1; - // rows in jb - for (var ib = 0; ib < brows; ib++) { - // b[ib, jb] - var vbij = bdata[ib][jb]; - // check b[ib, jb] != 0, avoid loops - if (!eq(vbij, zero)) { - // A values & index in ib column - for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // a row - var ia = aindex[ka]; - // check value exists in current j - if (w[ia] !== mark) { - // ia is new entry in j - w[ia] = mark; - // add i to pattern of C - cindex.push(ia); - // x(ia) = A - x[ia] = mf(vbij, avalues[ka]); - } - else { - // i exists in C already - x[ia] = af(x[ia], mf(vbij, avalues[ka])); - } - } - } - } - // copy values from x to column jb of c - for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) { - // row - var ic = cindex[p]; - // copy value - cvalues[p] = x[ic]; - } - } - // update ptr - cptr[bcolumns] = cindex.length; + var _eval$1 = { + name: name$56, + factory: factory_1$61 + }; - // return sparse matrix - return c; - } + var getSafeProperty$8 = customs.getSafeProperty; - /** - * C = A * B - * - * @param {Matrix} a SparseMatrix (MxN) - * @param {Matrix} b SparseMatrix (NxC) - * - * @return {Matrix} SparseMatrix (MxC) - */ - function _multiplySparseMatrixSparseMatrix(a, b) { - // a sparse - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var adt = a._datatype; - // b sparse - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bdt = b._datatype; - - // rows & columns - var arows = a._size[0]; - var bcolumns = b._size[1]; - // flag indicating both matrices (a & b) contain data - var values = avalues && bvalues; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - } - - // result - var cvalues = values ? [] : undefined; - var cindex = []; - var cptr = []; - // c matrix - var c = new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, bcolumns], - datatype: dt - }); + function factory$63 (type, config, load, typed, math) { + var docs = load(embeddedDocs); - // workspace - var x = values ? [] : undefined; - // vector with marks indicating a value x[i] exists in a given column - var w = []; - // variables - var ka, ka0, ka1, kb, kb0, kb1, ia, ib; - // loop b columns - for (var jb = 0; jb < bcolumns; jb++) { - // update ptr - cptr[jb] = cindex.length; - // mark in workspace for current column - var mark = jb + 1; - // B values & index in j - for (kb0 = bptr[jb], kb1 = bptr[jb + 1], kb = kb0; kb < kb1; kb++) { - // b row - ib = bindex[kb]; - // check we need to process values - if (values) { - // loop values in a[:,ib] - for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // row - ia = aindex[ka]; - // check value exists in current j - if (w[ia] !== mark) { - // ia is new entry in j - w[ia] = mark; - // add i to pattern of C - cindex.push(ia); - // x(ia) = A - x[ia] = mf(bvalues[kb], avalues[ka]); - } - else { - // i exists in C already - x[ia] = af(x[ia], mf(bvalues[kb], avalues[ka])); - } - } - } - else { - // loop values in a[:,ib] - for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // row - ia = aindex[ka]; - // check value exists in current j - if (w[ia] !== mark) { - // ia is new entry in j - w[ia] = mark; - // add i to pattern of C - cindex.push(ia); + /** + * Retrieve help on a function or data type. + * Help files are retrieved from the documentation in math.expression.docs. + * + * Syntax: + * + * math.help(search) + * + * Examples: + * + * console.log(math.help('sin').toString()); + * console.log(math.help(math.add).toString()); + * console.log(math.help(math.add).toJSON()); + * + * @param {Function | string | Object} search A function or function name + * for which to get help + * @return {Help} A help object + */ + return typed('help', { + 'any': function (search) { + var prop; + var name = search; + + if (typeof search !== 'string') { + for (prop in math) { + // search in functions and constants + if (math.hasOwnProperty(prop) && (search === math[prop])) { + name = prop; + break; } } + + /* TODO: implement help for data types + if (!text) { + // search data type + for (prop in math.type) { + if (math.type.hasOwnProperty(prop)) { + if (search === math.type[prop]) { + text = prop; + break; + } + } + } + } + */ } - } - // check we need to process matrix values (pattern matrix) - if (values) { - // copy values from x to column jb of c - for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) { - // row - var ic = cindex[p]; - // copy value - cvalues[p] = x[ic]; + + var doc = getSafeProperty$8(docs, name); + if (!doc) { + throw new Error('No documentation found on "' + name + '"'); } + return new type.Help(doc); } - } - // update ptr - cptr[bcolumns] = cindex.length; - - // return sparse matrix - return c; + }); } - multiply.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['multiply'] + '${args[1]}\\right)' - }; - - return multiply; -} + var math$9 = true; // request access to the math namespace as 5th argument of the factory function + var name$57 = 'help'; + var factory_1$62 = factory$63; -var name$71 = 'multiply'; -var factory_1$80 = factory$81; + var help$1 = { + math: math$9, + name: name$57, + factory: factory_1$62 + }; -var multiply$1 = { - name: name$71, - factory: factory_1$80 -}; + function factory$64 (type, config, load, typed) { + var parse$$1 = load(parse); -function factory$82 (type, config, load, typed) { - var latex$$1 = latex; + /** + * Parse an expression. Returns a node tree, which can be evaluated by + * invoking node.eval(); + * + * Note the evaluating arbitrary expressions may involve security risks, + * see [http://mathjs.org/docs/expressions/security.html](http://mathjs.org/docs/expressions/security.html) for more information. + * + * Syntax: + * + * math.parse(expr) + * math.parse(expr, options) + * math.parse([expr1, expr2, expr3, ...]) + * math.parse([expr1, expr2, expr3, ...], options) + * + * Example: + * + * var node = math.parse('sqrt(3^2 + 4^2)'); + * node.compile().eval(); // 5 + * + * var scope = {a:3, b:4} + * var node = math.parse('a * b'); // 12 + * var code = node.compile(); + * code.eval(scope); // 12 + * scope.a = 5; + * code.eval(scope); // 20 + * + * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); + * nodes[2].compile().eval(); // 12 + * + * See also: + * + * eval, compile + * + * @param {string | string[] | Matrix} expr Expression to be parsed + * @param {{nodes: Object}} [options] Available options: + * - `nodes` a set of custom nodes + * @return {Node | Node[]} node + * @throws {Error} + */ + return typed('parse', { + 'string | Array | Matrix': parse$$1, + 'string | Array | Matrix, Object': parse$$1 + }); + } - /** - * Inverse the sign of a value, apply a unary minus operation. - * - * For matrices, the function is evaluated element wise. Boolean values and - * strings will be converted to a number. For complex numbers, both real and - * complex value are inverted. - * - * Syntax: - * - * math.unaryMinus(x) - * - * Examples: - * - * math.unaryMinus(3.5); // returns -3.5 - * math.unaryMinus(-4.2); // returns 4.2 - * - * See also: - * - * add, subtract, unaryPlus - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Number to be inverted. - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Returns the value with inverted sign. - */ - var unaryMinus = typed('unaryMinus', { - 'number': function (x) { - return -x; - }, + var name$58 = 'parse'; + var factory_1$63 = factory$64; - 'Complex': function (x) { - return x.neg(); - }, + var parse$1 = { + name: name$58, + factory: factory_1$63 + }; - 'BigNumber': function (x) { - return x.neg(); - }, + var extend$1 = object.extend; - 'Fraction': function (x) { - return x.neg(); - }, - 'Unit': function (x) { - var res = x.clone(); - res.value = unaryMinus(x.value); - return res; - }, + function factory$65 (type, config, load, typed, math) { + var _parse = load(parse); - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since unaryMinus(0) = 0 - return deepMap(x, unaryMinus, true); + /** + * @constructor Parser + * Parser contains methods to evaluate or parse expressions, and has a number + * of convenience methods to get, set, and remove variables from memory. Parser + * keeps a scope containing variables in memory, which is used for all + * evaluations. + * + * Methods: + * var result = parser.eval(expr); // evaluate an expression + * var value = parser.get(name); // retrieve a variable from the parser + * var values = parser.getAll(); // retrieve all defined variables + * parser.set(name, value); // set a variable in the parser + * parser.remove(name); // clear a variable from the + * // parsers scope + * parser.clear(); // clear the parsers scope + * + * Example usage: + * var parser = new Parser(); + * // Note: there is a convenience method which can be used instead: + * // var parser = new math.parser(); + * + * // evaluate expressions + * parser.eval('sqrt(3^2 + 4^2)'); // 5 + * parser.eval('sqrt(-4)'); // 2i + * parser.eval('2 inch in cm'); // 5.08 cm + * parser.eval('cos(45 deg)'); // 0.7071067811865476 + * + * // define variables and functions + * parser.eval('x = 7 / 2'); // 3.5 + * parser.eval('x + 3'); // 6.5 + * parser.eval('function f(x, y) = x^y'); // f(x, y) + * parser.eval('f(2, 3)'); // 8 + * + * // get and set variables and functions + * var x = parser.get('x'); // 7 + * var f = parser.get('f'); // function + * var g = f(3, 2); // 9 + * parser.set('h', 500); + * var i = parser.eval('h / 2'); // 250 + * parser.set('hello', function (name) { + * return 'hello, ' + name + '!'; + * }); + * parser.eval('hello("user")'); // "hello, user!" + * + * // clear defined functions and variables + * parser.clear(); + * + */ + function Parser() { + if (!(this instanceof Parser)) { + throw new SyntaxError( + 'Constructor must be called with the new operator'); + } + this.scope = {}; } - // TODO: add support for string - }); + /** + * Attach type information + */ + Parser.prototype.type = 'Parser'; + Parser.prototype.isParser = true; - unaryMinus.toTex = { - 1: latex$$1.operators['unaryMinus'] + '\\left(${args[0]}\\right)' - }; + /** + * Parse an expression and return the parsed function node. + * The node tree can be compiled via `code = node.compile(math)`, + * and the compiled code can be executed as `code.eval([scope])` + * @param {string} expr + * @return {Node} node + * @throws {Error} + */ + Parser.prototype.parse = function (expr) { + throw new Error('Parser.parse is deprecated. Use math.parse instead.'); + }; - return unaryMinus; -} + /** + * Parse and compile an expression, return the compiled javascript code. + * The node can be evaluated via code.eval([scope]) + * @param {string} expr + * @return {{eval: function}} code + * @throws {Error} + */ + Parser.prototype.compile = function (expr) { + throw new Error('Parser.compile is deprecated. Use math.compile instead.'); + }; -var name$72 = 'unaryMinus'; -var factory_1$81 = factory$82; + /** + * Parse and evaluate the given expression + * @param {string} expr A string containing an expression, for example "2+3" + * @return {*} result The result, or undefined when the expression was empty + * @throws {Error} + */ + Parser.prototype.eval = function (expr) { + // TODO: validate arguments + return _parse(expr) + .compile() + .eval(this.scope); + }; -var unaryMinus$1 = { - name: name$72, - factory: factory_1$81 -}; + /** + * Get a variable (a function or variable) by name from the parsers scope. + * Returns undefined when not found + * @param {string} name + * @return {* | undefined} value + */ + Parser.prototype.get = function (name) { + // TODO: validate arguments + return name in this.scope + ? customs.getSafeProperty(this.scope, name) + : undefined; + }; -function factory$83 (type, config, load, typed) { + /** + * Get a map with all defined variables + * @return {Object} values + */ + Parser.prototype.getAll = function () { + return extend$1({}, this.scope); + }; - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; + /** + * Set a symbol (a function or variable) by name from the parsers scope. + * @param {string} name + * @param {* | undefined} value + */ + Parser.prototype.set = function (name, value) { + // TODO: validate arguments + return customs.setSafeProperty(this.scope, name, value); + }; - /** - * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). - * Callback function invoked MAX(NNZA, NNZB) times - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 || B(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm05 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = avalues && bvalues ? [] : undefined; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - - // workspaces - var xa = cvalues ? [] : undefined; - var xb = cvalues ? [] : undefined; - // marks indicating we have a value in x for a given column - var wa = []; - var wb = []; + /** + * Remove a variable from the parsers scope + * @param {string} name + */ + Parser.prototype.remove = function (name) { + // TODO: validate arguments + delete this.scope[name]; + }; - // vars - var i, j, k, k1; - - // loop columns - for (j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // columns mark - var mark = j + 1; - // loop values A(:,j) - for (k = aptr[j], k1 = aptr[j + 1]; k < k1; k++) { - // row - i = aindex[k]; - // push index - cindex.push(i); - // update workspace - wa[i] = mark; - // check we need to process values - if (xa) - xa[i] = avalues[k]; - } - // loop values B(:,j) - for (k = bptr[j], k1 = bptr[j + 1]; k < k1; k++) { - // row - i = bindex[k]; - // check row existed in A - if (wa[i] !== mark) { - // push index - cindex.push(i); + /** + * Clear the scope with variables and functions + */ + Parser.prototype.clear = function () { + for (var name in this.scope) { + if (this.scope.hasOwnProperty(name)) { + delete this.scope[name]; } - // update workspace - wb[i] = mark; - // check we need to process values - if (xb) - xb[i] = bvalues[k]; } - // check we need to process values (non pattern matrix) - if (cvalues) { - // initialize first index in j - k = cptr[j]; - // loop index in j - while (k < cindex.length) { - // row - i = cindex[k]; - // marks - var wai = wa[i]; - var wbi = wb[i]; - // check Aij or Bij are nonzero - if (wai === mark || wbi === mark) { - // matrix values @ i,j - var va = wai === mark ? xa[i] : zero; - var vb = wbi === mark ? xb[i] : zero; - // Cij - var vc = cf(va, vb); - // check for zero - if (!eq(vc, zero)) { - // push value - cvalues.push(vc); - // increment pointer - k++; - } - else { - // remove value @ i, do not increment pointer - cindex.splice(k, 1); - } - } - } + }; + + return Parser; + } + + var name$59 = 'Parser'; + var path$30 = 'expression'; + var factory_1$64 = factory$65; + var math$10 = true; // requires the math namespace as 5th argument + + var Parser = { + name: name$59, + path: path$30, + factory: factory_1$64, + math: math$10 + }; + + function factory$66 (type, config, load, typed, math) { + var Parser$$1 = load(Parser); + + /** + * Create a parser. The function creates a new `math.expression.Parser` object. + * + * Syntax: + * + * math.parser() + * + * Examples: + * + * var parser = new math.parser(); + * + * // evaluate expressions + * var a = parser.eval('sqrt(3^2 + 4^2)'); // 5 + * var b = parser.eval('sqrt(-4)'); // 2i + * var c = parser.eval('2 inch in cm'); // 5.08 cm + * var d = parser.eval('cos(45 deg)'); // 0.7071067811865476 + * + * // define variables and functions + * parser.eval('x = 7 / 2'); // 3.5 + * parser.eval('x + 3'); // 6.5 + * parser.eval('function f(x, y) = x^y'); // f(x, y) + * parser.eval('f(2, 3)'); // 8 + * + * // get and set variables and functions + * var x = parser.get('x'); // 7 + * var f = parser.get('f'); // function + * var g = f(3, 2); // 9 + * parser.set('h', 500); + * var i = parser.eval('h / 2'); // 250 + * parser.set('hello', function (name) { + * return 'hello, ' + name + '!'; + * }); + * parser.eval('hello("user")'); // "hello, user!" + * + * // clear defined functions and variables + * parser.clear(); + * + * See also: + * + * eval, compile, parse + * + * @return {Parser} Parser + */ + return typed('parser', { + '': function () { + return new Parser$$1(math); } - } - // update cptr - cptr[columns] = cindex.length; + }); + } + + var name$60 = 'parser'; + var factory_1$65 = factory$66; + var math$11 = true; // requires the math namespace as 5th argument - // return sparse matrix - return c; + var parser = { + name: name$60, + factory: factory_1$65, + math: math$11 }; - return algorithm05; -} + var _function$2 = [ + compile, + _eval$1, + help$1, + parse$1, + parser + ]; -var name$73 = 'algorithm05'; -var factory_1$82 = factory$83; + function factory$67 (type, config, load, typed) { + /** + * @constructor UpdateNode + */ + function UpdateNode() { + // TODO: deprecated since v3. Cleanup some day + throw new Error('UpdateNode is deprecated. Use AssignmentNode instead.'); + } + + return UpdateNode; + } + + var name$61 = 'UpdateNode'; + var path$31 = 'expression.node'; + var factory_1$66 = factory$67; + + var UpdateNode = { + name: name$61, + path: path$31, + factory: factory_1$66 + }; + + var node = [ + AccessorNode, + ArrayNode, + AssignmentNode, + BlockNode, + ConditionalNode, + ConstantNode, + IndexNode, + FunctionAssignmentNode, + FunctionNode, + Node, + ObjectNode, + OperatorNode, + ParenthesisNode, + RangeNode, + SymbolNode, + UpdateNode + ]; -var algorithm05 = { - name: name$73, - factory: factory_1$82 -}; + var clone$4 = object.clone; + var isInteger$4 = number.isInteger; -function factory$84 (type, config, load, typed) { - var latex$$1 = latex; - var matrix$$1 = load(matrix); - var addScalar$$1 = load(addScalar); - var unaryMinus = load(unaryMinus$1); - var algorithm01$$1 = load(algorithm01); - var algorithm03$$1 = load(algorithm03); - var algorithm05$$1 = load(algorithm05); - var algorithm10$$1 = load(algorithm10); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - // TODO: split function subtract in two: subtract and subtractScalar + function factory$68 (type, config, load, typed) { + var matrix$$1 = load(matrix); - /** - * Subtract two values, `x - y`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.subtract(x, y) - * - * Examples: - * - * math.subtract(5.3, 2); // returns number 3.3 - * - * var a = math.complex(2, 3); - * var b = math.complex(4, 1); - * math.subtract(a, b); // returns Complex -2 + 2i - * - * math.subtract([5, 7, 4], 4); // returns Array [1, 3, 0] - * - * var c = math.unit('2.1 km'); - * var d = math.unit('500m'); - * math.subtract(c, d); // returns Unit 1.6 km - * - * See also: - * - * add - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x - * Initial value - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y - * Value to subtract from `x` - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} - * Subtraction of `x` and `y` - */ - var subtract = typed('subtract', { + /** + * Concatenate two or more matrices. + * + * Syntax: + * + * math.concat(A, B, C, ...) + * math.concat(A, B, C, ..., dim) + * + * Where: + * + * - `dim: number` is a zero-based dimension over which to concatenate the matrices. + * By default the last dimension of the matrices. + * + * Examples: + * + * var A = [[1, 2], [5, 6]]; + * var B = [[3, 4], [7, 8]]; + * + * math.concat(A, B); // returns [[1, 2, 3, 4], [5, 6, 7, 8]] + * math.concat(A, B, 0); // returns [[1, 2], [5, 6], [3, 4], [7, 8]] + * math.concat('hello', ' ', 'world'); // returns 'hello world' + * + * See also: + * + * size, squeeze, subset, transpose + * + * @param {... Array | Matrix} args Two or more matrices + * @return {Array | Matrix} Concatenated matrix + */ + var concat = typed('concat', { + // TODO: change signature to '...Array | Matrix, dim?' when supported + '...Array | Matrix | number | BigNumber': function (args) { + var i; + var len = args.length; + var dim = -1; // zero-based dimension + var prevDim; + var asMatrix = false; + var matrices = []; // contains multi dimensional arrays + + for (i = 0; i < len; i++) { + var arg = args[i]; + + // test whether we need to return a Matrix (if not we return an Array) + if (type.isMatrix(arg)) { + asMatrix = true; + } - 'number, number': function (x, y) { - return x - y; - }, + if (type.isNumber(arg) || type.isBigNumber(arg)) { + if (i !== len - 1) { + throw new Error('Dimension must be specified as last argument'); + } - 'Complex, Complex': function (x, y) { - return x.sub(y); - }, + // last argument contains the dimension on which to concatenate + prevDim = dim; + dim = arg.valueOf(); // change BigNumber to number - 'BigNumber, BigNumber': function (x, y) { - return x.minus(y); - }, + if (!isInteger$4(dim)) { + throw new TypeError('Integer number expected for dimension'); + } - 'Fraction, Fraction': function (x, y) { - return x.sub(y); - }, + if (dim < 0 || (i > 0 && dim > prevDim)) { + // TODO: would be more clear when throwing a DimensionError here + throw new IndexError_1(dim, prevDim + 1); + } + } + else { + // this is a matrix or array + var m = clone$4(arg).valueOf(); + var size = array.size(m); + matrices[i] = m; + prevDim = dim; + dim = size.length - 1; + + // verify whether each of the matrices has the same number of dimensions + if (i > 0 && dim != prevDim) { + throw new DimensionError_1(prevDim + 1, dim + 1); + } + } + } + + if (matrices.length == 0) { + throw new SyntaxError('At least one matrix expected'); + } + + var res = matrices.shift(); + while (matrices.length) { + res = _concat(res, matrices.shift(), dim, 0); + } + + return asMatrix ? matrix$$1(res) : res; + }, - 'Unit, Unit': function (x, y) { - if (x.value == null) { - throw new Error('Parameter x contains a unit with undefined value'); + '...string': function (args) { + return args.join(''); } + }); - if (y.value == null) { - throw new Error('Parameter y contains a unit with undefined value'); + concat.toTex = undefined; // use default template + + return concat; + } + + /** + * Recursively concatenate two matrices. + * The contents of the matrices is not cloned. + * @param {Array} a Multi dimensional array + * @param {Array} b Multi dimensional array + * @param {number} concatDim The dimension on which to concatenate (zero-based) + * @param {number} dim The current dim (zero-based) + * @return {Array} c The concatenated matrix + * @private + */ + function _concat(a, b, concatDim, dim) { + if (dim < concatDim) { + // recurse into next dimension + if (a.length != b.length) { + throw new DimensionError_1(a.length, b.length); } - if (!x.equalBase(y)) { - throw new Error('Units do not match'); + var c = []; + for (var i = 0; i < a.length; i++) { + c[i] = _concat(a[i], b[i], concatDim, dim + 1); } + return c; + } + else { + // concatenate this dimension + return a.concat(b); + } + } - var res = x.clone(); - res.value = subtract(res.value, y.value); - res.fixPrefix = false; + var name$62 = 'concat'; + var factory_1$67 = factory$68; - return res; - }, + var concat$1 = { + name: name$62, + factory: factory_1$67 + }; - 'SparseMatrix, SparseMatrix': function (x, y) { - checkEqualDimensions(x, y); - return algorithm05$$1(x, y, subtract); - }, + var errorTransform$2 = error_transform.transform; - 'SparseMatrix, DenseMatrix': function (x, y) { - checkEqualDimensions(x, y); - return algorithm03$$1(y, x, subtract, true); - }, + /** + * Attach a transform function to math.range + * Adds a property transform containing the transform function. + * + * This transform changed the last `dim` parameter of function concat + * from one-based to zero based + */ + function factory$69 (type, config, load, typed) { + var concat = load(concat$1); - 'DenseMatrix, SparseMatrix': function (x, y) { - checkEqualDimensions(x, y); - return algorithm01$$1(x, y, subtract, false); - }, + // @see: comment of concat itself + return typed('concat', { + '...any': function (args) { + // change last argument from one-based to zero-based + var lastIndex = args.length - 1; + var last = args[lastIndex]; + if (type.isNumber(last)) { + args[lastIndex] = last - 1; + } + else if (type.isBigNumber(last)) { + args[lastIndex] = last.minus(1); + } - 'DenseMatrix, DenseMatrix': function (x, y) { - checkEqualDimensions(x, y); - return algorithm13$$1(x, y, subtract); - }, + try { + return concat.apply(null, args); + } + catch (err) { + throw errorTransform$2(err); + } + } + }); + } - 'Array, Array': function (x, y) { - // use matrix implementation - return subtract(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + var name$63 = 'concat'; + var path$32 = 'expression.transform'; + var factory_1$68 = factory$69; - 'Array, Matrix': function (x, y) { - // use matrix implementation - return subtract(matrix$$1(x), y); - }, + var concat_transform = { + name: name$63, + path: path$32, + factory: factory_1$68 + }; - 'Matrix, Array': function (x, y) { - // use matrix implementation - return subtract(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm10$$1(x, unaryMinus(y), addScalar$$1); - }, + function factory$70 (type, config, load, typed) { + /** + * Compile an inline expression like "x > 0" + * @param {Node} expression + * @param {Object} math + * @param {Object} scope + * @return {function} Returns a function with one argument which fills in the + * undefined variable (like "x") and evaluates the expression + */ + return function compileInlineExpression(expression, math, scope) { + // find an undefined symbol + var symbol = expression.filter(function (node) { + return type.isSymbolNode(node) && + !(node.name in math) && + !(node.name in scope); + })[0]; + + if (!symbol) { + throw new Error('No undefined variable found in inline expression "' + expression + '"'); + } + + // create a test function for this equation + var name = symbol.name; // variable name + var subScope = Object.create(scope); + var eq = expression.compile(); + return function inlineExpression(x) { + subScope[name] = x; + return eq.eval(subScope); + } + }; + } - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, subtract); - }, + var factory_1$69 = factory$70; - 'any, SparseMatrix': function (x, y) { - return algorithm10$$1(y, x, subtract, true); - }, + var compileInlineExpression = { + factory: factory_1$69 + }; - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, subtract, true); - }, + var filter$1 = array.filter; + var filterRegExp = array.filterRegExp; + var maxArgumentCount$1 = _function.maxArgumentCount; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, subtract, false).valueOf(); - }, + /** + * Attach a transform function to math.filter + * Adds a property transform containing the transform function. + * + * This transform adds support for equations as test function for math.filter, + * so you can do something like 'filter([3, -2, 5], x > 0)'. + */ + function factory$71 (type, config, load, typed) { + var compileInlineExpression$$1 = load(compileInlineExpression); + var matrix$$1 = load(matrix); + + function filterTransform(args, math, scope) { + var x, callback; + + if (args[0]) { + x = args[0].compile().eval(scope); + } + + if (args[1]) { + if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { + // a function pointer, like filter([3, -2, 5], myTestFunction); + callback = args[1].compile().eval(scope); + } + else { + // an expression like filter([3, -2, 5], x > 0) + callback = compileInlineExpression$$1(args[1], math, scope); + } + } - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, subtract, true).valueOf(); + return filter(x, callback); } - }); + filterTransform.rawArgs = true; - subtract.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['subtract'] + '${args[1]}\\right)' - }; + // one based version of function filter + var filter = typed('filter', { + 'Array, function': _filter, - return subtract; -} + 'Matrix, function': function (x, test) { + return matrix$$1(_filter(x.toArray(), test)); + }, -/** - * Check whether matrix x and y have the same number of dimensions. - * Throws a DimensionError when dimensions are not equal - * @param {Matrix} x - * @param {Matrix} y - */ -function checkEqualDimensions(x, y) { - var xsize = x.size(); - var ysize = y.size(); + 'Array, RegExp': filterRegExp, - if (xsize.length !== ysize.length) { - throw new DimensionError_1(xsize.length, ysize.length); - } -} + 'Matrix, RegExp': function (x, test) { + return matrix$$1(filterRegExp(x.toArray(), test)); + } + }); -var name$74 = 'subtract'; -var factory_1$83 = factory$84; + filter.toTex = undefined; // use default template -var subtract$1 = { - name: name$74, - factory: factory_1$83 -}; + return filterTransform; + } -function factory$85 (type, config, load, typed) { /** - * Calculate the absolute value of a number. For matrices, the function is - * evaluated element wise. - * - * Syntax: + * Filter values in a callback given a callback function * - * math.abs(x) + * !!! Passes a one-based index !!! * - * Examples: - * - * math.abs(3.5); // returns number 3.5 - * math.abs(-4.2); // returns number 4.2 - * - * math.abs([3, -5, -1, 0, 2]); // returns Array [3, 5, 1, 0, 2] - * - * See also: - * - * sign - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x - * A number or matrix for which to get the absolute value - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} - * Absolute value of `x` + * @param {Array} x + * @param {Function} callback + * @return {Array} Returns the filtered array + * @private */ - var abs = typed('abs', { - 'number': Math.abs, + function _filter (x, callback) { + // figure out what number of arguments the callback function expects + var args = maxArgumentCount$1(callback); - 'Complex': function (x) { - return x.abs(); - }, - - 'BigNumber': function (x) { - return x.abs(); - }, + return filter$1(x, function (value, index, array$$1) { + // invoke the callback function with the right number of arguments + if (args === 1) { + return callback(value); + } + else if (args === 2) { + return callback(value, [index + 1]); + } + else { // 3 or -1 + return callback(value, [index + 1], array$$1); + } + }); + } - 'Fraction': function (x) { - return x.abs(); - }, + var name$64 = 'filter'; + var path$33 = 'expression.transform'; + var factory_1$70 = factory$71; - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since abs(0) = 0 - return deepMap(x, abs, true); - }, + var filter_transform = { + name: name$64, + path: path$33, + factory: factory_1$70 + }; - 'Unit': function(x) { - return x.abs(); - } - }); + var maxArgumentCount$2 = _function.maxArgumentCount; + var forEach$3 = array.forEach; - abs.toTex = {1: '\\left|${args[0]}\\right|'}; - - return abs; -} - -var name$75 = 'abs'; -var factory_1$84 = factory$85; - -var abs$1 = { - name: name$75, - factory: factory_1$84 -}; - -var object$4 = utils.object; - -function factory$86 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var abs = load(abs$1); - var addScalar$$1 = load(addScalar); - var divideScalar$$1 = load(divideScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var subtract = load(subtract$1); - var larger$$1 = load(larger); - var equalScalar$$1 = load(equalScalar); - var unaryMinus = load(unaryMinus$1); - - var SparseMatrix = type.SparseMatrix; - var DenseMatrix = type.DenseMatrix; - var Spa = type.Spa; - /** - * Calculate the Matrix LU decomposition with partial pivoting. Matrix `A` is decomposed in two matrices (`L`, `U`) and a - * row permutation vector `p` where `A[p,:] = L * U` - * - * Syntax: - * - * math.lup(A); - * - * Example: - * - * var m = [[2, 1], [1, 4]]; - * var r = math.lup(m); - * // r = { - * // L: [[1, 0], [0.5, 1]], - * // U: [[2, 1], [0, 3.5]], - * // P: [0, 1] - * // } + * Attach a transform function to math.forEach + * Adds a property transform containing the transform function. * - * See also: - * - * slu, lsolve, lusolve, usolve - * - * @param {Matrix | Array} A A two dimensional matrix or array for which to get the LUP decomposition. - * - * @return {{L: Array | Matrix, U: Array | Matrix, P: Array.}} The lower triangular matrix, the upper triangular matrix and the permutation matrix. + * This transform creates a one-based index instead of a zero-based index */ - var lup = typed('lup', { + function factory$72 (type, config, load, typed) { + var compileInlineExpression$$1 = load(compileInlineExpression); - 'DenseMatrix': function (m) { - return _denseLUP(m); - }, - - 'SparseMatrix': function (m) { - return _sparseLUP(m); - }, + function forEachTransform(args, math, scope) { + var x, callback; - 'Array': function (a) { - // create dense matrix from array - var m = matrix$$1(a); - // lup, use matrix implementation - var r = _denseLUP(m); - // result - return { - L: r.L.valueOf(), - U: r.U.valueOf(), - p: r.p - }; - } - }); + if (args[0]) { + x = args[0].compile().eval(scope); + } - var _denseLUP = function (m) { - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // minimum rows and columns - var n = Math.min(rows, columns); - // matrix array, clone original data - var data = object$4.clone(m._data); - // l matrix arrays - var ldata = []; - var lsize = [rows, n]; - // u matrix arrays - var udata = []; - var usize = [n, columns]; - // vars - var i, j, k; - // permutation vector - var p = []; - for (i = 0; i < rows; i++) - p[i] = i; - // loop columns - for (j = 0; j < columns; j++) { - // skip first column in upper triangular matrix - if (j > 0) { - // loop rows - for (i = 0; i < rows; i++) { - // min i,j - var min = Math.min(i, j); - // v[i, j] - var s = 0; - // loop up to min - for (k = 0; k < min; k++) { - // s = l[i, k] - data[k, j] - s = addScalar$$1(s, multiplyScalar$$1(data[i][k], data[k][j])); - } - data[i][j] = subtract(data[i][j], s); - } - } - // row with larger value in cvector, row >= j - var pi = j; - var pabsv = 0; - var vjj = 0; - // loop rows - for (i = j; i < rows; i++) { - // data @ i, j - var v = data[i][j]; - // absolute value - var absv = abs(v); - // value is greater than pivote value - if (larger$$1(absv, pabsv)) { - // store row - pi = i; - // update max value - pabsv = absv; - // value @ [j, j] - vjj = v; + if (args[1]) { + if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { + // a function pointer, like forEach([3, -2, 5], myTestFunction); + callback = args[1].compile().eval(scope); } - } - // swap rows (j <-> pi) - if (j !== pi) { - // swap values j <-> pi in p - p[j] = [p[pi], p[pi] = p[j]][0]; - // swap j <-> pi in data - DenseMatrix._swapRows(j, pi, data); - } - // check column is in lower triangular matrix - if (j < rows) { - // loop rows (lower triangular matrix) - for (i = j + 1; i < rows; i++) { - // value @ i, j - var vij = data[i][j]; - if (!equalScalar$$1(vij, 0)) { - // update data - data[i][j] = divideScalar$$1(data[i][j], vjj); - } + else { + // an expression like forEach([3, -2, 5], x > 0 ? callback1(x) : callback2(x) ) + callback = compileInlineExpression$$1(args[1], math, scope); } } + + return _forEach(x, callback); } - // loop columns - for (j = 0; j < columns; j++) { - // loop rows - for (i = 0; i < rows; i++) { - // initialize row in arrays - if (j === 0) { - // check row exists in upper triangular matrix - if (i < columns) { - // U - udata[i] = []; - } - // L - ldata[i] = []; - } - // check we are in the upper triangular matrix - if (i < j) { - // check row exists in upper triangular matrix - if (i < columns) { - // U - udata[i][j] = data[i][j]; + forEachTransform.rawArgs = true; + + // one-based version of forEach + var _forEach = typed('forEach', { + 'Array | Matrix, function': function (array$$1, callback) { + // figure out what number of arguments the callback function expects + var args = maxArgumentCount$2(callback); + + var recurse = function (value, index) { + if (Array.isArray(value)) { + forEach$3(value, function (child, i) { + // we create a copy of the index array and append the new index value + recurse(child, index.concat(i + 1)); // one based index, hence i+1 + }); } - // check column exists in lower triangular matrix - if (j < rows) { - // L - ldata[i][j] = 0; + else { + // invoke the callback function with the right number of arguments + if (args === 1) { + callback(value); + } + else if (args === 2) { + callback(value, index); + } + else { // 3 or -1 + callback(value, index, array$$1); + } } - continue; + }; + recurse(array$$1.valueOf(), []); // pass Array + } + }); + + return forEachTransform; + } + + var name$65 = 'forEach'; + var path$34 = 'expression.transform'; + var factory_1$71 = factory$72; + + var forEach_transform = { + name: name$65, + path: path$34, + factory: factory_1$71 + }; + + /** + * Attach a transform function to math.index + * Adds a property transform containing the transform function. + * + * This transform creates a one-based index instead of a zero-based index + */ + function factory$73 (type, config, load) { + + return function indexTransform() { + var args = []; + for (var i = 0, ii = arguments.length; i < ii; i++) { + var arg = arguments[i]; + + // change from one-based to zero based, and convert BigNumber to number + if (type.isRange(arg)) { + arg.start--; + arg.end -= (arg.step > 0 ? 0 : 2); } - // diagonal value - if (i === j) { - // check row exists in upper triangular matrix - if (i < columns) { - // U - udata[i][j] = data[i][j]; - } - // check column exists in lower triangular matrix - if (j < rows) { - // L - ldata[i][j] = 1; - } - continue; + else if (arg && arg.isSet === true) { + arg = arg.map(function (v) { return v - 1; }); } - // check row exists in upper triangular matrix - if (i < columns) { - // U - udata[i][j] = 0; + else if (type.isArray(arg) || type.isMatrix(arg)) { + arg = arg.map(function (v) { return v - 1; }); } - // check column exists in lower triangular matrix - if (j < rows) { - // L - ldata[i][j] = data[i][j]; + else if (type.isNumber(arg)) { + arg--; } - } - } - // l matrix - var l = new DenseMatrix({ - data: ldata, - size: lsize - }); - // u matrix - var u = new DenseMatrix({ - data: udata, - size: usize - }); - // p vector - var pv = []; - for (i = 0, n = p.length; i < n; i++) - pv[p[i]] = i; - // return matrices - return { - L: l, - U: u, - p: pv, - toString: function () { - return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\nP: ' + this.p; - } - }; - }; - - var _sparseLUP = function (m) { - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // minimum rows and columns - var n = Math.min(rows, columns); - // matrix arrays (will not be modified, thanks to permutation vector) - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // l matrix arrays - var lvalues = []; - var lindex = []; - var lptr = []; - var lsize = [rows, n]; - // u matrix arrays - var uvalues = []; - var uindex = []; - var uptr = []; - var usize = [n, columns]; - // vars - var i, j, k; - // permutation vectors, (current index -> original index) and (original index -> current index) - var pv_co = []; - var pv_oc = []; - for (i = 0; i < rows; i++) { - pv_co[i] = i; - pv_oc[i] = i; - } - // swap indices in permutation vectors (condition x < y)! - var swapIndeces = function (x, y) { - // find pv indeces getting data from x and y - var kx = pv_oc[x]; - var ky = pv_oc[y]; - // update permutation vector current -> original - pv_co[kx] = y; - pv_co[ky] = x; - // update permutation vector original -> current - pv_oc[x] = ky; - pv_oc[y] = kx; - }; - // loop columns - for (j = 0; j < columns; j++) { - // sparse accumulator - var spa = new Spa(); - // check lower triangular matrix has a value @ column j - if (j < rows) { - // update ptr - lptr.push(lvalues.length); - // first value in j column for lower triangular matrix - lvalues.push(1); - lindex.push(j); - } - // update ptr - uptr.push(uvalues.length); - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // copy column j into sparse accumulator - for (k = k0; k < k1; k++) { - // row - i = index[k]; - // copy column values into sparse accumulator (use permutation vector) - spa.set(pv_co[i], values[k]); - } - // skip first column in upper triangular matrix - if (j > 0) { - // loop rows in column j (above diagonal) - spa.forEach(0, j - 1, function (k, vkj) { - // loop rows in column k (L) - SparseMatrix._forEachRow(k, lvalues, lindex, lptr, function (i, vik) { - // check row is below k - if (i > k) { - // update spa value - spa.accumulate(i, unaryMinus(multiplyScalar$$1(vik, vkj))); - } - }); - }); - } - // row with larger value in spa, row >= j - var pi = j; - var vjj = spa.get(j); - var pabsv = abs(vjj); - // loop values in spa (order by row, below diagonal) - spa.forEach(j + 1, rows - 1, function (x, v) { - // absolute value - var absv = abs(v); - // value is greater than pivote value - if (larger$$1(absv, pabsv)) { - // store row - pi = x; - // update max value - pabsv = absv; - // value @ [j, j] - vjj = v; + else if (type.isBigNumber(arg)) { + arg = arg.toNumber() - 1; } - }); - // swap rows (j <-> pi) - if (j !== pi) { - // swap values j <-> pi in L - SparseMatrix._swapRows(j, pi, lsize[1], lvalues, lindex, lptr); - // swap values j <-> pi in U - SparseMatrix._swapRows(j, pi, usize[1], uvalues, uindex, uptr); - // swap values in spa - spa.swap(j, pi); - // update permutation vector (swap values @ j, pi) - swapIndeces(j, pi); - } - // loop values in spa (order by row) - spa.forEach(0, rows - 1, function (x, v) { - // check we are above diagonal - if (x <= j) { - // update upper triangular matrix - uvalues.push(v); - uindex.push(x); + else if (typeof arg === 'string') { + // leave as is } else { - // update value - v = divideScalar$$1(v, vjj); - // check value is non zero - if (!equalScalar$$1(v, 0)) { - // update lower triangular matrix - lvalues.push(v); - lindex.push(x); - } + throw new TypeError('Dimension must be an Array, Matrix, number, string, or Range'); } - }); - } - // update ptrs - uptr.push(uvalues.length); - lptr.push(lvalues.length); - // return matrices - return { - L: new SparseMatrix({ - values: lvalues, - index: lindex, - ptr: lptr, - size: lsize - }), - U: new SparseMatrix({ - values: uvalues, - index: uindex, - ptr: uptr, - size: usize - }), - p: pv_co, - toString: function () { - return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\nP: ' + this.p; + args[i] = arg; } - }; - }; - - return lup; -} -var name$76 = 'lup'; -var factory_1$85 = factory$86; + var res = new type.Index(); + type.Index.apply(res, args); + return res; + }; + } -var lup$1 = { - name: name$76, - factory: factory_1$85 -}; + var name$66 = 'index'; + var path$35 = 'expression.transform'; + var factory_1$72 = factory$73; -var object$5 = utils.object; -var string$8 = utils.string; + var index_transform = { + name: name$66, + path: path$35, + factory: factory_1$72 + }; -function factory$87 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var add$$1 = load(add); - var subtract = load(subtract$1); - var multiply = load(multiply$1); - var unaryMinus = load(unaryMinus$1); - var lup = load(lup$1); + var maxArgumentCount$3 = _function.maxArgumentCount; + var map$6 = array.map; /** - * Calculate the determinant of a matrix. - * - * Syntax: - * - * math.det(x) - * - * Examples: - * - * math.det([[1, 2], [3, 4]]); // returns -2 - * - * var A = [ - * [-2, 2, 3], - * [-1, 1, 3], - * [2, 0, -1] - * ] - * math.det(A); // returns 6 + * Attach a transform function to math.map + * Adds a property transform containing the transform function. * - * See also: - * - * inv - * - * @param {Array | Matrix} x A matrix - * @return {number} The determinant of `x` + * This transform creates a one-based index instead of a zero-based index */ - var det = typed('det', { - 'any': function (x) { - return object$5.clone(x); - }, + function factory$74 (type, config, load, typed) { + var compileInlineExpression$$1 = load(compileInlineExpression); + var matrix$$1 = load(matrix); - 'Array | Matrix': function det (x) { - var size; - if (type.isMatrix(x)) { - size = x.size(); - } - else if (Array.isArray(x)) { - x = matrix$$1(x); - size = x.size(); - } - else { - // a scalar - size = []; + function mapTransform(args, math, scope) { + var x, callback; + + if (args[0]) { + x = args[0].compile().eval(scope); } - switch (size.length) { - case 0: - // scalar - return object$5.clone(x); + if (args[1]) { + if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { + // a function pointer, like filter([3, -2, 5], myTestFunction); + callback = args[1].compile().eval(scope); + } + else { + // an expression like filter([3, -2, 5], x > 0) + callback = compileInlineExpression$$1(args[1], math, scope); + } + } - case 1: - // vector - if (size[0] == 1) { - return object$5.clone(x.valueOf()[0]); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string$8.format(size) + ')'); - } + return map(x, callback); + } + mapTransform.rawArgs = true; - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - return _det(x.clone().valueOf(), rows, cols); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string$8.format(size) + ')'); - } + // one-based version of map function + var map = typed('map', { + 'Array, function': function (x, callback) { + return _map(x, callback, x); + }, - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + string$8.format(size) + ')'); + 'Matrix, function': function (x, callback) { + return matrix$$1(_map(x.valueOf(), callback, x)); } - } - }); - - det.toTex = {1: '\\det\\left(${args[0]}\\right)'}; + }); - return det; + return mapTransform; + } /** - * Calculate the determinant of a matrix - * @param {Array[]} matrix A square, two dimensional matrix - * @param {number} rows Number of rows of the matrix (zero-based) - * @param {number} cols Number of columns of the matrix (zero-based) - * @returns {number} det + * Map for a multi dimensional array. One-based indexes + * @param {Array} array + * @param {function} callback + * @param {Array} orig + * @return {Array} * @private */ - function _det (matrix$$1, rows, cols) { - if (rows == 1) { - // this is a 1 x 1 matrix - return object$5.clone(matrix$$1[0][0]); - } - else if (rows == 2) { - // this is a 2 x 2 matrix - // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12 - return subtract( - multiply(matrix$$1[0][0], matrix$$1[1][1]), - multiply(matrix$$1[1][0], matrix$$1[0][1]) - ); - } - else { + function _map (array$$1, callback, orig) { + // figure out what number of arguments the callback function expects + var argsCount = maxArgumentCount$3(callback); - // Compute the LU decomposition - var decomp = lup(matrix$$1); - - // The determinant is the product of the diagonal entries of U (and those of L, but they are all 1) - var det = decomp.U[0][0]; - for(var i=1; i= rows) break; - var j=i; - var cycleLen = 0; - while(!visited[decomp.p[j]]) { - visited[decomp.p[j]] = true; - j = decomp.p[j]; - cycleLen++; + else if (argsCount === 2) { + return callback(value, index); } - if(cycleLen % 2 === 0) { - evenCycles++; + else { // 3 or -1 + return callback(value, index, orig); } } - - return evenCycles % 2 === 0 ? det : unaryMinus(det); - } + + return recurse(array$$1, []); } -} -var name$77 = 'det'; -var factory_1$86 = factory$87; + var name$67 = 'map'; + var path$36 = 'expression.transform'; + var factory_1$73 = factory$74; -var det$1 = { - name: name$77, - factory: factory_1$86 -}; + var map_transform = { + name: name$67, + path: path$36, + factory: factory_1$73 + }; -var isInteger$5 = number.isInteger; + /** + * Test whether a value is a collection: an Array or Matrix + * @param {*} x + * @returns {boolean} isCollection + */ + var isCollection = function isCollection (x) { + return Array.isArray(x) || isMatrix(x); + }; -function factory$88 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - /** - * Create a 2-dimensional identity matrix with size m x n or n x n. - * The matrix has ones on the diagonal and zeros elsewhere. - * - * Syntax: - * - * math.eye(n) - * math.eye(n, format) - * math.eye(m, n) - * math.eye(m, n, format) - * math.eye([m, n]) - * math.eye([m, n], format) - * - * Examples: - * - * math.eye(3); // returns [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - * math.eye(3, 2); // returns [[1, 0], [0, 1], [0, 0]] - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.eye(math.size(A)); // returns [[1, 0, 0], [0, 1, 0]] - * - * See also: - * - * diag, ones, zeros, size, range - * - * @param {...number | Matrix | Array} size The size for the matrix - * @param {string} [format] The Matrix storage format - * - * @return {Matrix | Array | number} A matrix with ones on the diagonal. + * Recursively loop over all elements in a given multi dimensional array + * and invoke the callback on each of the elements. + * @param {Array | Matrix} array + * @param {Function} callback The callback method is invoked with one + * parameter: the current element in the array */ - var eye = typed('eye', { - '': function () { - return (config.matrix === 'Matrix') ? matrix$$1([]) : []; - }, + var deepForEach = function deepForEach (array, callback) { + if (isMatrix(array)) { + array = array.valueOf(); + } - 'string': function (format) { - return matrix$$1(format); - }, + for (var i = 0, ii = array.length; i < ii; i++) { + var value = array[i]; - 'number | BigNumber': function (rows) { - return _eye(rows, rows, config.matrix === 'Matrix' ? 'default' : undefined); - }, - - 'number | BigNumber, string': function (rows, format) { - return _eye(rows, rows, format); - }, + if (Array.isArray(value)) { + deepForEach(value, callback); + } + else { + callback(value); + } + } + }; - 'number | BigNumber, number | BigNumber': function (rows, cols) { - return _eye(rows, cols, config.matrix === 'Matrix' ? 'default' : undefined); - }, - - 'number | BigNumber, number | BigNumber, string': function (rows, cols, format) { - return _eye(rows, cols, format); - }, + var arraySize = array.size; - 'Array': function (size) { - return _eyeVector(size); - }, - - 'Array, string': function (size, format) { - return _eyeVector(size, format); - }, - 'Matrix': function (size) { - return _eyeVector(size.valueOf(), size.storage()); - }, - - 'Matrix, string': function (size, format) { - return _eyeVector(size.valueOf(), format); + + /** + * Reduce a given matrix or array to a new matrix or + * array with one less dimension, applying the given + * callback in the selected dimension. + * @param {Array | Matrix} mat + * @param {number} dim + * @param {Function} callback + * @return {Array | Matrix} res + */ + var reduce = function(mat, dim, callback) { + var size = Array.isArray(mat) ? arraySize(mat) : mat.size(); + if (dim < 0 || (dim >= size.length)) { + // TODO: would be more clear when throwing a DimensionError here + throw new IndexError_1(dim, size.length); } - }); - eye.toTex = undefined; // use default template + if (isMatrix(mat)) { + return mat.create(_reduce(mat.valueOf(), dim, callback)); + }else { + return _reduce(mat, dim, callback); + } + }; - return eye; + /** + * Recursively reduce a matrix + * @param {Array} mat + * @param {number} dim + * @param {Function} callback + * @returns {Array} ret + * @private + */ + function _reduce(mat, dim, callback){ + var i, ret, val, tran; - function _eyeVector (size, format) { - switch (size.length) { - case 0: return format ? matrix$$1(format) : []; - case 1: return _eye(size[0], size[0], format); - case 2: return _eye(size[0], size[1], format); - default: throw new Error('Vector containing two values expected'); + if(dim<=0){ + if( !Array.isArray(mat[0]) ){ + val = mat[0]; + for(i=1; i 2 + ? ' (type: ' + getType(value) + ', value: ' + JSON.stringify(value) + ')' + : ' (type: ' + err.data.actual + ')'; + + return new TypeError('Cannot calculate ' + fnName + ', unexpected type of argument' + details); } - }, - 'any': function (x) { - // scalar - return divideScalar$$1(1, x); // FIXME: create a BigNumber one when configured for bignumbers - } - }); + if (String(err).indexOf('complex numbers') !== -1) { + details = arguments.length > 2 + ? ' (type: ' + getType(value) + ', value: ' + JSON.stringify(value) + ')' + : ''; - /** - * Calculate the inverse of a square matrix - * @param {Array[]} mat A square matrix - * @param {number} rows Number of rows - * @param {number} cols Number of columns, must equal rows - * @return {Array[]} inv Inverse matrix - * @private - */ - function _inv (mat, rows, cols){ - var r, s, f, value, temp; - - if (rows == 1) { - // this is a 1 x 1 matrix - value = mat[0][0]; - if (value == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [[ - divideScalar$$1(1, value) - ]]; - } - else if (rows == 2) { - // this is a 2 x 2 matrix - var d = det(mat); - if (d == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [ - [ - divideScalar$$1(mat[1][1], d), - divideScalar$$1(unaryMinus(mat[0][1]), d) - ], - [ - divideScalar$$1(unaryMinus(mat[1][0]), d), - divideScalar$$1(mat[0][0], d) - ] - ]; - } - else { - // this is a matrix of 3 x 3 or larger - // calculate inverse using gauss-jordan elimination - // http://en.wikipedia.org/wiki/Gaussian_elimination - // http://mathworld.wolfram.com/MatrixInverse.html - // http://math.uww.edu/~mcfarlat/inverse.htm - - // make a copy of the matrix (only the arrays, not of the elements) - var A = mat.concat(); - for (r = 0; r < rows; r++) { - A[r] = A[r].concat(); - } - - // create an identity matrix which in the end will contain the - // matrix inverse - var B = eye(rows).valueOf(); - - // loop over all columns, and perform row reductions - for (var c = 0; c < cols; c++) { - // Pivoting: Swap row c with row r, where row r contains the largest element A[r][c] - var A_big = abs(A[c][c]); - var r_big = c; - r = c+1; - while (r < rows) { - if(abs(A[r][c]) > A_big) { - A_big = abs(A[r][c]); - r_big = r; - } - r++; - } - if(A_big == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - r = r_big; - if (r != c) { - temp = A[c]; A[c] = A[r]; A[r] = temp; - temp = B[c]; B[c] = B[r]; B[r] = temp; - } - - // eliminate non-zero values on the other rows at column c - var Ac = A[c], - Bc = B[c]; - for (r = 0; r < rows; r++) { - var Ar = A[r], - Br = B[r]; - if(r != c) { - // eliminate value at column c and row r - if (Ar[c] != 0) { - f = divideScalar$$1(unaryMinus(Ar[c]), Ac[c]); - - // add (f * row c) to row r to eliminate the value - // at column c - for (s = c; s < cols; s++) { - Ar[s] = addScalar$$1(Ar[s], multiply(f, Ac[s])); - } - for (s = 0; s < cols; s++) { - Br[s] = addScalar$$1(Br[s], multiply(f, Bc[s])); - } - } - } - else { - // normalize value at Acc to 1, - // divide each value on row r with the value at Acc - f = Ac[c]; - for (s = c; s < cols; s++) { - Ar[s] = divideScalar$$1(Ar[s], f); - } - for (s = 0; s < cols; s++) { - Br[s] = divideScalar$$1(Br[s], f); - } - } - } + return new TypeError('Cannot calculate ' + fnName + ', no ordering relation is defined for complex numbers' + details); } - return B; + + return err; } } - inv.toTex = {1: '\\left(${args[0]}\\right)^{-1}'}; - - return inv; -} + var factory_1$74 = factory$75; -var name$79 = 'inv'; -var factory_1$88 = factory$89; - -var inv$1 = { - name: name$79, - factory: factory_1$88 -}; + var improveErrorMessage = { + factory: factory_1$74 + }; -var extend$3 = object.extend; + function factory$76 (type, config, load, typed) { + var larger$$1 = load(larger); + var improveErrorMessage$$1 = load(improveErrorMessage); -function factory$90 (type, config, load, typed) { + /** + * Compute the maximum value of a matrix or a list with values. + * In case of a multi dimensional array, the maximum of the flattened array + * will be calculated. When `dim` is provided, the maximum over the selected + * dimension will be calculated. Parameter `dim` is zero-based. + * + * Syntax: + * + * math.max(a, b, c, ...) + * math.max(A) + * math.max(A, dim) + * + * Examples: + * + * math.max(2, 1, 4, 3); // returns 4 + * math.max([2, 1, 4, 3]); // returns 4 + * + * // maximum over a specified dimension (zero-based) + * math.max([[2, 5], [4, 3], [1, 7]], 0); // returns [4, 7] + * math.max([[2, 5], [4, 3]], [1, 7], 1); // returns [5, 4, 7] + * + * math.max(2.7, 7.1, -4.5, 2.0, 4.1); // returns 7.1 + * math.min(2.7, 7.1, -4.5, 2.0, 4.1); // returns -4.5 + * + * See also: + * + * mean, median, min, prod, std, sum, var + * + * @param {... *} args A single matrix or or multiple scalar values + * @return {*} The maximum value + */ + var max = typed('max', { + // max([a, b, c, d, ...]) + 'Array | Matrix': _max, - var divideScalar$$1 = load(divideScalar); - var multiply = load(multiply$1); - var inv = load(inv$1); - var matrix$$1 = load(matrix); + // max([a, b, c, d, ...], dim) + 'Array | Matrix, number | BigNumber': function (array, dim) { + return reduce(array, dim.valueOf(), _largest); + }, - var algorithm11$$1 = load(algorithm11); - var algorithm14$$1 = load(algorithm14); - - /** - * Divide two values, `x / y`. - * To divide matrices, `x` is multiplied with the inverse of `y`: `x * inv(y)`. - * - * Syntax: - * - * math.divide(x, y) - * - * Examples: - * - * math.divide(2, 3); // returns number 0.6666666666666666 - * - * var a = math.complex(5, 14); - * var b = math.complex(4, 1); - * math.divide(a, b); // returns Complex 2 + 3i - * - * var c = [[7, -6], [13, -4]]; - * var d = [[1, 2], [4, 3]]; - * math.divide(c, d); // returns Array [[-9, 4], [-11, 6]] - * - * var e = math.unit('18 km'); - * math.divide(e, 4.5); // returns Unit 4 km - * - * See also: - * - * multiply - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Numerator - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} y Denominator - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Quotient, `x / y` - */ - var divide = typed('divide', extend$3({ - // we extend the signatures of divideScalar with signatures dealing with matrices - - 'Array | Matrix, Array | Matrix': function (x, y) { - // TODO: implement matrix right division using pseudo inverse - // http://www.mathworks.nl/help/matlab/ref/mrdivide.html - // http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html - // http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour - return multiply(x, inv(y)); - }, + // max(a, b, c, d, ...) + '...': function (args) { + if (containsCollections(args)) { + throw new TypeError('Scalar values expected in function max'); + } - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, divideScalar$$1, false); - }, + return _max(args); + } + }); - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, divideScalar$$1, false); - }, + max.toTex = '\\max\\left(${args}\\right)'; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, divideScalar$$1, false).valueOf(); - }, + return max; - 'any, Array | Matrix': function (x, y) { - return multiply(x, inv(y)); + /** + * Return the largest of two values + * @param {*} x + * @param {*} y + * @returns {*} Returns x when x is largest, or y when y is largest + * @private + */ + function _largest(x, y) { + try { + return larger$$1(x, y) ? x : y; + } + catch (err) { + throw improveErrorMessage$$1(err, 'max', y); + } } - }, divideScalar$$1.signatures)); - divide.toTex = {2: '\\frac{${args[0]}}{${args[1]}}'}; + /** + * Recursively calculate the maximum value in an n-dimensional array + * @param {Array} array + * @return {number} max + * @private + */ + function _max(array) { + var max = undefined; - return divide; -} + deepForEach(array, function (value) { + try { + if (max === undefined || larger$$1(value, max)) { + max = value; + } + } + catch (err) { + throw improveErrorMessage$$1(err, 'max', value); + } + }); -var name$80 = 'divide'; -var factory_1$89 = factory$90; + if (max === undefined) { + throw new Error('Cannot calculate max of an empty array'); + } -var divide$1 = { - name: name$80, - factory: factory_1$89 -}; + return max; + } -var size$1 = array.size; + } + var name$68 = 'max'; + var factory_1$75 = factory$76; + var max$1 = { + name: name$68, + factory: factory_1$75 + }; + var errorTransform$3 = error_transform.transform; -function factory$91 (type, config, load, typed) { - var add$$1 = load(add); - var divide = load(divide$1); - var improveErrorMessage$$1 = load(improveErrorMessage); /** - * Compute the mean value of matrix or a list with values. - * In case of a multi dimensional array, the mean of the flattened array - * will be calculated. When `dim` is provided, the maximum over the selected - * dimension will be calculated. Parameter `dim` is zero-based. - * - * Syntax: + * Attach a transform function to math.max + * Adds a property transform containing the transform function. * - * math.mean(a, b, c, ...) - * math.mean(A) - * math.mean(A, dim) - * - * Examples: - * - * math.mean(2, 1, 4, 3); // returns 2.5 - * math.mean([1, 2.7, 3.2, 4]); // returns 2.725 - * - * math.mean([[2, 5], [6, 3], [1, 7]], 0); // returns [3, 5] - * math.mean([[2, 5], [6, 3], [1, 7]], 1); // returns [3.5, 4.5, 4] - * - * See also: - * - * median, min, max, sum, prod, std, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The mean of all values + * This transform changed the last `dim` parameter of function max + * from one-based to zero based */ - var mean = typed('mean', { - // mean([a, b, c, d, ...]) - 'Array | Matrix': _mean, + function factory$77 (type, config, load, typed) { + var max = load(max$1); - // mean([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': _nmeanDim, + return typed('max', { + '...any': function (args) { + // change last argument dim from one-based to zero-based + if (args.length == 2 && isCollection(args[0])) { + var dim = args[1]; + if (type.isNumber(dim)) { + args[1] = dim - 1; + } + else if (type.isBigNumber(dim)) { + args[1] = dim.minus(1); + } + } - // mean(a, b, c, d, ...) - '...': function (args) { - if (containsCollections(args)) { - throw new TypeError('Scalar values expected in function mean'); + try { + return max.apply(null, args); + } + catch (err) { + throw errorTransform$3(err); + } } + }); + } - return _mean(args); - } - }); - - mean.toTex = undefined; // use default template + var name$69 = 'max'; + var path$37 = 'expression.transform'; + var factory_1$76 = factory$77; - return mean; + var max_transform = { + name: name$69, + path: path$37, + factory: factory_1$76 + }; - /** - * Calculate the mean value in an n-dimensional array, returning a - * n-1 dimensional array - * @param {Array} array - * @param {number} dim - * @return {number} mean - * @private - */ - function _nmeanDim(array$$1, dim) { - try { - var sum = reduce(array$$1, dim, add$$1); - var s = Array.isArray(array$$1) ? size$1(array$$1) : array$$1.size(); - return divide(sum, s[dim]); - } - catch (err) { - throw improveErrorMessage$$1(err, 'mean'); - } - } + function factory$78(type, config, load, typed) { + + /** + * Multiply two scalar values, `x * y`. + * This function is meant for internal use: it is used by the public function + * `multiply` + * + * This function does not support collections (Array or Matrix), and does + * not validate the number of of inputs. + * + * @param {number | BigNumber | Fraction | Complex | Unit} x First value to multiply + * @param {number | BigNumber | Fraction | Complex} y Second value to multiply + * @return {number | BigNumber | Fraction | Complex | Unit} Multiplication of `x` and `y` + * @private + */ + var multiplyScalar = typed('multiplyScalar', { - /** - * Recursively calculate the mean value in an n-dimensional array - * @param {Array} array - * @return {number} mean - * @private - */ - function _mean(array$$1) { - var sum = 0; - var num = 0; + 'number, number': function (x, y) { + return x * y; + }, - deepForEach(array$$1, function (value) { - try { - sum = add$$1(sum, value); - num++; - } - catch (err) { - throw improveErrorMessage$$1(err, 'mean', value); - } - }); + 'Complex, Complex': function (x, y) { + return x.mul(y); + }, - if (num === 0) { - throw new Error('Cannot calculate mean of an empty array'); - } + 'BigNumber, BigNumber': function (x, y) { + return x.times(y); + }, - return divide(sum, num); - } -} + 'Fraction, Fraction': function (x, y) { + return x.mul(y); + }, -var name$81 = 'mean'; -var factory_1$90 = factory$91; + 'number | Fraction | BigNumber | Complex, Unit': function (x, y) { + var res = y.clone(); + res.value = (res.value === null) ? res._normalize(x) : multiplyScalar(res.value, x); + return res; + }, -var mean$1 = { - name: name$81, - factory: factory_1$90 -}; + 'Unit, number | Fraction | BigNumber | Complex': function (x, y) { + var res = x.clone(); + res.value = (res.value === null) ? res._normalize(y) : multiplyScalar(res.value, y); + return res; + }, -var errorTransform$4 = error_transform.transform; + 'Unit, Unit': function (x, y) { + return x.multiply(y); + } + }); -/** - * Attach a transform function to math.mean - * Adds a property transform containing the transform function. - * - * This transform changed the last `dim` parameter of function mean - * from one-based to zero based - */ -function factory$92 (type, config, load, typed) { - var mean = load(mean$1); + return multiplyScalar; + } - return typed('mean', { - '...any': function (args) { - // change last argument dim from one-based to zero-based - if (args.length == 2 && isCollection(args[0])) { - var dim = args[1]; - if (type.isNumber(dim)) { - args[1] = dim - 1; - } - else if (type.isBigNumber(dim)) { - args[1] = dim.minus(1); - } - } + var factory_1$77 = factory$78; - try { - return mean.apply(null, args); - } - catch (err) { - throw errorTransform$4(err); - } - } - }); -} - -var name$82 = 'mean'; -var path$38 = 'expression.transform'; -var factory_1$91 = factory$92; - -var mean_transform = { - name: name$82, - path: path$38, - factory: factory_1$91 -}; - -function factory$93 (type, config, load, typed) { - var smaller$$1 = load(smaller); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the maximum value of a matrix or a list of values. - * In case of a multi dimensional array, the maximum of the flattened array - * will be calculated. When `dim` is provided, the maximum over the selected - * dimension will be calculated. Parameter `dim` is zero-based. - * - * Syntax: - * - * math.min(a, b, c, ...) - * math.min(A) - * math.min(A, dim) - * - * Examples: - * - * math.min(2, 1, 4, 3); // returns 1 - * math.min([2, 1, 4, 3]); // returns 1 - * - * // maximum over a specified dimension (zero-based) - * math.min([[2, 5], [4, 3], [1, 7]], 0); // returns [1, 3] - * math.min([[2, 5], [4, 3], [1, 7]], 1); // returns [2, 3, 1] - * - * math.max(2.7, 7.1, -4.5, 2.0, 4.1); // returns 7.1 - * math.min(2.7, 7.1, -4.5, 2.0, 4.1); // returns -4.5 - * - * See also: - * - * mean, median, max, prod, std, sum, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The minimum value - */ - var min = typed('min', { - // min([a, b, c, d, ...]) - 'Array | Matrix': _min, + var multiplyScalar = { + factory: factory_1$77 + }; - // min([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': function (array, dim) { - return reduce(array, dim.valueOf(), _smallest); - }, + function factory$79(type, config, load, typed) { + var multiplyScalar$$1 = load(multiplyScalar); - // min(a, b, c, d, ...) - '...': function (args) { - if (containsCollections(args)) { - throw new TypeError('Scalar values expected in function min'); - } + /** + * Divide two scalar values, `x / y`. + * This function is meant for internal use: it is used by the public functions + * `divide` and `inv`. + * + * This function does not support collections (Array or Matrix), and does + * not validate the number of of inputs. + * + * @param {number | BigNumber | Fraction | Complex | Unit} x Numerator + * @param {number | BigNumber | Fraction | Complex} y Denominator + * @return {number | BigNumber | Fraction | Complex | Unit} Quotient, `x / y` + * @private + */ + var divideScalar = typed('divide', { + 'number, number': function (x, y) { + return x / y; + }, - return _min(args); - } - }); + 'Complex, Complex': function (x, y) { + return x.div(y); + }, - min.toTex = '\\min\\left(${args}\\right)'; + 'BigNumber, BigNumber': function (x, y) { + return x.div(y); + }, - return min; + 'Fraction, Fraction': function (x, y) { + return x.div(y); + }, - /** - * Return the smallest of two values - * @param {*} x - * @param {*} y - * @returns {*} Returns x when x is smallest, or y when y is smallest - * @private - */ - function _smallest(x, y) { - try { - return smaller$$1(x, y) ? x : y; - } - catch (err) { - throw improveErrorMessage$$1(err, 'min', y); - } - } + 'Unit, number | Fraction | BigNumber': function (x, y) { + var res = x.clone(); + // TODO: move the divide function to Unit.js, it uses internals of Unit + res.value = divideScalar(((res.value === null) ? res._normalize(1) : res.value), y); + return res; + }, - /** - * Recursively calculate the minimum value in an n-dimensional array - * @param {Array} array - * @return {number} min - * @private - */ - function _min(array) { - var min = undefined; + 'number | Fraction | BigNumber, Unit': function (x, y) { + var res = y.pow(-1); + // TODO: move the divide function to Unit.js, it uses internals of Unit + res.value = multiplyScalar$$1(((res.value === null) ? res._normalize(1) : res.value), x); + return res; + }, - deepForEach(array, function (value) { - try { - if (min === undefined || smaller$$1(value, min)) { - min = value; - } - } - catch (err) { - throw improveErrorMessage$$1(err, 'min', value); + 'Unit, Unit': function (x, y) { + return x.divide(y); } - }); - if (min === undefined) { - throw new Error('Cannot calculate min of an empty array'); - } + }); - return min; + return divideScalar; } -} -var name$83 = 'min'; -var factory_1$92 = factory$93; + var factory_1$78 = factory$79; -var min$1 = { - name: name$83, - factory: factory_1$92 -}; + var divideScalar = { + factory: factory_1$78 + }; -var errorTransform$5 = error_transform.transform; + function factory$80 (type, config, load, typed) { + var equalScalar$$1 = load(equalScalar); -/** - * Attach a transform function to math.min - * Adds a property transform containing the transform function. - * - * This transform changed the last `dim` parameter of function min - * from one-based to zero based - */ -function factory$94 (type, config, load, typed) { - var min = load(min$1); + var SparseMatrix = type.SparseMatrix; - return typed('min', { - '...any': function (args) { - // change last argument dim from one-based to zero-based - if (args.length == 2 && isCollection(args[0])) { - var dim = args[1]; - if (type.isNumber(dim)) { - args[1] = dim - 1; - } - else if (type.isBigNumber(dim)) { - args[1] = dim.minus(1); + /** + * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). + * Callback function invoked NZ times (number of nonzero items in S). + * + * + * ┌ f(Sij, b) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} s The SparseMatrix instance (S) + * @param {Scalar} b The Scalar value + * @param {Function} callback The f(Aij,b) operation to invoke + * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) + * + * @return {Matrix} SparseMatrix (C) + * + * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 + */ + var algorithm11 = function (s, b, callback, inverse) { + // sparse matrix arrays + var avalues = s._values; + var aindex = s._index; + var aptr = s._ptr; + var asize = s._size; + var adt = s._datatype; + + // sparse matrix cannot be a Pattern matrix + if (!avalues) + throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); + + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // datatype + var dt; + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string') { + // datatype + dt = adt; + // find signature that matches (dt, dt) + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // convert b to the same datatype + b = typed.convert(b, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result arrays + var cvalues = []; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); + + // loop columns + for (var j = 0; j < columns; j++) { + // initialize ptr + cptr[j] = cindex.length; + // values in j + for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + var i = aindex[k]; + // invoke callback + var v = inverse ? cf(b, avalues[k]) : cf(avalues[k], b); + // check value is zero + if (!eq(v, zero)) { + // push index & value + cindex.push(i); + cvalues.push(v); + } } } + // update ptr + cptr[columns] = cindex.length; - try { - return min.apply(null, args); - } - catch (err) { - throw errorTransform$5(err); - } - } - }); -} + // return sparse matrix + return c; + }; -var name$84 = 'min'; -var path$39 = 'expression.transform'; -var factory_1$93 = factory$94; + return algorithm11; + } -var min_transform = { - name: name$84, - path: path$39, - factory: factory_1$93 -}; + var name$70 = 'algorithm11'; + var factory_1$79 = factory$80; -function factory$95 (type, config, load, typed) { - var matrix$$1 = load(matrix); + var algorithm11 = { + name: name$70, + factory: factory_1$79 + }; - var ZERO = new type.BigNumber(0); - var ONE = new type.BigNumber(1); + var extend$2 = object.extend; - /** - * Create an array from a range. - * By default, the range end is excluded. This can be customized by providing - * an extra parameter `includeEnd`. - * - * Syntax: - * - * math.range(str [, includeEnd]) // Create a range from a string, - * // where the string contains the - * // start, optional step, and end, - * // separated by a colon. - * math.range(start, end [, includeEnd]) // Create a range with start and - * // end and a step size of 1. - * math.range(start, end, step [, includeEnd]) // Create a range with start, step, - * // and end. - * - * Where: - * - * - `str: string` - * A string 'start:end' or 'start:step:end' - * - `start: {number | BigNumber}` - * Start of the range - * - `end: number | BigNumber` - * End of the range, excluded by default, included when parameter includeEnd=true - * - `step: number | BigNumber` - * Step size. Default value is 1. - * - `includeEnd: boolean` - * Option to specify whether to include the end or not. False by default. - * - * Examples: - * - * math.range(2, 6); // [2, 3, 4, 5] - * math.range(2, -3, -1); // [2, 1, 0, -1, -2] - * math.range('2:1:6'); // [2, 3, 4, 5] - * math.range(2, 6, true); // [2, 3, 4, 5, 6] - * - * See also: - * - * ones, zeros, size, subset - * - * @param {*} args Parameters describing the ranges `start`, `end`, and optional `step`. - * @return {Array | Matrix} range - */ - var range = typed('range', { - // TODO: simplify signatures when typed-function supports default values and optional arguments - // TODO: a number or boolean should not be converted to string here - 'string': _strRange, - 'string, boolean': _strRange, + function factory$81 (type, config, load, typed) { + var latex$$1 = latex; - 'number, number': function (start, end) { - return _out(_rangeEx(start, end, 1)); - }, - 'number, number, number': function (start, end, step) { - return _out(_rangeEx(start, end, step)); - }, - 'number, number, boolean': function (start, end, includeEnd) { - return includeEnd - ? _out(_rangeInc(start, end, 1)) - : _out(_rangeEx(start, end, 1)); - }, - 'number, number, number, boolean': function (start, end, step, includeEnd) { - return includeEnd - ? _out(_rangeInc(start, end, step)) - : _out(_rangeEx(start, end, step)); - }, + var matrix$$1 = load(matrix); + var addScalar$$1 = load(addScalar); + var multiplyScalar$$1 = load(multiplyScalar); + var equalScalar$$1 = load(equalScalar); - 'BigNumber, BigNumber': function (start, end) { - return _out(_bigRangeEx(start, end, ONE)); - }, - 'BigNumber, BigNumber, BigNumber': function (start, end, step) { - return _out(_bigRangeEx(start, end, step)); - }, - 'BigNumber, BigNumber, boolean': function (start, end, includeEnd) { - return includeEnd - ? _out(_bigRangeInc(start, end, ONE)) - : _out(_bigRangeEx(start, end, ONE)); - }, - 'BigNumber, BigNumber, BigNumber, boolean': function (start, end, step, includeEnd) { - return includeEnd - ? _out(_bigRangeInc(start, end, step)) - : _out(_bigRangeEx(start, end, step)); - } + var algorithm11$$1 = load(algorithm11); + var algorithm14$$1 = load(algorithm14); + + var DenseMatrix = type.DenseMatrix; + var SparseMatrix = type.SparseMatrix; - }); + /** + * Multiply two or more values, `x * y`. + * For matrices, the matrix product is calculated. + * + * Syntax: + * + * math.multiply(x, y) + * math.multiply(x, y, z, ...) + * + * Examples: + * + * math.multiply(4, 5.2); // returns number 20.8 + * math.multiply(2, 3, 4); // returns number 24 + * + * var a = math.complex(2, 3); + * var b = math.complex(4, 1); + * math.multiply(a, b); // returns Complex 5 + 14i + * + * var c = [[1, 2], [4, 3]]; + * var d = [[1, 2, 3], [3, -4, 7]]; + * math.multiply(c, d); // returns Array [[7, -6, 17], [13, -4, 33]] + * + * var e = math.unit('2.1 km'); + * math.multiply(3, e); // returns Unit 6.3 km + * + * See also: + * + * divide, prod, cross, dot + * + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to multiply + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to multiply + * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` + */ + var multiply = typed('multiply', extend$2({ + // we extend the signatures of multiplyScalar with signatures dealing with matrices - range.toTex = undefined; // use default template + 'Array, Array': function (x, y) { + // check dimensions + _validateMatrixDimensions(array.size(x), array.size(y)); - return range; + // use dense matrix implementation + var m = multiply(matrix$$1(x), matrix$$1(y)); + // return array or scalar + return type.isMatrix(m) ? m.valueOf() : m; + }, - function _out(arr) { - return config.matrix === 'Array' ? arr : matrix$$1(arr); - } + 'Matrix, Matrix': function (x, y) { + // dimensions + var xsize = x.size(); + var ysize = y.size(); - function _strRange (str, includeEnd) { - var r = _parse(str); - if (!r){ - throw new SyntaxError('String "' + str + '" is no valid range'); - } + // check dimensions + _validateMatrixDimensions(xsize, ysize); - var fn; - if (config.number === 'BigNumber') { - fn = includeEnd ? _bigRangeInc : _bigRangeEx; - return _out(fn( - new type.BigNumber(r.start), - new type.BigNumber(r.end), - new type.BigNumber(r.step))); - } - else { - fn = includeEnd ? _rangeInc : _rangeEx; - return _out(fn(r.start, r.end, r.step)); - } - } + // process dimensions + if (xsize.length === 1) { + // process y dimensions + if (ysize.length === 1) { + // Vector * Vector + return _multiplyVectorVector(x, y, xsize[0]); + } + // Vector * Matrix + return _multiplyVectorMatrix(x, y); + } + // process y dimensions + if (ysize.length === 1) { + // Matrix * Vector + return _multiplyMatrixVector(x, y); + } + // Matrix * Matrix + return _multiplyMatrixMatrix(x, y); + }, - /** - * Create a range with numbers. End is excluded - * @param {number} start - * @param {number} end - * @param {number} step - * @returns {Array} range - * @private - */ - function _rangeEx (start, end, step) { - var array = [], - x = start; - if (step > 0) { - while (x < end) { - array.push(x); - x += step; - } - } - else if (step < 0) { - while (x > end) { - array.push(x); - x += step; - } - } + 'Matrix, Array': function (x, y) { + // use Matrix * Matrix implementation + return multiply(x, matrix$$1(y)); + }, - return array; - } + 'Array, Matrix': function (x, y) { + // use Matrix * Matrix implementation + return multiply(matrix$$1(x, y.storage()), y); + }, - /** - * Create a range with numbers. End is included - * @param {number} start - * @param {number} end - * @param {number} step - * @returns {Array} range - * @private - */ - function _rangeInc (start, end, step) { - var array = [], - x = start; - if (step > 0) { - while (x <= end) { - array.push(x); - x += step; - } - } - else if (step < 0) { - while (x >= end) { - array.push(x); - x += step; - } - } + 'SparseMatrix, any': function (x, y) { + return algorithm11$$1(x, y, multiplyScalar$$1, false); + }, - return array; - } + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, multiplyScalar$$1, false); + }, - /** - * Create a range with big numbers. End is excluded - * @param {BigNumber} start - * @param {BigNumber} end - * @param {BigNumber} step - * @returns {Array} range - * @private - */ - function _bigRangeEx (start, end, step) { - var array = [], - x = start; - if (step.gt(ZERO)) { - while (x.lt(end)) { - array.push(x); - x = x.plus(step); + 'any, SparseMatrix': function (x, y) { + return algorithm11$$1(y, x, multiplyScalar$$1, true); + }, + + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, multiplyScalar$$1, true); + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, multiplyScalar$$1, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, multiplyScalar$$1, true).valueOf(); + }, + + 'any, any': multiplyScalar$$1, + + 'any, any, ...any': function (x, y, rest) { + var result = multiply(x, y); + + for (var i = 0; i < rest.length; i++) { + result = multiply(result, rest[i]); + } + + return result; } - } - else if (step.lt(ZERO)) { - while (x.gt(end)) { - array.push(x); - x = x.plus(step); + }, multiplyScalar$$1.signatures)); + + var _validateMatrixDimensions = function (size1, size2) { + // check left operand dimensions + switch (size1.length) { + case 1: + // check size2 + switch (size2.length) { + case 1: + // Vector x Vector + if (size1[0] !== size2[0]) { + // throw error + throw new RangeError('Dimension mismatch in multiplication. Vectors must have the same length'); + } + break; + case 2: + // Vector x Matrix + if (size1[0] !== size2[0]) { + // throw error + throw new RangeError('Dimension mismatch in multiplication. Vector length (' + size1[0] + ') must match Matrix rows (' + size2[0] + ')'); + } + break; + default: + throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)'); + } + break; + case 2: + // check size2 + switch (size2.length) { + case 1: + // Matrix x Vector + if (size1[1] !== size2[0]) { + // throw error + throw new RangeError('Dimension mismatch in multiplication. Matrix columns (' + size1[1] + ') must match Vector length (' + size2[0] + ')'); + } + break; + case 2: + // Matrix x Matrix + if (size1[1] !== size2[0]) { + // throw error + throw new RangeError('Dimension mismatch in multiplication. Matrix A columns (' + size1[1] + ') must match Matrix B rows (' + size2[0] + ')'); + } + break; + default: + throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)'); + } + break; + default: + throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix A has ' + size1.length + ' dimensions)'); } - } + }; - return array; - } + /** + * C = A * B + * + * @param {Matrix} a Dense Vector (N) + * @param {Matrix} b Dense Vector (N) + * + * @return {number} Scalar value + */ + var _multiplyVectorVector = function (a, b, n) { + // check empty vector + if (n === 0) + throw new Error('Cannot multiply two empty vectors'); + + // a dense + var adata = a._data; + var adt = a._datatype; + // b dense + var bdata = b._data; + var bdt = b._datatype; - /** - * Create a range with big numbers. End is included - * @param {BigNumber} start - * @param {BigNumber} end - * @param {BigNumber} step - * @returns {Array} range - * @private - */ - function _bigRangeInc (start, end, step) { - var array = [], - x = start; - if (step.gt(ZERO)) { - while (x.lte(end)) { - array.push(x); - x = x.plus(step); + // datatype + var dt; + // addScalar signature to use + var af = addScalar$$1; + // multiplyScalar signature to use + var mf = multiplyScalar$$1; + + // process data types + if (adt && bdt && adt === bdt && typeof adt === 'string') { + // datatype + dt = adt; + // find signatures that matches (dt, dt) + af = typed.find(addScalar$$1, [dt, dt]); + mf = typed.find(multiplyScalar$$1, [dt, dt]); } - } - else if (step.lt(ZERO)) { - while (x.gte(end)) { - array.push(x); - x = x.plus(step); + + // result (do not initialize it with zero) + var c = mf(adata[0], bdata[0]); + // loop data + for (var i = 1; i < n; i++) { + // multiply and accumulate + c = af(c, mf(adata[i], bdata[i])); } - } + return c; + }; - return array; - } + /** + * C = A * B + * + * @param {Matrix} a Dense Vector (M) + * @param {Matrix} b Matrix (MxN) + * + * @return {Matrix} Dense Vector (N) + */ + var _multiplyVectorMatrix = function (a, b) { + // process storage + if (b.storage() !== 'dense') { + throw new Error('Support for SparseMatrix not implemented'); + } + return _multiplyVectorDenseMatrix(a, b); + }; - /** - * 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 {{start: number, end: number, step: number} | null} range Object containing properties start, end, step - * @private - */ - function _parse (str) { - var args = str.split(':'); + /** + * C = A * B + * + * @param {Matrix} a Dense Vector (M) + * @param {Matrix} b Dense Matrix (MxN) + * + * @return {Matrix} Dense Vector (N) + */ + var _multiplyVectorDenseMatrix = function (a, b) { + // a dense + var adata = a._data; + var asize = a._size; + var adt = a._datatype; + // b dense + var bdata = b._data; + var bsize = b._size; + var bdt = b._datatype; + // rows & columns + var alength = asize[0]; + var bcolumns = bsize[1]; - // number - var nums = args.map(function (arg) { - // use Number and not parseFloat as Number returns NaN on invalid garbage in the string - return Number(arg); - }); + // datatype + var dt; + // addScalar signature to use + var af = addScalar$$1; + // multiplyScalar signature to use + var mf = multiplyScalar$$1; - var invalid = nums.some(function (num) { - return isNaN(num); - }); - if(invalid) { - return null; - } + // process data types + if (adt && bdt && adt === bdt && typeof adt === 'string') { + // datatype + dt = adt; + // find signatures that matches (dt, dt) + af = typed.find(addScalar$$1, [dt, dt]); + mf = typed.find(multiplyScalar$$1, [dt, dt]); + } - switch (nums.length) { - case 2: - return { - start: nums[0], - end: nums[1], - step: 1 - }; + // result + var c = []; - case 3: - return { - start: nums[0], - end: nums[2], - step: nums[1] - }; + // loop matrix columns + for (var j = 0; j < bcolumns; j++) { + // sum (do not initialize it with zero) + var sum = mf(adata[0], bdata[0][j]); + // loop vector + for (var i = 1; i < alength; i++) { + // multiply & accumulate + sum = af(sum, mf(adata[i], bdata[i][j])); + } + c[j] = sum; + } - default: - return null; - } - } + // return matrix + return new DenseMatrix({ + data: c, + size: [bcolumns], + datatype: dt + }); + }; -} + /** + * C = A * B + * + * @param {Matrix} a Matrix (MxN) + * @param {Matrix} b Dense Vector (N) + * + * @return {Matrix} Dense Vector (M) + */ + var _multiplyMatrixVector = typed('_multiplyMatrixVector', { + 'DenseMatrix, any': _multiplyDenseMatrixVector, + 'SparseMatrix, any': _multiplySparseMatrixVector + }); -var name$85 = 'range'; -var factory_1$94 = factory$95; + /** + * C = A * B + * + * @param {Matrix} a Matrix (MxN) + * @param {Matrix} b Matrix (NxC) + * + * @return {Matrix} Matrix (MxC) + */ + var _multiplyMatrixMatrix = typed('_multiplyMatrixMatrix', { + 'DenseMatrix, DenseMatrix': _multiplyDenseMatrixDenseMatrix, + 'DenseMatrix, SparseMatrix': _multiplyDenseMatrixSparseMatrix, + 'SparseMatrix, DenseMatrix': _multiplySparseMatrixDenseMatrix, + 'SparseMatrix, SparseMatrix': _multiplySparseMatrixSparseMatrix + }); -var range$1 = { - name: name$85, - factory: factory_1$94 -}; + /** + * C = A * B + * + * @param {Matrix} a DenseMatrix (MxN) + * @param {Matrix} b Dense Vector (N) + * + * @return {Matrix} Dense Vector (M) + */ + function _multiplyDenseMatrixVector(a, b) { + // a dense + var adata = a._data; + var asize = a._size; + var adt = a._datatype; + // b dense + var bdata = b._data; + var bdt = b._datatype; + // rows & columns + var arows = asize[0]; + var acolumns = asize[1]; -/** - * Attach a transform function to math.range - * Adds a property transform containing the transform function. - * - * This transform creates a range which includes the end value - */ -function factory$96 (type, config, load, typed) { - var range = load(range$1); + // datatype + var dt; + // addScalar signature to use + var af = addScalar$$1; + // multiplyScalar signature to use + var mf = multiplyScalar$$1; - return typed('range', { - '...any': function (args) { - var lastIndex = args.length - 1; - var last = args[lastIndex]; - if (typeof last !== 'boolean') { - // append a parameter includeEnd=true - args.push(true); + // process data types + if (adt && bdt && adt === bdt && typeof adt === 'string') { + // datatype + dt = adt; + // find signatures that matches (dt, dt) + af = typed.find(addScalar$$1, [dt, dt]); + mf = typed.find(multiplyScalar$$1, [dt, dt]); } - return range.apply(null, args); - } - }); -} - -var name$86 = 'range'; -var path$40 = 'expression.transform'; -var factory_1$95 = factory$96; - -var range_transform = { - name: name$86, - path: path$40, - factory: factory_1$95 -}; - -var errorTransform$6 = error_transform.transform; - -/** - * Attach a transform function to math.subset - * Adds a property transform containing the transform function. - * - * This transform creates a range which includes the end value - */ -function factory$97 (type, config, load, typed) { - var subset = load(subset$1); - - return typed('subset', { - '...any': function (args) { - try { - return subset.apply(null, args); - } - catch (err) { - throw errorTransform$6(err); + // result + var c = []; + + // loop matrix a rows + for (var i = 0; i < arows; i++) { + // current row + var row = adata[i]; + // sum (do not initialize it with zero) + var sum = mf(row[0], bdata[0]); + // loop matrix a columns + for (var j = 1; j < acolumns; j++) { + // multiply & accumulate + sum = af(sum, mf(row[j], bdata[j])); + } + c[i] = sum; } - } - }); -} - -var name$87 = 'subset'; -var path$41 = 'expression.transform'; -var factory_1$96 = factory$97; - -var subset_transform = { - name: name$87, - path: path$41, - factory: factory_1$96 -}; - -var transform$1 = [ - concat_transform, - filter_transform, - forEach_transform, - index_transform, - map_transform, - max_transform, - mean_transform, - min_transform, - range_transform, - subset_transform -]; - -function factory$98 (type, config, load, typed) { - var parser$$1 = load(parser)(); - /** - * Documentation object - * @param {Object} doc Object containing properties: - * {string} name - * {string} category - * {string} description - * {string[]} syntax - * {string[]} examples - * {string[]} seealso - * @constructor - */ - function Help(doc) { - if (!(this instanceof Help)) { - throw new SyntaxError('Constructor must be called with the new operator'); + // return matrix + return new DenseMatrix({ + data: c, + size: [arows], + datatype: dt + }); } - if (!doc) throw new Error('Argument "doc" missing'); - - this.doc = doc; - } - - /** - * Attach type information - */ - Help.prototype.type = 'Help'; - Help.prototype.isHelp = true; - - /** - * Generate a string representation of the Help object - * @return {string} Returns a string - * @private - */ - Help.prototype.toString = function () { - var doc = this.doc || {}; - var desc = '\n'; - - if (doc.name) { - desc += 'Name: ' + doc.name + '\n\n'; - } - if (doc.category) { - desc += 'Category: ' + doc.category + '\n\n'; - } - if (doc.description) { - desc += 'Description:\n ' + doc.description + '\n\n'; - } - if (doc.syntax) { - desc += 'Syntax:\n ' + doc.syntax.join('\n ') + '\n\n'; - } - if (doc.examples) { - desc += 'Examples:\n'; - for (var i = 0; i < doc.examples.length; i++) { - var expr = doc.examples[i]; - desc += ' ' + expr + '\n'; + /** + * C = A * B + * + * @param {Matrix} a DenseMatrix (MxN) + * @param {Matrix} b DenseMatrix (NxC) + * + * @return {Matrix} DenseMatrix (MxC) + */ + function _multiplyDenseMatrixDenseMatrix (a, b) { + // a dense + var adata = a._data; + var asize = a._size; + var adt = a._datatype; + // b dense + var bdata = b._data; + var bsize = b._size; + var bdt = b._datatype; + // rows & columns + var arows = asize[0]; + var acolumns = asize[1]; + var bcolumns = bsize[1]; - var res; - try { - // note: res can be undefined when `expr` is an empty string - res = parser$$1.eval(expr); - } - catch (e) { - res = e; - } - if (res !== undefined && !type.isHelp(res)) { - desc += ' ' + string.format(res, {precision: 14}) + '\n'; + // datatype + var dt; + // addScalar signature to use + var af = addScalar$$1; + // multiplyScalar signature to use + var mf = multiplyScalar$$1; + + // process data types + if (adt && bdt && adt === bdt && typeof adt === 'string') { + // datatype + dt = adt; + // find signatures that matches (dt, dt) + af = typed.find(addScalar$$1, [dt, dt]); + mf = typed.find(multiplyScalar$$1, [dt, dt]); + } + + // result + var c = []; + + // loop matrix a rows + for (var i = 0; i < arows; i++) { + // current row + var row = adata[i]; + // initialize row array + c[i] = []; + // loop matrix b columns + for (var j = 0; j < bcolumns; j++) { + // sum (avoid initializing sum to zero) + var sum = mf(row[0], bdata[0][j]); + // loop matrix a columns + for (var x = 1; x < acolumns; x++) { + // multiply & accumulate + sum = af(sum, mf(row[x], bdata[x][j])); + } + c[i][j] = sum; } } - desc += '\n'; - } - if (doc.seealso && doc.seealso.length) { - desc += 'See also: ' + doc.seealso.join(', ') + '\n'; + + // return matrix + return new DenseMatrix({ + data: c, + size: [arows, bcolumns], + datatype: dt + }); } - return desc; - }; + /** + * C = A * B + * + * @param {Matrix} a DenseMatrix (MxN) + * @param {Matrix} b SparseMatrix (NxC) + * + * @return {Matrix} SparseMatrix (MxC) + */ + function _multiplyDenseMatrixSparseMatrix (a, b) { + // a dense + var adata = a._data; + var asize = a._size; + var adt = a._datatype; + // b sparse + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; + // validate b matrix + if (!bvalues) + throw new Error('Cannot multiply Dense Matrix times Pattern only Matrix'); + // rows & columns + var arows = asize[0]; + var bcolumns = bsize[1]; + + // datatype + var dt; + // addScalar signature to use + var af = addScalar$$1; + // multiplyScalar signature to use + var mf = multiplyScalar$$1; + // equalScalar signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + + // process data types + if (adt && bdt && adt === bdt && typeof adt === 'string') { + // datatype + dt = adt; + // find signatures that matches (dt, dt) + af = typed.find(addScalar$$1, [dt, dt]); + mf = typed.find(multiplyScalar$$1, [dt, dt]); + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + } - /** - * Export the help object to JSON - */ - Help.prototype.toJSON = function () { - var obj = object.clone(this.doc); - obj.mathjs = 'Help'; - return obj; - }; + // result + var cvalues = []; + var cindex = []; + var cptr = []; + // c matrix + var c = new SparseMatrix({ + values : cvalues, + index: cindex, + ptr: cptr, + size: [arows, bcolumns], + datatype: dt + }); - /** - * Instantiate a Help object from a JSON object - * @param {Object} json - * @returns {Help} Returns a new Help object - */ - Help.fromJSON = function (json) { - var doc = {}; - for (var prop in json) { - if (prop !== 'mathjs') { // ignore mathjs field - doc[prop] = json[prop]; + // loop b columns + for (var jb = 0; jb < bcolumns; jb++) { + // update ptr + cptr[jb] = cindex.length; + // indeces in column jb + var kb0 = bptr[jb]; + var kb1 = bptr[jb + 1]; + // do not process column jb if no data exists + if (kb1 > kb0) { + // last row mark processed + var last = 0; + // loop a rows + for (var i = 0; i < arows; i++) { + // column mark + var mark = i + 1; + // C[i, jb] + var cij; + // values in b column j + for (var kb = kb0; kb < kb1; kb++) { + // row + var ib = bindex[kb]; + // check value has been initialized + if (last !== mark) { + // first value in column jb + cij = mf(adata[i][ib], bvalues[kb]); + // update mark + last = mark; + } + else { + // accumulate value + cij = af(cij, mf(adata[i][ib], bvalues[kb])); + } + } + // check column has been processed and value != 0 + if (last === mark && !eq(cij, zero)) { + // push row & value + cindex.push(i); + cvalues.push(cij); + } + } + } } + // update ptr + cptr[bcolumns] = cindex.length; + + // return sparse matrix + return c; } - return new Help(doc); - }; - /** - * Returns a string representation of the Help object - */ - Help.prototype.valueOf = Help.prototype.toString; - - return Help; -} - -var name$88 = 'Help'; -var path$42 = 'type'; -var factory_1$97 = factory$98; - -var Help = { - name: name$88, - path: path$42, - factory: factory_1$97 -}; - -var expression = [ - // Note that the docs folder is called "embeddedDocs" and not "docs" to prevent issues - // with yarn autoclean. See https://github.com/josdejong/mathjs/issues/969 - embeddedDocs, - _function$2, - node, - transform$1, - - Help, - parse, - Parser -]; - -function factory$99 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - var latex$$1 = latex; + /** + * C = A * B + * + * @param {Matrix} a SparseMatrix (MxN) + * @param {Matrix} b Dense Vector (N) + * + * @return {Matrix} SparseMatrix (M, 1) + */ + function _multiplySparseMatrixVector(a, b) { + // a sparse + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var adt = a._datatype; + // validate a matrix + if (!avalues) + throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix'); + // b dense + var bdata = b._data; + var bdt = b._datatype; + // rows & columns + var arows = a._size[0]; + var brows = b._size[0]; + // result + var cvalues = []; + var cindex = []; + var cptr = []; + + // datatype + var dt; + // addScalar signature to use + var af = addScalar$$1; + // multiplyScalar signature to use + var mf = multiplyScalar$$1; + // equalScalar signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + + // process data types + if (adt && bdt && adt === bdt && typeof adt === 'string') { + // datatype + dt = adt; + // find signatures that matches (dt, dt) + af = typed.find(addScalar$$1, [dt, dt]); + mf = typed.find(multiplyScalar$$1, [dt, dt]); + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + } + + // workspace + var x = []; + // vector with marks indicating a value x[i] exists in a given column + var w = []; - /** - * Test whether two values are equal. - * - * The function tests whether the relative difference between x and y is - * smaller than the configured epsilon. The function cannot be used to - * compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im. - * - * Values `null` and `undefined` are compared strictly, thus `null` is only - * equal to `null` and nothing else, and `undefined` is only equal to - * `undefined` and nothing else. Strings are compared by their numerical value. - * - * Syntax: - * - * math.equal(x, y) - * - * Examples: - * - * math.equal(2 + 2, 3); // returns false - * math.equal(2 + 2, 4); // returns true - * - * var a = math.unit('50 cm'); - * var b = math.unit('5 m'); - * math.equal(a, b); // returns true - * - * var c = [2, 5, 1]; - * var d = [2, 7, 1]; - * - * math.equal(c, d); // returns [true, false, true] - * math.deepEqual(c, d); // returns false - * - * math.equal("1000", "1e3"); // returns true - * math.equal(0, null); // returns false - * - * See also: - * - * unequal, smaller, smallerEq, larger, largerEq, compare, deepEqual, equalText - * - * @param {number | BigNumber | boolean | Complex | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | boolean | Complex | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the compared values are equal, else returns false - */ - var equal = typed('equal', { - - 'any, any': function (x, y) { - // strict equality for null and undefined? - if (x === null) { return y === null; } - if (y === null) { return x === null; } - if (x === undefined) { return y === undefined; } - if (y === undefined) { return x === undefined; } - - return equalScalar$$1(x, y); - }, + // update ptr + cptr[0] = 0; + // rows in b + for (var ib = 0; ib < brows; ib++) { + // b[ib] + var vbi = bdata[ib]; + // check b[ib] != 0, avoid loops + if (!eq(vbi, zero)) { + // A values & index in ib column + for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { + // a row + var ia = aindex[ka]; + // check value exists in current j + if (!w[ia]) { + // ia is new entry in j + w[ia] = true; + // add i to pattern of C + cindex.push(ia); + // x(ia) = A + x[ia] = mf(vbi, avalues[ka]); + } + else { + // i exists in C already + x[ia] = af(x[ia], mf(vbi, avalues[ka])); + } + } + } + } + // copy values from x to column jb of c + for (var p1 = cindex.length, p = 0; p < p1; p++) { + // row + var ic = cindex[p]; + // copy value + cvalues[p] = x[ic]; + } + // update ptr + cptr[1] = cindex.length; + + // return sparse matrix + return new SparseMatrix({ + values : cvalues, + index: cindex, + ptr: cptr, + size: [arows, 1], + datatype: dt + }); + } - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, equalScalar$$1); - }, + /** + * C = A * B + * + * @param {Matrix} a SparseMatrix (MxN) + * @param {Matrix} b DenseMatrix (NxC) + * + * @return {Matrix} SparseMatrix (MxC) + */ + function _multiplySparseMatrixDenseMatrix(a, b) { + // a sparse + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var adt = a._datatype; + // validate a matrix + if (!avalues) + throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix'); + // b dense + var bdata = b._data; + var bdt = b._datatype; + // rows & columns + var arows = a._size[0]; + var brows = b._size[0]; + var bcolumns = b._size[1]; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, equalScalar$$1, true); - }, + // datatype + var dt; + // addScalar signature to use + var af = addScalar$$1; + // multiplyScalar signature to use + var mf = multiplyScalar$$1; + // equalScalar signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + + // process data types + if (adt && bdt && adt === bdt && typeof adt === 'string') { + // datatype + dt = adt; + // find signatures that matches (dt, dt) + af = typed.find(addScalar$$1, [dt, dt]); + mf = typed.find(multiplyScalar$$1, [dt, dt]); + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + } - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, equalScalar$$1, false); - }, + // result + var cvalues = []; + var cindex = []; + var cptr = []; + // c matrix + var c = new SparseMatrix({ + values : cvalues, + index: cindex, + ptr: cptr, + size: [arows, bcolumns], + datatype: dt + }); - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, equalScalar$$1); - }, + // workspace + var x = []; + // vector with marks indicating a value x[i] exists in a given column + var w = []; - 'Array, Array': function (x, y) { - // use matrix implementation - return equal(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + // loop b columns + for (var jb = 0; jb < bcolumns; jb++) { + // update ptr + cptr[jb] = cindex.length; + // mark in workspace for current column + var mark = jb + 1; + // rows in jb + for (var ib = 0; ib < brows; ib++) { + // b[ib, jb] + var vbij = bdata[ib][jb]; + // check b[ib, jb] != 0, avoid loops + if (!eq(vbij, zero)) { + // A values & index in ib column + for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { + // a row + var ia = aindex[ka]; + // check value exists in current j + if (w[ia] !== mark) { + // ia is new entry in j + w[ia] = mark; + // add i to pattern of C + cindex.push(ia); + // x(ia) = A + x[ia] = mf(vbij, avalues[ka]); + } + else { + // i exists in C already + x[ia] = af(x[ia], mf(vbij, avalues[ka])); + } + } + } + } + // copy values from x to column jb of c + for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) { + // row + var ic = cindex[p]; + // copy value + cvalues[p] = x[ic]; + } + } + // update ptr + cptr[bcolumns] = cindex.length; - 'Array, Matrix': function (x, y) { - // use matrix implementation - return equal(matrix$$1(x), y); - }, + // return sparse matrix + return c; + } - 'Matrix, Array': function (x, y) { - // use matrix implementation - return equal(x, matrix$$1(y)); - }, + /** + * C = A * B + * + * @param {Matrix} a SparseMatrix (MxN) + * @param {Matrix} b SparseMatrix (NxC) + * + * @return {Matrix} SparseMatrix (MxC) + */ + function _multiplySparseMatrixSparseMatrix(a, b) { + // a sparse + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var adt = a._datatype; + // b sparse + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bdt = b._datatype; + + // rows & columns + var arows = a._size[0]; + var bcolumns = b._size[1]; + // flag indicating both matrices (a & b) contain data + var values = avalues && bvalues; - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, equalScalar$$1, false); - }, + // datatype + var dt; + // addScalar signature to use + var af = addScalar$$1; + // multiplyScalar signature to use + var mf = multiplyScalar$$1; + + // process data types + if (adt && bdt && adt === bdt && typeof adt === 'string') { + // datatype + dt = adt; + // find signatures that matches (dt, dt) + af = typed.find(addScalar$$1, [dt, dt]); + mf = typed.find(multiplyScalar$$1, [dt, dt]); + } + + // result + var cvalues = values ? [] : undefined; + var cindex = []; + var cptr = []; + // c matrix + var c = new SparseMatrix({ + values : cvalues, + index: cindex, + ptr: cptr, + size: [arows, bcolumns], + datatype: dt + }); - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, equalScalar$$1, false); - }, + // workspace + var x = values ? [] : undefined; + // vector with marks indicating a value x[i] exists in a given column + var w = []; + // variables + var ka, ka0, ka1, kb, kb0, kb1, ia, ib; + // loop b columns + for (var jb = 0; jb < bcolumns; jb++) { + // update ptr + cptr[jb] = cindex.length; + // mark in workspace for current column + var mark = jb + 1; + // B values & index in j + for (kb0 = bptr[jb], kb1 = bptr[jb + 1], kb = kb0; kb < kb1; kb++) { + // b row + ib = bindex[kb]; + // check we need to process values + if (values) { + // loop values in a[:,ib] + for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { + // row + ia = aindex[ka]; + // check value exists in current j + if (w[ia] !== mark) { + // ia is new entry in j + w[ia] = mark; + // add i to pattern of C + cindex.push(ia); + // x(ia) = A + x[ia] = mf(bvalues[kb], avalues[ka]); + } + else { + // i exists in C already + x[ia] = af(x[ia], mf(bvalues[kb], avalues[ka])); + } + } + } + else { + // loop values in a[:,ib] + for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { + // row + ia = aindex[ka]; + // check value exists in current j + if (w[ia] !== mark) { + // ia is new entry in j + w[ia] = mark; + // add i to pattern of C + cindex.push(ia); + } + } + } + } + // check we need to process matrix values (pattern matrix) + if (values) { + // copy values from x to column jb of c + for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) { + // row + var ic = cindex[p]; + // copy value + cvalues[p] = x[ic]; + } + } + } + // update ptr + cptr[bcolumns] = cindex.length; - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, equalScalar$$1, true); - }, + // return sparse matrix + return c; + } - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, equalScalar$$1, true); - }, + multiply.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['multiply'] + '${args[1]}\\right)' + }; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, equalScalar$$1, false).valueOf(); - }, + return multiply; + } - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, equalScalar$$1, true).valueOf(); - } - }); + var name$71 = 'multiply'; + var factory_1$80 = factory$81; - equal.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['equal'] + '${args[1]}\\right)' + var multiply$1 = { + name: name$71, + factory: factory_1$80 }; - return equal; -} - -var name$89 = 'equal'; -var factory_1$98 = factory$99; + function factory$82 (type, config, load, typed) { + var latex$$1 = latex; -var equal$1 = { - name: name$89, - factory: factory_1$98 -}; + /** + * Inverse the sign of a value, apply a unary minus operation. + * + * For matrices, the function is evaluated element wise. Boolean values and + * strings will be converted to a number. For complex numbers, both real and + * complex value are inverted. + * + * Syntax: + * + * math.unaryMinus(x) + * + * Examples: + * + * math.unaryMinus(3.5); // returns -3.5 + * math.unaryMinus(-4.2); // returns 4.2 + * + * See also: + * + * add, subtract, unaryPlus + * + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Number to be inverted. + * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Returns the value with inverted sign. + */ + var unaryMinus = typed('unaryMinus', { + 'number': function (x) { + return -x; + }, -function factory$100(type, config, load, typed, math) { - var FunctionNode = math.expression.node.FunctionNode; - var OperatorNode = math.expression.node.OperatorNode; - var SymbolNode = math.expression.node.SymbolNode; + 'Complex': function (x) { + return x.neg(); + }, - // TODO commutative/associative properties rely on the arguments - // e.g. multiply is not commutative for matrices - // The properties should be calculated from an argument to simplify, or possibly something in math.config - // the other option is for typed() to specify a return type so that we can evaluate the type of arguments - var commutative = { - 'add': true, - 'multiply': true - }; - var associative = { - 'add': true, - 'multiply': true - }; + 'BigNumber': function (x) { + return x.neg(); + }, + 'Fraction': function (x) { + return x.neg(); + }, - function isCommutative(node, context) { - if (!type.isOperatorNode(node)) { - return true; - } - var name = node.fn.toString(); - if (context && context.hasOwnProperty(name) && context[name].hasOwnProperty('commutative')) { - return context[name].commutative; - } - return commutative[name] || false; - } + 'Unit': function (x) { + var res = x.clone(); + res.value = unaryMinus(x.value); + return res; + }, - function isAssociative(node, context) { - if (!type.isOperatorNode(node)) { - return false; - } - var name = node.fn.toString(); - if (context && context.hasOwnProperty(name) && context[name].hasOwnProperty('associative')) { - return context[name].associative; - } - return associative[name] || false; - } + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since unaryMinus(0) = 0 + return deepMap(x, unaryMinus, true); + } - /** - * Flatten all associative operators in an expression tree. - * Assumes parentheses have already been removed. - */ - function flatten(node) { - if (!node.args || node.args.length === 0) { - return node; - } - node.args = allChildren(node); - for (var i=0; i 2 && isAssociative(node)) { - var curnode = node.args.pop(); - while (node.args.length > 0) { - curnode = makeNode([node.args.pop(), curnode]); - } - node.args = curnode.args; - } + return unaryMinus; } - /** - * Unflatten all flattened operators to a left-heavy binary tree. - */ - function unflattenl(node) { - if (!node.args || node.args.length === 0) { - return; - } - var makeNode = createMakeNodeFunction(node); - var l = node.args.length; - for (var i = 0; i < l; i++) { - unflattenl(node.args[i]); - } - if (l > 2 && isAssociative(node)) { - var curnode = node.args.shift(); - while (node.args.length > 0) { - curnode = makeNode([curnode, node.args.shift()]); - } - node.args = curnode.args; - } - } + var name$72 = 'unaryMinus'; + var factory_1$81 = factory$82; - function createMakeNodeFunction(node) { - if (type.isOperatorNode(node)) { - return function(args){ - try{ - return new OperatorNode(node.op, node.fn, args); - } catch(err){ - console.error(err); - return []; - } - }; - } - else { - return function(args){ - return new FunctionNode(new SymbolNode(node.name), args); - }; - } - } - return { - createMakeNodeFunction: createMakeNodeFunction, - isCommutative: isCommutative, - isAssociative: isAssociative, - flatten: flatten, - allChildren: allChildren, - unflattenr: unflattenr, - unflattenl: unflattenl + var unaryMinus$1 = { + name: name$72, + factory: factory_1$81 }; -} -var factory_1$99 = factory$100; -var math$12 = true; + function factory$83 (type, config, load, typed) { -var util = { - factory: factory_1$99, - math: math$12 -}; + var equalScalar$$1 = load(equalScalar); + + var SparseMatrix = type.SparseMatrix; -function factory$101 (type, config, load, typed) { - /** - * Test whether a value is an numeric value. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isNumeric(x) - * - * Examples: - * - * math.isNumeric(2); // returns true - * math.isNumeric(0); // returns true - * math.isNumeric(math.bignumber(500)); // returns true - * math.isNumeric(math.fraction(4)); // returns true - * math.isNumeric(math.complex('2-4i'); // returns false - * math.isNumeric('3'); // returns false - * math.isNumeric([2.3, 'foo', false]); // returns [true, false, true] - * - * See also: - * - * isZero, isPositive, isNegative, isInteger - * - * @param {*} x Value to be tested - * @return {boolean} Returns true when `x` is a `number`, `BigNumber`, - * `Fraction`, or `boolean`. Returns false for other types. - * Throws an error in case of unknown types. - */ - var isNumeric = typed('isNumeric', { - 'number | BigNumber | Fraction | boolean': function () { - return true; - }, + /** + * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). + * Callback function invoked MAX(NNZA, NNZB) times + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 || B(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {Function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm05 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + // sparse matrix arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; - 'Complex | Unit | string': function () { - return false; - }, + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - 'Array | Matrix': function (x) { - return deepMap(x, isNumeric); - } - }); + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - return isNumeric; -} + // rows & columns + var rows = asize[0]; + var columns = asize[1]; -var name$90 = 'isNumeric'; -var factory_1$100 = factory$101; + // datatype + var dt; + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // find signature that matches (dt, dt) + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result arrays + var cvalues = avalues && bvalues ? [] : undefined; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); -var isNumeric$1 = { - name: name$90, - factory: factory_1$100 -}; + // workspaces + var xa = cvalues ? [] : undefined; + var xb = cvalues ? [] : undefined; + // marks indicating we have a value in x for a given column + var wa = []; + var wb = []; -var digits$1 = number.digits; -// TODO this could be improved by simplifying seperated constants under associative and commutative operators -function factory$102(type, config, load, typed, math) { - var util$$1 = load(util); - var isNumeric = load(isNumeric$1); - var isCommutative = util$$1.isCommutative; - var isAssociative = util$$1.isAssociative; - var allChildren = util$$1.allChildren; - var createMakeNodeFunction = util$$1.createMakeNodeFunction; - var ConstantNode = math.expression.node.ConstantNode; - var OperatorNode = math.expression.node.OperatorNode; - var FunctionNode = math.expression.node.FunctionNode; + // vars + var i, j, k, k1; + + // loop columns + for (j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // columns mark + var mark = j + 1; + // loop values A(:,j) + for (k = aptr[j], k1 = aptr[j + 1]; k < k1; k++) { + // row + i = aindex[k]; + // push index + cindex.push(i); + // update workspace + wa[i] = mark; + // check we need to process values + if (xa) + xa[i] = avalues[k]; + } + // loop values B(:,j) + for (k = bptr[j], k1 = bptr[j + 1]; k < k1; k++) { + // row + i = bindex[k]; + // check row existed in A + if (wa[i] !== mark) { + // push index + cindex.push(i); + } + // update workspace + wb[i] = mark; + // check we need to process values + if (xb) + xb[i] = bvalues[k]; + } + // check we need to process values (non pattern matrix) + if (cvalues) { + // initialize first index in j + k = cptr[j]; + // loop index in j + while (k < cindex.length) { + // row + i = cindex[k]; + // marks + var wai = wa[i]; + var wbi = wb[i]; + // check Aij or Bij are nonzero + if (wai === mark || wbi === mark) { + // matrix values @ i,j + var va = wai === mark ? xa[i] : zero; + var vb = wbi === mark ? xb[i] : zero; + // Cij + var vc = cf(va, vb); + // check for zero + if (!eq(vc, zero)) { + // push value + cvalues.push(vc); + // increment pointer + k++; + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + } + } + } + // update cptr + cptr[columns] = cindex.length; - function simplifyConstant(expr) { - var res = foldFraction(expr); - return type.isNode(res) ? res : _toNode(res); - } + // return sparse matrix + return c; + }; - function _eval(fnname, args) { - try { - return _toNumber(math[fnname].apply(null, args)); - } - catch (ignore) { - // sometimes the implicit type conversion causes the evaluation to fail, so we'll try again after removing Fractions - args = args.map(function(x){ - if (type.isFraction(x)) { - return x.valueOf(); - } - return x; - }); - return _toNumber(math[fnname].apply(null, args)); - } + return algorithm05; } - var _toNode = typed({ - 'Fraction': _fractionToNode, - 'number': function(n) { - if (n < 0) { - return unaryMinusNode(new ConstantNode(-n)); - } - return new ConstantNode(n); - }, - 'BigNumber': function(n) { - if (n < 0) { - return unaryMinusNode(new ConstantNode(n.negated().toString(), 'number')); - } - return new ConstantNode(n.toString(), 'number'); - }, - 'Complex': function(s) { - throw 'Cannot convert Complex number to Node'; - } - }); + var name$73 = 'algorithm05'; + var factory_1$82 = factory$83; - // convert a number to a fraction only if it can be expressed exactly - function _exactFraction(n) { - if (isFinite(n)) { - var f = math.fraction(n); - if (f.valueOf() === n) { - return f; - } - } - return n; - } - - // Convert numbers to a preferred number type in preference order: Fraction, number, Complex - // BigNumbers are left alone - var _toNumber = typed({ - 'string': function(s) { - if (config.number === 'BigNumber') { - return math.bignumber(s); - } - else if (config.number === 'Fraction') { - return math.fraction(s); - } - else { - return _exactFraction(parseFloat(s)); - } - }, + var algorithm05 = { + name: name$73, + factory: factory_1$82 + }; - 'Fraction': function(s) { return s; }, + function factory$84 (type, config, load, typed) { + var latex$$1 = latex; - 'BigNumber': function(s) { return s; }, + var matrix$$1 = load(matrix); + var addScalar$$1 = load(addScalar); + var unaryMinus = load(unaryMinus$1); - 'number': function(s) { - return _exactFraction(s); - }, + var algorithm01$$1 = load(algorithm01); + var algorithm03$$1 = load(algorithm03); + var algorithm05$$1 = load(algorithm05); + var algorithm10$$1 = load(algorithm10); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - 'Complex': function(s) { - if (s.im !== 0) { - return s; - } - return _exactFraction(s.re); - }, - }); + // TODO: split function subtract in two: subtract and subtractScalar - function unaryMinusNode(n) { - return new OperatorNode('-', 'unaryMinus', [n]); - } + /** + * Subtract two values, `x - y`. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.subtract(x, y) + * + * Examples: + * + * math.subtract(5.3, 2); // returns number 3.3 + * + * var a = math.complex(2, 3); + * var b = math.complex(4, 1); + * math.subtract(a, b); // returns Complex -2 + 2i + * + * math.subtract([5, 7, 4], 4); // returns Array [1, 3, 0] + * + * var c = math.unit('2.1 km'); + * var d = math.unit('500m'); + * math.subtract(c, d); // returns Unit 1.6 km + * + * See also: + * + * add + * + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x + * Initial value + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y + * Value to subtract from `x` + * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} + * Subtraction of `x` and `y` + */ + var subtract = typed('subtract', { - function _fractionToNode(f) { - var n; - var vn = f.s*f.n; - if (vn < 0) { - n = new OperatorNode('-', 'unaryMinus', [new ConstantNode(-vn)]); - } - else { - n = new ConstantNode(vn); - } + 'number, number': function (x, y) { + return x - y; + }, - if (f.d === 1) { - return n; - } - return new OperatorNode('/', 'divide', [n, new ConstantNode(f.d)]); - } + 'Complex, Complex': function (x, y) { + return x.sub(y); + }, - /* - * Create a binary tree from a list of Fractions and Nodes. - * Tries to fold Fractions by evaluating them until the first Node in the list is hit, so - * `args` should be sorted to have the Fractions at the start (if the operator is commutative). - * @param args - list of Fractions and Nodes - * @param fn - evaluator for the binary operation evaluator that accepts two Fractions - * @param makeNode - creates a binary OperatorNode/FunctionNode from a list of child Nodes - * if args.length is 1, returns args[0] - * @return - Either a Node representing a binary expression or Fraction - */ - function foldOp(fn, args, makeNode) { - return args.reduce(function(a, b) { - if (!type.isNode(a) && !type.isNode(b)) { - try { - return _eval(fn, [a,b]); - } - catch (ignoreandcontinue) {} - a = _toNode(a); - b = _toNode(b); - } - else if (!type.isNode(a)) { - a = _toNode(a); - } - else if (!type.isNode(b)) { - b = _toNode(b); - } + 'BigNumber, BigNumber': function (x, y) { + return x.minus(y); + }, - return makeNode([a, b]); - }); - } + 'Fraction, Fraction': function (x, y) { + return x.sub(y); + }, - // destroys the original node and returns a folded one - function foldFraction(node) { - switch(node.type) { - case 'SymbolNode': - return node; - case 'ConstantNode': - if (typeof node.value === 'number') { - return _toNumber(node.value); - } - return node; - case 'FunctionNode': - if (math[node.name] && math[node.name].rawArgs) { - return node; + 'Unit, Unit': function (x, y) { + if (x.value == null) { + throw new Error('Parameter x contains a unit with undefined value'); } - // Process operators as OperatorNode - var operatorFunctions = [ 'add', 'multiply' ]; - if (operatorFunctions.indexOf(node.name) === -1) { - var args = node.args.map(foldFraction); - - // If all args are numbers - if (!args.some(type.isNode)) { - try { - return _eval(node.name, args); - } - catch (ignoreandcontine) {} - } - - // Convert all args to nodes and construct a symbolic function call - args = args.map(function(arg) { - return type.isNode(arg) ? arg : _toNode(arg); - }); - return new FunctionNode(node.name, args); - } - else { - // treat as operator - } - /* falls through */ - case 'OperatorNode': - var fn = node.fn.toString(); - var args; - var res; - var makeNode = createMakeNodeFunction(node); - if (node.isUnary()) { - args = [foldFraction(node.args[0])]; - if (!type.isNode(args[0])) { - res = _eval(fn, args); - } - else { - res = makeNode(args); - } + if (y.value == null) { + throw new Error('Parameter y contains a unit with undefined value'); } - else if (isAssociative(node)) { - args = allChildren(node); - args = args.map(foldFraction); - if (isCommutative(fn)) { - // commutative binary operator - var consts = [], vars = []; + if (!x.equalBase(y)) { + throw new Error('Units do not match'); + } - for (var i=0; i < args.length; i++) { - if (!type.isNode(args[i])) { - consts.push(args[i]); - } - else { - vars.push(args[i]); - } - } + var res = x.clone(); + res.value = subtract(res.value, y.value); + res.fixPrefix = false; - if (consts.length > 1) { - res = foldOp(fn, consts, makeNode); - vars.unshift(res); - res = foldOp(fn, vars, makeNode); - } - else { - // we won't change the children order since it's not neccessary - res = foldOp(fn, args, makeNode); - } - } - else { - // non-commutative binary operator - res = foldOp(fn, args, makeNode); - } - } - else { - // non-associative binary operator - args = node.args.map(foldFraction); - res = foldOp(fn, args, makeNode); - } return res; - case 'ParenthesisNode': - // remove the uneccessary parenthesis - return foldFraction(node.content); - case 'AccessorNode': - /* falls through */ - case 'ArrayNode': - /* falls through */ - case 'AssignmentNode': - /* falls through */ - case 'BlockNode': - /* falls through */ - case 'FunctionAssignmentNode': - /* falls through */ - case 'IndexNode': - /* falls through */ - case 'ObjectNode': - /* falls through */ - case 'RangeNode': - /* falls through */ - case 'UpdateNode': - /* falls through */ - case 'ConditionalNode': - /* falls through */ - default: - throw 'Unimplemented node type in simplifyConstant: '+node.type; - } - } + }, - return simplifyConstant; -} + 'SparseMatrix, SparseMatrix': function (x, y) { + checkEqualDimensions(x, y); + return algorithm05$$1(x, y, subtract); + }, -var math$13 = true; -var name$91 = 'simplifyConstant'; -var path$43 = 'algebra.simplify'; -var factory_1$101 = factory$102; + 'SparseMatrix, DenseMatrix': function (x, y) { + checkEqualDimensions(x, y); + return algorithm03$$1(y, x, subtract, true); + }, -var simplifyConstant = { - math: math$13, - name: name$91, - path: path$43, - factory: factory_1$101 -}; + 'DenseMatrix, SparseMatrix': function (x, y) { + checkEqualDimensions(x, y); + return algorithm01$$1(x, y, subtract, false); + }, -function factory$103 (type, config, load, typed) { - /** - * Test whether a value is zero. - * The function can check for zero for types `number`, `BigNumber`, `Fraction`, - * `Complex`, and `Unit`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isZero(x) - * - * Examples: - * - * math.isZero(0); // returns true - * math.isZero(2); // returns false - * math.isZero(0.5); // returns false - * math.isZero(math.bignumber(0)); // returns true - * math.isZero(math.fraction(0)); // returns true - * math.isZero(math.fraction(1,3)); // returns false - * math.isZero(math.complex('2 - 4i'); // returns false - * math.isZero(math.complex('0i'); // returns true - * math.isZero('0'); // returns true - * math.isZero('2'); // returns false - * math.isZero([2, 0, -3]'); // returns [false, true, false] - * - * See also: - * - * isNumeric, isPositive, isNegative, isInteger - * - * @param {number | BigNumber | Complex | Fraction | Unit | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is zero. - * Throws an error in case of an unknown data type. - */ - var isZero = typed('isZero', { - 'number': function (x) { - return x === 0; - }, + 'DenseMatrix, DenseMatrix': function (x, y) { + checkEqualDimensions(x, y); + return algorithm13$$1(x, y, subtract); + }, - 'BigNumber': function (x) { - return x.isZero(); - }, + 'Array, Array': function (x, y) { + // use matrix implementation + return subtract(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - 'Complex': function (x) { - return x.re === 0 && x.im === 0; - }, + 'Array, Matrix': function (x, y) { + // use matrix implementation + return subtract(matrix$$1(x), y); + }, - 'Fraction': function (x) { - return x.d === 1 && x.n === 0; - }, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return subtract(x, matrix$$1(y)); + }, + + 'SparseMatrix, any': function (x, y) { + return algorithm10$$1(x, unaryMinus(y), addScalar$$1); + }, - 'Unit': function (x) { - return isZero(x.value); - }, + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, subtract); + }, - 'Array | Matrix': function (x) { - return deepMap(x, isZero); - } - }); + 'any, SparseMatrix': function (x, y) { + return algorithm10$$1(y, x, subtract, true); + }, - return isZero; -} + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, subtract, true); + }, -var name$92 = 'isZero'; -var factory_1$102 = factory$103; + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, subtract, false).valueOf(); + }, -var isZero$1 = { - name: name$92, - factory: factory_1$102 -}; + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, subtract, true).valueOf(); + } + }); -var isInteger$6 = number.isInteger; -var size$2 = array.size; + subtract.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['subtract'] + '${args[1]}\\right)' + }; -function factory$104 (type, config, load, typed) { - var latex$$1 = latex; - var eye = load(eye$1); - var multiply = load(multiply$1); - var matrix$$1 = load(matrix); - var fraction = load(fraction$2); - var number$$1 = load(number$3); + return subtract; + } /** - * Calculates the power of x to y, `x ^ y`. - * Matrix exponentiation is supported for square matrices `x`, and positive - * integer exponents `y`. - * - * For cubic roots of negative numbers, the function returns the principal - * root by default. In order to let the function return the real root, - * math.js can be configured with `math.config({predictable: true})`. - * To retrieve all cubic roots of a value, use `math.cbrt(x, true)`. - * - * Syntax: - * - * math.pow(x, y) - * - * Examples: - * - * math.pow(2, 3); // returns number 8 - * - * var a = math.complex(2, 3); - * math.pow(a, 2) // returns Complex -5 + 12i - * - * var b = [[1, 2], [4, 3]]; - * math.pow(b, 2); // returns Array [[9, 8], [16, 17]] - * - * See also: - * - * multiply, sqrt, cbrt, nthRoot - * - * @param {number | BigNumber | Complex | Array | Matrix} x The base - * @param {number | BigNumber | Complex} y The exponent - * @return {number | BigNumber | Complex | Array | Matrix} The value of `x` to the power `y` + * Check whether matrix x and y have the same number of dimensions. + * Throws a DimensionError when dimensions are not equal + * @param {Matrix} x + * @param {Matrix} y */ - var pow = typed('pow', { - 'number, number': _pow, - - 'Complex, Complex': function (x, y) { - return x.pow(y); - }, - - 'BigNumber, BigNumber': function (x, y) { - if (y.isInteger() || x >= 0 || config.predictable) { - return x.pow(y); - } - else { - return new type.Complex(x.toNumber(), 0).pow(y.toNumber(), 0); - } - }, - - 'Fraction, Fraction': function (x, y) { - if (y.d !== 1) { - if (config.predictable) { - throw new Error('Function pow does not support non-integer exponents for fractions.'); - } - else { - return _pow(x.valueOf(), y.valueOf()); - } - } - else { - return x.pow(y); - } - }, - - 'Array, number': _powArray, + function checkEqualDimensions(x, y) { + var xsize = x.size(); + var ysize = y.size(); - 'Array, BigNumber': function (x, y) { - return _powArray(x, y.toNumber()); - }, - - 'Matrix, number': _powMatrix, - - 'Matrix, BigNumber': function (x, y) { - return _powMatrix(x, y.toNumber()); - }, - - 'Unit, number': function (x, y) { - return x.pow(y); + if (xsize.length !== ysize.length) { + throw new DimensionError_1(xsize.length, ysize.length); } + } - }); - - /** - * Calculates the power of x to y, x^y, for two numbers. - * @param {number} x - * @param {number} y - * @return {number | Complex} res - * @private - */ - function _pow(x, y) { - - // Alternatively could define a 'realmode' config option or something, but - // 'predictable' will work for now - if (config.predictable && !isInteger$6(y) && x < 0) { - // Check to see if y can be represented as a fraction - try { - var yFrac = fraction(y); - var yNum = number$$1(yFrac); - if(y === yNum || Math.abs((y - yNum) / y) < 1e-14) { - if(yFrac.d % 2 === 1) { - return (yFrac.n % 2 === 0 ? 1 : -1) * Math.pow(-x, y); - } - } - } - catch (ex) { - // fraction() throws an error if y is Infinity, etc. - } + var name$74 = 'subtract'; + var factory_1$83 = factory$84; - // Unable to express y as a fraction, so continue on - } + var subtract$1 = { + name: name$74, + factory: factory_1$83 + }; + function factory$85 (type, config, load, typed) { + /** + * Calculate the absolute value of a number. For matrices, the function is + * evaluated element wise. + * + * Syntax: + * + * math.abs(x) + * + * Examples: + * + * math.abs(3.5); // returns number 3.5 + * math.abs(-4.2); // returns number 4.2 + * + * math.abs([3, -5, -1, 0, 2]); // returns Array [3, 5, 1, 0, 2] + * + * See also: + * + * sign + * + * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x + * A number or matrix for which to get the absolute value + * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} + * Absolute value of `x` + */ + var abs = typed('abs', { + 'number': Math.abs, - // x^Infinity === 0 if -1 < x < 1 - // A real number 0 is returned instead of complex(0) - if ((x*x < 1 && y === Infinity) || - (x*x > 1 && y === -Infinity)) { - return 0; - } + 'Complex': function (x) { + return x.abs(); + }, - // **for predictable mode** x^Infinity === NaN if x < -1 - // N.B. this behavour is different from `Math.pow` which gives - // (-2)^Infinity === Infinity - if (config.predictable && - ((x < -1 && y === Infinity) || - (x > -1 && x < 0 && y === -Infinity))) { - return NaN; - } + 'BigNumber': function (x) { + return x.abs(); + }, - if (isInteger$6(y) || x >= 0 || config.predictable) { - return Math.pow(x, y); - } - else { - return new type.Complex(x, 0).pow(y, 0); - } - } + 'Fraction': function (x) { + return x.abs(); + }, - /** - * Calculate the power of a 2d array - * @param {Array} x must be a 2 dimensional, square matrix - * @param {number} y a positive, integer value - * @returns {Array} - * @private - */ - function _powArray(x, y) { - if (!isInteger$6(y) || y < 0) { - throw new TypeError('For A^b, b must be a positive integer (value is ' + y + ')'); - } - // verify that A is a 2 dimensional square matrix - var s = size$2(x); - if (s.length != 2) { - throw new Error('For A^b, A must be 2 dimensional (A has ' + s.length + ' dimensions)'); - } - if (s[0] != s[1]) { - throw new Error('For A^b, A must be square (size is ' + s[0] + 'x' + s[1] + ')'); - } + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since abs(0) = 0 + return deepMap(x, abs, true); + }, - var res = eye(s[0]).valueOf(); - var px = x; - while (y >= 1) { - if ((y & 1) == 1) { - res = multiply(px, res); + 'Unit': function(x) { + return x.abs(); } - y >>= 1; - px = multiply(px, px); - } - return res; - } + }); - /** - * Calculate the power of a 2d matrix - * @param {Matrix} x must be a 2 dimensional, square matrix - * @param {number} y a positive, integer value - * @returns {Matrix} - * @private - */ - function _powMatrix (x, y) { - return matrix$$1(_powArray(x.valueOf(), y)); - } + abs.toTex = {1: '\\left|${args[0]}\\right|'}; + return abs; + } + var name$75 = 'abs'; + var factory_1$84 = factory$85; - pow.toTex = { - 2: '\\left(${args[0]}\\right)' + latex$$1.operators['pow'] + '{${args[1]}}' + var abs$1 = { + name: name$75, + factory: factory_1$84 }; - return pow; -} - -var name$93 = 'pow'; -var factory_1$103 = factory$104; - -var pow$1 = { - name: name$93, - factory: factory_1$103 -}; + var object$4 = utils.object; -function factory$105(type, config, load, typed, math) { - var equal = load(equal$1); - var isZero = load(isZero$1); - var isNumeric = load(isNumeric$1); - var add$$1 = load(add); - var subtract = load(subtract$1); - var multiply = load(multiply$1); - var divide = load(divide$1); - var pow = load(pow$1); + function factory$86 (type, config, load, typed) { - var ConstantNode = math.expression.node.ConstantNode; - var OperatorNode = math.expression.node.OperatorNode; - var FunctionNode = math.expression.node.FunctionNode; - var ParenthesisNode = math.expression.node.ParenthesisNode; - - var node0 = new ConstantNode(0); - var node1 = new ConstantNode(1); + var matrix$$1 = load(matrix); + var abs = load(abs$1); + var addScalar$$1 = load(addScalar); + var divideScalar$$1 = load(divideScalar); + var multiplyScalar$$1 = load(multiplyScalar); + var subtract = load(subtract$1); + var larger$$1 = load(larger); + var equalScalar$$1 = load(equalScalar); + var unaryMinus = load(unaryMinus$1); + + var SparseMatrix = type.SparseMatrix; + var DenseMatrix = type.DenseMatrix; + var Spa = type.Spa; + + /** + * Calculate the Matrix LU decomposition with partial pivoting. Matrix `A` is decomposed in two matrices (`L`, `U`) and a + * row permutation vector `p` where `A[p,:] = L * U` + * + * Syntax: + * + * math.lup(A); + * + * Example: + * + * var m = [[2, 1], [1, 4]]; + * var r = math.lup(m); + * // r = { + * // L: [[1, 0], [0.5, 1]], + * // U: [[2, 1], [0, 3.5]], + * // P: [0, 1] + * // } + * + * See also: + * + * slu, lsolve, lusolve, usolve + * + * @param {Matrix | Array} A A two dimensional matrix or array for which to get the LUP decomposition. + * + * @return {{L: Array | Matrix, U: Array | Matrix, P: Array.}} The lower triangular matrix, the upper triangular matrix and the permutation matrix. + */ + var lup = typed('lup', { - /** - * simplifyCore() performs single pass simplification suitable for - * applications requiring ultimate performance. In contrast, simplify() - * extends simplifyCore() with additional passes to provide deeper - * simplification. - * - * Syntax: - * - * simplify.simplifyCore(expr) - * - * Examples: - * - * var f = math.parse('2 * 1 * x ^ (2 - 1)'); - * math.simplify.simpifyCore(f); // Node {2 * x} - * math.simplify('2 * 1 * x ^ (2 - 1)', [math.simplify.simpifyCore]); // Node {2 * x}; - * - * See also: - * - * derivative - * - * @param {Node} node - * The expression to be simplified - */ - function simplifyCore(node) { - if (type.isOperatorNode(node) && node.isUnary()) { - var a0 = simplifyCore(node.args[0]); + 'DenseMatrix': function (m) { + return _denseLUP(m); + }, + + 'SparseMatrix': function (m) { + return _sparseLUP(m); + }, - if (node.op === '+') { // unary plus - return a0; + 'Array': function (a) { + // create dense matrix from array + var m = matrix$$1(a); + // lup, use matrix implementation + var r = _denseLUP(m); + // result + return { + L: r.L.valueOf(), + U: r.U.valueOf(), + p: r.p + }; } + }); - if (node.op === '-') { // unary minus - if (type.isOperatorNode(a0)) { - if (a0.isUnary() && a0.op === '-') { - return a0.args[0]; - } else if (a0.isBinary() && a0.fn === 'subtract') { - return new OperatorNode('-', 'subtract', [a0.args[1], a0.args[0]]); + var _denseLUP = function (m) { + // rows & columns + var rows = m._size[0]; + var columns = m._size[1]; + // minimum rows and columns + var n = Math.min(rows, columns); + // matrix array, clone original data + var data = object$4.clone(m._data); + // l matrix arrays + var ldata = []; + var lsize = [rows, n]; + // u matrix arrays + var udata = []; + var usize = [n, columns]; + // vars + var i, j, k; + // permutation vector + var p = []; + for (i = 0; i < rows; i++) + p[i] = i; + // loop columns + for (j = 0; j < columns; j++) { + // skip first column in upper triangular matrix + if (j > 0) { + // loop rows + for (i = 0; i < rows; i++) { + // min i,j + var min = Math.min(i, j); + // v[i, j] + var s = 0; + // loop up to min + for (k = 0; k < min; k++) { + // s = l[i, k] - data[k, j] + s = addScalar$$1(s, multiplyScalar$$1(data[i][k], data[k][j])); + } + data[i][j] = subtract(data[i][j], s); } - } - return new OperatorNode(node.op, node.fn, [a0]); - } - } - else if (type.isOperatorNode(node) && node.isBinary()) { - var a0 = simplifyCore(node.args[0]); - var a1 = simplifyCore(node.args[1]); - - if (node.op === "+") { - if (type.isConstantNode(a0)) { - if (isZero(a0.value)) { - return a1; - } else if (type.isConstantNode(a1)) { - return new ConstantNode(add$$1(a0.value, a1.value)); - } + } + // row with larger value in cvector, row >= j + var pi = j; + var pabsv = 0; + var vjj = 0; + // loop rows + for (i = j; i < rows; i++) { + // data @ i, j + var v = data[i][j]; + // absolute value + var absv = abs(v); + // value is greater than pivote value + if (larger$$1(absv, pabsv)) { + // store row + pi = i; + // update max value + pabsv = absv; + // value @ [j, j] + vjj = v; } - if (type.isConstantNode(a1) && isZero(a1.value)) { - return a0; + } + // swap rows (j <-> pi) + if (j !== pi) { + // swap values j <-> pi in p + p[j] = [p[pi], p[pi] = p[j]][0]; + // swap j <-> pi in data + DenseMatrix._swapRows(j, pi, data); + } + // check column is in lower triangular matrix + if (j < rows) { + // loop rows (lower triangular matrix) + for (i = j + 1; i < rows; i++) { + // value @ i, j + var vij = data[i][j]; + if (!equalScalar$$1(vij, 0)) { + // update data + data[i][j] = divideScalar$$1(data[i][j], vjj); + } } - if (type.isOperatorNode(a1) && a1.isUnary() && a1.op === '-') { - return new OperatorNode('-', 'subtract', [a0,a1.args[0]]); + } + } + // loop columns + for (j = 0; j < columns; j++) { + // loop rows + for (i = 0; i < rows; i++) { + // initialize row in arrays + if (j === 0) { + // check row exists in upper triangular matrix + if (i < columns) { + // U + udata[i] = []; + } + // L + ldata[i] = []; } - return new OperatorNode(node.op, node.fn, a1 ? [a0,a1] : [a0]); - } else if (node.op === "-") { - if (type.isConstantNode(a0) && a1) { - if (type.isConstantNode(a1)) { - return new ConstantNode(subtract(a0.value, a1.value)); - } else if (isZero(a0.value)) { - return new OperatorNode("-", "unaryMinus", [a1]); - } + // check we are in the upper triangular matrix + if (i < j) { + // check row exists in upper triangular matrix + if (i < columns) { + // U + udata[i][j] = data[i][j]; + } + // check column exists in lower triangular matrix + if (j < rows) { + // L + ldata[i][j] = 0; + } + continue; } - // if (node.fn === "subtract" && node.args.length === 2) { - if (node.fn === "subtract") { - if (type.isConstantNode(a1) && isZero(a1.value)) { - return a0; - } - if (type.isOperatorNode(a1) && a1.isUnary() && a1.op === '-') { - return simplifyCore(new OperatorNode("+", "add", [a0, a1.args[0]])); - } - return new OperatorNode(node.op, node.fn, [a0,a1]); - } - } else if (node.op === "*") { - if (type.isConstantNode(a0)) { - if (isZero(a0.value)) { - return node0; - } else if (equal(a0.value, 1)) { - return a1; - } else if (type.isConstantNode(a1)) { - return new ConstantNode(multiply(a0.value, a1.value)); - } + // diagonal value + if (i === j) { + // check row exists in upper triangular matrix + if (i < columns) { + // U + udata[i][j] = data[i][j]; + } + // check column exists in lower triangular matrix + if (j < rows) { + // L + ldata[i][j] = 1; + } + continue; } - if (type.isConstantNode(a1)) { - if (isZero(a1.value)) { - return node0; - } else if (equal(a1.value, 1)) { - return a0; - } else if (type.isOperatorNode(a0) && a0.isBinary() && a0.op === node.op) { - var a00 = a0.args[0]; - if (type.isConstantNode(a00)) { - var a00_a1 = new ConstantNode(multiply(a00.value, a1.value)); - return new OperatorNode(node.op, node.fn, [a00_a1, a0.args[1]]); // constants on left - } - } - return new OperatorNode(node.op, node.fn, [a1, a0]); // constants on left - } - return new OperatorNode(node.op, node.fn, [a0, a1]); - } else if (node.op === "/") { - if (type.isConstantNode(a0)) { - if (isZero(a0.value)) { - return node0; - } else if (type.isConstantNode(a1) && - (equal(a1.value, 1) || equal(a1.value, 2) || equal(a1.value, 4))) { - return new ConstantNode(divide(a0.value, a1.value)); - } + // check row exists in upper triangular matrix + if (i < columns) { + // U + udata[i][j] = 0; } - return new OperatorNode(node.op, node.fn, [a0, a1]); - } else if (node.op === "^") { - if (type.isConstantNode(a1)) { - if (isZero(a1.value)) { - return node1; - } else if (equal(a1.value, 1)) { - return a0; - } else { - if (type.isConstantNode(a0)) { - // fold constant - return new ConstantNode(pow(a0.value, a1.value)); - } else if (type.isOperatorNode(a0) && a0.isBinary() && a0.op === "^") { - var a01 = a0.args[1]; - if (type.isConstantNode(a01)) { - return new OperatorNode(node.op, node.fn, [ - a0.args[0], - new ConstantNode(multiply(a01.value, a1.value)) - ]); - } - } - } + // check column exists in lower triangular matrix + if (j < rows) { + // L + ldata[i][j] = data[i][j]; } - return new OperatorNode(node.op, node.fn, [a0, a1]); + } } - } else if (type.isParenthesisNode(node)) { - var c = simplifyCore(node.content); - if (type.isParenthesisNode(c) || type.isSymbolNode(c) || type.isConstantNode(c)) { - return c; + // l matrix + var l = new DenseMatrix({ + data: ldata, + size: lsize + }); + // u matrix + var u = new DenseMatrix({ + data: udata, + size: usize + }); + // p vector + var pv = []; + for (i = 0, n = p.length; i < n; i++) + pv[p[i]] = i; + // return matrices + return { + L: l, + U: u, + p: pv, + toString: function () { + return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\nP: ' + this.p; } - return new ParenthesisNode(c); - } else if (type.isFunctionNode(node)) { - var args = node.args - .map(simplifyCore) - .map(function (arg) { - return type.isParenthesisNode(arg) ? arg.content : arg; - }); - return new FunctionNode(simplifyCore(node.fn), args); - } else { - // cannot simplify - } - return node; - } - - return simplifyCore; -} - -var math$14 = true; -var name$94 = 'simplifyCore'; -var path$44 = 'algebra.simplify'; -var factory_1$104 = factory$105; - -var simplifyCore = { - math: math$14, - name: name$94, - path: path$44, - factory: factory_1$104 -}; - -function factory$106(type, config, load, typed, math) { - var Node = math.expression.node.Node; - var OperatorNode = math.expression.node.OperatorNode; - var FunctionNode = math.expression.node.FunctionNode; - var ParenthesisNode = math.expression.node.ParenthesisNode; - - /** - * resolve(expr, scope) replaces variable nodes with their scoped values - * - * Syntax: - * - * simplify.resolve(expr, scope) - * - * Examples: - * - * math.simplify.resolve('x + y', {x:1, y:2}) // Node {1 + 2} - * math.simplify.resolve(math.parse('x+y'), {x:1, y:2}) // Node {1 + 2} - * math.simplify('x+y', {x:2, y:'x+x'}).toString(); // "6" - * - * @param {Node} node - * The expression tree to be simplified - * @param {Object} scope with variables to be resolved - */ - function resolve(node, scope) { - if (!scope) { - return node; - } - if (type.isSymbolNode(node)) { - var value = scope[node.name]; - if (value instanceof Node) { - return resolve(value, scope); - } else if (typeof value === 'number') { - return math.parse(String(value)); + }; + }; + + var _sparseLUP = function (m) { + // rows & columns + var rows = m._size[0]; + var columns = m._size[1]; + // minimum rows and columns + var n = Math.min(rows, columns); + // matrix arrays (will not be modified, thanks to permutation vector) + var values = m._values; + var index = m._index; + var ptr = m._ptr; + // l matrix arrays + var lvalues = []; + var lindex = []; + var lptr = []; + var lsize = [rows, n]; + // u matrix arrays + var uvalues = []; + var uindex = []; + var uptr = []; + var usize = [n, columns]; + // vars + var i, j, k; + // permutation vectors, (current index -> original index) and (original index -> current index) + var pv_co = []; + var pv_oc = []; + for (i = 0; i < rows; i++) { + pv_co[i] = i; + pv_oc[i] = i; + } + // swap indices in permutation vectors (condition x < y)! + var swapIndeces = function (x, y) { + // find pv indeces getting data from x and y + var kx = pv_oc[x]; + var ky = pv_oc[y]; + // update permutation vector current -> original + pv_co[kx] = y; + pv_co[ky] = x; + // update permutation vector original -> current + pv_oc[x] = ky; + pv_oc[y] = kx; + }; + // loop columns + for (j = 0; j < columns; j++) { + // sparse accumulator + var spa = new Spa(); + // check lower triangular matrix has a value @ column j + if (j < rows) { + // update ptr + lptr.push(lvalues.length); + // first value in j column for lower triangular matrix + lvalues.push(1); + lindex.push(j); } - } else if (type.isOperatorNode(node)) { - var args = node.args.map(function (arg) { - return resolve(arg, scope) + // update ptr + uptr.push(uvalues.length); + // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] + var k0 = ptr[j]; + var k1 = ptr[j + 1]; + // copy column j into sparse accumulator + for (k = k0; k < k1; k++) { + // row + i = index[k]; + // copy column values into sparse accumulator (use permutation vector) + spa.set(pv_co[i], values[k]); + } + // skip first column in upper triangular matrix + if (j > 0) { + // loop rows in column j (above diagonal) + spa.forEach(0, j - 1, function (k, vkj) { + // loop rows in column k (L) + SparseMatrix._forEachRow(k, lvalues, lindex, lptr, function (i, vik) { + // check row is below k + if (i > k) { + // update spa value + spa.accumulate(i, unaryMinus(multiplyScalar$$1(vik, vkj))); + } + }); + }); + } + // row with larger value in spa, row >= j + var pi = j; + var vjj = spa.get(j); + var pabsv = abs(vjj); + // loop values in spa (order by row, below diagonal) + spa.forEach(j + 1, rows - 1, function (x, v) { + // absolute value + var absv = abs(v); + // value is greater than pivote value + if (larger$$1(absv, pabsv)) { + // store row + pi = x; + // update max value + pabsv = absv; + // value @ [j, j] + vjj = v; + } }); - return new OperatorNode(node.op, node.fn, args); - } else if (type.isParenthesisNode(node)) { - return new ParenthesisNode(resolve(node.content, scope)); - } else if (type.isFunctionNode(node)) { - var args = node.args.map(function (arg) { - return resolve(arg, scope) + // swap rows (j <-> pi) + if (j !== pi) { + // swap values j <-> pi in L + SparseMatrix._swapRows(j, pi, lsize[1], lvalues, lindex, lptr); + // swap values j <-> pi in U + SparseMatrix._swapRows(j, pi, usize[1], uvalues, uindex, uptr); + // swap values in spa + spa.swap(j, pi); + // update permutation vector (swap values @ j, pi) + swapIndeces(j, pi); + } + // loop values in spa (order by row) + spa.forEach(0, rows - 1, function (x, v) { + // check we are above diagonal + if (x <= j) { + // update upper triangular matrix + uvalues.push(v); + uindex.push(x); + } + else { + // update value + v = divideScalar$$1(v, vjj); + // check value is non zero + if (!equalScalar$$1(v, 0)) { + // update lower triangular matrix + lvalues.push(v); + lindex.push(x); + } + } }); - return new FunctionNode(node.name, args); - } - return node; - } - - return resolve; -} - -var math$15 = true; -var name$95 = 'resolve'; -var path$45 = 'algebra.simplify'; -var factory_1$105 = factory$106; - -var resolve = { - math: math$15, - name: name$95, - path: path$45, - factory: factory_1$105 -}; - -function factory$107 (type, config, load, typed, math) { - var parse$$1 = load(parse); - var equal = load(equal$1); - var ConstantNode$$1 = load(ConstantNode); - var FunctionNode$$1 = load(FunctionNode); - var OperatorNode$$1 = load(OperatorNode); - var ParenthesisNode$$1 = load(ParenthesisNode); - var SymbolNode$$1 = load(SymbolNode); - var Node$$1 = load(Node); - var simplifyConstant$$1 = load(simplifyConstant); - var simplifyCore$$1 = load(simplifyCore); - var resolve$$1 = load(resolve); - - var util$$1 = load(util); - var isCommutative = util$$1.isCommutative; - var isAssociative = util$$1.isAssociative; - var flatten = util$$1.flatten; - var unflattenr = util$$1.unflattenr; - var unflattenl = util$$1.unflattenl; - var createMakeNodeFunction = util$$1.createMakeNodeFunction; + } + // update ptrs + uptr.push(uvalues.length); + lptr.push(lvalues.length); - /** - * Simplify an expression tree. - * - * A list of rules are applied to an expression, repeating over the list until - * no further changes are made. - * It's possible to pass a custom set of rules to the function as second - * argument. A rule can be specified as an object, string, or function: - * - * var rules = [ - * { l: 'n1*n3 + n2*n3', r: '(n1+n2)*n3' }, - * 'n1*n3 + n2*n3 -> (n1+n2)*n3', - * function (node) { - * // ... return a new node or return the node unchanged - * return node - * } - * ] - * - * String and object rules consist of a left and right pattern. The left is - * used to match against the expression and the right determines what matches - * are replaced with. The main difference between a pattern and a normal - * expression is that variables starting with the following characters are - * interpreted as wildcards: - * - * - 'n' - matches any Node - * - 'c' - matches any ConstantNode - * - 'v' - matches any Node that is not a ConstantNode - * - * The default list of rules is exposed on the function as `simplify.rules` - * and can be used as a basis to built a set of custom rules. - * - * For more details on the theory, see: - * - * - [Strategies for simplifying math expressions (Stackoverflow)](http://stackoverflow.com/questions/7540227/strategies-for-simplifying-math-expressions) - * - [Symbolic computation - Simplification (Wikipedia)](https://en.wikipedia.org/wiki/Symbolic_computation#Simplification) - * - * Syntax: - * - * simplify(expr) - * simplify(expr, rules) - * simplify(expr, rules, scope) - * simplify(expr, scope) - * - * Examples: - * - * math.simplify('2 * 1 * x ^ (2 - 1)'); // Node {2 * x} - * math.simplify('2 * 3 * x', {x: 4}); // Node {24} - * var f = math.parse('2 * 1 * x ^ (2 - 1)'); - * math.simplify(f); // Node {2 * x} - * - * See also: - * - * derivative, parse, eval - * - * @param {Node | string} expr - * The expression to be simplified - * @param {Array<{l:string, r: string} | string | function>} [rules] - * Optional list with custom rules - * @return {Node} Returns the simplified form of `expr` - */ - var simplify = typed('simplify', { - 'string': function (expr) { - return simplify(parse$$1(expr), simplify.rules, {}); - }, + // return matrices + return { + L: new SparseMatrix({ + values: lvalues, + index: lindex, + ptr: lptr, + size: lsize + }), + U: new SparseMatrix({ + values: uvalues, + index: uindex, + ptr: uptr, + size: usize + }), + p: pv_co, + toString: function () { + return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\nP: ' + this.p; + } + }; + }; + + return lup; + } - 'string, Object': function (expr, scope) { - return simplify(parse$$1(expr), simplify.rules, scope); - }, + var name$76 = 'lup'; + var factory_1$85 = factory$86; - 'string, Array': function (expr, rules) { - return simplify(parse$$1(expr), rules, {}); - }, + var lup$1 = { + name: name$76, + factory: factory_1$85 + }; - 'string, Array, Object': function (expr, rules, scope) { - return simplify(parse$$1(expr), rules, scope); - }, + var object$5 = utils.object; + var string$8 = utils.string; - 'Node, Object': function (expr, scope) { - return simplify(expr, simplify.rules, scope); - }, + function factory$87 (type, config, load, typed) { + var matrix$$1 = load(matrix); + var add$$1 = load(add); + var subtract = load(subtract$1); + var multiply = load(multiply$1); + var unaryMinus = load(unaryMinus$1); + var lup = load(lup$1); - 'Node': function (expr) { - return simplify(expr, simplify.rules, {}); - }, + /** + * Calculate the determinant of a matrix. + * + * Syntax: + * + * math.det(x) + * + * Examples: + * + * math.det([[1, 2], [3, 4]]); // returns -2 + * + * var A = [ + * [-2, 2, 3], + * [-1, 1, 3], + * [2, 0, -1] + * ] + * math.det(A); // returns 6 + * + * See also: + * + * inv + * + * @param {Array | Matrix} x A matrix + * @return {number} The determinant of `x` + */ + var det = typed('det', { + 'any': function (x) { + return object$5.clone(x); + }, - 'Node, Array': function (expr, rules) { - return simplify(expr, rules, {}); - }, + 'Array | Matrix': function det (x) { + var size; + if (type.isMatrix(x)) { + size = x.size(); + } + else if (Array.isArray(x)) { + x = matrix$$1(x); + size = x.size(); + } + else { + // a scalar + size = []; + } - 'Node, Array, Object': function (expr, rules, scope) { - rules = _buildRules(rules); + switch (size.length) { + case 0: + // scalar + return object$5.clone(x); - var res = resolve$$1(expr, scope); - var res = removeParens(res); - var visited = {}; + case 1: + // vector + if (size[0] == 1) { + return object$5.clone(x.valueOf()[0]); + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string$8.format(size) + ')'); + } - var str = res.toString({parenthesis: 'all'}); - while(!visited[str]) { - visited[str] = true; - _lastsym = 0; // counter for placeholder symbols - for (var i=0; i c1 * n1' - */ - function _buildRules(rules) { - // Array of rules to be used to simplify expressions - var ruleSet = []; - for(var i=0; i'); - if (lr.length !== 2) { - throw SyntaxError('Could not parse rule: ' + rule); + /** + * Calculate the determinant of a matrix + * @param {Array[]} matrix A square, two dimensional matrix + * @param {number} rows Number of rows of the matrix (zero-based) + * @param {number} cols Number of columns of the matrix (zero-based) + * @returns {number} det + * @private + */ + function _det (matrix$$1, rows, cols) { + if (rows == 1) { + // this is a 1 x 1 matrix + return object$5.clone(matrix$$1[0][0]); + } + else if (rows == 2) { + // this is a 2 x 2 matrix + // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12 + return subtract( + multiply(matrix$$1[0][0], matrix$$1[1][1]), + multiply(matrix$$1[1][0], matrix$$1[0][1]) + ); + } + else { + + // Compute the LU decomposition + var decomp = lup(matrix$$1); + + // The determinant is the product of the diagonal entries of U (and those of L, but they are all 1) + var det = decomp.U[0][0]; + for(var i=1; i= rows) break; + var j=i; + var cycleLen = 0; + while(!visited[decomp.p[j]]) { + visited[decomp.p[j]] = true; + j = decomp.p[j]; + cycleLen++; } - if(rule.evaluate) { - newRule.evaluate = parse$$1(rule.evaluate); + if(cycleLen % 2 === 0) { + evenCycles++; } + } + + return evenCycles % 2 === 0 ? det : unaryMinus(det); - if (isAssociative(newRule.l)) { - var makeNode = createMakeNodeFunction(newRule.l); - var expandsym = _getExpandPlaceholderSymbol(); - newRule.expanded = {}; - newRule.expanded.l = makeNode([newRule.l.clone(), expandsym]); - // Push the expandsym into the deepest possible branch. - // This helps to match the newRule against nodes returned from getSplits() later on. - flatten(newRule.expanded.l); - unflattenr(newRule.expanded.l); - newRule.expanded.r = makeNode([newRule.r, expandsym]); - } - break; - case 'function': - newRule = rule; - break; - default: - throw TypeError('Unsupported type of rule: ' + ruleType); } - // console.log('Adding rule: ' + rules[i]); - // console.log(newRule); - ruleSet.push(newRule); } - return ruleSet; } - var _lastsym = 0; - function _getExpandPlaceholderSymbol() { - return new SymbolNode$$1('_p' + _lastsym++); - } + var name$77 = 'det'; + var factory_1$86 = factory$87; - /** - * Returns a simplfied form of node, or the original node if no simplification was possible. - * - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node - * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The simplified form of `expr`, or the original node if no simplification was possible. - */ - var applyRule = typed('applyRule', { - 'Node, Object': function (node, rule) { + var det$1 = { + name: name$77, + factory: factory_1$86 + }; - //console.log('Entering applyRule(' + node.toString() + ')'); + var isInteger$5 = number.isInteger; - // Do not clone node unless we find a match - var res = node; + function factory$88 (type, config, load, typed) { + + var matrix$$1 = load(matrix); + + /** + * Create a 2-dimensional identity matrix with size m x n or n x n. + * The matrix has ones on the diagonal and zeros elsewhere. + * + * Syntax: + * + * math.eye(n) + * math.eye(n, format) + * math.eye(m, n) + * math.eye(m, n, format) + * math.eye([m, n]) + * math.eye([m, n], format) + * + * Examples: + * + * math.eye(3); // returns [[1, 0, 0], [0, 1, 0], [0, 0, 1]] + * math.eye(3, 2); // returns [[1, 0], [0, 1], [0, 0]] + * + * var A = [[1, 2, 3], [4, 5, 6]]; + * math.eye(math.size(A)); // returns [[1, 0, 0], [0, 1, 0]] + * + * See also: + * + * diag, ones, zeros, size, range + * + * @param {...number | Matrix | Array} size The size for the matrix + * @param {string} [format] The Matrix storage format + * + * @return {Matrix | Array | number} A matrix with ones on the diagonal. + */ + var eye = typed('eye', { + '': function () { + return (config.matrix === 'Matrix') ? matrix$$1([]) : []; + }, - // First replace our child nodes with their simplified versions - // If a child could not be simplified, the assignments will have - // no effect since the node is returned unchanged - if (res instanceof OperatorNode$$1 || res instanceof FunctionNode$$1) { - if (res.args) { - for(var i=0; i [ - * +(node1, +(node2, node3)), - * +(node2, +(node1, node3)), - * +(node3, +(node1, node2))] - * - */ - function getSplits(node, context) { - var res = []; - var right, rightArgs; - var makeNode = createMakeNodeFunction(node); - if (isCommutative(node, context)) { - for (var i=0; i= 2 && rule.args.length === 2) { // node is flattened, rule is not - // Associative operators/functions can be split in different ways so we check if the rule matches each - // them and return their union. - var splits = getSplits(node, rule.context); - var splitMatches = []; - for(var i = 0; i < splits.length; i++) { - var matchSet = _ruleMatch(rule, splits[i], true); // recursing at the same tree depth here - splitMatches = splitMatches.concat(matchSet); + else if (rows == 2) { + // this is a 2 x 2 matrix + var d = det(mat); + if (d == 0) { + throw Error('Cannot calculate inverse, determinant is zero'); } - return splitMatches; - } - else if (rule.args.length > 2) { - throw Error('Unexpected non-binary associative function: ' + rule.toString()); + return [ + [ + divideScalar$$1(mat[1][1], d), + divideScalar$$1(unaryMinus(mat[0][1]), d) + ], + [ + divideScalar$$1(unaryMinus(mat[1][0]), d), + divideScalar$$1(mat[0][0], d) + ] + ]; } else { - // Incorrect number of arguments in rule and node, so no match - return []; - } - } - else if (rule instanceof SymbolNode$$1) { - // If the rule is a SymbolNode, then it carries a special meaning - // according to the first character of the symbol node name. - // c.* matches a ConstantNode - // n.* matches any node - if (rule.name.length === 0) { - throw new Error('Symbol in rule has 0 length...!?'); - } - if (math.hasOwnProperty(rule.name)) { - if (!SUPPORTED_CONSTANTS[rule.name]) { - throw new Error('Built in constant: ' + rule.name + ' is not supported by simplify.'); - } + // this is a matrix of 3 x 3 or larger + // calculate inverse using gauss-jordan elimination + // http://en.wikipedia.org/wiki/Gaussian_elimination + // http://mathworld.wolfram.com/MatrixInverse.html + // http://math.uww.edu/~mcfarlat/inverse.htm + + // make a copy of the matrix (only the arrays, not of the elements) + var A = mat.concat(); + for (r = 0; r < rows; r++) { + A[r] = A[r].concat(); + } + + // create an identity matrix which in the end will contain the + // matrix inverse + var B = eye(rows).valueOf(); + + // loop over all columns, and perform row reductions + for (var c = 0; c < cols; c++) { + // Pivoting: Swap row c with row r, where row r contains the largest element A[r][c] + var A_big = abs(A[c][c]); + var r_big = c; + r = c+1; + while (r < rows) { + if(abs(A[r][c]) > A_big) { + A_big = abs(A[r][c]); + r_big = r; + } + r++; + } + if(A_big == 0) { + throw Error('Cannot calculate inverse, determinant is zero'); + } + r = r_big; + if (r != c) { + temp = A[c]; A[c] = A[r]; A[r] = temp; + temp = B[c]; B[c] = B[r]; B[r] = temp; + } - // built-in constant must match exactly - if(rule.name !== node.name) { - return []; - } - } - else if (rule.name[0] === 'n' || rule.name.substring(0,2) === '_p') { - // rule matches _anything_, so assign this node to the rule.name placeholder - // Assign node to the rule.name placeholder. - // Our parent will check for matches among placeholders. - res[0].placeholders[rule.name] = node; - } - else if (rule.name[0] === 'v') { - // rule matches any variable thing (not a ConstantNode) - if(!type.isConstantNode(node)) { - res[0].placeholders[rule.name] = node; - } - else { - // Mis-match: rule was expecting something other than a ConstantNode - return []; - } - } - else if (rule.name[0] === 'c') { - // rule matches any ConstantNode - if(node instanceof ConstantNode$$1) { - res[0].placeholders[rule.name] = node; - } - else { - // Mis-match: rule was expecting a ConstantNode - return []; + // eliminate non-zero values on the other rows at column c + var Ac = A[c], + Bc = B[c]; + for (r = 0; r < rows; r++) { + var Ar = A[r], + Br = B[r]; + if(r != c) { + // eliminate value at column c and row r + if (Ar[c] != 0) { + f = divideScalar$$1(unaryMinus(Ar[c]), Ac[c]); + + // add (f * row c) to row r to eliminate the value + // at column c + for (s = c; s < cols; s++) { + Ar[s] = addScalar$$1(Ar[s], multiply(f, Ac[s])); + } + for (s = 0; s < cols; s++) { + Br[s] = addScalar$$1(Br[s], multiply(f, Bc[s])); + } + } + } + else { + // normalize value at Acc to 1, + // divide each value on row r with the value at Acc + f = Ac[c]; + for (s = c; s < cols; s++) { + Ar[s] = divideScalar$$1(Ar[s], f); + } + for (s = 0; s < cols; s++) { + Br[s] = divideScalar$$1(Br[s], f); + } + } + } } - } - else { - throw new Error('Invalid symbol in rule: ' + rule.name); - } - } - else if (rule instanceof ConstantNode$$1) { - // Literal constant must match exactly - if(!equal(rule.value, node.value)) { - return []; + return B; } } - else { - // Some other node was encountered which we aren't prepared for, so no match - return []; - } - // It's a match! + inv.toTex = {1: '\\left(${args[0]}\\right)^{-1}'}; - // console.log('_ruleMatch(' + rule.toString() + ', ' + node.toString() + ') found a match'); - return res; + return inv; } + var name$79 = 'inv'; + var factory_1$88 = factory$89; - /** - * Determines whether p and q (and all their children nodes) are identical. - * - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} p - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} q - * @return {Object} Information about the match, if it exists. - */ - function _exactMatch(p, q) { - if(p instanceof ConstantNode$$1 && q instanceof ConstantNode$$1) { - if(!equal(p.value, q.value)) { - return false; - } - } - else if(p instanceof SymbolNode$$1 && q instanceof SymbolNode$$1) { - if(p.name !== q.name) { - return false; - } - } - else if(p instanceof OperatorNode$$1 && q instanceof OperatorNode$$1 - || p instanceof FunctionNode$$1 && q instanceof FunctionNode$$1) { - if (p instanceof OperatorNode$$1) { - if (p.op !== q.op || p.fn !== q.fn) { - return false; - } - } - else if (p instanceof FunctionNode$$1) { - if (p.name !== q.name) { - return false; - } - } + var inv$1 = { + name: name$79, + factory: factory_1$88 + }; - if(p.args.length !== q.args.length) { - return false; - } + var extend$3 = object.extend; - for(var i=0; i implement as an option {order: number} - 'Node, SymbolNode, ConstantNode': function (expr, variable, {order}) { - var res = expr; - for (var i = 0; i < order; i++) { - var constNodes = {}; - constTag(constNodes, expr, variable.name); - res = _derivative(res, constNodes); + // mean(a, b, c, d, ...) + '...': function (args) { + if (containsCollections(args)) { + throw new TypeError('Scalar values expected in function mean'); + } + + return _mean(args); } - return res; - } - */ - }); + }); - derivative._simplify = true; + mean.toTex = undefined; // use default template - derivative.toTex = function(deriv) { - return _derivTex.apply(null, deriv.args); - }; + return mean; - var _derivTex = typed('_derivTex', { - 'Node, SymbolNode': function (expr, x) { - return _derivTex(expr.toString(), x.toString(), 1); - }, - 'Node, SymbolNode, ConstantNode': function (expr, x, order) { - return _derivTex(expr.toString(), x.name, order.value); - }, - 'string, string, number': function (expr, x, order) { - var d; - if (order === 1) { - d = "{d\\over d" + x + "}"; + /** + * Calculate the mean value in an n-dimensional array, returning a + * n-1 dimensional array + * @param {Array} array + * @param {number} dim + * @return {number} mean + * @private + */ + function _nmeanDim(array$$1, dim) { + try { + var sum = reduce(array$$1, dim, add$$1); + var s = Array.isArray(array$$1) ? size$1(array$$1) : array$$1.size(); + return divide(sum, s[dim]); } - else { - d = "{d^{" + order + "}\\over d" + x + "^{" + order + "}}"; + catch (err) { + throw improveErrorMessage$$1(err, 'mean'); } - return d + "\\left[" + expr + "\\right]" } - }); - /** - * Does a depth-first search on the expression tree to identify what Nodes - * are constants (e.g. 2 + 2), and stores the ones that are constants in - * constNodes. Classification is done as follows: - * - * 1. ConstantNodes are constants. - * 2. If there exists a SymbolNode, of which we are differentiating over, - * in the subtree it is not constant. - * - * @param {Object} constNodes Holds the nodes that are constant - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node - * @param {string} varName Variable that we are differentiating - * @return {boolean} if node is constant - */ - // TODO: can we rewrite constTag into a pure function? - var constTag = typed('constTag', { - 'Object, ConstantNode, string': function (constNodes, node) { - return constNodes[node] = true; - }, + /** + * Recursively calculate the mean value in an n-dimensional array + * @param {Array} array + * @return {number} mean + * @private + */ + function _mean(array$$1) { + var sum = 0; + var num = 0; - 'Object, SymbolNode, string': function (constNodes, node, varName) { - // Treat other variables like constants. For reasoning, see: - // https://en.wikipedia.org/wiki/Partial_derivative - if (node.name !== varName) { - return constNodes[node] = true; + deepForEach(array$$1, function (value) { + try { + sum = add$$1(sum, value); + num++; + } + catch (err) { + throw improveErrorMessage$$1(err, 'mean', value); + } + }); + + if (num === 0) { + throw new Error('Cannot calculate mean of an empty array'); } - return false; - }, - 'Object, ParenthesisNode, string': function (constNodes, node, varName) { - return constTag(constNodes, node.content, varName); - }, + return divide(sum, num); + } + } - 'Object, FunctionAssignmentNode, string': function (constNodes, node, varName) { - if (node.params.indexOf(varName) === -1) { - return constNodes[node] = true; - } - return constTag(constNodes, node.expr, varName); - }, + var name$81 = 'mean'; + var factory_1$90 = factory$91; - 'Object, FunctionNode | OperatorNode, string': function (constNodes, node, varName) { - if (node.args.length > 0) { - var isConst = constTag(constNodes, node.args[0], varName); - for (var i = 1; i < node.args.length; ++i) { - isConst = constTag(constNodes, node.args[i], varName) && isConst; - } + var mean$1 = { + name: name$81, + factory: factory_1$90 + }; + + var errorTransform$4 = error_transform.transform; - if (isConst) { - return constNodes[node] = true; - } - } - return false; - } - }); /** - * Applies differentiation rules. + * Attach a transform function to math.mean + * Adds a property transform containing the transform function. * - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node - * @param {Object} constNodes Holds the nodes that are constant - * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The derivative of `expr` + * This transform changed the last `dim` parameter of function mean + * from one-based to zero based */ - var _derivative = typed('_derivative', { - 'ConstantNode, Object': function (node) { - return createConstantNode(0); - }, - - 'SymbolNode, Object': function (node, constNodes) { - if (constNodes[node] !== undefined) { - return createConstantNode(0); - } - return createConstantNode(1); - }, - - 'ParenthesisNode, Object': function (node, constNodes) { - return new ParenthesisNode$$1(_derivative(node.content, constNodes)); - }, + function factory$92 (type, config, load, typed) { + var mean = load(mean$1); - 'FunctionAssignmentNode, Object': function (node, constNodes) { - if (constNodes[node] !== undefined) { - return createConstantNode(0); - } - return _derivative(node.expr, constNodes); - }, + return typed('mean', { + '...any': function (args) { + // change last argument dim from one-based to zero-based + if (args.length == 2 && isCollection(args[0])) { + var dim = args[1]; + if (type.isNumber(dim)) { + args[1] = dim - 1; + } + else if (type.isBigNumber(dim)) { + args[1] = dim.minus(1); + } + } - 'FunctionNode, Object': function (node, constNodes) { - if (node.args.length !== 1) { - funcArgsCheck(node); + try { + return mean.apply(null, args); + } + catch (err) { + throw errorTransform$4(err); + } } + }); + } - if (constNodes[node] !== undefined) { - return createConstantNode(0); - } + var name$82 = 'mean'; + var path$38 = 'expression.transform'; + var factory_1$91 = factory$92; - var arg0 = node.args[0]; - var arg1; + var mean_transform = { + name: name$82, + path: path$38, + factory: factory_1$91 + }; - var div = false; // is output a fraction? - var negative = false; // is output negative? + function factory$93 (type, config, load, typed) { + var smaller$$1 = load(smaller); + var improveErrorMessage$$1 = load(improveErrorMessage); + + /** + * Compute the maximum value of a matrix or a list of values. + * In case of a multi dimensional array, the maximum of the flattened array + * will be calculated. When `dim` is provided, the maximum over the selected + * dimension will be calculated. Parameter `dim` is zero-based. + * + * Syntax: + * + * math.min(a, b, c, ...) + * math.min(A) + * math.min(A, dim) + * + * Examples: + * + * math.min(2, 1, 4, 3); // returns 1 + * math.min([2, 1, 4, 3]); // returns 1 + * + * // maximum over a specified dimension (zero-based) + * math.min([[2, 5], [4, 3], [1, 7]], 0); // returns [1, 3] + * math.min([[2, 5], [4, 3], [1, 7]], 1); // returns [2, 3, 1] + * + * math.max(2.7, 7.1, -4.5, 2.0, 4.1); // returns 7.1 + * math.min(2.7, 7.1, -4.5, 2.0, 4.1); // returns -4.5 + * + * See also: + * + * mean, median, max, prod, std, sum, var + * + * @param {... *} args A single matrix or or multiple scalar values + * @return {*} The minimum value + */ + var min = typed('min', { + // min([a, b, c, d, ...]) + 'Array | Matrix': _min, - var funcDerivative; - switch (node.name) { - case 'cbrt': - // d/dx(cbrt(x)) = 1 / (3x^(2/3)) - div = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - createConstantNode(3), - new OperatorNode$$1('^', 'pow', [ - arg0, - new OperatorNode$$1('/', 'divide', [ - createConstantNode(2), - createConstantNode(3) - ]) - ]) - ]); - break; - case 'sqrt': - case 'nthRoot': - // d/dx(sqrt(x)) = 1 / (2*sqrt(x)) - if (node.args.length === 1) { - div = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - createConstantNode(2), - new FunctionNode$$1('sqrt', [arg0]) - ]); - } - else if (node.args.length === 2) { - // Rearrange from nthRoot(x, a) -> x^(1/a) - arg1 = new OperatorNode$$1('/', 'divide', [ - createConstantNode(1), - node.args[1] - ]); + // min([a, b, c, d, ...], dim) + 'Array | Matrix, number | BigNumber': function (array, dim) { + return reduce(array, dim.valueOf(), _smallest); + }, - // Is a variable? - constNodes[arg1] = constNodes[node.args[1]]; + // min(a, b, c, d, ...) + '...': function (args) { + if (containsCollections(args)) { + throw new TypeError('Scalar values expected in function min'); + } - return _derivative(new OperatorNode$$1('^', 'pow', [arg0, arg1]), constNodes); - } - break; - case 'log10': - arg1 = createConstantNode(10); - /* fall through! */ - case 'log': - if (!arg1 && node.args.length === 1) { - // d/dx(log(x)) = 1 / x - funcDerivative = arg0.clone(); - div = true; - } else if ((node.args.length === 1 && arg1) || - (node.args.length === 2 && constNodes[node.args[1]] !== undefined)) { - // d/dx(log(x, c)) = 1 / (x*ln(c)) - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - arg0.clone(), - new FunctionNode$$1('log', [arg1 || node.args[1]]) - ]); - div = true; - } else if (node.args.length === 2) { - // d/dx(log(f(x), g(x))) = d/dx(log(f(x)) / log(g(x))) - return _derivative(new OperatorNode$$1('/', 'divide', [ - new FunctionNode$$1('log', [arg0]), - new FunctionNode$$1('log', [node.args[1]]) - ]), constNodes); - } - break; - case 'exp': - // d/dx(e^x) = e^x - funcDerivative = new FunctionNode$$1('exp', [arg0.clone()]); - break; - case 'sin': - // d/dx(sin(x)) = cos(x) - funcDerivative = new FunctionNode$$1('cos', [arg0.clone()]); - break; - case 'cos': - // d/dx(cos(x)) = -sin(x) - funcDerivative = new OperatorNode$$1('-', 'unaryMinus', [ - new FunctionNode$$1('sin', [arg0.clone()]) - ]); - break; - case 'tan': - // d/dx(tan(x)) = sec(x)^2 - funcDerivative = new OperatorNode$$1('^', 'pow', [ - new FunctionNode$$1('sec', [arg0.clone()]), - createConstantNode(2) - ]); - break; - case 'sec': - // d/dx(sec(x)) = sec(x)tan(x) - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - node, - new FunctionNode$$1('tan', [arg0.clone()]) - ]); - break; - case 'csc': - // d/dx(csc(x)) = -csc(x)cot(x) - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - node, - new FunctionNode$$1('cot', [arg0.clone()]) - ]); - break; - case 'cot': - // d/dx(cot(x)) = -csc(x)^2 - negative = true; - funcDerivative = new OperatorNode$$1('^', 'pow', [ - new FunctionNode$$1('csc', [arg0.clone()]), - createConstantNode(2) - ]); - break; - case 'asin': - // d/dx(asin(x)) = 1 / sqrt(1 - x^2) - div = true; - funcDerivative = new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]) - ]); - break; - case 'acos': - // d/dx(acos(x)) = -1 / sqrt(1 - x^2) - div = true; - negative = true; - funcDerivative = new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]) - ]); - break; - case 'atan': - // d/dx(atan(x)) = 1 / (x^2 + 1) - div = true; - funcDerivative = new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]); - break; - case 'asec': - // d/dx(asec(x)) = 1 / (|x|*sqrt(x^2 - 1)) - div = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - new FunctionNode$$1('abs', [arg0.clone()]), - new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]) - ]); - break; - case 'acsc': - // d/dx(acsc(x)) = -1 / (|x|*sqrt(x^2 - 1)) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - new FunctionNode$$1('abs', [arg0.clone()]), - new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]) - ]); - break; - case 'acot': - // d/dx(acot(x)) = -1 / (x^2 + 1) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]); - break; - case 'sinh': - // d/dx(sinh(x)) = cosh(x) - funcDerivative = new FunctionNode$$1('cosh', [arg0.clone()]); - break; - case 'cosh': - // d/dx(cosh(x)) = sinh(x) - funcDerivative = new FunctionNode$$1('sinh', [arg0.clone()]); - break; - case 'tanh': - // d/dx(tanh(x)) = sech(x)^2 - funcDerivative = new OperatorNode$$1('^', 'pow', [ - new FunctionNode$$1('sech', [arg0.clone()]), - createConstantNode(2) - ]); - break; - case 'sech': - // d/dx(sech(x)) = -sech(x)tanh(x) - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - node, - new FunctionNode$$1('tanh', [arg0.clone()]) - ]); - break; - case 'csch': - // d/dx(csch(x)) = -csch(x)coth(x) - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - node, - new FunctionNode$$1('coth', [arg0.clone()]) - ]); - break; - case 'coth': - // d/dx(coth(x)) = -csch(x)^2 - negative = true; - funcDerivative = new OperatorNode$$1('^', 'pow', [ - new FunctionNode$$1('csch', [arg0.clone()]), - createConstantNode(2) - ]); - break; - case 'asinh': - // d/dx(asinh(x)) = 1 / sqrt(x^2 + 1) - div = true; - funcDerivative = new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]); - break; - case 'acosh': - // d/dx(acosh(x)) = 1 / sqrt(x^2 - 1); XXX potentially only for x >= 1 (the real spectrum) - div = true; - funcDerivative = new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]); - break; - case 'atanh': - // d/dx(atanh(x)) = 1 / (1 - x^2) - div = true; - funcDerivative = new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]); - break; - case 'asech': - // d/dx(asech(x)) = -1 / (x*sqrt(1 - x^2)) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - arg0.clone(), - new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]) - ]) - ]); - break; - case 'acsch': - // d/dx(acsch(x)) = -1 / (|x|*sqrt(x^2 + 1)) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - new FunctionNode$$1('abs', [arg0.clone()]), - new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]) - ]); - break; - case 'acoth': - // d/dx(acoth(x)) = -1 / (1 - x^2) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]); - break; - case 'abs': - // d/dx(abs(x)) = abs(x)/x - funcDerivative = new OperatorNode$$1('/', 'divide', [ - new FunctionNode$$1(new SymbolNode$$1('abs'), [arg0.clone()]), - arg0.clone() - ]); - break; - case 'gamma': // Needs digamma function, d/dx(gamma(x)) = gamma(x)digamma(x) - default: throw new Error('Function "' + node.name + '" is not supported by derivative, or a wrong number of arguments is passed'); + return _min(args); } + }); - var op, func; - if (div) { - op = '/'; - func = 'divide'; - } else { - op = '*'; - func = 'multiply'; - } + min.toTex = '\\min\\left(${args}\\right)'; - /* Apply chain rule to all functions: - F(x) = f(g(x)) - F'(x) = g'(x)*f'(g(x)) */ - var chainDerivative = _derivative(arg0, constNodes); - if (negative) { - chainDerivative = new OperatorNode$$1('-', 'unaryMinus', [chainDerivative]); - } - return new OperatorNode$$1(op, func, [chainDerivative, funcDerivative]); - }, + return min; - 'OperatorNode, Object': function (node, constNodes) { - if (constNodes[node] !== undefined) { - return createConstantNode(0); + /** + * Return the smallest of two values + * @param {*} x + * @param {*} y + * @returns {*} Returns x when x is smallest, or y when y is smallest + * @private + */ + function _smallest(x, y) { + try { + return smaller$$1(x, y) ? x : y; } - - if (node.op === '+') { - // d/dx(sum(f(x)) = sum(f'(x)) - return new OperatorNode$$1(node.op, node.fn, node.args.map(function(arg) { - return _derivative(arg, constNodes); - })); + catch (err) { + throw improveErrorMessage$$1(err, 'min', y); } + } - if (node.op === '-') { - // d/dx(+/-f(x)) = +/-f'(x) - if (node.isUnary()) { - return new OperatorNode$$1(node.op, node.fn, [ - _derivative(node.args[0], constNodes) - ]); - } + /** + * Recursively calculate the minimum value in an n-dimensional array + * @param {Array} array + * @return {number} min + * @private + */ + function _min(array) { + var min = undefined; - // Linearity of differentiation, d/dx(f(x) +/- g(x)) = f'(x) +/- g'(x) - if (node.isBinary()) { - return new OperatorNode$$1(node.op, node.fn, [ - _derivative(node.args[0], constNodes), - _derivative(node.args[1], constNodes) - ]); + deepForEach(array, function (value) { + try { + if (min === undefined || smaller$$1(value, min)) { + min = value; + } } - } + catch (err) { + throw improveErrorMessage$$1(err, 'min', value); + } + }); - if (node.op === '*') { - // d/dx(c*f(x)) = c*f'(x) - var constantTerms = node.args.filter(function(arg) { - return constNodes[arg] !== undefined; - }); + if (min === undefined) { + throw new Error('Cannot calculate min of an empty array'); + } - if (constantTerms.length > 0) { - var nonConstantTerms = node.args.filter(function(arg) { - return constNodes[arg] === undefined; - }); + return min; + } + } - var nonConstantNode = nonConstantTerms.length === 1 - ? nonConstantTerms[0] - : new OperatorNode$$1('*', 'multiply', nonConstantTerms); + var name$83 = 'min'; + var factory_1$92 = factory$93; - var newArgs = constantTerms.concat(_derivative(nonConstantNode, constNodes)); + var min$1 = { + name: name$83, + factory: factory_1$92 + }; - return new OperatorNode$$1('*', 'multiply', newArgs); - } + var errorTransform$5 = error_transform.transform; - // Product Rule, d/dx(f(x)*g(x)) = f'(x)*g(x) + f(x)*g'(x) - return new OperatorNode$$1('+', 'add', node.args.map(function(argOuter) { - return new OperatorNode$$1('*', 'multiply', node.args.map(function(argInner) { - return (argInner === argOuter) - ? _derivative(argInner, constNodes) - : argInner.clone(); - })); - })); - } - if (node.op === '/' && node.isBinary()) { - var arg0 = node.args[0]; - var arg1 = node.args[1]; + /** + * Attach a transform function to math.min + * Adds a property transform containing the transform function. + * + * This transform changed the last `dim` parameter of function min + * from one-based to zero based + */ + function factory$94 (type, config, load, typed) { + var min = load(min$1); - // d/dx(f(x) / c) = f'(x) / c - if (constNodes[arg1] !== undefined) { - return new OperatorNode$$1('/', 'divide', [_derivative(arg0, constNodes), arg1]); + return typed('min', { + '...any': function (args) { + // change last argument dim from one-based to zero-based + if (args.length == 2 && isCollection(args[0])) { + var dim = args[1]; + if (type.isNumber(dim)) { + args[1] = dim - 1; + } + else if (type.isBigNumber(dim)) { + args[1] = dim.minus(1); + } } - // Reciprocal Rule, d/dx(c / f(x)) = -c(f'(x)/f(x)^2) - if (constNodes[arg0] !== undefined) { - return new OperatorNode$$1('*', 'multiply', [ - new OperatorNode$$1('-', 'unaryMinus', [arg0]), - new OperatorNode$$1('/', 'divide', [ - _derivative(arg1, constNodes), - new OperatorNode$$1('^', 'pow', [arg1.clone(), createConstantNode(2)]) - ]) - ]); + try { + return min.apply(null, args); + } + catch (err) { + throw errorTransform$5(err); } - - // Quotient rule, d/dx(f(x) / g(x)) = (f'(x)g(x) - f(x)g'(x)) / g(x)^2 - return new OperatorNode$$1('/', 'divide', [ - new OperatorNode$$1('-', 'subtract', [ - new OperatorNode$$1('*', 'multiply', [_derivative(arg0, constNodes), arg1.clone()]), - new OperatorNode$$1('*', 'multiply', [arg0.clone(), _derivative(arg1, constNodes)]) - ]), - new OperatorNode$$1('^', 'pow', [arg1.clone(), createConstantNode(2)]) - ]); } + }); + } - if (node.op === '^' && node.isBinary()) { - var arg0 = node.args[0]; - var arg1 = node.args[1]; + var name$84 = 'min'; + var path$39 = 'expression.transform'; + var factory_1$93 = factory$94; - if (constNodes[arg0] !== undefined) { - // If is secretly constant; 0^f(x) = 1 (in JS), 1^f(x) = 1 - if (type.isConstantNode(arg0) && (isZero(arg0.value) || equal(arg0.value, 1))) { - return createConstantNode(0); - } + var min_transform = { + name: name$84, + path: path$39, + factory: factory_1$93 + }; - // d/dx(c^f(x)) = c^f(x)*ln(c)*f'(x) - return new OperatorNode$$1('*', 'multiply', [ - node, - new OperatorNode$$1('*', 'multiply', [ - new FunctionNode$$1('log', [arg0.clone()]), - _derivative(arg1.clone(), constNodes) - ]) - ]); - } + function factory$95 (type, config, load, typed) { + var matrix$$1 = load(matrix); - if (constNodes[arg1] !== undefined) { - if (type.isConstantNode(arg1)) { - // If is secretly constant; f(x)^0 = 1 -> d/dx(1) = 0 - if (isZero(arg1.value)) { - return createConstantNode(0); - } - // Ignore exponent; f(x)^1 = f(x) - if (equal(arg1.value,1)) { - return _derivative(arg0, constNodes); - } - } + var ZERO = new type.BigNumber(0); + var ONE = new type.BigNumber(1); - // Elementary Power Rule, d/dx(f(x)^c) = c*f'(x)*f(x)^(c-1) - var powMinusOne = new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - new OperatorNode$$1('-', 'subtract', [ - arg1, - createConstantNode(1) - ]) - ]); + /** + * Create an array from a range. + * By default, the range end is excluded. This can be customized by providing + * an extra parameter `includeEnd`. + * + * Syntax: + * + * math.range(str [, includeEnd]) // Create a range from a string, + * // where the string contains the + * // start, optional step, and end, + * // separated by a colon. + * math.range(start, end [, includeEnd]) // Create a range with start and + * // end and a step size of 1. + * math.range(start, end, step [, includeEnd]) // Create a range with start, step, + * // and end. + * + * Where: + * + * - `str: string` + * A string 'start:end' or 'start:step:end' + * - `start: {number | BigNumber}` + * Start of the range + * - `end: number | BigNumber` + * End of the range, excluded by default, included when parameter includeEnd=true + * - `step: number | BigNumber` + * Step size. Default value is 1. + * - `includeEnd: boolean` + * Option to specify whether to include the end or not. False by default. + * + * Examples: + * + * math.range(2, 6); // [2, 3, 4, 5] + * math.range(2, -3, -1); // [2, 1, 0, -1, -2] + * math.range('2:1:6'); // [2, 3, 4, 5] + * math.range(2, 6, true); // [2, 3, 4, 5, 6] + * + * See also: + * + * ones, zeros, size, subset + * + * @param {*} args Parameters describing the ranges `start`, `end`, and optional `step`. + * @return {Array | Matrix} range + */ + var range = typed('range', { + // TODO: simplify signatures when typed-function supports default values and optional arguments - return new OperatorNode$$1('*', 'multiply', [ - arg1.clone(), - new OperatorNode$$1('*', 'multiply', [ - _derivative(arg0, constNodes), - powMinusOne - ]) - ]); - } + // TODO: a number or boolean should not be converted to string here + 'string': _strRange, + 'string, boolean': _strRange, - // Functional Power Rule, d/dx(f^g) = f^g*[f'*(g/f) + g'ln(f)] - return new OperatorNode$$1('*', 'multiply', [ - new OperatorNode$$1('^', 'pow', [arg0.clone(), arg1.clone()]), - new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('*', 'multiply', [ - _derivative(arg0, constNodes), - new OperatorNode$$1('/', 'divide', [arg1.clone(), arg0.clone()]) - ]), - new OperatorNode$$1('*', 'multiply', [ - _derivative(arg1, constNodes), - new FunctionNode$$1('log', [arg0.clone()]) - ]) - ]) - ]); + 'number, number': function (start, end) { + return _out(_rangeEx(start, end, 1)); + }, + 'number, number, number': function (start, end, step) { + return _out(_rangeEx(start, end, step)); + }, + 'number, number, boolean': function (start, end, includeEnd) { + return includeEnd + ? _out(_rangeInc(start, end, 1)) + : _out(_rangeEx(start, end, 1)); + }, + 'number, number, number, boolean': function (start, end, step, includeEnd) { + return includeEnd + ? _out(_rangeInc(start, end, step)) + : _out(_rangeEx(start, end, step)); + }, + + 'BigNumber, BigNumber': function (start, end) { + return _out(_bigRangeEx(start, end, ONE)); + }, + 'BigNumber, BigNumber, BigNumber': function (start, end, step) { + return _out(_bigRangeEx(start, end, step)); + }, + 'BigNumber, BigNumber, boolean': function (start, end, includeEnd) { + return includeEnd + ? _out(_bigRangeInc(start, end, ONE)) + : _out(_bigRangeEx(start, end, ONE)); + }, + 'BigNumber, BigNumber, BigNumber, boolean': function (start, end, step, includeEnd) { + return includeEnd + ? _out(_bigRangeInc(start, end, step)) + : _out(_bigRangeEx(start, end, step)); } - throw new Error('Operator "' + node.op + '" is not supported by derivative, or a wrong number of arguments is passed'); - } - }); + }); - /** - * Ensures the number of arguments for a function are correct, - * and will throw an error otherwise. - * - * @param {FunctionNode} node - */ - function funcArgsCheck(node) { - //TODO add min, max etc - if ((node.name === 'log' || node.name === 'nthRoot') && node.args.length === 2) { - return; - } + range.toTex = undefined; // use default template - // There should be an incorrect number of arguments if we reach here + return range; - // Change all args to constants to avoid unidentified - // symbol error when compiling function - for (var i = 0; i < node.args.length; ++i) { - node.args[i] = createConstantNode(0); + function _out(arr) { + return config.matrix === 'Array' ? arr : matrix$$1(arr); } - node.compile().eval(); - throw new Error('Expected TypeError, but none found'); - } - - /** - * Helper function to create a constant node with a specific type - * (number, BigNumber, Fraction) - * @param {number} value - * @param {string} [valueType] - * @return {ConstantNode} - */ - function createConstantNode(value, valueType) { - return new ConstantNode$$1(numeric$$1(value, valueType || config.number)); - } - - return derivative; -} - -var name$97 = 'derivative'; -var factory_1$107 = factory$108; - -var derivative$1 = { - name: name$97, - factory: factory_1$107 -}; - -function factory$109 (type, config, load, typed) { - var simplify = load(simplify$1); - var simplifyCore$$1 = load(simplifyCore); - var simplifyConstant$$1 = load(simplifyConstant); - var ArgumentsError = ArgumentsError_1; - var parse = load(parse$1); - var number$$1 = number; - var ConstantNode$$1 = load(ConstantNode); - var OperatorNode$$1 = load(OperatorNode); - var SymbolNode$$1 = load(SymbolNode); - - /** - * Transform a rationalizable expression in a rational fraction. - * If rational fraction is one variable polynomial then converts - * the numerator and denominator in canonical form, with decreasing - * exponents, returning the coefficients of numerator. - * - * Syntax: - * - * rationalize(expr) - * rationalize(expr, detailed) - * rationalize(expr, scope) - * rationalize(expr, scope, detailed) - * - * Examples: - * - * math.rationalize('sin(x)+y') // Error: There is an unsolved function call - * math.rationalize('2x/y - y/(x+1)') // (2*x^2-y^2+2*x)/(x*y+y) - * math.rationalize('(2x+1)^6') - * // 64*x^6+192*x^5+240*x^4+160*x^3+60*x^2+12*x+1 - * math.rationalize('2x/( (2x-1) / (3x+2) ) - 5x/ ( (3x+4) / (2x^2-5) ) + 3') - * // -20*x^4+28*x^3+104*x^2+6*x-12)/(6*x^2+5*x-4) - * math.rationalize('x/(1-x)/(x-2)/(x-3)/(x-4) + 2x/ ( (1-2x)/(2-3x) )/ ((3-4x)/(4-5x) )') = - * // (-30*x^7+344*x^6-1506*x^5+3200*x^4-3472*x^3+1846*x^2-381*x)/ - * // (-8*x^6+90*x^5-383*x^4+780*x^3-797*x^2+390*x-72) - * - * math.rationalize('x+x+x+y',{y:1}) // 3*x+1 - * math.rationalize('x+x+x+y',{}) // 3*x+y - * ret = math.rationalize('x+x+x+y',{},true) - * // ret.expression=3*x+y, ret.variables = ["x","y"] - * ret = math.rationalize('-2+5x^2',{},true) - * // ret.expression=5*x^2-2, ret.variables = ["x"], ret.coefficients=[-2,0,5] - * - * See also: - * - * simplify - * - * @param {Node|string} expr The expression to check if is a polynomial expression - * @param {Object|boolean} optional scope of expression or true for already evaluated rational expression at input - * @param {Boolean} detailed optional True if return an object, false if return expression node (default) - * - * @return {Object | Expression Node} The rational polynomial of `expr` or na object - * {Object} - * {Expression Node} expression: node simplified expression - * {Expression Node} numerator: simplified numerator of expression - * {Expression Node | boolean} denominator: simplified denominator or false (if there is no denominator) - * {Array} variables: variable names - * {Array} coefficients: coefficients of numerator sorted by increased exponent - * {Expression Node} node simplified expression - * - */ - var rationalize = typed('rationalize', { - 'string': function (expr) { - return rationalize(parse(expr), {}, false); - }, - - 'string, boolean': function (expr, detailed) { - return rationalize(parse(expr), {} , detailed); - }, - - 'string, Object': function (expr, scope) { - return rationalize(parse(expr), scope, false); - }, + function _strRange (str, includeEnd) { + var r = _parse(str); + if (!r){ + throw new SyntaxError('String "' + str + '" is no valid range'); + } - 'string, Object, boolean': function (expr, scope, detailed) { - return rationalize(parse(expr), scope, detailed); - }, + var fn; + if (config.number === 'BigNumber') { + fn = includeEnd ? _bigRangeInc : _bigRangeEx; + return _out(fn( + new type.BigNumber(r.start), + new type.BigNumber(r.end), + new type.BigNumber(r.step))); + } + else { + fn = includeEnd ? _rangeInc : _rangeEx; + return _out(fn(r.start, r.end, r.step)); + } + } - 'Node': function (expr) { - return rationalize(expr, {}, false); - }, + /** + * Create a range with numbers. End is excluded + * @param {number} start + * @param {number} end + * @param {number} step + * @returns {Array} range + * @private + */ + function _rangeEx (start, end, step) { + var array = [], + x = start; + if (step > 0) { + while (x < end) { + array.push(x); + x += step; + } + } + else if (step < 0) { + while (x > end) { + array.push(x); + x += step; + } + } - 'Node, boolean': function (expr, detailed) { - return rationalize(expr, {}, detailed); - }, + return array; + } - 'Node, Object': function (expr, scope) { - return rationalize(expr, scope, false); - }, + /** + * Create a range with numbers. End is included + * @param {number} start + * @param {number} end + * @param {number} step + * @returns {Array} range + * @private + */ + function _rangeInc (start, end, step) { + var array = [], + x = start; + if (step > 0) { + while (x <= end) { + array.push(x); + x += step; + } + } + else if (step < 0) { + while (x >= end) { + array.push(x); + x += step; + } + } - 'Node, Object, boolean': function (expr, scope, detailed) { + return array; + } - var polyRet = polynomial(expr, scope, true); // Check if expression is a rationalizable polynomial - var nVars = polyRet.variables.length; - var expr = polyRet.expression; - - if (nVars>=1) { // If expression in not a constant - var setRules = rulesRationalize(); // Rules for change polynomial in near canonical form - expr = expandPower(expr); // First expand power of polynomials (cannot be made from rules!) - var redoInic = true; // If has change after start, redo the beginning - var s = ""; // New expression - var sBefore; // Previous expression - var rules; - var eDistrDiv = true; - - expr = simplify(expr, setRules.firstRules); // Apply the initial rules, including succ div rules - s = expr.toString(); - - - while (true) { // Apply alternately successive division rules and distr.div.rules - rules = eDistrDiv ? setRules.distrDivRules : setRules.sucDivRules; - expr = simplify(expr,rules); // until no more changes - eDistrDiv = ! eDistrDiv; // Swap between Distr.Div and Succ. Div. Rules - - s = expr.toString(); - if (s===sBefore) break // No changes : end of the loop - - redoInic = true; - sBefore = s; - } - - if (redoInic) { // Apply first rules again without succ div rules (if there are changes) - expr = simplify(expr,setRules.firstRulesAgain); + /** + * Create a range with big numbers. End is excluded + * @param {BigNumber} start + * @param {BigNumber} end + * @param {BigNumber} step + * @returns {Array} range + * @private + */ + function _bigRangeEx (start, end, step) { + var array = [], + x = start; + if (step.gt(ZERO)) { + while (x.lt(end)) { + array.push(x); + x = x.plus(step); } - expr = simplify(expr,setRules.finalRules); // Aplly final rules - - } // NVars >= 1 + } + else if (step.lt(ZERO)) { + while (x.gt(end)) { + array.push(x); + x = x.plus(step); + } + } - var coefficients=[]; - var retRationalize = {}; + return array; + } - if (expr.type === 'OperatorNode' && expr.isBinary() && expr.op === '/') { // Separate numerator from denominator - if (nVars==1) { - expr.args[0] = polyToCanonical(expr.args[0],coefficients); - expr.args[1] = polyToCanonical(expr.args[1]); - } - if (detailed) { - retRationalize.numerator = expr.args[0]; - retRationalize.denominator = expr.args[1]; - } - } else { - if (nVars==1) expr = polyToCanonical(expr,coefficients); - if (detailed) { - retRationalize.numerator = expr; - retRationalize.denominator = null; - } + /** + * Create a range with big numbers. End is included + * @param {BigNumber} start + * @param {BigNumber} end + * @param {BigNumber} step + * @returns {Array} range + * @private + */ + function _bigRangeInc (start, end, step) { + var array = [], + x = start; + if (step.gt(ZERO)) { + while (x.lte(end)) { + array.push(x); + x = x.plus(step); + } + } + else if (step.lt(ZERO)) { + while (x.gte(end)) { + array.push(x); + x = x.plus(step); + } } - // nVars - if (! detailed) return expr; - retRationalize.coefficients = coefficients; - retRationalize.variables = polyRet.variables; - retRationalize.expression = expr; - return retRationalize; - } // ^^^^^^^ end of rationalize ^^^^^^^^ - }); // end of typed rationalize + return array; + } - /** - * Function to simplify an expression using an optional scope and - * return it if the expression is a polynomial expression, i.e. - * an expression with one or more variables and the operators - * +, -, *, and ^, where the exponent can only be a positive integer. - * - * Syntax: - * - * polynomial(expr,scope,extended) - * - * @param {Node | string} expr The expression to simplify and check if is polynomial expression - * @param {object} scope Optional scope for expression simplification - * @param {boolean} extended Optional. Default is false. When true allows divide operator. - * - * - * @return {Object} - * {Object} node: node simplified expression - * {Array} variables: variable names - */ - function polynomial (expr, scope, extended) { - var variables = []; - var node = simplify(expr,scope); // Resolves any variables and functions with all defined parameters - extended = !! extended; + /** + * 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 {{start: number, end: number, step: number} | null} range Object containing properties start, end, step + * @private + */ + function _parse (str) { + var args = str.split(':'); - var oper = '+-*' + (extended ? '/' : ''); - recPoly(node); - var retFunc ={}; - retFunc.expression = node; - retFunc.variables = variables; - return retFunc; + // number + var nums = args.map(function (arg) { + // use Number and not parseFloat as Number returns NaN on invalid garbage in the string + return Number(arg); + }); - //------------------------------------------------------------------------------------------------------- + var invalid = nums.some(function (num) { + return isNaN(num); + }); + if(invalid) { + return null; + } - /** - * Function to simplify an expression using an optional scope and - * return it if the expression is a polynomial expression, i.e. - * an expression with one or more variables and the operators - * +, -, *, and ^, where the exponent can only be a positive integer. - * - * Syntax: - * - * recPoly(node) - * - * - * @param {Node} node The current sub tree expression in recursion - * - * @return nothing, throw an exception if error - */ - function recPoly(node) { - var tp = node.type; // node type - if (tp==='FunctionNode') - throw new ArgumentsError('There is an unsolved function call') // No function call in polynomial expression - else if (tp==='OperatorNode') { - if (node.op === '^' && node.isBinary()) { - if (node.args[1].type!=='ConstantNode' || ! number$$1.isInteger(parseFloat(node.args[1].value))) - throw new ArgumentsError('There is a non-integer exponent'); - else - recPoly(node.args[0]); - } else { - if (oper.indexOf(node.op) === -1) throw new ArgumentsError('Operator ' + node.op + ' invalid in polynomial expression'); - for (var i=0;i infinite loop - // setRules.allRules =oldRules.concat(rulesFirst,rulesDistrDiv,rulesSucDiv); - - setRules.firstRules =oldRules.concat(rulesFirst,rulesSucDiv); // First rule set - setRules.distrDivRules = rulesDistrDiv; // Just distr. div. rules - setRules.sucDivRules = rulesSucDiv; // Jus succ. div. rules - setRules.firstRulesAgain = oldRules.concat(rulesFirst); // Last rules set without succ. div. - - // Division simplification - - // Second rule set. - // There is no aggregate expression with parentesis, but the only variable can be scattered. - setRules.finalRules=[ simplifyCore$$1, // simplify.rules[0] - { l: 'n*-n', r: '-n^2' }, // Joining multiply with power 1 - { l: 'n*n', r: 'n^2' }, // Joining multiply with power 2 - simplifyConstant$$1, // simplify.rules[14] old 3rd index in oldRules - { l: 'n*-n^n1', r: '-n^(n1+1)' }, // Joining multiply with power 3 - { l: 'n*n^n1', r: 'n^(n1+1)' }, // Joining multiply with power 4 - { l: 'n^n1*-n^n2', r: '-n^(n1+n2)' }, // Joining multiply with power 5 - { l: 'n^n1*n^n2', r: 'n^(n1+n2)' }, // Joining multiply with power 6 - { l: 'n^n1*-n', r: '-n^(n1+1)' }, // Joining multiply with power 7 - { l: 'n^n1*n', r: 'n^(n1+1)' }, // Joining multiply with power 8 - { l: 'n^n1/-n', r: '-n^(n1-1)' }, // Joining multiply with power 8 - { l: 'n^n1/n', r: 'n^(n1-1)' }, // Joining division with power 1 - { l: 'n/-n^n1', r: '-n^(1-n1)' }, // Joining division with power 2 - { l: 'n/n^n1', r: 'n^(1-n1)' }, // Joining division with power 3 - { l: 'n^n1/-n^n2', r: 'n^(n1-n2)' }, // Joining division with power 4 - { l: 'n^n1/n^n2', r: 'n^(n1-n2)' }, // Joining division with power 5 - { l: 'n1+(-n2*n3)', r: 'n1-n2*n3' }, // Solving useless parenthesis 1 - { l: 'v*(-c)', r: '-c*v' }, // Solving useless unary 2 - { l: 'n1+-n2', r: 'n1-n2' }, // Solving +- together (new!) - { l: 'v*c', r: 'c*v' }, // inversion constant with variable - { l: '(n1^n2)^n3', r:'(n1^(n2*n3))'}, // Power to Power - - ]; - return setRules; - } // End rulesRationalize + function factory$96 (type, config, load, typed) { + var range = load(range$1); - //--------------------------------------------------------------------------------------- - /** - * Expand recursively a tree node for handling with expressions with exponents - * (it's not for constants, symbols or functions with exponents) - * PS: The other parameters are internal for recursion - * - * Syntax: - * - * expandPower(node) - * - * @param {Node} node Current expression node - * @param {node} parent Parent current node inside the recursion - * @param (int} Parent number of chid inside the rercursion - * - * @return {node} node expression with all powers expanded. - */ - function expandPower(node,parent,indParent) { - var tp = node.type; - var internal = (arguments.length>1); // TRUE in internal calls - - if (tp === 'OperatorNode' && node.isBinary()) { - var does = false; - if (node.op==='^') { // First operator: Parenthesis or UnaryMinus - if ( ( node.args[0].type==='ParenthesisNode' || - node.args[0].type==='OperatorNode' ) - && (node.args[1].type==='ConstantNode') ) { // Second operator: Constant - var val = parseFloat(node.args[1].value); - does = (val>=2 && number$$1.isInteger(val)); + return typed('range', { + '...any': function (args) { + var lastIndex = args.length - 1; + var last = args[lastIndex]; + if (typeof last !== 'boolean') { + // append a parameter includeEnd=true + args.push(true); } - } - if (does) { // Exponent >= 2 - //Before: - // operator A --> Subtree - // parent pow - // constant - // - if (val>2) { // Exponent > 2, - //AFTER: (exponent > 2) - // operator A --> Subtree - // parent * - // deep clone (operator A --> Subtree - // pow - // constant - 1 - // - var nEsqTopo = node.args[0]; - var nDirTopo = new OperatorNode$$1('^', 'pow', [node.args[0].cloneDeep(),new ConstantNode$$1(val-1)]); - node = new OperatorNode$$1('*', 'multiply', [nEsqTopo, nDirTopo]); - } else // Expo = 2 - no power + return range.apply(null, args); + } + }); + } - //AFTER: (exponent = 2) - // operator A --> Subtree - // parent oper - // deep clone (operator A --> Subtree) - // - node = new OperatorNode$$1('*', 'multiply', [node.args[0], node.args[0].cloneDeep()]); - - if (internal) // Change parent references in internal recursive calls - if (indParent==='content') - parent.content = node; - else - parent.args[indParent] = node; - } // does - } // binary OperatorNode - - if (tp==='ParenthesisNode' ) // Recursion - expandPower(node.content,node,'content'); - else if (tp!=='ConstantNode' && tp!=='SymbolNode') - for (var i=0;i=0 ;i--) { - if (coefficients[i]===0) continue; - var n1 = new ConstantNode$$1( - first ? coefficients[i] : Math.abs(coefficients[i])); - var op = coefficients[i]<0 ? '-' : '+'; - - if (i>0) { // Is not a constant without variable - var n2 = new SymbolNode$$1(varname); - if (i>1) { - var n3 = new ConstantNode$$1(i); - n2 = new OperatorNode$$1('^', 'pow', [n2, n3]); - } - if (coefficients[i]===-1 && first) - n1 = new OperatorNode$$1('-', 'unaryMinus', [n2]); - else if (Math.abs(coefficients[i])===1) - n1 = n2; - else - n1 = new OperatorNode$$1('*', 'multiply', [n1, n2]); + return typed('subset', { + '...any': function (args) { + try { + return subset.apply(null, args); + } + catch (err) { + throw errorTransform$6(err); + } } + }); + } - var no; - if (first) - no = n1; - else if (op==='+') - no = new OperatorNode$$1('+', 'add', [no, n1]); - else - no = new OperatorNode$$1('-', 'subtract', [no, n1]); + var name$87 = 'subset'; + var path$41 = 'expression.transform'; + var factory_1$96 = factory$97; + + var subset_transform = { + name: name$87, + path: path$41, + factory: factory_1$96 + }; - first = false; - } // for + var transform$1 = [ + concat_transform, + filter_transform, + forEach_transform, + index_transform, + map_transform, + max_transform, + mean_transform, + min_transform, + range_transform, + subset_transform + ]; - if (first) - return new ConstantNode$$1(0); - else - return no; + function factory$98 (type, config, load, typed) { + var parser$$1 = load(parser)(); /** - * Recursive auxilary function inside polyToCanonical for - * converting expression in canonical form - * - * Syntax: - * - * recurPol(node, noPai, obj) - * - * @param {Node} node The current subpolynomial expression - * @param {Node | Null} noPai The current parent node - * @param {object} obj Object with many internal flags - * - * @return {} No return. If error, throws an exception + * Documentation object + * @param {Object} doc Object containing properties: + * {string} name + * {string} category + * {string} description + * {string[]} syntax + * {string[]} examples + * {string[]} seealso + * @constructor */ - function recurPol(node,noPai,o) { + function Help(doc) { + if (!(this instanceof Help)) { + throw new SyntaxError('Constructor must be called with the new operator'); + } - var tp = node.type; - if (tp==='FunctionNode') // ***** FunctionName ***** - // No function call in polynomial expression - throw new ArgumentsError('There is an unsolved function call') - - else if (tp==='OperatorNode') { // ***** OperatorName ***** - if ('+-*^'.indexOf(node.op) === -1) throw new ArgumentsError('Operator ' + node.op + ' invalid'); - - if (noPai!==null) { - // -(unary),^ : children of *,+,- - if ( (node.fn==='unaryMinus' || node.fn==='pow') && noPai.fn !=='add' && - noPai.fn!=='subtract' && noPai.fn!=='multiply' ) - throw new ArgumentsError('Invalid ' + node.op + ' placing') - - // -,+,* : children of +,- - if ((node.fn==='subtract' || node.fn==='add' || node.fn==='multiply') && - noPai.fn!=='add' && noPai.fn!=='subtract' ) - throw new ArgumentsError('Invalid ' + node.op + ' placing'); - - // -,+ : first child - if ((node.fn==='subtract' || node.fn==='add' || - node.fn==='unaryMinus' ) && o.noFil!==0 ) - throw new ArgumentsError('Invalid ' + node.op + ' placing') - } // Has parent - - // Firers: ^,* Old: ^,&,-(unary): firers - if (node.op==='^' || node.op==='*') o.fire = node.op; - - for (var i=0;i it means there is no exponent above, so it's 1 (cte * var) - if (o.fire==='' || o.fire==='*' ) { - if (maxExpo<1) coefficients[1]=0; - coefficients[1] += o.cte* (o.oper==='+' ? 1 : -1); - maxExpo = Math.max(1,maxExpo); - } + /** + * Generate a string representation of the Help object + * @return {string} Returns a string + * @private + */ + Help.prototype.toString = function () { + var doc = this.doc || {}; + var desc = '\n'; - } else if (tp==='ConstantNode') { - var valor = parseFloat(node.value); - if (noPai === null) { - coefficients[0] = valor; - return; - } - if (noPai.op==='^') { - // cte: second child of power - if (o.noFil!==1) throw new ArgumentsError('Constant cannot be powered') - - if (! number$$1.isInteger(valor) || valor<=0 ) - throw new ArgumentsError('Non-integer exponent is not allowed'); - - for (var i=maxExpo+1;imaxExpo) coefficients[valor]=0; - coefficients[valor] += o.cte * (o.oper==='+' ? 1 : -1); - maxExpo = Math.max(valor,maxExpo); - return; + if (doc.name) { + desc += 'Name: ' + doc.name + '\n\n'; + } + if (doc.category) { + desc += 'Category: ' + doc.category + '\n\n'; + } + if (doc.description) { + desc += 'Description:\n ' + doc.description + '\n\n'; + } + if (doc.syntax) { + desc += 'Syntax:\n ' + doc.syntax.join('\n ') + '\n\n'; + } + if (doc.examples) { + desc += 'Examples:\n'; + for (var i = 0; i < doc.examples.length; i++) { + var expr = doc.examples[i]; + desc += ' ' + expr + '\n'; + + var res; + try { + // note: res can be undefined when `expr` is an empty string + res = parser$$1.eval(expr); + } + catch (e) { + res = e; + } + if (res !== undefined && !type.isHelp(res)) { + desc += ' ' + string.format(res, {precision: 14}) + '\n'; + } } - o.cte = valor; + desc += '\n'; + } + if (doc.seealso && doc.seealso.length) { + desc += 'See also: ' + doc.seealso.join(', ') + '\n'; + } - // Cte: firer '' => There is no exponent and no multiplication, so the exponent is 0. - if (o.fire==='') - coefficients[0] += o.cte * (o.oper==='+'? 1 : -1); + return desc; + }; + /** + * Export the help object to JSON + */ + Help.prototype.toJSON = function () { + var obj = object.clone(this.doc); + obj.mathjs = 'Help'; + return obj; + }; - } else - throw new ArgumentsError('Type ' + tp + ' is not allowed'); - return; - } // End of recurPol - - } // End of polyToCanonical + /** + * Instantiate a Help object from a JSON object + * @param {Object} json + * @returns {Help} Returns a new Help object + */ + Help.fromJSON = function (json) { + var doc = {}; + for (var prop in json) { + if (prop !== 'mathjs') { // ignore mathjs field + doc[prop] = json[prop]; + } + } + return new Help(doc); + }; - return rationalize; -} // end of factory + /** + * Returns a string representation of the Help object + */ + Help.prototype.valueOf = Help.prototype.toString; -var name$98 = 'rationalize'; -var factory_1$108 = factory$109; + return Help; + } -var rationalize$1 = { - name: name$98, - factory: factory_1$108 -}; + var name$88 = 'Help'; + var path$42 = 'type'; + var factory_1$97 = factory$98; -var isInteger$7 = number.isInteger; -var resize$1 = array.resize; + var Help = { + name: name$88, + path: path$42, + factory: factory_1$97 + }; -function factory$110 (type, config, load, typed) { - var matrix$$1 = load(matrix); + var expression = [ + // Note that the docs folder is called "embeddedDocs" and not "docs" to prevent issues + // with yarn autoclean. See https://github.com/josdejong/mathjs/issues/969 + embeddedDocs, + _function$2, + node, + transform$1, - /** - * Create a matrix filled with zeros. The created matrix can have one or - * multiple dimensions. - * - * Syntax: - * - * math.zeros(m) - * math.zeros(m, format) - * math.zeros(m, n) - * math.zeros(m, n, format) - * math.zeros([m, n]) - * math.zeros([m, n], format) - * - * Examples: - * - * math.zeros(3); // returns [0, 0, 0] - * math.zeros(3, 2); // returns [[0, 0], [0, 0], [0, 0]] - * math.zeros(3, 'dense'); // returns [0, 0, 0] - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.zeros(math.size(A)); // returns [[0, 0, 0], [0, 0, 0]] - * - * See also: - * - * ones, eye, size, range - * - * @param {...number | Array} size The size of each dimension of the matrix - * @param {string} [format] The Matrix storage format - * - * @return {Array | Matrix} A matrix filled with zeros - */ - var zeros = typed('zeros', { - '': function () { - return (config.matrix === 'Array') - ? _zeros([]) - : _zeros([], 'default'); - }, + Help, + parse, + Parser + ]; - // math.zeros(m, n, p, ..., format) - // TODO: more accurate signature '...number | BigNumber, string' as soon as typed-function supports this - '...number | BigNumber | string': function (size) { - var last = size[size.length - 1]; - if (typeof last === 'string') { - var format = size.pop(); - return _zeros(size, format); - } - else if (config.matrix === 'Array') { - return _zeros(size); - } - else { - return _zeros(size, 'default'); - } - }, + function factory$99 (type, config, load, typed) { + + var matrix$$1 = load(matrix); + var equalScalar$$1 = load(equalScalar); - 'Array': _zeros, + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - 'Matrix': function (size) { - var format = size.storage(); - return _zeros(size.valueOf(), format); - }, + var latex$$1 = latex; - 'Array | Matrix, string': function (size, format) { - return _zeros (size.valueOf(), format); - } - }); + /** + * Test whether two values are equal. + * + * The function tests whether the relative difference between x and y is + * smaller than the configured epsilon. The function cannot be used to + * compare values smaller than approximately 2.22e-16. + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im. + * + * Values `null` and `undefined` are compared strictly, thus `null` is only + * equal to `null` and nothing else, and `undefined` is only equal to + * `undefined` and nothing else. Strings are compared by their numerical value. + * + * Syntax: + * + * math.equal(x, y) + * + * Examples: + * + * math.equal(2 + 2, 3); // returns false + * math.equal(2 + 2, 4); // returns true + * + * var a = math.unit('50 cm'); + * var b = math.unit('5 m'); + * math.equal(a, b); // returns true + * + * var c = [2, 5, 1]; + * var d = [2, 7, 1]; + * + * math.equal(c, d); // returns [true, false, true] + * math.deepEqual(c, d); // returns false + * + * math.equal("1000", "1e3"); // returns true + * math.equal(0, null); // returns false + * + * See also: + * + * unequal, smaller, smallerEq, larger, largerEq, compare, deepEqual, equalText + * + * @param {number | BigNumber | boolean | Complex | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | boolean | Complex | Unit | string | Array | Matrix} y Second value to compare + * @return {boolean | Array | Matrix} Returns true when the compared values are equal, else returns false + */ + var equal = typed('equal', { + + 'any, any': function (x, y) { + // strict equality for null and undefined? + if (x === null) { return y === null; } + if (y === null) { return x === null; } + if (x === undefined) { return y === undefined; } + if (y === undefined) { return x === undefined; } + + return equalScalar$$1(x, y); + }, - zeros.toTex = undefined; // use default template + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm07$$1(x, y, equalScalar$$1); + }, - return zeros; + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, equalScalar$$1, true); + }, - /** - * Create an Array or Matrix with zeros - * @param {Array} size - * @param {string} [format='default'] - * @return {Array | Matrix} - * @private - */ - function _zeros(size, format) { - var hasBigNumbers = _normalize(size); - var defaultValue = hasBigNumbers ? new type.BigNumber(0) : 0; - _validate(size); - - if (format) { - // return a matrix - var m = matrix$$1(format); - if (size.length > 0) { - return m.resize(size, defaultValue); - } - return m; - } - else { - // return an Array - var arr = []; - if (size.length > 0) { - return resize$1(arr, size, defaultValue); - } - return arr; - } - } + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, equalScalar$$1, false); + }, - // replace BigNumbers with numbers, returns true if size contained BigNumbers - function _normalize(size) { - var hasBigNumbers = false; - size.forEach(function (value, index, arr) { - if (type.isBigNumber(value)) { - hasBigNumbers = true; - arr[index] = value.toNumber(); - } - }); - return hasBigNumbers; - } + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, equalScalar$$1); + }, - // validate arguments - function _validate (size) { - size.forEach(function (value) { - if (typeof value !== 'number' || !isInteger$7(value) || value < 0) { - throw new Error('Parameters in function zeros must be positive integers'); - } - }); - } -} + 'Array, Array': function (x, y) { + // use matrix implementation + return equal(matrix$$1(x), matrix$$1(y)).valueOf(); + }, -// TODO: zeros contains almost the same code as ones. Reuse this? + 'Array, Matrix': function (x, y) { + // use matrix implementation + return equal(matrix$$1(x), y); + }, -var name$99 = 'zeros'; -var factory_1$109 = factory$110; + 'Matrix, Array': function (x, y) { + // use matrix implementation + return equal(x, matrix$$1(y)); + }, -var zeros$1 = { - name: name$99, - factory: factory_1$109 -}; + 'SparseMatrix, any': function (x, y) { + return algorithm12$$1(x, y, equalScalar$$1, false); + }, -function factory$111 (type, config, load, typed) { - /** - * Clone an object. - * - * Syntax: - * - * math.clone(x) - * - * Examples: - * - * math.clone(3.5); // returns number 3.5 - * math.clone(math.complex('2-4i'); // returns Complex 2 - 4i - * math.clone(math.unit(45, 'deg')); // returns Unit 45 deg - * math.clone([[1, 2], [3, 4]]); // returns Array [[1, 2], [3, 4]] - * math.clone("hello world"); // returns string "hello world" - * - * @param {*} x Object to be cloned - * @return {*} A clone of object x - */ - var clone = typed('clone', { - 'any': object.clone - }); + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, equalScalar$$1, false); + }, - clone.toTex = undefined; // use default template + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, equalScalar$$1, true); + }, - return clone; -} + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, equalScalar$$1, true); + }, -var name$100 = 'clone'; -var factory_1$110 = factory$111; + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, equalScalar$$1, false).valueOf(); + }, -var clone$5 = { - name: name$100, - factory: factory_1$110 -}; + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, equalScalar$$1, true).valueOf(); + } + }); -function factory$112 (type, config, load, typed) { - /** - * Test whether a value is positive: larger than zero. - * The function supports types `number`, `BigNumber`, `Fraction`, and `Unit`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isPositive(x) - * - * Examples: - * - * math.isPositive(3); // returns true - * math.isPositive(-2); // returns false - * math.isPositive(0); // returns false - * math.isPositive(-0); // returns false - * math.isPositive(0.5); // returns true - * math.isPositive(math.bignumber(2)); // returns true - * math.isPositive(math.fraction(-2, 5)); // returns false - * math.isPositive(math.fraction(1,3)); // returns false - * math.isPositive('2'); // returns true - * math.isPositive([2, 0, -3]'); // returns [true, false, false] - * - * See also: - * - * isNumeric, isZero, isNegative, isInteger - * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is larger than zero. - * Throws an error in case of an unknown data type. - */ - var isPositive = typed('isPositive', { - 'number': function (x) { - return x > 0; - }, + equal.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['equal'] + '${args[1]}\\right)' + }; - 'BigNumber': function (x) { - return !x.isNeg() && !x.isZero() && !x.isNaN(); - }, + return equal; + } - 'Fraction': function (x) { - return x.s > 0 && x.n > 0; - }, + var name$89 = 'equal'; + var factory_1$98 = factory$99; - 'Unit': function (x) { - return isPositive(x.value); - }, + var equal$1 = { + name: name$89, + factory: factory_1$98 + }; - 'Array | Matrix': function (x) { - return deepMap(x, isPositive); - } - }); + function factory$100(type, config, load, typed, math) { + var FunctionNode = math.expression.node.FunctionNode; + var OperatorNode = math.expression.node.OperatorNode; + var SymbolNode = math.expression.node.SymbolNode; - return isPositive; -} + // TODO commutative/associative properties rely on the arguments + // e.g. multiply is not commutative for matrices + // The properties should be calculated from an argument to simplify, or possibly something in math.config + // the other option is for typed() to specify a return type so that we can evaluate the type of arguments + var commutative = { + 'add': true, + 'multiply': true + }; + var associative = { + 'add': true, + 'multiply': true + }; -var name$101 = 'isPositive'; -var factory_1$111 = factory$112; -var isPositive$1 = { - name: name$101, - factory: factory_1$111 -}; + function isCommutative(node, context) { + if (!type.isOperatorNode(node)) { + return true; + } + var name = node.fn.toString(); + if (context && context.hasOwnProperty(name) && context[name].hasOwnProperty('commutative')) { + return context[name].commutative; + } + return commutative[name] || false; + } -var nearlyEqual$4 = number.nearlyEqual; + function isAssociative(node, context) { + if (!type.isOperatorNode(node)) { + return false; + } + var name = node.fn.toString(); + if (context && context.hasOwnProperty(name) && context[name].hasOwnProperty('associative')) { + return context[name].associative; + } + return associative[name] || false; + } + /** + * Flatten all associative operators in an expression tree. + * Assumes parentheses have already been removed. + */ + function flatten(node) { + if (!node.args || node.args.length === 0) { + return node; + } + node.args = allChildren(node); + for (var i=0; i 2 && isAssociative(node)) { + var curnode = node.args.pop(); + while (node.args.length > 0) { + curnode = makeNode([node.args.pop(), curnode]); + } + node.args = curnode.args; + } + } - var latex$$1 = latex; + /** + * Unflatten all flattened operators to a left-heavy binary tree. + */ + function unflattenl(node) { + if (!node.args || node.args.length === 0) { + return; + } + var makeNode = createMakeNodeFunction(node); + var l = node.args.length; + for (var i = 0; i < l; i++) { + unflattenl(node.args[i]); + } + if (l > 2 && isAssociative(node)) { + var curnode = node.args.shift(); + while (node.args.length > 0) { + curnode = makeNode([curnode, node.args.shift()]); + } + node.args = curnode.args; + } + } - /** - * Test whether two values are unequal. - * - * The function tests whether the relative difference between x and y is - * larger than the configured epsilon. The function cannot be used to compare - * values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im. - * Strings are compared by their numerical value. - * - * Values `null` and `undefined` are compared strictly, thus `null` is unequal - * with everything except `null`, and `undefined` is unequal with everything - * except `undefined`. - * - * Syntax: - * - * math.unequal(x, y) - * - * Examples: - * - * math.unequal(2 + 2, 3); // returns true - * math.unequal(2 + 2, 4); // returns false - * - * var a = math.unit('50 cm'); - * var b = math.unit('5 m'); - * math.unequal(a, b); // returns false - * - * var c = [2, 5, 1]; - * var d = [2, 7, 1]; - * - * math.unequal(c, d); // returns [false, true, false] - * math.deepEqual(c, d); // returns false - * - * math.unequal(0, null); // returns true - * See also: - * - * equal, deepEqual, smaller, smallerEq, larger, largerEq, compare - * - * @param {number | BigNumber | Fraction | boolean | Complex | Unit | string | Array | Matrix | undefined} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Complex | Unit | string | Array | Matrix | undefined} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the compared values are unequal, else returns false - */ - var unequal = typed('unequal', { - - 'any, any': function (x, y) { - // strict equality for null and undefined? - if (x === null) { return y !== null; } - if (y === null) { return x !== null; } - if (x === undefined) { return y !== undefined; } - if (y === undefined) { return x !== undefined; } - - return _unequal(x, y); - }, + function createMakeNodeFunction(node) { + if (type.isOperatorNode(node)) { + return function(args){ + try{ + return new OperatorNode(node.op, node.fn, args); + } catch(err){ + console.error(err); + return []; + } + }; + } + else { + return function(args){ + return new FunctionNode(new SymbolNode(node.name), args); + }; + } + } + return { + createMakeNodeFunction: createMakeNodeFunction, + isCommutative: isCommutative, + isAssociative: isAssociative, + flatten: flatten, + allChildren: allChildren, + unflattenr: unflattenr, + unflattenl: unflattenl + }; + } - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, _unequal); - }, + var factory_1$99 = factory$100; + var math$12 = true; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, _unequal, true); - }, + var util = { + factory: factory_1$99, + math: math$12 + }; - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, _unequal, false); - }, + function factory$101 (type, config, load, typed) { + /** + * Test whether a value is an numeric value. + * + * The function is evaluated element-wise in case of Array or Matrix input. + * + * Syntax: + * + * math.isNumeric(x) + * + * Examples: + * + * math.isNumeric(2); // returns true + * math.isNumeric(0); // returns true + * math.isNumeric(math.bignumber(500)); // returns true + * math.isNumeric(math.fraction(4)); // returns true + * math.isNumeric(math.complex('2-4i'); // returns false + * math.isNumeric('3'); // returns false + * math.isNumeric([2.3, 'foo', false]); // returns [true, false, true] + * + * See also: + * + * isZero, isPositive, isNegative, isInteger + * + * @param {*} x Value to be tested + * @return {boolean} Returns true when `x` is a `number`, `BigNumber`, + * `Fraction`, or `boolean`. Returns false for other types. + * Throws an error in case of unknown types. + */ + var isNumeric = typed('isNumeric', { + 'number | BigNumber | Fraction | boolean': function () { + return true; + }, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, _unequal); - }, + 'Complex | Unit | string': function () { + return false; + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return unequal(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'Array | Matrix': function (x) { + return deepMap(x, isNumeric); + } + }); - 'Array, Matrix': function (x, y) { - // use matrix implementation - return unequal(matrix$$1(x), y); - }, + return isNumeric; + } - 'Matrix, Array': function (x, y) { - // use matrix implementation - return unequal(x, matrix$$1(y)); - }, + var name$90 = 'isNumeric'; + var factory_1$100 = factory$101; - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, _unequal, false); - }, + var isNumeric$1 = { + name: name$90, + factory: factory_1$100 + }; - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, _unequal, false); - }, + var digits$1 = number.digits; + // TODO this could be improved by simplifying seperated constants under associative and commutative operators + function factory$102(type, config, load, typed, math) { + var util$$1 = load(util); + var isNumeric = load(isNumeric$1); + var isCommutative = util$$1.isCommutative; + var isAssociative = util$$1.isAssociative; + var allChildren = util$$1.allChildren; + var createMakeNodeFunction = util$$1.createMakeNodeFunction; + var ConstantNode = math.expression.node.ConstantNode; + var OperatorNode = math.expression.node.OperatorNode; + var FunctionNode = math.expression.node.FunctionNode; - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, _unequal, true); - }, + function simplifyConstant(expr) { + var res = foldFraction(expr); + return type.isNode(res) ? res : _toNode(res); + } - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, _unequal, true); - }, + function _eval(fnname, args) { + try { + return _toNumber(math[fnname].apply(null, args)); + } + catch (ignore) { + // sometimes the implicit type conversion causes the evaluation to fail, so we'll try again after removing Fractions + args = args.map(function(x){ + if (type.isFraction(x)) { + return x.valueOf(); + } + return x; + }); + return _toNumber(math[fnname].apply(null, args)); + } + } - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, _unequal, false).valueOf(); - }, + var _toNode = typed({ + 'Fraction': _fractionToNode, + 'number': function(n) { + if (n < 0) { + return unaryMinusNode(new ConstantNode(-n)); + } + return new ConstantNode(n); + }, + 'BigNumber': function(n) { + if (n < 0) { + return unaryMinusNode(new ConstantNode(n.negated().toString(), 'number')); + } + return new ConstantNode(n.toString(), 'number'); + }, + 'Complex': function(s) { + throw 'Cannot convert Complex number to Node'; + } + }); - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, _unequal, true).valueOf(); + // convert a number to a fraction only if it can be expressed exactly + function _exactFraction(n) { + if (isFinite(n)) { + var f = math.fraction(n); + if (f.valueOf() === n) { + return f; + } + } + return n; } - }); - var _unequal = typed('_unequal', { + // Convert numbers to a preferred number type in preference order: Fraction, number, Complex + // BigNumbers are left alone + var _toNumber = typed({ + 'string': function(s) { + if (config.number === 'BigNumber') { + return math.bignumber(s); + } + else if (config.number === 'Fraction') { + return math.fraction(s); + } + else { + return _exactFraction(parseFloat(s)); + } + }, - 'boolean, boolean': function (x, y) { - return x !== y; - }, + 'Fraction': function(s) { return s; }, - 'number, number': function (x, y) { - return !nearlyEqual$4(x, y, config.epsilon); - }, + 'BigNumber': function(s) { return s; }, - 'BigNumber, BigNumber': function (x, y) { - return !nearlyEqual(x, y, config.epsilon); - }, + 'number': function(s) { + return _exactFraction(s); + }, - 'Fraction, Fraction': function (x, y) { - return !x.equals(y); - }, + 'Complex': function(s) { + if (s.im !== 0) { + return s; + } + return _exactFraction(s.re); + }, + }); - 'Complex, Complex': function (x, y) { - return !x.equals(y); - }, + function unaryMinusNode(n) { + return new OperatorNode('-', 'unaryMinus', [n]); + } - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); + function _fractionToNode(f) { + var n; + var vn = f.s*f.n; + if (vn < 0) { + n = new OperatorNode('-', 'unaryMinus', [new ConstantNode(-vn)]); + } + else { + n = new ConstantNode(vn); } - return unequal(x.value, y.value); - } - }); - unequal.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['unequal'] + '${args[1]}\\right)' - }; + if (f.d === 1) { + return n; + } + return new OperatorNode('/', 'divide', [n, new ConstantNode(f.d)]); + } - return unequal; -} + /* + * Create a binary tree from a list of Fractions and Nodes. + * Tries to fold Fractions by evaluating them until the first Node in the list is hit, so + * `args` should be sorted to have the Fractions at the start (if the operator is commutative). + * @param args - list of Fractions and Nodes + * @param fn - evaluator for the binary operation evaluator that accepts two Fractions + * @param makeNode - creates a binary OperatorNode/FunctionNode from a list of child Nodes + * if args.length is 1, returns args[0] + * @return - Either a Node representing a binary expression or Fraction + */ + function foldOp(fn, args, makeNode) { + return args.reduce(function(a, b) { + if (!type.isNode(a) && !type.isNode(b)) { + try { + return _eval(fn, [a,b]); + } + catch (ignoreandcontinue) {} + a = _toNode(a); + b = _toNode(b); + } + else if (!type.isNode(a)) { + a = _toNode(a); + } + else if (!type.isNode(b)) { + b = _toNode(b); + } -var name$102 = 'unequal'; -var factory_1$112 = factory$113; + return makeNode([a, b]); + }); + } -var unequal$1 = { - name: name$102, - factory: factory_1$112 -}; + // destroys the original node and returns a folded one + function foldFraction(node) { + switch(node.type) { + case 'SymbolNode': + return node; + case 'ConstantNode': + if (typeof node.value === 'number') { + return _toNumber(node.value); + } + return node; + case 'FunctionNode': + if (math[node.name] && math[node.name].rawArgs) { + return node; + } -function factory$114 (type, config, load, typed) { - /** - * Compute the sign of a value. The sign of a value x is: - * - * - 1 when x > 1 - * - -1 when x < 0 - * - 0 when x == 0 - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sign(x) - * - * Examples: - * - * math.sign(3.5); // returns 1 - * math.sign(-4.2); // returns -1 - * math.sign(0); // returns 0 - * - * math.sign([3, 5, -2, 0, 2]); // returns [1, 1, -1, 0, 1] - * - * See also: - * - * abs - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x - * The number for which to determine the sign - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit}e - * The sign of `x` - */ - var sign = typed('sign', { - 'number': number.sign, + // Process operators as OperatorNode + var operatorFunctions = [ 'add', 'multiply' ]; + if (operatorFunctions.indexOf(node.name) === -1) { + var args = node.args.map(foldFraction); - 'Complex': function (x) { - return x.sign(); - }, + // If all args are numbers + if (!args.some(type.isNode)) { + try { + return _eval(node.name, args); + } + catch (ignoreandcontine) {} + } - 'BigNumber': function (x) { - return new type.BigNumber(x.cmp(0)); - }, + // Convert all args to nodes and construct a symbolic function call + args = args.map(function(arg) { + return type.isNode(arg) ? arg : _toNode(arg); + }); + return new FunctionNode(node.name, args); + } + else { + // treat as operator + } + /* falls through */ + case 'OperatorNode': + var fn = node.fn.toString(); + var args; + var res; + var makeNode = createMakeNodeFunction(node); + if (node.isUnary()) { + args = [foldFraction(node.args[0])]; + if (!type.isNode(args[0])) { + res = _eval(fn, args); + } + else { + res = makeNode(args); + } + } + else if (isAssociative(node)) { + args = allChildren(node); + args = args.map(foldFraction); - 'Fraction': function (x) { - return new type.Fraction(x.s, 1); - }, + if (isCommutative(fn)) { + // commutative binary operator + var consts = [], vars = []; - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since sign(0) = 0 - return deepMap(x, sign, true); - }, + for (var i=0; i < args.length; i++) { + if (!type.isNode(args[i])) { + consts.push(args[i]); + } + else { + vars.push(args[i]); + } + } - 'Unit': function(x) { - return sign(x.value); + if (consts.length > 1) { + res = foldOp(fn, consts, makeNode); + vars.unshift(res); + res = foldOp(fn, vars, makeNode); + } + else { + // we won't change the children order since it's not neccessary + res = foldOp(fn, args, makeNode); + } + } + else { + // non-commutative binary operator + res = foldOp(fn, args, makeNode); + } + } + else { + // non-associative binary operator + args = node.args.map(foldFraction); + res = foldOp(fn, args, makeNode); + } + return res; + case 'ParenthesisNode': + // remove the uneccessary parenthesis + return foldFraction(node.content); + case 'AccessorNode': + /* falls through */ + case 'ArrayNode': + /* falls through */ + case 'AssignmentNode': + /* falls through */ + case 'BlockNode': + /* falls through */ + case 'FunctionAssignmentNode': + /* falls through */ + case 'IndexNode': + /* falls through */ + case 'ObjectNode': + /* falls through */ + case 'RangeNode': + /* falls through */ + case 'UpdateNode': + /* falls through */ + case 'ConditionalNode': + /* falls through */ + default: + throw 'Unimplemented node type in simplifyConstant: '+node.type; + } } - }); - sign.toTex = {1: '\\mathrm{${name}}\\left(${args[0]}\\right)'}; + return simplifyConstant; + } - return sign; -} + var math$13 = true; + var name$91 = 'simplifyConstant'; + var path$43 = 'algebra.simplify'; + var factory_1$101 = factory$102; -var name$103 = 'sign'; -var factory_1$113 = factory$114; + var simplifyConstant = { + math: math$13, + name: name$91, + path: path$43, + factory: factory_1$101 + }; -var sign$1 = { - name: name$103, - factory: factory_1$113 -}; + function factory$103 (type, config, load, typed) { + /** + * Test whether a value is zero. + * The function can check for zero for types `number`, `BigNumber`, `Fraction`, + * `Complex`, and `Unit`. + * + * The function is evaluated element-wise in case of Array or Matrix input. + * + * Syntax: + * + * math.isZero(x) + * + * Examples: + * + * math.isZero(0); // returns true + * math.isZero(2); // returns false + * math.isZero(0.5); // returns false + * math.isZero(math.bignumber(0)); // returns true + * math.isZero(math.fraction(0)); // returns true + * math.isZero(math.fraction(1,3)); // returns false + * math.isZero(math.complex('2 - 4i'); // returns false + * math.isZero(math.complex('0i'); // returns true + * math.isZero('0'); // returns true + * math.isZero('2'); // returns false + * math.isZero([2, 0, -3]'); // returns [false, true, false] + * + * See also: + * + * isNumeric, isPositive, isNegative, isInteger + * + * @param {number | BigNumber | Complex | Fraction | Unit | Array | Matrix} x Value to be tested + * @return {boolean} Returns true when `x` is zero. + * Throws an error in case of an unknown data type. + */ + var isZero = typed('isZero', { + 'number': function (x) { + return x === 0; + }, -function factory$115 (type, config, load, typed) { - /** - * Calculate the square root of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sqrt(x) - * - * Examples: - * - * math.sqrt(25); // returns 5 - * math.square(5); // returns 25 - * math.sqrt(-4); // returns Complex 2i - * - * See also: - * - * square, multiply, cube, cbrt, sqrtm - * - * @param {number | BigNumber | Complex | Array | Matrix | Unit} x - * Value for which to calculate the square root. - * @return {number | BigNumber | Complex | Array | Matrix | Unit} - * Returns the square root of `x` - */ - var sqrt = typed('sqrt', { - 'number': _sqrtNumber, + 'BigNumber': function (x) { + return x.isZero(); + }, - 'Complex': function (x) { - return x.sqrt(); - }, + 'Complex': function (x) { + return x.re === 0 && x.im === 0; + }, - 'BigNumber': function (x) { - if (!x.isNegative() || config.predictable) { - return x.sqrt(); - } - else { - // negative value -> downgrade to number to do complex value computation - return _sqrtNumber(x.toNumber()); + 'Fraction': function (x) { + return x.d === 1 && x.n === 0; + }, + + 'Unit': function (x) { + return isZero(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, isZero); } - }, + }); - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since sqrt(0) = 0 - return deepMap(x, sqrt, true); - }, + return isZero; + } - 'Unit': function (x) { - // Someday will work for complex units when they are implemented - return x.pow(0.5); - } + var name$92 = 'isZero'; + var factory_1$102 = factory$103; - }); + var isZero$1 = { + name: name$92, + factory: factory_1$102 + }; - /** - * Calculate sqrt for a number - * @param {number} x - * @returns {number | Complex} Returns the square root of x - * @private - */ - function _sqrtNumber(x) { - if (x >= 0 || config.predictable) { - return Math.sqrt(x); - } - else { - return new type.Complex(x, 0).sqrt(); - } - } + var isInteger$6 = number.isInteger; + var size$2 = array.size; - sqrt.toTex = {1: '\\sqrt{${args[0]}}'}; + function factory$104 (type, config, load, typed) { + var latex$$1 = latex; + var eye = load(eye$1); + var multiply = load(multiply$1); + var matrix$$1 = load(matrix); + var fraction = load(fraction$2); + var number$$1 = load(number$3); - return sqrt; -} + /** + * Calculates the power of x to y, `x ^ y`. + * Matrix exponentiation is supported for square matrices `x`, and positive + * integer exponents `y`. + * + * For cubic roots of negative numbers, the function returns the principal + * root by default. In order to let the function return the real root, + * math.js can be configured with `math.config({predictable: true})`. + * To retrieve all cubic roots of a value, use `math.cbrt(x, true)`. + * + * Syntax: + * + * math.pow(x, y) + * + * Examples: + * + * math.pow(2, 3); // returns number 8 + * + * var a = math.complex(2, 3); + * math.pow(a, 2) // returns Complex -5 + 12i + * + * var b = [[1, 2], [4, 3]]; + * math.pow(b, 2); // returns Array [[9, 8], [16, 17]] + * + * See also: + * + * multiply, sqrt, cbrt, nthRoot + * + * @param {number | BigNumber | Complex | Array | Matrix} x The base + * @param {number | BigNumber | Complex} y The exponent + * @return {number | BigNumber | Complex | Array | Matrix} The value of `x` to the power `y` + */ + var pow = typed('pow', { + 'number, number': _pow, -var name$104 = 'sqrt'; -var factory_1$114 = factory$115; + 'Complex, Complex': function (x, y) { + return x.pow(y); + }, -var sqrt$1 = { - name: name$104, - factory: factory_1$114 -}; + 'BigNumber, BigNumber': function (x, y) { + if (y.isInteger() || x >= 0 || config.predictable) { + return x.pow(y); + } + else { + return new type.Complex(x.toNumber(), 0).pow(y.toNumber(), 0); + } + }, -function factory$116 (type, config, load, typed) { - /** - * Compute the complex conjugate of a complex value. - * If `x = a+bi`, the complex conjugate of `x` is `a - bi`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.conj(x) - * - * Examples: - * - * math.conj(math.complex('2 + 3i')); // returns Complex 2 - 3i - * math.conj(math.complex('2 - 3i')); // returns Complex 2 + 3i - * math.conj(math.complex('-5.2i')); // returns Complex 5.2i - * - * See also: - * - * re, im, arg, abs - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * A complex number or array with complex numbers - * @return {number | BigNumber | Complex | Array | Matrix} - * The complex conjugate of x - */ - var conj = typed('conj', { - 'number': function (x) { - return x; - }, + 'Fraction, Fraction': function (x, y) { + if (y.d !== 1) { + if (config.predictable) { + throw new Error('Function pow does not support non-integer exponents for fractions.'); + } + else { + return _pow(x.valueOf(), y.valueOf()); + } + } + else { + return x.pow(y); + } + }, - 'BigNumber': function (x) { - return x; - }, + 'Array, number': _powArray, - 'Complex': function (x) { - return x.conjugate(); - }, + 'Array, BigNumber': function (x, y) { + return _powArray(x, y.toNumber()); + }, - 'Array | Matrix': function (x) { - return deepMap(x, conj); - } - }); + 'Matrix, number': _powMatrix, - conj.toTex = {1: '\\left(${args[0]}\\right)^*'}; + 'Matrix, BigNumber': function (x, y) { + return _powMatrix(x, y.toNumber()); + }, - return conj; -} + 'Unit, number': function (x, y) { + return x.pow(y); + } -var name$105 = 'conj'; -var factory_1$115 = factory$116; + }); -var conj$1 = { - name: name$105, - factory: factory_1$115 -}; + /** + * Calculates the power of x to y, x^y, for two numbers. + * @param {number} x + * @param {number} y + * @return {number | Complex} res + * @private + */ + function _pow(x, y) { -function factory$117 (type, config, load, typed) { + // Alternatively could define a 'realmode' config option or something, but + // 'predictable' will work for now + if (config.predictable && !isInteger$6(y) && x < 0) { + // Check to see if y can be represented as a fraction + try { + var yFrac = fraction(y); + var yNum = number$$1(yFrac); + if(y === yNum || Math.abs((y - yNum) / y) < 1e-14) { + if(yFrac.d % 2 === 1) { + return (yFrac.n % 2 === 0 ? 1 : -1) * Math.pow(-x, y); + } + } + } + catch (ex) { + // fraction() throws an error if y is Infinity, etc. + } - var matrix$$1 = load(matrix); - var zeros = load(zeros$1); - var eye = load(eye$1); - var clone = load(clone$5); - - var isZero = load(isZero$1); - var isPositive = load(isPositive$1); - var unequal = load(unequal$1); - - var abs = load(abs$1); - var sign = load(sign$1); - var sqrt = load(sqrt$1); - var conj = load(conj$1); - - var unaryMinus = load(unaryMinus$1); - var addScalar$$1 = load(addScalar); - var divideScalar$$1 = load(divideScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var subtract = load(subtract$1); - - - /** - * Calculate the Matrix QR decomposition. Matrix `A` is decomposed in - * two matrices (`Q`, `R`) where `Q` is an - * orthogonal matrix and `R` is an upper triangular matrix. - * - * Syntax: - * - * math.qr(A); - * - * Example: - * - * var m = [ - * [1, -1, 4], - * [1, 4, -2], - * [1, 4, 2], - * [1, -1, 0] - * ]; - * var result = math.qr(m); - * // r = { - * // Q: [ - * // [0.5, -0.5, 0.5], - * // [0.5, 0.5, -0.5], - * // [0.5, 0.5, 0.5], - * // [0.5, -0.5, -0.5], - * // ], - * // R: [ - * // [2, 3, 2], - * // [0, 5, -2], - * // [0, 0, 4], - * // [0, 0, 0] - * // ] - * // } - * - * See also: - * - * lu - * - * @param {Matrix | Array} A A two dimensional matrix or array - * for which to get the QR decomposition. - * - * @return {{Q: Array | Matrix, R: Array | Matrix}} Q: the orthogonal - * matrix and R: the upper triangular matrix - */ - var qr = typed('qr', { + // Unable to express y as a fraction, so continue on + } - 'DenseMatrix': function (m) { - return _denseQR(m); - }, - - 'SparseMatrix': function (m) { - return _sparseQR(m); - }, - 'Array': function (a) { - // create dense matrix from array - var m = matrix$$1(a); - // lup, use matrix implementation - var r = _denseQR(m); - // result - return { - Q: r.Q.valueOf(), - R: r.R.valueOf() - }; + // x^Infinity === 0 if -1 < x < 1 + // A real number 0 is returned instead of complex(0) + if ((x*x < 1 && y === Infinity) || + (x*x > 1 && y === -Infinity)) { + return 0; + } + + // **for predictable mode** x^Infinity === NaN if x < -1 + // N.B. this behavour is different from `Math.pow` which gives + // (-2)^Infinity === Infinity + if (config.predictable && + ((x < -1 && y === Infinity) || + (x > -1 && x < 0 && y === -Infinity))) { + return NaN; + } + + if (isInteger$6(y) || x >= 0 || config.predictable) { + return Math.pow(x, y); + } + else { + return new type.Complex(x, 0).pow(y, 0); + } } - }); - var _denseQR = function (m) { - - // rows & columns (m x n) - var rows = m._size[0]; // m - var cols = m._size[1]; // n - - var Q = eye([rows], 'dense'); - var Qdata = Q._data; - - var R = m.clone(); - var Rdata = R._data; - - // vars - var i, j, k; - - var w = zeros([rows], ''); - - for (k = 0; k < Math.min(cols, rows); ++k) { - - /* - * **k-th Household matrix** - * - * The matrix I - 2*v*transpose(v) - * x = first column of A - * x1 = first element of x - * alpha = x1 / |x1| * |x| - * e1 = tranpose([1, 0, 0, ...]) - * u = x - alpha * e1 - * v = u / |u| - * - * Household matrix = I - 2 * v * tranpose(v) - * - * * Initially Q = I and R = A. - * * Household matrix is a reflection in a plane normal to v which - * will zero out all but the top right element in R. - * * Appplying reflection to both Q and R will not change product. - * * Repeat this process on the (1,1) minor to get R as an upper - * triangular matrix. - * * Reflections leave the magnitude of the columns of Q unchanged - * so Q remains othoganal. - * - */ - - var pivot = Rdata[k][k]; - var sgn = unaryMinus(sign(pivot)); - var conjSgn = conj(sgn); - - var alphaSquared = 0; + /** + * Calculate the power of a 2d array + * @param {Array} x must be a 2 dimensional, square matrix + * @param {number} y a positive, integer value + * @returns {Array} + * @private + */ + function _powArray(x, y) { + if (!isInteger$6(y) || y < 0) { + throw new TypeError('For A^b, b must be a positive integer (value is ' + y + ')'); + } + // verify that A is a 2 dimensional square matrix + var s = size$2(x); + if (s.length != 2) { + throw new Error('For A^b, A must be 2 dimensional (A has ' + s.length + ' dimensions)'); + } + if (s[0] != s[1]) { + throw new Error('For A^b, A must be square (size is ' + s[0] + 'x' + s[1] + ')'); + } - for(i = k; i < rows; i++) { - alphaSquared = addScalar$$1(alphaSquared, multiplyScalar$$1(Rdata[i][k], conj(Rdata[i][k]))); + var res = eye(s[0]).valueOf(); + var px = x; + while (y >= 1) { + if ((y & 1) == 1) { + res = multiply(px, res); + } + y >>= 1; + px = multiply(px, px); } - - var alpha = multiplyScalar$$1(sgn, sqrt(alphaSquared)); - - - if (!isZero(alpha)) { - - // first element in vector u - var u1 = subtract(pivot, alpha); - - // w = v * u1 / |u| (only elements k to (rows-1) are used) - w[k] = 1; - - for (i = k+1; i < rows; i++) { - w[i] = divideScalar$$1(Rdata[i][k], u1); - } - - // tau = - conj(u1 / alpha) - var tau = unaryMinus(conj(divideScalar$$1(u1, alpha))); - - var s; - - /* - * tau and w have been choosen so that - * - * 2 * v * tranpose(v) = tau * w * tranpose(w) - */ - - /* - * -- calculate R = R - tau * w * tranpose(w) * R -- - * Only do calculation with rows k to (rows-1) - * Additionally columns 0 to (k-1) will not be changed by this - * multiplication so do not bother recalculating them - */ - for (j = k; j < cols; j++) { - s = 0.0; - - // calculate jth element of [tranpose(w) * R] - for (i = k; i < rows; i++) { - s = addScalar$$1(s, multiplyScalar$$1(conj(w[i]), Rdata[i][j])); - } - - // calculate the jth element of [tau * transpose(w) * R] - s = multiplyScalar$$1(s, tau); - - for (i = k; i < rows; i++) { - Rdata[i][j] = multiplyScalar$$1( - subtract(Rdata[i][j], multiplyScalar$$1(w[i], s)), - conjSgn - ); - } - } - /* - * -- calculate Q = Q - tau * Q * w * transpose(w) -- - * Q is a square matrix (rows x rows) - * Only do calculation with columns k to (rows-1) - * Additionally rows 0 to (k-1) will not be changed by this - * multiplication so do not bother recalculating them - */ - for (i = 0; i < rows; i++) { - s = 0.0; - - // calculate ith element of [Q * w] - for (j = k; j < rows; j++) { - s = addScalar$$1(s, multiplyScalar$$1(Qdata[i][j], w[j])); - } - - // calculate the ith element of [tau * Q * w] - s = multiplyScalar$$1(s, tau); - - for (j = k; j < rows; ++j) { - Qdata[i][j] = divideScalar$$1( - subtract(Qdata[i][j], multiplyScalar$$1(s, conj(w[j]))), - conjSgn - ); - } - - } - } - + return res; } - - // coerse almost zero elements to zero - // TODO I feel uneasy just zeroing these values - for (i = 0; i < rows; ++i) { - for (j = 0; j < i && j < cols; ++j) { - if (unequal(0, divideScalar$$1(Rdata[i][j], 1e5))) { - throw new Error('math.qr(): unknown error - ' + - 'R is not lower triangular (element (' + - i + ', ' + j + ') = ' + Rdata[i][j] + ')' - ); - } - Rdata[i][j] = multiplyScalar$$1(Rdata[i][j], 0); - } + + /** + * Calculate the power of a 2d matrix + * @param {Matrix} x must be a 2 dimensional, square matrix + * @param {number} y a positive, integer value + * @returns {Matrix} + * @private + */ + function _powMatrix (x, y) { + return matrix$$1(_powArray(x.valueOf(), y)); } - - // return matrices - return { - Q: Q, - R: R, - toString: function () { - return 'Q: ' + this.Q.toString() + '\nR: ' + this.R.toString(); - } - }; - }; - - var _sparseQR = function (m) { - - throw new Error('qr not implemented for sparse matrices yet'); - - }; - - return qr; -} -var name$106 = 'qr'; -var factory_1$116 = factory$117; -var qr$1 = { - name: name$106, - factory: factory_1$116 -}; -function factory$118 () { + pow.toTex = { + 2: '\\left(${args[0]}\\right)' + latex$$1.operators['pow'] + '{${args[1]}}' + }; - /** - * This function "flips" its input about the integer -1. - * - * @param {Number} i The value to flip - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_flip = function (i) { - // flip the value - return -i - 2; + return pow; + } + + var name$93 = 'pow'; + var factory_1$103 = factory$104; + + var pow$1 = { + name: name$93, + factory: factory_1$103 }; - return cs_flip; -} + function factory$105(type, config, load, typed, math) { + var equal = load(equal$1); + var isZero = load(isZero$1); + var isNumeric = load(isNumeric$1); + var add$$1 = load(add); + var subtract = load(subtract$1); + var multiply = load(multiply$1); + var divide = load(divide$1); + var pow = load(pow$1); -var name$107 = 'cs_flip'; -var path$46 = 'sparse'; -var factory_1$117 = factory$118; + var ConstantNode = math.expression.node.ConstantNode; + var OperatorNode = math.expression.node.OperatorNode; + var FunctionNode = math.expression.node.FunctionNode; + var ParenthesisNode = math.expression.node.ParenthesisNode; -var cs_flip = { - name: name$107, - path: path$46, - factory: factory_1$117 -}; + var node0 = new ConstantNode(0); + var node1 = new ConstantNode(1); -function factory$119 () { + /** + * simplifyCore() performs single pass simplification suitable for + * applications requiring ultimate performance. In contrast, simplify() + * extends simplifyCore() with additional passes to provide deeper + * simplification. + * + * Syntax: + * + * simplify.simplifyCore(expr) + * + * Examples: + * + * var f = math.parse('2 * 1 * x ^ (2 - 1)'); + * math.simplify.simpifyCore(f); // Node {2 * x} + * math.simplify('2 * 1 * x ^ (2 - 1)', [math.simplify.simpifyCore]); // Node {2 * x}; + * + * See also: + * + * derivative + * + * @param {Node} node + * The expression to be simplified + */ + function simplifyCore(node) { + if (type.isOperatorNode(node) && node.isUnary()) { + var a0 = simplifyCore(node.args[0]); - /** - * Keeps entries in the matrix when the callback function returns true, removes the entry otherwise - * - * @param {Matrix} a The sparse matrix - * @param {function} callback The callback function, function will be invoked with the following args: - * - The entry row - * - The entry column - * - The entry value - * - The state parameter - * @param {any} other The state - * - * @return The number of nonzero elements in the matrix - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_fkeep = function (a, callback, other) { - // a arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - // columns - var n = asize[1]; - // nonzero items - var nz = 0; - // loop columns - for (var j = 0; j < n; j++) { - // get current location of col j - var p = aptr[j]; - // record new location of col j - aptr[j] = nz; - for (; p < aptr[j+1]; p++) { - // check we need to keep this item - if (callback(aindex[p], j, avalues ? avalues[p] : 1, other)) { - // keep A(i,j) - aindex[nz] = aindex[p]; - // check we need to process values (pattern only) - if (avalues) - avalues[nz] = avalues[p]; - // increment nonzero items - nz++; + if (node.op === '+') { // unary plus + return a0; + } + + if (node.op === '-') { // unary minus + if (type.isOperatorNode(a0)) { + if (a0.isUnary() && a0.op === '-') { + return a0.args[0]; + } else if (a0.isBinary() && a0.fn === 'subtract') { + return new OperatorNode('-', 'subtract', [a0.args[1], a0.args[0]]); + } + } + return new OperatorNode(node.op, node.fn, [a0]); + } + } + else if (type.isOperatorNode(node) && node.isBinary()) { + var a0 = simplifyCore(node.args[0]); + var a1 = simplifyCore(node.args[1]); + + if (node.op === "+") { + if (type.isConstantNode(a0)) { + if (isZero(a0.value)) { + return a1; + } else if (type.isConstantNode(a1)) { + return new ConstantNode(add$$1(a0.value, a1.value)); + } + } + if (type.isConstantNode(a1) && isZero(a1.value)) { + return a0; + } + if (type.isOperatorNode(a1) && a1.isUnary() && a1.op === '-') { + return new OperatorNode('-', 'subtract', [a0,a1.args[0]]); + } + return new OperatorNode(node.op, node.fn, a1 ? [a0,a1] : [a0]); + } else if (node.op === "-") { + if (type.isConstantNode(a0) && a1) { + if (type.isConstantNode(a1)) { + return new ConstantNode(subtract(a0.value, a1.value)); + } else if (isZero(a0.value)) { + return new OperatorNode("-", "unaryMinus", [a1]); + } + } + // if (node.fn === "subtract" && node.args.length === 2) { + if (node.fn === "subtract") { + if (type.isConstantNode(a1) && isZero(a1.value)) { + return a0; + } + if (type.isOperatorNode(a1) && a1.isUnary() && a1.op === '-') { + return simplifyCore(new OperatorNode("+", "add", [a0, a1.args[0]])); + } + return new OperatorNode(node.op, node.fn, [a0,a1]); + } + } else if (node.op === "*") { + if (type.isConstantNode(a0)) { + if (isZero(a0.value)) { + return node0; + } else if (equal(a0.value, 1)) { + return a1; + } else if (type.isConstantNode(a1)) { + return new ConstantNode(multiply(a0.value, a1.value)); + } + } + if (type.isConstantNode(a1)) { + if (isZero(a1.value)) { + return node0; + } else if (equal(a1.value, 1)) { + return a0; + } else if (type.isOperatorNode(a0) && a0.isBinary() && a0.op === node.op) { + var a00 = a0.args[0]; + if (type.isConstantNode(a00)) { + var a00_a1 = new ConstantNode(multiply(a00.value, a1.value)); + return new OperatorNode(node.op, node.fn, [a00_a1, a0.args[1]]); // constants on left + } + } + return new OperatorNode(node.op, node.fn, [a1, a0]); // constants on left + } + return new OperatorNode(node.op, node.fn, [a0, a1]); + } else if (node.op === "/") { + if (type.isConstantNode(a0)) { + if (isZero(a0.value)) { + return node0; + } else if (type.isConstantNode(a1) && + (equal(a1.value, 1) || equal(a1.value, 2) || equal(a1.value, 4))) { + return new ConstantNode(divide(a0.value, a1.value)); + } + } + return new OperatorNode(node.op, node.fn, [a0, a1]); + } else if (node.op === "^") { + if (type.isConstantNode(a1)) { + if (isZero(a1.value)) { + return node1; + } else if (equal(a1.value, 1)) { + return a0; + } else { + if (type.isConstantNode(a0)) { + // fold constant + return new ConstantNode(pow(a0.value, a1.value)); + } else if (type.isOperatorNode(a0) && a0.isBinary() && a0.op === "^") { + var a01 = a0.args[1]; + if (type.isConstantNode(a01)) { + return new OperatorNode(node.op, node.fn, [ + a0.args[0], + new ConstantNode(multiply(a01.value, a1.value)) + ]); + } + } + } + } + return new OperatorNode(node.op, node.fn, [a0, a1]); } + } else if (type.isParenthesisNode(node)) { + var c = simplifyCore(node.content); + if (type.isParenthesisNode(c) || type.isSymbolNode(c) || type.isConstantNode(c)) { + return c; + } + return new ParenthesisNode(c); + } else if (type.isFunctionNode(node)) { + var args = node.args + .map(simplifyCore) + .map(function (arg) { + return type.isParenthesisNode(arg) ? arg.content : arg; + }); + return new FunctionNode(simplifyCore(node.fn), args); + } else { + // cannot simplify } + return node; } - // finalize A - aptr[n] = nz; - // trim arrays - aindex.splice(nz, aindex.length - nz); - // check we need to process values (pattern only) - if (avalues) - avalues.splice(nz, avalues.length - nz); - // return number of nonzero items - return (nz); - }; - - return cs_fkeep; -} -var name$108 = 'cs_fkeep'; -var path$47 = 'sparse'; -var factory_1$118 = factory$119; + return simplifyCore; + } -var cs_fkeep = { - name: name$108, - path: path$47, - factory: factory_1$118 -}; + var math$14 = true; + var name$94 = 'simplifyCore'; + var path$44 = 'algebra.simplify'; + var factory_1$104 = factory$105; -function factory$120 () { + var simplifyCore = { + math: math$14, + name: name$94, + path: path$44, + factory: factory_1$104 + }; - /** - * Depth-first search and postorder of a tree rooted at node j - * - * @param {Number} j The tree node - * @param {Number} k - * @param {Array} w The workspace array - * @param {Number} head The index offset within the workspace for the head array - * @param {Number} next The index offset within the workspace for the next array - * @param {Array} post The post ordering array - * @param {Number} stack The index offset within the workspace for the stack array - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_tdfs = function (j, k, w, head, next, post, stack) { - // variables - var top = 0; - // place j on the stack - w[stack] = j; - // while (stack is not empty) - while (top >= 0) { - // p = top of stack - var p = w[stack + top]; - // i = youngest child of p - var i = w[head + p]; - if (i == -1) { - // p has no unordered children left - top--; - // node p is the kth postordered node - post[k++] = p; + function factory$106(type, config, load, typed, math) { + var Node = math.expression.node.Node; + var OperatorNode = math.expression.node.OperatorNode; + var FunctionNode = math.expression.node.FunctionNode; + var ParenthesisNode = math.expression.node.ParenthesisNode; + + /** + * resolve(expr, scope) replaces variable nodes with their scoped values + * + * Syntax: + * + * simplify.resolve(expr, scope) + * + * Examples: + * + * math.simplify.resolve('x + y', {x:1, y:2}) // Node {1 + 2} + * math.simplify.resolve(math.parse('x+y'), {x:1, y:2}) // Node {1 + 2} + * math.simplify('x+y', {x:2, y:'x+x'}).toString(); // "6" + * + * @param {Node} node + * The expression tree to be simplified + * @param {Object} scope with variables to be resolved + */ + function resolve(node, scope) { + if (!scope) { + return node; } - else { - // remove i from children of p - w[head + p] = w[next + i]; - // increment top - ++top; - // start dfs on child node i - w[stack + top] = i; + if (type.isSymbolNode(node)) { + var value = scope[node.name]; + if (value instanceof Node) { + return resolve(value, scope); + } else if (typeof value === 'number') { + return math.parse(String(value)); + } + } else if (type.isOperatorNode(node)) { + var args = node.args.map(function (arg) { + return resolve(arg, scope) + }); + return new OperatorNode(node.op, node.fn, args); + } else if (type.isParenthesisNode(node)) { + return new ParenthesisNode(resolve(node.content, scope)); + } else if (type.isFunctionNode(node)) { + var args = node.args.map(function (arg) { + return resolve(arg, scope) + }); + return new FunctionNode(node.name, args); } + return node; } - return k; - }; - return cs_tdfs; -} + return resolve; + } + + var math$15 = true; + var name$95 = 'resolve'; + var path$45 = 'algebra.simplify'; + var factory_1$105 = factory$106; -var name$109 = 'cs_tdfs'; -var path$48 = 'sparse'; -var factory_1$119 = factory$120; + var resolve = { + math: math$15, + name: name$95, + path: path$45, + factory: factory_1$105 + }; -var cs_tdfs = { - name: name$109, - path: path$48, - factory: factory_1$119 -}; + function factory$107 (type, config, load, typed, math) { + var parse$$1 = load(parse); + var equal = load(equal$1); + var ConstantNode$$1 = load(ConstantNode); + var FunctionNode$$1 = load(FunctionNode); + var OperatorNode$$1 = load(OperatorNode); + var ParenthesisNode$$1 = load(ParenthesisNode); + var SymbolNode$$1 = load(SymbolNode); + var Node$$1 = load(Node); + var simplifyConstant$$1 = load(simplifyConstant); + var simplifyCore$$1 = load(simplifyCore); + var resolve$$1 = load(resolve); -var clone$6 = object.clone; -var format$4 = string.format; + var util$$1 = load(util); + var isCommutative = util$$1.isCommutative; + var isAssociative = util$$1.isAssociative; + var flatten = util$$1.flatten; + var unflattenr = util$$1.unflattenr; + var unflattenl = util$$1.unflattenl; + var createMakeNodeFunction = util$$1.createMakeNodeFunction; -function factory$121 (type, config, load, typed) { - var latex$$1 = latex; + /** + * Simplify an expression tree. + * + * A list of rules are applied to an expression, repeating over the list until + * no further changes are made. + * It's possible to pass a custom set of rules to the function as second + * argument. A rule can be specified as an object, string, or function: + * + * var rules = [ + * { l: 'n1*n3 + n2*n3', r: '(n1+n2)*n3' }, + * 'n1*n3 + n2*n3 -> (n1+n2)*n3', + * function (node) { + * // ... return a new node or return the node unchanged + * return node + * } + * ] + * + * String and object rules consist of a left and right pattern. The left is + * used to match against the expression and the right determines what matches + * are replaced with. The main difference between a pattern and a normal + * expression is that variables starting with the following characters are + * interpreted as wildcards: + * + * - 'n' - matches any Node + * - 'c' - matches any ConstantNode + * - 'v' - matches any Node that is not a ConstantNode + * + * The default list of rules is exposed on the function as `simplify.rules` + * and can be used as a basis to built a set of custom rules. + * + * For more details on the theory, see: + * + * - [Strategies for simplifying math expressions (Stackoverflow)](http://stackoverflow.com/questions/7540227/strategies-for-simplifying-math-expressions) + * - [Symbolic computation - Simplification (Wikipedia)](https://en.wikipedia.org/wiki/Symbolic_computation#Simplification) + * + * Syntax: + * + * simplify(expr) + * simplify(expr, rules) + * simplify(expr, rules, scope) + * simplify(expr, scope) + * + * Examples: + * + * math.simplify('2 * 1 * x ^ (2 - 1)'); // Node {2 * x} + * math.simplify('2 * 3 * x', {x: 4}); // Node {24} + * var f = math.parse('2 * 1 * x ^ (2 - 1)'); + * math.simplify(f); // Node {2 * x} + * + * See also: + * + * derivative, parse, eval + * + * @param {Node | string} expr + * The expression to be simplified + * @param {Array<{l:string, r: string} | string | function>} [rules] + * Optional list with custom rules + * @return {Node} Returns the simplified form of `expr` + */ + var simplify = typed('simplify', { + 'string': function (expr) { + return simplify(parse$$1(expr), simplify.rules, {}); + }, - var matrix$$1 = load(matrix); + 'string, Object': function (expr, scope) { + return simplify(parse$$1(expr), simplify.rules, scope); + }, - var DenseMatrix = type.DenseMatrix, - SparseMatrix = type.SparseMatrix; + 'string, Array': function (expr, rules) { + return simplify(parse$$1(expr), rules, {}); + }, - /** - * Transpose a matrix. All values of the matrix are reflected over its - * main diagonal. Only applicable to two dimensional matrices containing - * a vector (i.e. having size `[1,n]` or `[n,1]`). One dimensional - * vectors and scalars return the input unchanged. - * - * Syntax: - * - * math.transpose(x) - * - * Examples: - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.transpose(A); // returns [[1, 4], [2, 5], [3, 6]] - * - * See also: - * - * diag, inv, subset, squeeze - * - * @param {Array | Matrix} x Matrix to be transposed - * @return {Array | Matrix} The transposed matrix - */ - var transpose = typed('transpose', { + 'string, Array, Object': function (expr, rules, scope) { + return simplify(parse$$1(expr), rules, scope); + }, - 'Array': function (x) { - // use dense matrix implementation - return transpose(matrix$$1(x)).valueOf(); - }, + 'Node, Object': function (expr, scope) { + return simplify(expr, simplify.rules, scope); + }, - 'Matrix': function (x) { - // matrix size - var size = x.size(); + 'Node': function (expr) { + return simplify(expr, simplify.rules, {}); + }, - // result - var c; - - // process dimensions - switch (size.length) { - case 1: - // vector - c = x.clone(); - break; + 'Node, Array': function (expr, rules) { + return simplify(expr, rules, {}); + }, - case 2: - // rows and columns - var rows = size[0]; - var columns = size[1]; + 'Node, Array, Object': function (expr, rules, scope) { + rules = _buildRules(rules); - // check columns - if (columns === 0) { - // throw exception - throw new RangeError('Cannot transpose a 2D matrix with no columns (size: ' + format$4(size) + ')'); - } + var res = resolve$$1(expr, scope); + var res = removeParens(res); + var visited = {}; - // process storage format - switch (x.storage()) { - case 'dense': - c = _denseTranspose(x, rows, columns); - break; - case 'sparse': - c = _sparseTranspose(x, rows, columns); - break; + var str = res.toString({parenthesis: 'all'}); + while(!visited[str]) { + visited[str] = true; + _lastsym = 0; // counter for placeholder symbols + for (var i=0; i c1 * n1' + */ + function _buildRules(rules) { + // Array of rules to be used to simplify expressions + var ruleSet = []; + for(var i=0; i'); + if (lr.length !== 2) { + throw SyntaxError('Could not parse rule: ' + rule); + } + rule = {l: lr[0], r: lr[1]}; + /* falls through */ + case 'object': + newRule = { + l: removeParens(parse$$1(rule.l)), + r: removeParens(parse$$1(rule.r)), + }; + if(rule.context) { + newRule.evaluate = rule.context; + } + if(rule.evaluate) { + newRule.evaluate = parse$$1(rule.evaluate); + } + + if (isAssociative(newRule.l)) { + var makeNode = createMakeNodeFunction(newRule.l); + var expandsym = _getExpandPlaceholderSymbol(); + newRule.expanded = {}; + newRule.expanded.l = makeNode([newRule.l.clone(), expandsym]); + // Push the expandsym into the deepest possible branch. + // This helps to match the newRule against nodes returned from getSplits() later on. + flatten(newRule.expanded.l); + unflattenr(newRule.expanded.l); + newRule.expanded.r = makeNode([newRule.r, expandsym]); + } + break; + case 'function': + newRule = rule; + break; + default: + throw TypeError('Unsupported type of rule: ' + ruleType); + } + // console.log('Adding rule: ' + rules[i]); + // console.log(newRule); + ruleSet.push(newRule); } + return ruleSet; } - // return matrix - return new DenseMatrix({ - data: transposed, - size: [columns, rows], - datatype: m._datatype - }); - }; - var _sparseTranspose = function (m, rows, columns) { - // matrix arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // result matrices - var cvalues = values ? [] : undefined; - var cindex = []; - var cptr = []; - // row counts - var w = []; - for (var x = 0; x < rows; x++) - w[x] = 0; - // vars - var p, l, j; - // loop values in matrix - for (p = 0, l = index.length; p < l; p++) { - // number of values in row - w[index[p]]++; - } - // cumulative sum - var sum = 0; - // initialize cptr with the cummulative sum of row counts - for (var i = 0; i < rows; i++) { - // update cptr - cptr.push(sum); - // update sum - sum += w[i]; - // update w - w[i] = cptr[i]; - } - // update cptr - cptr.push(sum); - // loop columns - for (j = 0; j < columns; j++) { - // values & index in column - for (var k0 = ptr[j], k1 = ptr[j + 1], k = k0; k < k1; k++) { - // C values & index - var q = w[index[k]]++; - // C[j, i] = A[i, j] - cindex[q] = j; - // check we need to process values (pattern matrix) - if (values) - cvalues[q] = clone$6(values[k]); - } - } - // return matrix - return new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [columns, rows], - datatype: m._datatype - }); - }; - - transpose.toTex = {1: '\\left(${args[0]}\\right)' + latex$$1.operators['transpose']}; + var _lastsym = 0; + function _getExpandPlaceholderSymbol() { + return new SymbolNode$$1('_p' + _lastsym++); + } - return transpose; -} + /** + * Returns a simplfied form of node, or the original node if no simplification was possible. + * + * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node + * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The simplified form of `expr`, or the original node if no simplification was possible. + */ + var applyRule = typed('applyRule', { + 'Node, Object': function (node, rule) { -var name$110 = 'transpose'; -var factory_1$120 = factory$121; + //console.log('Entering applyRule(' + node.toString() + ')'); -var transpose$1 = { - name: name$110, - factory: factory_1$120 -}; + // Do not clone node unless we find a match + var res = node; -function factory$122 (type, config, load) { + // First replace our child nodes with their simplified versions + // If a child could not be simplified, the assignments will have + // no effect since the node is returned unchanged + if (res instanceof OperatorNode$$1 || res instanceof FunctionNode$$1) { + if (res.args) { + for(var i=0; i 3) - return null; - // a matrix arrays - var asize = a._size; - // rows and columns - var m = asize[0]; - var n = asize[1]; - // initialize vars - var lemax = 0; - // dense threshold - var dense = Math.max(16, 10 * Math.sqrt(n)); - dense = Math.min(n - 2, dense); - // create target matrix C - var cm = _createTargetMatrix(order, a, m, n, dense); - // drop diagonal entries - cs_fkeep$$1(cm, _diag, null); - // C matrix arrays - var cindex = cm._index; - var cptr = cm._ptr; - - // number of nonzero elements in C - var cnz = cptr[n]; - - // allocate result (n+1) - var P = []; - - // create workspace (8 * (n + 1)) - var W = []; - var len = 0; // first n + 1 entries - var nv = n + 1; // next n + 1 entries - var next = 2 * (n + 1); // next n + 1 entries - var head = 3 * (n + 1); // next n + 1 entries - var elen = 4 * (n + 1); // next n + 1 entries - var degree = 5 * (n + 1); // next n + 1 entries - var w = 6 * (n + 1); // next n + 1 entries - var hhead = 7 * (n + 1); // last n + 1 entries - - // use P as workspace for last - var last = P; - - // initialize quotient graph - var mark = _initializeQuotientGraph(n, cptr, W, len, head, last, next, hhead, nv, w, elen, degree); - - // initialize degree lists - var nel = _initializeDegreeLists(n, cptr, W, degree, elen, w, dense, nv, head, last, next); - - // minimum degree node - var mindeg = 0; - - // vars - var i, j, k, k1, k2, e, pj, ln, nvi, pk, eln, p1, p2, pn, h, d; - - // while (selecting pivots) do - while (nel < n) { - // select node of minimum approximate degree. amd() is now ready to start eliminating the graph. It first - // finds a node k of minimum degree and removes it from its degree list. The variable nel keeps track of thow - // many nodes have been eliminated. - for (k = -1; mindeg < n && (k = W[head + mindeg]) == -1; mindeg++); - if (W[next + k] != -1) - last[W[next + k]] = -1; - // remove k from degree list - W[head + mindeg] = W[next + k]; - // elenk = |Ek| - var elenk = W[elen + k]; - // # of nodes k represents - var nvk = W[nv + k]; - // W[nv + k] nodes of A eliminated - nel += nvk; - - // Construct a new element. The new element Lk is constructed in place if |Ek| = 0. nv[i] is - // negated for all nodes i in Lk to flag them as members of this set. Each node i is removed from the - // degree lists. All elements e in Ek are absorved into element k. - var dk = 0; - // flag k as in Lk - W[nv + k] = -nvk; - var p = cptr[k]; - // do in place if W[elen + k] == 0 - var pk1 = (elenk === 0) ? p : cnz; - var pk2 = pk1; - for (k1 = 1; k1 <= elenk + 1; k1++) { - if (k1 > elenk) { - // search the nodes in k - e = k; - // list of nodes starts at cindex[pj] - pj = p; - // length of list of nodes in k - ln = W[len + k] - elenk; + // If the rule is associative operator, we can try matching it while allowing additional terms. + // This allows us to match rules like 'n+n' to the expression '(1+x)+x' or even 'x+1+x' if the operator is commutative. + if (!matches && rule.expanded) { + repl = rule.expanded.r; + matches = _ruleMatch(rule.expanded.l, res)[0]; } - else { - // search the nodes in e - e = cindex[p++]; - pj = cptr[e]; - // length of list of nodes in e - ln = W[len + e]; - } - for (k2 = 1; k2 <= ln; k2++) { - i = cindex[pj++]; - // check node i dead, or seen - if ((nvi = W[nv + i]) <= 0) - continue; - // W[degree + Lk] += size of node i - dk += nvi; - // negate W[nv + i] to denote i in Lk - W[nv + i] = -nvi; - // place i in Lk - cindex[pk2++] = i; - if (W[next + i] != -1) - last[W[next + i]] = last[i]; - // check we need to remove i from degree list - if (last[i] != -1) - W[next + last[i]] = W[next + i]; - else - W[head + W[degree + i]] = W[next + i]; - } - if (e != k) { - // absorb e into k - cptr[e] = cs_flip$$1(k); - // e is now a dead element - W[w + e] = 0; - } - } - // cindex[cnz...nzmax] is free - if (elenk !== 0) - cnz = pk2; - // external degree of k - |Lk\i| - W[degree + k] = dk; - // element k is in cindex[pk1..pk2-1] - cptr[k] = pk1; - W[len + k] = pk2 - pk1; - // k is now an element - W[elen + k] = -2; - - // Find set differences. The scan1 function now computes the set differences |Le \ Lk| for all elements e. At the start of the - // scan, no entry in the w array is greater than or equal to mark. - - // clear w if necessary - mark = _wclear(mark, lemax, W, w, n); - // scan 1: find |Le\Lk| - for (pk = pk1; pk < pk2; pk++) { - i = cindex[pk]; - // check if W[elen + i] empty, skip it - if ((eln = W[elen + i]) <= 0) - continue; - // W[nv + i] was negated - nvi = -W[nv + i]; - var wnvi = mark - nvi; - // scan Ei - for (p = cptr[i], p1 = cptr[i] + eln - 1; p <= p1; p++) { - e = cindex[p]; - if (W[w + e] >= mark) { - // decrement |Le\Lk| - W[w + e] -= nvi; - } - else if (W[w + e] !== 0) { - // ensure e is a live element, 1st time e seen in scan 1 - W[w + e] = W[degree + e] + wnvi; - } - } - } - - // degree update - // The second pass computes the approximate degree di, prunes the sets Ei and Ai, and computes a hash - // function h(i) for all nodes in Lk. - - // scan2: degree update - for (pk = pk1; pk < pk2; pk++) { - // consider node i in Lk - i = cindex[pk]; - p1 = cptr[i]; - p2 = p1 + W[elen + i] - 1; - pn = p1; - // scan Ei - for (h = 0, d = 0, p = p1; p <= p2; p++) { - e = cindex[p]; - // check e is an unabsorbed element - if (W[w + e] !== 0) { - // dext = |Le\Lk| - var dext = W[w + e] - mark; - if (dext > 0) { - // sum up the set differences - d += dext; - // keep e in Ei - cindex[pn++] = e; - // compute the hash of node i - h += e; + + if (matches) { + // var before = res.toString({parenthesis: 'all'}); + + // Create a new node by cloning the rhs of the matched rule + res = repl.clone(); + + // Replace placeholders with their respective nodes without traversing deeper into the replaced nodes + var _transform = function(node) { + if(node.isSymbolNode && matches.placeholders.hasOwnProperty(node.name)) { + return matches.placeholders[node.name].clone(); } else { - // aggressive absorb. e->k - cptr[e] = cs_flip$$1(k); - // e is a dead element - W[w + e] = 0; + return node.map(_transform); } - } - } - // W[elen + i] = |Ei| - W[elen + i] = pn - p1 + 1; - var p3 = pn; - var p4 = p1 + W[len + i]; - // prune edges in Ai - for (p = p2 + 1; p < p4; p++) { - j = cindex[p]; - // check node j dead or in Lk - var nvj = W[nv + j]; - if (nvj <= 0) - continue; - // degree(i) += |j| - d += nvj; - // place j in node list of i - cindex[pn++] = j; - // compute hash for node i - h += j; - } - // check for mass elimination - if (d === 0) { - // absorb i into k - cptr[i] = cs_flip$$1(k); - nvi = -W[nv + i]; - // |Lk| -= |i| - dk -= nvi; - // |k| += W[nv + i] - nvk += nvi; - nel += nvi; - W[nv + i] = 0; - // node i is dead - W[elen + i] = -1; + }; + + res = _transform(res); + + // var after = res.toString({parenthesis: 'all'}); + // console.log('Simplified ' + before + ' to ' + after); } - else { - // update degree(i) - W[degree + i] = Math.min(W[degree + i], d); - // move first node to end - cindex[pn] = cindex[p3]; - // move 1st el. to end of Ei - cindex[p3] = cindex[p1]; - // add k as 1st element in of Ei - cindex[p1] = k; - // new len of adj. list of node i - W[len + i] = pn - p1 + 1; - // finalize hash of i - h = (h < 0 ? -h : h) % n; - // place i in hash bucket - W[next + i] = W[hhead + h]; - W[hhead + h] = i; - // save hash of i in last[i] - last[i] = h; - } - } - // finalize |Lk| - W[degree + k] = dk; - lemax = Math.max(lemax, dk); - // clear w - mark = _wclear(mark + lemax, lemax, W, w, n); - - // Supernode detection. Supernode detection relies on the hash function h(i) computed for each node i. - // If two nodes have identical adjacency lists, their hash functions wil be identical. - for (pk = pk1; pk < pk2; pk++) { - i = cindex[pk]; - // check i is dead, skip it - if (W[nv + i] >= 0) - continue; - // scan hash bucket of node i - h = last[i]; - i = W[hhead + h]; - // hash bucket will be empty - W[hhead + h] = -1; - for (; i != -1 && W[next + i] != -1; i = W[next + i], mark++) { - ln = W[len + i]; - eln = W[elen + i]; - for (p = cptr[i] + 1; p <= cptr[i] + ln - 1; p++) - W[w + cindex[p]] = mark; - var jlast = i; - // compare i with all j - for (j = W[next + i]; j != -1; ) { - var ok = W[len + j] === ln && W[elen + j] === eln; - for (p = cptr[j] + 1; ok && p <= cptr[j] + ln - 1; p++) { - // compare i and j - if (W[w + cindex[p]] != mark) - ok = 0; - } - // check i and j are identical - if (ok) { - // absorb j into i - cptr[j] = cs_flip$$1(i); - W[nv + i] += W[nv + j]; - W[nv + j] = 0; - // node j is dead - W[elen + j] = -1; - // delete j from hash bucket - j = W[next + j]; - W[next + jlast] = j; - } - else { - // j and i are different - jlast = j; - j = W[next + j]; - } - } + + return res; + } + }); + + /** + * Get (binary) combinations of a flattened binary node + * e.g. +(node1, node2, node3) -> [ + * +(node1, +(node2, node3)), + * +(node2, +(node1, node3)), + * +(node3, +(node1, node2))] + * + */ + function getSplits(node, context) { + var res = []; + var right, rightArgs; + var makeNode = createMakeNodeFunction(node); + if (isCommutative(node, context)) { + for (var i=0; i 0). It is from this information only that the final permutation - // is computed. The tree is restored by unflipping all of ptr. - - // fix assembly tree - for (i = 0; i < n; i++) - cptr[i] = cs_flip$$1(cptr[i]); - for (j = 0; j <= n; j++) - W[head + j] = -1; - // place unordered nodes in lists - for (j = n; j >= 0; j--) { - // skip if j is an element - if (W[nv + j] > 0) - continue; - // place j in list of its parent - W[next + j] = W[head + cptr[j]]; - W[head + cptr[j]] = j; - } - // place elements in lists - for (e = n; e >= 0; e--) { - // skip unless e is an element - if (W[nv + e] <= 0) - continue; - if (cptr[e] != -1) { - // place e in list of its parent - W[next + e] = W[head + cptr[e]]; - W[head + cptr[e]] = e; + + /** + * Returns the set union of two match-placeholders or null if there is a conflict. + */ + function mergeMatch(match1, match2) { + var res = {placeholders:{}}; + + // Some matches may not have placeholders; this is OK + if (!match1.placeholders && !match2.placeholders) { + return res; + } + else if (!match1.placeholders) { + return match2; + } + else if (!match2.placeholders) { + return match1; } - } - // postorder the assembly tree - for (k = 0, i = 0; i <= n; i++) { - if (cptr[i] == -1) - k = cs_tdfs$$1(i, k, W, head, next, P, w); - } - // remove last item in array - P.splice(P.length - 1, 1); - // return P - return P; - }; - - /** - * Creates the matrix that will be used by the approximate minimum degree ordering algorithm. The function accepts the matrix M as input and returns a permutation - * vector P. The amd algorithm operates on a symmetrix matrix, so one of three symmetric matrices is formed. - * - * Order: 0 - * A natural ordering P=null matrix is returned. - * - * Order: 1 - * Matrix must be square. This is appropriate for a Cholesky or LU factorization. - * P = M + M' - * - * Order: 2 - * Dense columns from M' are dropped, M recreated from M'. This is appropriatefor LU factorization of unsymmetric matrices. - * P = M' * M - * - * Order: 3 - * This is best used for QR factorization or LU factorization is matrix M has no dense rows. A dense row is a row with more than 10*sqr(columns) entries. - * P = M' * M - */ - var _createTargetMatrix = function (order, a, m, n, dense) { - // compute A' - var at = transpose(a); - // check order = 1, matrix must be square - if (order === 1 && n === m) { - // C = A + A' - return add$$1(a, at); - } - - // check order = 2, drop dense columns from M' - if (order == 2) { - // transpose arrays - var tindex = at._index; - var tptr = at._ptr; - // new column index - var p2 = 0; - // loop A' columns (rows) - for (var j = 0; j < m; j++) { - // column j of AT starts here - var p = tptr[j]; - // new column j starts here - tptr[j] = p2; - // skip dense col j - if (tptr[j + 1] - p > dense) - continue; - // map rows in column j of A - for (var p1 = tptr[j + 1]; p < p1; p++) - tindex[p2++] = tindex[p]; - } - // finalize AT - tptr[m] = p2; - // recreate A from new transpose matrix - a = transpose(at); - // use A' * A - return multiply(at, a); + // Placeholders with the same key must match exactly + for (var key in match1.placeholders) { + res.placeholders[key] = match1.placeholders[key]; + if (match2.placeholders.hasOwnProperty(key)) { + if (!_exactMatch(match1.placeholders[key], match2.placeholders[key] )) { + return null; + } + } + } + + for (var key in match2.placeholders) { + res.placeholders[key] = match2.placeholders[key]; + } + + return res; } - - // use A' * A, square or rectangular matrix - return multiply(at, a); - }; - /** - * Initialize quotient graph. There are four kind of nodes and elements that must be represented: - * - * - A live node is a node i (or a supernode) that has not been selected as a pivot nad has not been merged into another supernode. - * - A dead node i is one that has been removed from the graph, having been absorved into r = flip(ptr[i]). - * - A live element e is one that is in the graph, having been formed when node e was selected as the pivot. - * - A dead element e is one that has benn absorved into a subsequent element s = flip(ptr[e]). - */ - var _initializeQuotientGraph = function (n, cptr, W, len, head, last, next, hhead, nv, w, elen, degree) { - // Initialize quotient graph - for (var k = 0; k < n; k++) - W[len + k] = cptr[k + 1] - cptr[k]; - W[len + n] = 0; - // initialize workspace - for (var i = 0; i <= n; i++) { - // degree list i is empty - W[head + i] = -1; - last[i] = -1; - W[next + i] = -1; - // hash list i is empty - W[hhead + i] = -1; - // node i is just one node - W[nv + i] = 1; - // node i is alive - W[w + i] = 1; - // Ek of node i is empty - W[elen + i] = 0; - // degree of node i - W[degree + i] = W[len + i]; - } - // clear w - var mark = _wclear(0, 0, W, w, n); - // n is a dead element - W[elen + n] = -2; - // n is a root of assembly tree - cptr[n] = -1; - // n is a dead element - W[w + n] = 0; - // return mark - return mark; - }; + /** + * Combine two lists of matches by applying mergeMatch to the cartesian product of two lists of matches. + * Each list represents matches found in one child of a node. + */ + function combineChildMatches(list1, list2) { + var res = []; - /** - * Initialize degree lists. Each node is placed in its degree lists. Nodes of zero degree are eliminated immediately. Nodes with - * degree >= dense are alsol eliminated and merged into a placeholder node n, a dead element. Thes nodes will appera last in the - * output permutation p. - */ - var _initializeDegreeLists = function (n, cptr, W, degree, elen, w, dense, nv, head, last, next) { - // result - var nel = 0; - // loop columns - for (var i = 0; i < n; i++) { - // degree @ i - var d = W[degree + i]; - // check node i is empty - if (d === 0) { - // element i is dead - W[elen + i] = -2; - nel++; - // i is a root of assembly tree - cptr[i] = -1; - W[w + i] = 0; - } - else if (d > dense) { - // absorb i into element n - W[nv + i] = 0; - // node i is dead - W[elen + i] = -1; - nel++; - cptr[i] = cs_flip$$1(n); - W[nv + n]++; + if (list1.length === 0 || list2.length === 0) { + return res; } - else { - var h = W[head + d]; - if (h != -1) - last[h] = i; - // put node i in degree list d - W[next + i] = W[head + d]; - W[head + d] = i; + + var merged; + for (var i1 = 0; i1 < list1.length; i1++) { + for (var i2 = 0; i2 < list2.length; i2++) { + merged = mergeMatch(list1[i1], list2[i2]); + if (merged) { + res.push(merged); + } + } } + return res; } - return nel; - }; - var _wclear = function(mark, lemax, W, w, n) { - if (mark < 2 || (mark + lemax < 0)) { - for (var k = 0; k < n; k++) { - if (W[w + k] !== 0) - W[w + k] = 1; + /** + * Combine multiple lists of matches by applying mergeMatch to the cartesian product of two lists of matches. + * Each list represents matches found in one child of a node. + * Returns a list of unique matches. + */ + function mergeChildMatches(childMatches) { + if (childMatches.length === 0) { + return childMatches; } - mark = 2 ; + + var sets = childMatches.reduce(combineChildMatches); + var uniqueSets = []; + var unique = {}; + for(var i = 0; i < sets.length; i++) { + var s = JSON.stringify(sets[i]); + if (!unique[s]) { + unique[s] = true; + uniqueSets.push(sets[i]); + } + } + return uniqueSets; } - // at this point, W [0..n-1] < mark holds - return mark; - }; - - var _diag = function (i, j) { - return i != j; - }; - - return cs_amd; -} -var name$111 = 'cs_amd'; -var path$49 = 'sparse'; -var factory_1$121 = factory$122; + /** + * Determines whether node matches rule. + * + * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} rule + * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node + * @return {Object} Information about the match, if it exists. + */ + function _ruleMatch(rule, node, isSplit) { + // console.log('Entering _ruleMatch(' + JSON.stringify(rule) + ', ' + JSON.stringify(node) + ')'); + // console.log('rule = ' + rule); + // console.log('node = ' + node); -var cs_amd = { - name: name$111, - path: path$49, - factory: factory_1$121 -}; + // console.log('Entering _ruleMatch(' + rule.toString() + ', ' + node.toString() + ')'); + var res = [{placeholders:{}}]; -function factory$123 (type) { + if (rule instanceof OperatorNode$$1 && node instanceof OperatorNode$$1 + || rule instanceof FunctionNode$$1 && node instanceof FunctionNode$$1) { - var SparseMatrix = type.SparseMatrix; + // If the rule is an OperatorNode or a FunctionNode, then node must match exactly + if (rule instanceof OperatorNode$$1) { + if (rule.op !== node.op || rule.fn !== node.fn) { + return []; + } + } + else if (rule instanceof FunctionNode$$1) { + if (rule.name !== node.name) { + return []; + } + } - /** - * Permutes a sparse matrix C = P * A * Q - * - * @param {Matrix} a The Matrix A - * @param {Array} pinv The row permutation vector - * @param {Array} q The column permutation vector - * @param {boolean} values Create a pattern matrix (false), values and pattern otherwise - * - * @return {Matrix} C = P * A * Q, null on error - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_permute = function (a, pinv, q, values) { - // a arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // rows & columns - var m = asize[0]; - var n = asize[1]; - // c arrays - var cvalues = values && a._values ? [] : null; - var cindex = []; // (aptr[n]); - var cptr = []; // (n + 1); - // initialize vars - var nz = 0; - // loop columns - for (var k = 0; k < n; k++) { - // column k of C is column q[k] of A - cptr[k] = nz; - // apply column permutation - var j = q ? (q[k]) : k; - // loop values in column j of A - for (var t0 = aptr[j], t1 = aptr[j + 1], t = t0; t < t1; t++) { - // row i of A is row pinv[i] of C - var r = pinv ? pinv[aindex[t]] : aindex[t]; - // index - cindex[nz] = r; - // check we need to populate values - if (cvalues) - cvalues[nz] = avalues[t]; - // increment number of nonzero elements - nz++; - } - } - // finalize the last column of C - cptr[n] = nz; - // return C matrix - return new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [m, n], - datatype: adt - }); - }; + // rule and node match. Search the children of rule and node. + if (node.args.length === 1 && rule.args.length === 1 || !isAssociative(node) || isSplit) { + // Expect non-associative operators to match exactly + var childMatches = []; + for (var i = 0; i < rule.args.length; i++) { + var childMatch = _ruleMatch(rule.args[i], node.args[i]); + if (childMatch.length === 0) { + // Child did not match, so stop searching immediately + return []; + } + // The child matched, so add the information returned from the child to our result + childMatches.push(childMatch); + } + res = mergeChildMatches(childMatches); + } + else if (node.args.length >= 2 && rule.args.length === 2) { // node is flattened, rule is not + // Associative operators/functions can be split in different ways so we check if the rule matches each + // them and return their union. + var splits = getSplits(node, rule.context); + var splitMatches = []; + for(var i = 0; i < splits.length; i++) { + var matchSet = _ruleMatch(rule, splits[i], true); // recursing at the same tree depth here + splitMatches = splitMatches.concat(matchSet); + } + return splitMatches; + } + else if (rule.args.length > 2) { + throw Error('Unexpected non-binary associative function: ' + rule.toString()); + } + else { + // Incorrect number of arguments in rule and node, so no match + return []; + } + } + else if (rule instanceof SymbolNode$$1) { + // If the rule is a SymbolNode, then it carries a special meaning + // according to the first character of the symbol node name. + // c.* matches a ConstantNode + // n.* matches any node + if (rule.name.length === 0) { + throw new Error('Symbol in rule has 0 length...!?'); + } + if (math.hasOwnProperty(rule.name)) { + if (!SUPPORTED_CONSTANTS[rule.name]) { + throw new Error('Built in constant: ' + rule.name + ' is not supported by simplify.'); + } - return cs_permute; -} + // built-in constant must match exactly + if(rule.name !== node.name) { + return []; + } + } + else if (rule.name[0] === 'n' || rule.name.substring(0,2) === '_p') { + // rule matches _anything_, so assign this node to the rule.name placeholder + // Assign node to the rule.name placeholder. + // Our parent will check for matches among placeholders. + res[0].placeholders[rule.name] = node; + } + else if (rule.name[0] === 'v') { + // rule matches any variable thing (not a ConstantNode) + if(!type.isConstantNode(node)) { + res[0].placeholders[rule.name] = node; + } + else { + // Mis-match: rule was expecting something other than a ConstantNode + return []; + } + } + else if (rule.name[0] === 'c') { + // rule matches any ConstantNode + if(node instanceof ConstantNode$$1) { + res[0].placeholders[rule.name] = node; + } + else { + // Mis-match: rule was expecting a ConstantNode + return []; + } + } + else { + throw new Error('Invalid symbol in rule: ' + rule.name); + } + } + else if (rule instanceof ConstantNode$$1) { + // Literal constant must match exactly + if(!equal(rule.value, node.value)) { + return []; + } + } + else { + // Some other node was encountered which we aren't prepared for, so no match + return []; + } -var name$112 = 'cs_permute'; -var path$50 = 'sparse'; -var factory_1$122 = factory$123; + // It's a match! -var cs_permute = { - name: name$112, - path: path$50, - factory: factory_1$122 -}; + // console.log('_ruleMatch(' + rule.toString() + ', ' + node.toString() + ') found a match'); + return res; + } -function factory$124 () { - /** - * Computes the elimination tree of Matrix A (using triu(A)) or the - * elimination tree of A'A without forming A'A. - * - * @param {Matrix} a The A Matrix - * @param {boolean} ata A value of true the function computes the etree of A'A - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_etree = function (a, ata) { - // check inputs - if (!a) - return null; - // a arrays - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - // rows & columns - var m = asize[0]; - var n = asize[1]; - - // allocate result - var parent = []; // (n) - - // allocate workspace - var w = []; // (n + (ata ? m : 0)) - var ancestor = 0; // first n entries in w - var prev = n; // last m entries (ata = true) - - var i, inext; - - // check we are calculating A'A - if (ata) { - // initialize workspace - for (i = 0; i < m; i++) - w[prev + i] = -1; - } - // loop columns - for (var k = 0; k < n; k++) { - // node k has no parent yet - parent[k] = -1; - // nor does k have an ancestor - w[ancestor + k] = -1; - // values in column k - for (var p0 = aptr[k], p1 = aptr[k + 1], p = p0; p < p1; p++) { - // row - var r = aindex[p]; - // node - i = ata ? (w[prev + r]) : r; - // traverse from i to k - for (; i != -1 && i < k; i = inext) { - // inext = ancestor of i - inext = w[ancestor + i]; - // path compression - w[ancestor + i] = k; - // check no anc., parent is k - if (inext == -1) - parent[i] = k; + /** + * Determines whether p and q (and all their children nodes) are identical. + * + * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} p + * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} q + * @return {Object} Information about the match, if it exists. + */ + function _exactMatch(p, q) { + if(p instanceof ConstantNode$$1 && q instanceof ConstantNode$$1) { + if(!equal(p.value, q.value)) { + return false; } - if (ata) - w[prev + r] = k; } - } - return parent; - }; + else if(p instanceof SymbolNode$$1 && q instanceof SymbolNode$$1) { + if(p.name !== q.name) { + return false; + } + } + else if(p instanceof OperatorNode$$1 && q instanceof OperatorNode$$1 + || p instanceof FunctionNode$$1 && q instanceof FunctionNode$$1) { + if (p instanceof OperatorNode$$1) { + if (p.op !== q.op || p.fn !== q.fn) { + return false; + } + } + else if (p instanceof FunctionNode$$1) { + if (p.name !== q.name) { + return false; + } + } - return cs_etree; -} + if(p.args.length !== q.args.length) { + return false; + } -var name$113 = 'cs_etree'; -var path$51 = 'sparse'; -var factory_1$123 = factory$124; + for(var i=0; i= 0; j--) { - // check j is a root - if (parent[j] == -1) - continue; - // add j to list of its parent - w[next + j] = w[head + parent[j]]; - w[head + parent[j]] = j; - } - // loop nodes - for (j = 0; j < n; j++) { - // skip j if it is not a root - if (parent[j] != -1) - continue; - // depth-first search - k = cs_tdfs$$1(j, k, w, head, next, post, stack); - } - return post; + var simplify$1 = { + math: math$16, + name: name$96, + factory: factory_1$106 }; - return cs_post; -} + function factory$108 (type, config, load, typed) { + var parse$$1 = load(parse); + var simplify = load(simplify$1); + var equal = load(equal$1); + var isZero = load(isZero$1); + var numeric$$1 = load(numeric); + var ConstantNode$$1 = load(ConstantNode); + var FunctionNode$$1 = load(FunctionNode); + var OperatorNode$$1 = load(OperatorNode); + var ParenthesisNode$$1 = load(ParenthesisNode); + var SymbolNode$$1 = load(SymbolNode); -var name$114 = 'cs_post'; -var path$52 = 'sparse'; -var factory_1$124 = factory$125; + /** + * Takes the derivative of an expression expressed in parser Nodes. + * The derivative will be taken over the supplied variable in the + * second parameter. If there are multiple variables in the expression, + * it will return a partial derivative. + * + * This uses rules of differentiation which can be found here: + * + * - [Differentiation rules (Wikipedia)](http://en.wikipedia.org/wiki/Differentiation_rules) + * + * Syntax: + * + * derivative(expr, variable) + * derivative(expr, variable, options) + * + * Examples: + * + * math.derivative('x^2', 'x'); // Node {2 * x} + * math.derivative('x^2', 'x', {simplify: false}); // Node {2 * 1 * x ^ (2 - 1) + * math.derivative('sin(2x)', 'x')); // Node {2 * cos(2 * x)} + * math.derivative('2*x', 'x').eval(); // number 2 + * math.derivative('x^2', 'x').eval({x: 4}); // number 8 + * var f = math.parse('x^2'); + * var x = math.parse('x'); + * math.derivative(f, x); // Node {2 * x} + * + * See also: + * + * simplify, parse, eval + * + * @param {Node | string} expr The expression to differentiate + * @param {SymbolNode | string} variable The variable over which to differentiate + * @param {{simplify: boolean}} [options] + * There is one option available, `simplify`, which + * is true by default. When false, output will not + * be simplified. + * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The derivative of `expr` + */ + var derivative = typed('derivative', { + 'Node, SymbolNode, Object': function (expr, variable, options) { + var constNodes = {}; + constTag(constNodes, expr, variable.name); + var res = _derivative(expr, constNodes); + return options.simplify ? simplify(res) : res; + }, + 'Node, SymbolNode': function (expr, variable) { + return derivative(expr, variable, {simplify: true}) + }, -var cs_post = { - name: name$114, - path: path$52, - factory: factory_1$124 -}; + 'string, SymbolNode': function (expr, variable) { + return derivative(parse$$1(expr), variable) + }, + 'string, SymbolNode, Object': function (expr, variable, options) { + return derivative(parse$$1(expr), variable, options) + }, -function factory$126 () { + 'string, string': function (expr, variable) { + return derivative(parse$$1(expr), parse$$1(variable)) + }, + 'string, string, Object': function (expr, variable, options) { + return derivative(parse$$1(expr), parse$$1(variable), options) + }, - /** - * This function determines if j is a leaf of the ith row subtree. - * Consider A(i,j), node j in ith row subtree and return lca(jprev,j) - * - * @param {Number} i The ith row subtree - * @param {Number} j The node to test - * @param {Array} w The workspace array - * @param {Number} first The index offset within the workspace for the first array - * @param {Number} maxfirst The index offset within the workspace for the maxfirst array - * @param {Number} prevleaf The index offset within the workspace for the prevleaf array - * @param {Number} ancestor The index offset within the workspace for the ancestor array - * - * @return {Object} - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_leaf = function (i, j, w, first, maxfirst, prevleaf, ancestor) { - - var s, sparent, jprev; - - // our result - var jleaf = 0; - var q; - - // check j is a leaf - if (i <= j || w[first + j] <= w[maxfirst + i]) - return (-1); - // update max first[j] seen so far - w[maxfirst + i] = w[first + j]; - // jprev = previous leaf of ith subtree - jprev = w[prevleaf + i]; - w[prevleaf + i] = j; - - // check j is first or subsequent leaf - if (jprev === -1) { - // 1st leaf, q = root of ith subtree - jleaf = 1; - q = i; - } - else { - // update jleaf - jleaf = 2; - // q = least common ancester (jprev,j) - for (q = jprev; q != w[ancestor + q]; q = w[ancestor + q]); - for (s = jprev; s != q; s = sparent) { - // path compression - sparent = w[ancestor + s]; - w[ancestor + s] = q; - } - } - return { - jleaf: jleaf, - q: q - }; - }; - - return cs_leaf; -} - -var name$115 = 'cs_leaf'; -var path$53 = 'sparse'; -var factory_1$125 = factory$126; - -var cs_leaf = { - name: name$115, - path: path$53, - factory: factory_1$125 -}; - -function factory$127 (type, config, load) { - - var transpose = load(transpose$1); - - var cs_leaf$$1 = load(cs_leaf); - - /** - * Computes the column counts using the upper triangular part of A. - * It transposes A internally, none of the input parameters are modified. - * - * @param {Matrix} a The sparse matrix A - * - * @param {Matrix} ata Count the columns of A'A instead - * - * @return An array of size n of the column counts or null on error - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_counts = function (a, parent, post, ata) { - // check inputs - if (!a || !parent || !post) - return null; - // a matrix arrays - var asize = a._size; - // rows and columns - var m = asize[0]; - var n = asize[1]; - // variables - var i, j, k, J, p, p0, p1; - - // workspace size - var s = 4 * n + (ata ? (n + m + 1) : 0); - // allocate workspace - var w = []; // (s) - var ancestor = 0; // first n entries - var maxfirst = n; // next n entries - var prevleaf = 2 * n; // next n entries - var first = 3 * n; // next n entries - var head = 4 * n; // next n + 1 entries (used when ata is true) - var next = 5 * n + 1; // last entries in workspace - // clear workspace w[0..s-1] - for (k = 0; k < s; k++) - w[k] = -1; - - // allocate result - var colcount = []; // (n); - - // AT = A' - var at = transpose(a); - // at arrays - var tindex = at._index; - var tptr = at._ptr; - - // find w[first + j] - for (k = 0; k < n; k++) { - j = post[k]; - // colcount[j]=1 if j is a leaf - colcount[j] = (w[first + j] == -1) ? 1 : 0; - for (; j != -1 && w[first + j] == -1; j = parent[j]) - w[first + j] = k; - } - - // initialize ata if needed - if (ata) { - // invert post - for (k = 0; k < n; k++) - w[post[k]] = k; - // loop rows (columns in AT) - for (i = 0; i < m; i++) { - // values in column i of AT - for (k = n, p0 = tptr[i], p1 = tptr[i + 1], p = p0; p < p1; p++) - k = Math.min(k, w[tindex[p]]); - // place row i in linked list k - w[next + i] = w[head + k]; - w[head + k] = i; - } - } - - // each node in its own set - for (i = 0; i < n; i++) - w[ancestor + i] = i; - - for (k = 0; k < n; k++) { - // j is the kth node in postordered etree - j = post[k]; - // check j is not a root - if (parent[j] != -1) - colcount[parent[j]]--; - - // J=j for LL'=A case - for (J = (ata ? w[head + k] : j); J != -1; J = (ata ? w[next + J] : -1)) { - for (p = tptr[J]; p < tptr[J+1]; p++) { - i = tindex[p]; - var r = cs_leaf$$1(i, j, w, first, maxfirst, prevleaf, ancestor); - // check A(i,j) is in skeleton - if (r.jleaf >= 1) - colcount[j]++; - // check account for overlap in q - if (r.jleaf == 2) - colcount[r.q]--; - } - } - if (parent[j] != -1) - w[ancestor + j] = parent[j]; - } - // sum up colcount's of each child - for (j = 0; j < n; j++) { - if (parent[j] != -1) - colcount[parent[j]] += colcount[j]; - } - return colcount; - }; - - return cs_counts; -} - -var name$116 = 'cs_counts'; -var path$54 = 'sparse'; -var factory_1$126 = factory$127; - -var cs_counts = { - name: name$116, - path: path$54, - factory: factory_1$126 -}; - -function factory$128 (type, config, load) { - - var cs_amd$$1 = load(cs_amd); - var cs_permute$$1 = load(cs_permute); - var cs_etree$$1 = load(cs_etree); - var cs_post$$1 = load(cs_post); - var cs_counts$$1 = load(cs_counts); - - /** - * Symbolic ordering and analysis for QR and LU decompositions. - * - * @param {Number} order The ordering strategy (see cs_amd for more details) - * @param {Matrix} a The A matrix - * @param {boolean} qr Symbolic ordering and analysis for QR decomposition (true) or - * symbolic ordering and analysis for LU decomposition (false) - * - * @return {Object} The Symbolic ordering and analysis for matrix A - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_sqr = function (order, a, qr) { - // a arrays - var aptr = a._ptr; - var asize = a._size; - // columns - var n = asize[1]; - // vars - var k; - // symbolic analysis result - var s = {}; - // fill-reducing ordering - s.q = cs_amd$$1(order, a); - // validate results - if (order && !s.q) - return null; - // QR symbolic analysis - if (qr) { - // apply permutations if needed - var c = order ? cs_permute$$1(a, null, s.q, 0) : a; - // etree of C'*C, where C=A(:,q) - s.parent = cs_etree$$1(c, 1); - // post order elimination tree - var post = cs_post$$1 (s.parent, n); - // col counts chol(C'*C) - s.cp = cs_counts$$1(c, s.parent, post, 1); - // check we have everything needed to calculate number of nonzero elements - if (c && s.parent && s.cp && _vcount(c, s)) { - // calculate number of nonzero elements - for (s.unz = 0, k = 0; k < n; k++) - s.unz += s.cp[k]; + 'Node, string': function (expr, variable) { + return derivative(expr, parse$$1(variable)) + }, + 'Node, string, Object': function (expr, variable, options) { + return derivative(expr, parse$$1(variable), options) } - } - else { - // for LU factorization only, guess nnz(L) and nnz(U) - s.unz = 4 * (aptr[n]) + n; - s.lnz = s.unz; - } - // return result S - return s; - }; - - /** - * Compute nnz(V) = s.lnz, s.pinv, s.leftmost, s.m2 from A and s.parent - */ - var _vcount = function (a, s) { - // a arrays - var aptr = a._ptr; - var aindex = a._index; - var asize = a._size; - // rows & columns - var m = asize[0]; - var n = asize[1]; - // initialize s arrays - s.pinv = []; // (m + n); - s.leftmost = []; // (m); - // vars - var parent = s.parent; - var pinv = s.pinv; - var leftmost = s.leftmost; - // workspace, next: first m entries, head: next n entries, tail: next n entries, nque: next n entries - var w = []; // (m + 3 * n); - var next = 0; - var head = m; - var tail = m + n; - var nque = m + 2 * n; - // vars - var i, k, p, p0, p1; - // initialize w - for (k = 0; k < n; k++) { - // queue k is empty - w[head + k] = -1; - w[tail + k] = -1; - w[nque + k] = 0; - } - // initialize row arrays - for (i = 0; i < m; i++) - leftmost[i] = -1; - // loop columns backwards - for (k = n - 1; k >= 0; k--) { - // values & index for column k - for (p0 = aptr[k], p1 = aptr[k + 1], p = p0; p < p1; p++) { - // leftmost[i] = min(find(A(i,:))) - leftmost[aindex[p]] = k; - } - } - // scan rows in reverse order - for (i = m - 1; i >= 0; i--) { - // row i is not yet ordered - pinv[i] = -1; - k = leftmost[i]; - // check row i is empty - if (k == -1) - continue; - // first row in queue k - if (w[nque + k]++ === 0) - w[tail + k] = i; - // put i at head of queue k - w[next + i] = w[head + k]; - w[head + k] = i; - } - s.lnz = 0; - s.m2 = m; - // find row permutation and nnz(V) - for (k = 0; k < n; k++) { - // remove row i from queue k - i = w[head + k]; - // count V(k,k) as nonzero - s.lnz++; - // add a fictitious row - if (i < 0) - i = s.m2++; - // associate row i with V(:,k) - pinv[i] = k; - // skip if V(k+1:m,k) is empty - if (--nque[k] <= 0) - continue; - // nque[k] is nnz (V(k+1:m,k)) - s.lnz += w[nque + k]; - // move all rows to parent of k - var pa = parent[k]; - if (pa != -1) { - if (w[nque + pa] === 0) - w[tail + pa] = w[tail + k]; - w[next + w[tail + k]] = w[head + pa]; - w[head + pa] = w[next + i]; - w[nque + pa] += w[nque + k]; - } - } - for (i = 0; i < m; i++) { - if (pinv[i] < 0) - pinv[i] = k++; - } - return true; - }; - - return cs_sqr; -} -var name$117 = 'cs_sqr'; -var path$55 = 'sparse'; -var factory_1$127 = factory$128; + // TODO: replace the 8 signatures above with 4 as soon as typed-function supports optional arguments -var cs_sqr = { - name: name$117, - path: path$55, - factory: factory_1$127 -}; - -var nearlyEqual$5 = number.nearlyEqual; - - -function factory$129 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - var latex$$1 = latex; - - /** - * Test whether value x is larger or equal to y. - * - * The function returns true when x is larger than y or the relative - * difference between x and y is smaller than the configured epsilon. The - * function cannot be used to compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.largerEq(x, y) - * - * Examples: - * - * math.larger(2, 1 + 1); // returns false - * math.largerEq(2, 1 + 1); // returns true - * - * See also: - * - * equal, unequal, smaller, smallerEq, larger, compare - * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the x is larger or equal to y, else returns false - */ - var largerEq = typed('largerEq', { - - 'boolean, boolean': function (x, y) { - return x >= y; - }, - - 'number, number': function (x, y) { - return x >= y || nearlyEqual$5(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.gte(y) || nearlyEqual(x, y, config.epsilon); - }, - - 'Fraction, Fraction': function (x, y) { - return x.compare(y) !== -1; - }, - - 'Complex, Complex': function () { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); + /* TODO: implement and test syntax with order of derivatives -> implement as an option {order: number} + 'Node, SymbolNode, ConstantNode': function (expr, variable, {order}) { + var res = expr; + for (var i = 0; i < order; i++) { + var constNodes = {}; + constTag(constNodes, expr, variable.name); + res = _derivative(res, constNodes); + } + return res; } - return largerEq(x.value, y.value); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, largerEq); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, largerEq, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, largerEq, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, largerEq); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return largerEq(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return largerEq(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return largerEq(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, largerEq, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, largerEq, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, largerEq, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, largerEq, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, largerEq, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, largerEq, true).valueOf(); - } - }); - - largerEq.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['largerEq'] + '${args[1]}\\right)' - }; - - return largerEq; -} - -var name$118 = 'largerEq'; -var factory_1$128 = factory$129; - -var largerEq$1 = { - name: name$118, - factory: factory_1$128 -}; - -function factory$130 () { - - /** - * Checks if the node at w[j] is marked - * - * @param {Array} w The array - * @param {Number} j The array index - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_marked = function (w, j) { - // check node is marked - return w[j] < 0; - }; - - return cs_marked; -} - -var name$119 = 'cs_marked'; -var path$56 = 'sparse'; -var factory_1$129 = factory$130; - -var cs_marked = { - name: name$119, - path: path$56, - factory: factory_1$129 -}; - -function factory$131 (type, config, load) { - - var cs_flip$$1 = load(cs_flip); - - /** - * Marks the node at w[j] - * - * @param {Array} w The array - * @param {Number} j The array index - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_mark = function (w, j) { - // mark w[j] - w[j] = cs_flip$$1(w [j]); - }; - - return cs_mark; -} - -var name$120 = 'cs_mark'; -var path$57 = 'sparse'; -var factory_1$130 = factory$131; - -var cs_mark = { - name: name$120, - path: path$57, - factory: factory_1$130 -}; - -function factory$132 (type, config, load) { - - var cs_flip$$1 = load(cs_flip); - - /** - * Flips the value if it is negative of returns the same value otherwise. - * - * @param {Number} i The value to flip - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_unflip = function (i) { - // flip the value if it is negative - return i < 0 ? cs_flip$$1(i) : i; - }; - - return cs_unflip; -} - -var name$121 = 'cs_unflip'; -var path$58 = 'sparse'; -var factory_1$131 = factory$132; - -var cs_unflip = { - name: name$121, - path: path$58, - factory: factory_1$131 -}; + */ + }); -function factory$133 (type, config, load) { + derivative._simplify = true; - var cs_marked$$1 = load(cs_marked); - var cs_mark$$1 = load(cs_mark); - var cs_unflip$$1 = load(cs_unflip); + derivative.toTex = function(deriv) { + return _derivTex.apply(null, deriv.args); + }; - /** - * Depth-first search computes the nonzero pattern xi of the directed graph G (Matrix) starting - * at nodes in B (see cs_reach()). - * - * @param {Number} j The starting node for the DFS algorithm - * @param {Matrix} g The G matrix to search, ptr array modified, then restored - * @param {Number} top Start index in stack xi[top..n-1] - * @param {Number} k The kth column in B - * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n - * The first n entries is the nonzero pattern, the last n entries is the stack - * @param {Array} pinv The inverse row permutation vector, must be null for L * x = b - * - * @return {Number} New value of top - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_dfs = function (j, g, top, xi, pinv) { - // g arrays - var index = g._index; - var ptr = g._ptr; - var size = g._size; - // columns - var n = size[1]; - // vars - var i, p, p2; - // initialize head - var head = 0; - // initialize the recursion stack - xi[0] = j; - // loop - while (head >= 0) { - // get j from the top of the recursion stack - j = xi[head]; - // apply permutation vector - var jnew = pinv ? pinv[j] : j; - // check node j is marked - if (!cs_marked$$1(ptr, j)) { - // mark node j as visited - cs_mark$$1(ptr, j); - // update stack (last n entries in xi) - xi[n + head] = jnew < 0 ? 0 : cs_unflip$$1(ptr[jnew]); - } - // node j done if no unvisited neighbors - var done = 1; - // examine all neighbors of j, stack (last n entries in xi) - for (p = xi[n + head], p2 = jnew < 0 ? 0 : cs_unflip$$1(ptr[jnew+1]); p < p2; p++) { - // consider neighbor node i - i = index[p]; - // check we have visited node i, skip it - if (cs_marked$$1(ptr, i)) - continue; - // pause depth-first search of node j, update stack (last n entries in xi) - xi[n + head] = p; - // start dfs at node i - xi[++head] = i; - // node j is not done - done = 0; - // break, to start dfs(i) - break; - } - // check depth-first search at node j is done - if (done) { - // remove j from the recursion stack - head--; - // and place in the output stack - xi[--top] = j; + var _derivTex = typed('_derivTex', { + 'Node, SymbolNode': function (expr, x) { + return _derivTex(expr.toString(), x.toString(), 1); + }, + 'Node, SymbolNode, ConstantNode': function (expr, x, order) { + return _derivTex(expr.toString(), x.name, order.value); + }, + 'string, string, number': function (expr, x, order) { + var d; + if (order === 1) { + d = "{d\\over d" + x + "}"; + } + else { + d = "{d^{" + order + "}\\over d" + x + "^{" + order + "}}"; + } + return d + "\\left[" + expr + "\\right]" } - } - return top; - }; + }); - return cs_dfs; -} + /** + * Does a depth-first search on the expression tree to identify what Nodes + * are constants (e.g. 2 + 2), and stores the ones that are constants in + * constNodes. Classification is done as follows: + * + * 1. ConstantNodes are constants. + * 2. If there exists a SymbolNode, of which we are differentiating over, + * in the subtree it is not constant. + * + * @param {Object} constNodes Holds the nodes that are constant + * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node + * @param {string} varName Variable that we are differentiating + * @return {boolean} if node is constant + */ + // TODO: can we rewrite constTag into a pure function? + var constTag = typed('constTag', { + 'Object, ConstantNode, string': function (constNodes, node) { + return constNodes[node] = true; + }, -var name$122 = 'cs_dfs'; -var path$59 = 'sparse'; -var factory_1$132 = factory$133; + 'Object, SymbolNode, string': function (constNodes, node, varName) { + // Treat other variables like constants. For reasoning, see: + // https://en.wikipedia.org/wiki/Partial_derivative + if (node.name !== varName) { + return constNodes[node] = true; + } + return false; + }, -var cs_dfs = { - name: name$122, - path: path$59, - factory: factory_1$132 -}; + 'Object, ParenthesisNode, string': function (constNodes, node, varName) { + return constTag(constNodes, node.content, varName); + }, -function factory$134 (type, config, load) { + 'Object, FunctionAssignmentNode, string': function (constNodes, node, varName) { + if (node.params.indexOf(varName) === -1) { + return constNodes[node] = true; + } + return constTag(constNodes, node.expr, varName); + }, - var cs_dfs$$1 = load(cs_dfs); - var cs_marked$$1 = load(cs_marked); - var cs_mark$$1 = load(cs_mark); + 'Object, FunctionNode | OperatorNode, string': function (constNodes, node, varName) { + if (node.args.length > 0) { + var isConst = constTag(constNodes, node.args[0], varName); + for (var i = 1; i < node.args.length; ++i) { + isConst = constTag(constNodes, node.args[i], varName) && isConst; + } - /** - * The cs_reach function computes X = Reach(B), where B is the nonzero pattern of the n-by-1 - * sparse column of vector b. The function returns the set of nodes reachable from any node in B. The - * nonzero pattern xi of the solution x to the sparse linear system Lx=b is given by X=Reach(B). - * - * @param {Matrix} g The G matrix - * @param {Matrix} b The B matrix - * @param {Number} k The kth column in B - * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n - * The first n entries is the nonzero pattern, the last n entries is the stack - * @param {Array} pinv The inverse row permutation vector - * - * @return {Number} The index for the nonzero pattern - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_reach = function (g, b, k, xi, pinv) { - // g arrays - var gptr = g._ptr; - var gsize = g._size; - // b arrays - var bindex = b._index; - var bptr = b._ptr; - // columns - var n = gsize[1]; - // vars - var p, p0, p1; - // initialize top - var top = n; - // loop column indeces in B - for (p0 = bptr[k], p1 = bptr[k + 1], p = p0; p < p1; p++) { - // node i - var i = bindex[p]; - // check node i is marked - if (!cs_marked$$1(gptr, i)) { - // start a dfs at unmarked node i - top = cs_dfs$$1(i, g, top, xi, pinv); + if (isConst) { + return constNodes[node] = true; + } + } + return false; } - } - // loop columns from top -> n - 1 - for (p = top; p < n; p++) { - // restore G - cs_mark$$1(gptr, xi[p]); - } - return top; - }; - - return cs_reach; -} - -var name$123 = 'cs_reach'; -var path$60 = 'sparse'; -var factory_1$133 = factory$134; + }); -var cs_reach = { - name: name$123, - path: path$60, - factory: factory_1$133 -}; + /** + * Applies differentiation rules. + * + * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node + * @param {Object} constNodes Holds the nodes that are constant + * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The derivative of `expr` + */ + var _derivative = typed('_derivative', { + 'ConstantNode, Object': function (node) { + return createConstantNode(0); + }, -function factory$135 (type, config, load) { + 'SymbolNode, Object': function (node, constNodes) { + if (constNodes[node] !== undefined) { + return createConstantNode(0); + } + return createConstantNode(1); + }, - var divideScalar$$1 = load(divideScalar); - var multiply = load(multiply$1); - var subtract = load(subtract$1); + 'ParenthesisNode, Object': function (node, constNodes) { + return new ParenthesisNode$$1(_derivative(node.content, constNodes)); + }, - var cs_reach$$1 = load(cs_reach); + 'FunctionAssignmentNode, Object': function (node, constNodes) { + if (constNodes[node] !== undefined) { + return createConstantNode(0); + } + return _derivative(node.expr, constNodes); + }, - /** - * The function cs_spsolve() computes the solution to G * x = bk, where bk is the - * kth column of B. When lo is true, the function assumes G = L is lower triangular with the - * diagonal entry as the first entry in each column. When lo is true, the function assumes G = U - * is upper triangular with the diagonal entry as the last entry in each column. - * - * @param {Matrix} g The G matrix - * @param {Matrix} b The B matrix - * @param {Number} k The kth column in B - * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n - * The first n entries is the nonzero pattern, the last n entries is the stack - * @param {Array} x The soluton to the linear system G * x = b - * @param {Array} pinv The inverse row permutation vector, must be null for L * x = b - * @param {boolean} lo The lower (true) upper triangular (false) flag - * - * @return {Number} The index for the nonzero pattern - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_spsolve = function (g, b, k, xi, x, pinv, lo) { - // g arrays - var gvalues = g._values; - var gindex = g._index; - var gptr = g._ptr; - var gsize = g._size; - // columns - var n = gsize[1]; - // b arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - // vars - var p, p0, p1, q; - // xi[top..n-1] = cs_reach(B(:,k)) - var top = cs_reach$$1(g, b, k, xi, pinv); - // clear x - for (p = top; p < n; p++) - x[xi[p]] = 0; - // scatter b - for (p0 = bptr[k], p1 = bptr[k + 1], p = p0; p < p1; p++) - x[bindex[p]] = bvalues[p]; - // loop columns - for (var px = top; px < n; px++) { - // x array index for px - var j = xi[px]; - // apply permutation vector (U x = b), j maps to column J of G - var J = pinv ? pinv[j] : j; - // check column J is empty - if (J < 0) - continue; - // column value indeces in G, p0 <= p < p1 - p0 = gptr[J]; - p1 = gptr[J + 1]; - // x(j) /= G(j,j) - x[j] = divideScalar$$1(x[j], gvalues[lo ? p0 : (p1 - 1)]); - // first entry L(j,j) - p = lo ? (p0 + 1) : p0; - q = lo ? (p1) : (p1 - 1); - // loop - for ( ; p < q ; p++) { - // row - var i = gindex[p]; - // x(i) -= G(i,j) * x(j) - x[i] = subtract(x[i], multiply(gvalues[p], x[j])); - } - } - // return top of stack - return top; - }; - - return cs_spsolve; -} + 'FunctionNode, Object': function (node, constNodes) { + if (node.args.length !== 1) { + funcArgsCheck(node); + } -var name$124 = 'cs_spsolve'; -var path$61 = 'sparse'; -var factory_1$134 = factory$135; + if (constNodes[node] !== undefined) { + return createConstantNode(0); + } -var cs_spsolve = { - name: name$124, - path: path$61, - factory: factory_1$134 -}; + var arg0 = node.args[0]; + var arg1; -function factory$136 (type, config, load) { + var div = false; // is output a fraction? + var negative = false; // is output negative? - var abs = load(abs$1); - var divideScalar$$1 = load(divideScalar); - var multiply = load(multiply$1); - - var larger$$1 = load(larger); - var largerEq = load(largerEq$1); - - var cs_spsolve$$1 = load(cs_spsolve); + var funcDerivative; + switch (node.name) { + case 'cbrt': + // d/dx(cbrt(x)) = 1 / (3x^(2/3)) + div = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + createConstantNode(3), + new OperatorNode$$1('^', 'pow', [ + arg0, + new OperatorNode$$1('/', 'divide', [ + createConstantNode(2), + createConstantNode(3) + ]) + ]) + ]); + break; + case 'sqrt': + case 'nthRoot': + // d/dx(sqrt(x)) = 1 / (2*sqrt(x)) + if (node.args.length === 1) { + div = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + createConstantNode(2), + new FunctionNode$$1('sqrt', [arg0]) + ]); + } + else if (node.args.length === 2) { + // Rearrange from nthRoot(x, a) -> x^(1/a) + arg1 = new OperatorNode$$1('/', 'divide', [ + createConstantNode(1), + node.args[1] + ]); - var SparseMatrix = type.SparseMatrix; + // Is a variable? + constNodes[arg1] = constNodes[node.args[1]]; - /** - * Computes the numeric LU factorization of the sparse matrix A. Implements a Left-looking LU factorization - * algorithm that computes L and U one column at a tume. At the kth step, it access columns 1 to k-1 of L - * and column k of A. Given the fill-reducing column ordering q (see parameter s) computes L, U and pinv so - * L * U = A(p, q), where p is the inverse of pinv. - * - * @param {Matrix} m The A Matrix to factorize - * @param {Object} s The symbolic analysis from cs_sqr(). Provides the fill-reducing - * column ordering q - * @param {Number} tol Partial pivoting threshold (1 for partial pivoting) - * - * @return {Number} The numeric LU factorization of A or null - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_lu = function (m, s, tol) { - // validate input - if (!m) - return null; - // m arrays - var size = m._size; - // columns - var n = size[1]; - // symbolic analysis result - var q; - var lnz = 100; - var unz = 100; - // update symbolic analysis parameters - if (s) { - q = s.q; - lnz = s.lnz || lnz; - unz = s.unz || unz; - } - // L arrays - var lvalues = []; // (lnz) - var lindex = []; // (lnz); - var lptr = []; // (n + 1); - // L - var L = new SparseMatrix({ - values: lvalues, - index: lindex, - ptr: lptr, - size: [n, n] - }); - // U arrays - var uvalues = []; // (unz); - var uindex = []; // (unz); - var uptr = []; // (n + 1); - // U - var U = new SparseMatrix({ - values: uvalues, - index: uindex, - ptr: uptr, - size: [n, n] - }); - // inverse of permutation vector - var pinv = []; // (n); - // vars - var i, p; - // allocate arrays - var x = []; // (n); - var xi = []; // (2 * n); - // initialize variables - for (i = 0; i < n; i++) { - // clear workspace - x[i] = 0; - // no rows pivotal yet - pinv[i] = -1; - // no cols of L yet - lptr[i + 1] = 0; - } - // reset number of nonzero elements in L and U - lnz = 0; - unz = 0; - // compute L(:,k) and U(:,k) - for (var k = 0; k < n; k++) { - // update ptr - lptr[k] = lnz; - uptr[k] = unz; - // apply column permutations if needed - var col = q ? q[k] : k; - // solve triangular system, x = L\A(:,col) - var top = cs_spsolve$$1(L, m, col, xi, x, pinv, 1); - // find pivot - var ipiv = -1; - var a = -1; - // loop xi[] from top -> n - for (p = top; p < n; p++) { - // x[i] is nonzero - i = xi[p]; - // check row i is not yet pivotal - if (pinv[i] < 0) { - // absolute value of x[i] - var xabs = abs(x[i]); - // check absoulte value is greater than pivot value - if (larger$$1(xabs, a)) { - // largest pivot candidate so far - a = xabs; - ipiv = i; - } + return _derivative(new OperatorNode$$1('^', 'pow', [arg0, arg1]), constNodes); + } + break; + case 'log10': + arg1 = createConstantNode(10); + /* fall through! */ + case 'log': + if (!arg1 && node.args.length === 1) { + // d/dx(log(x)) = 1 / x + funcDerivative = arg0.clone(); + div = true; + } else if ((node.args.length === 1 && arg1) || + (node.args.length === 2 && constNodes[node.args[1]] !== undefined)) { + // d/dx(log(x, c)) = 1 / (x*ln(c)) + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + arg0.clone(), + new FunctionNode$$1('log', [arg1 || node.args[1]]) + ]); + div = true; + } else if (node.args.length === 2) { + // d/dx(log(f(x), g(x))) = d/dx(log(f(x)) / log(g(x))) + return _derivative(new OperatorNode$$1('/', 'divide', [ + new FunctionNode$$1('log', [arg0]), + new FunctionNode$$1('log', [node.args[1]]) + ]), constNodes); + } + break; + case 'exp': + // d/dx(e^x) = e^x + funcDerivative = new FunctionNode$$1('exp', [arg0.clone()]); + break; + case 'sin': + // d/dx(sin(x)) = cos(x) + funcDerivative = new FunctionNode$$1('cos', [arg0.clone()]); + break; + case 'cos': + // d/dx(cos(x)) = -sin(x) + funcDerivative = new OperatorNode$$1('-', 'unaryMinus', [ + new FunctionNode$$1('sin', [arg0.clone()]) + ]); + break; + case 'tan': + // d/dx(tan(x)) = sec(x)^2 + funcDerivative = new OperatorNode$$1('^', 'pow', [ + new FunctionNode$$1('sec', [arg0.clone()]), + createConstantNode(2) + ]); + break; + case 'sec': + // d/dx(sec(x)) = sec(x)tan(x) + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + node, + new FunctionNode$$1('tan', [arg0.clone()]) + ]); + break; + case 'csc': + // d/dx(csc(x)) = -csc(x)cot(x) + negative = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + node, + new FunctionNode$$1('cot', [arg0.clone()]) + ]); + break; + case 'cot': + // d/dx(cot(x)) = -csc(x)^2 + negative = true; + funcDerivative = new OperatorNode$$1('^', 'pow', [ + new FunctionNode$$1('csc', [arg0.clone()]), + createConstantNode(2) + ]); + break; + case 'asin': + // d/dx(asin(x)) = 1 / sqrt(1 - x^2) + div = true; + funcDerivative = new FunctionNode$$1('sqrt', [ + new OperatorNode$$1('-', 'subtract', [ + createConstantNode(1), + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]) + ]) + ]); + break; + case 'acos': + // d/dx(acos(x)) = -1 / sqrt(1 - x^2) + div = true; + negative = true; + funcDerivative = new FunctionNode$$1('sqrt', [ + new OperatorNode$$1('-', 'subtract', [ + createConstantNode(1), + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]) + ]) + ]); + break; + case 'atan': + // d/dx(atan(x)) = 1 / (x^2 + 1) + div = true; + funcDerivative = new OperatorNode$$1('+', 'add', [ + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]), + createConstantNode(1) + ]); + break; + case 'asec': + // d/dx(asec(x)) = 1 / (|x|*sqrt(x^2 - 1)) + div = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + new FunctionNode$$1('abs', [arg0.clone()]), + new FunctionNode$$1('sqrt', [ + new OperatorNode$$1('-', 'subtract', [ + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]), + createConstantNode(1) + ]) + ]) + ]); + break; + case 'acsc': + // d/dx(acsc(x)) = -1 / (|x|*sqrt(x^2 - 1)) + div = true; + negative = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + new FunctionNode$$1('abs', [arg0.clone()]), + new FunctionNode$$1('sqrt', [ + new OperatorNode$$1('-', 'subtract', [ + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]), + createConstantNode(1) + ]) + ]) + ]); + break; + case 'acot': + // d/dx(acot(x)) = -1 / (x^2 + 1) + div = true; + negative = true; + funcDerivative = new OperatorNode$$1('+', 'add', [ + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]), + createConstantNode(1) + ]); + break; + case 'sinh': + // d/dx(sinh(x)) = cosh(x) + funcDerivative = new FunctionNode$$1('cosh', [arg0.clone()]); + break; + case 'cosh': + // d/dx(cosh(x)) = sinh(x) + funcDerivative = new FunctionNode$$1('sinh', [arg0.clone()]); + break; + case 'tanh': + // d/dx(tanh(x)) = sech(x)^2 + funcDerivative = new OperatorNode$$1('^', 'pow', [ + new FunctionNode$$1('sech', [arg0.clone()]), + createConstantNode(2) + ]); + break; + case 'sech': + // d/dx(sech(x)) = -sech(x)tanh(x) + negative = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + node, + new FunctionNode$$1('tanh', [arg0.clone()]) + ]); + break; + case 'csch': + // d/dx(csch(x)) = -csch(x)coth(x) + negative = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + node, + new FunctionNode$$1('coth', [arg0.clone()]) + ]); + break; + case 'coth': + // d/dx(coth(x)) = -csch(x)^2 + negative = true; + funcDerivative = new OperatorNode$$1('^', 'pow', [ + new FunctionNode$$1('csch', [arg0.clone()]), + createConstantNode(2) + ]); + break; + case 'asinh': + // d/dx(asinh(x)) = 1 / sqrt(x^2 + 1) + div = true; + funcDerivative = new FunctionNode$$1('sqrt', [ + new OperatorNode$$1('+', 'add', [ + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]), + createConstantNode(1) + ]) + ]); + break; + case 'acosh': + // d/dx(acosh(x)) = 1 / sqrt(x^2 - 1); XXX potentially only for x >= 1 (the real spectrum) + div = true; + funcDerivative = new FunctionNode$$1('sqrt', [ + new OperatorNode$$1('-', 'subtract', [ + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]), + createConstantNode(1) + ]) + ]); + break; + case 'atanh': + // d/dx(atanh(x)) = 1 / (1 - x^2) + div = true; + funcDerivative = new OperatorNode$$1('-', 'subtract', [ + createConstantNode(1), + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]) + ]); + break; + case 'asech': + // d/dx(asech(x)) = -1 / (x*sqrt(1 - x^2)) + div = true; + negative = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + arg0.clone(), + new FunctionNode$$1('sqrt', [ + new OperatorNode$$1('-', 'subtract', [ + createConstantNode(1), + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]) + ]) + ]) + ]); + break; + case 'acsch': + // d/dx(acsch(x)) = -1 / (|x|*sqrt(x^2 + 1)) + div = true; + negative = true; + funcDerivative = new OperatorNode$$1('*', 'multiply', [ + new FunctionNode$$1('abs', [arg0.clone()]), + new FunctionNode$$1('sqrt', [ + new OperatorNode$$1('+', 'add', [ + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]), + createConstantNode(1) + ]) + ]) + ]); + break; + case 'acoth': + // d/dx(acoth(x)) = -1 / (1 - x^2) + div = true; + negative = true; + funcDerivative = new OperatorNode$$1('-', 'subtract', [ + createConstantNode(1), + new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + createConstantNode(2) + ]) + ]); + break; + case 'abs': + // d/dx(abs(x)) = abs(x)/x + funcDerivative = new OperatorNode$$1('/', 'divide', [ + new FunctionNode$$1(new SymbolNode$$1('abs'), [arg0.clone()]), + arg0.clone() + ]); + break; + case 'gamma': // Needs digamma function, d/dx(gamma(x)) = gamma(x)digamma(x) + default: throw new Error('Function "' + node.name + '" is not supported by derivative, or a wrong number of arguments is passed'); } - else { - // x(i) is the entry U(pinv[i],k) - uindex[unz] = pinv[i]; - uvalues[unz++] = x[i]; + + var op, func; + if (div) { + op = '/'; + func = 'divide'; + } else { + op = '*'; + func = 'multiply'; } - } - // validate we found a valid pivot - if (ipiv == -1 || a <= 0) - return null; - // update actual pivot column, give preference to diagonal value - if (pinv[col] < 0 && largerEq(abs(x[col]), multiply(a, tol))) - ipiv = col; - // the chosen pivot - var pivot = x[ipiv]; - // last entry in U(:,k) is U(k,k) - uindex[unz] = k; - uvalues[unz++] = pivot; - // ipiv is the kth pivot row - pinv[ipiv] = k; - // first entry in L(:,k) is L(k,k) = 1 - lindex[lnz] = ipiv; - lvalues[lnz++] = 1; - // L(k+1:n,k) = x / pivot - for (p = top; p < n; p++) { - // row - i = xi[p]; - // check x(i) is an entry in L(:,k) - if (pinv[i] < 0) { - // save unpermuted row in L - lindex[lnz] = i; - // scale pivot column - lvalues[lnz++] = divideScalar$$1(x[i], pivot); - } - // x[0..n-1] = 0 for next k - x[i] = 0; - } - } - // update ptr - lptr[n] = lnz; - uptr[n] = unz; - // fix row indices of L for final pinv - for (p = 0; p < lnz; p++) - lindex[p] = pinv[lindex[p]]; - // trim arrays - lvalues.splice(lnz, lvalues.length - lnz); - lindex.splice(lnz, lindex.length - lnz); - uvalues.splice(unz, uvalues.length - unz); - uindex.splice(unz, uindex.length - unz); - // return LU factor - return { - L: L, - U: U, - pinv: pinv - }; - }; - return cs_lu; -} + /* Apply chain rule to all functions: + F(x) = f(g(x)) + F'(x) = g'(x)*f'(g(x)) */ + var chainDerivative = _derivative(arg0, constNodes); + if (negative) { + chainDerivative = new OperatorNode$$1('-', 'unaryMinus', [chainDerivative]); + } + return new OperatorNode$$1(op, func, [chainDerivative, funcDerivative]); + }, -var name$125 = 'cs_lu'; -var path$62 = 'sparse'; -var factory_1$135 = factory$136; + 'OperatorNode, Object': function (node, constNodes) { + if (constNodes[node] !== undefined) { + return createConstantNode(0); + } -var cs_lu = { - name: name$125, - path: path$62, - factory: factory_1$135 -}; + if (node.op === '+') { + // d/dx(sum(f(x)) = sum(f'(x)) + return new OperatorNode$$1(node.op, node.fn, node.args.map(function(arg) { + return _derivative(arg, constNodes); + })); + } -var number$5 = utils.number, - - isInteger$8 = number$5.isInteger; + if (node.op === '-') { + // d/dx(+/-f(x)) = +/-f'(x) + if (node.isUnary()) { + return new OperatorNode$$1(node.op, node.fn, [ + _derivative(node.args[0], constNodes) + ]); + } -function factory$137 (type, config, load, typed) { + // Linearity of differentiation, d/dx(f(x) +/- g(x)) = f'(x) +/- g'(x) + if (node.isBinary()) { + return new OperatorNode$$1(node.op, node.fn, [ + _derivative(node.args[0], constNodes), + _derivative(node.args[1], constNodes) + ]); + } + } - var cs_sqr$$1 = load(cs_sqr); - var cs_lu$$1 = load(cs_lu); + if (node.op === '*') { + // d/dx(c*f(x)) = c*f'(x) + var constantTerms = node.args.filter(function(arg) { + return constNodes[arg] !== undefined; + }); - /** - * Calculate the Sparse Matrix LU decomposition with full pivoting. Sparse Matrix `A` is decomposed in two matrices (`L`, `U`) and two permutation vectors (`pinv`, `q`) where - * - * `P * A * Q = L * U` - * - * Syntax: - * - * math.slu(A, order, threshold); - * - * Examples: - * - * var A = math.sparse([[4,3], [6, 3]]) - * math.slu(A, 1, 0.001) - * // returns: - * // { - * // L: [[1, 0], [1.5, 1]] - * // U: [[4, 3], [0, -1.5]] - * // p: [0, 1] - * // q: [0, 1] - * // } - * - * See also: - * - * lup, lsolve, usolve, lusolve - * - * @param {SparseMatrix} A A two dimensional sparse matrix for which to get the LU decomposition. - * @param {Number} order The Symbolic Ordering and Analysis order: - * 0 - Natural ordering, no permutation vector q is returned - * 1 - Matrix must be square, symbolic ordering and analisis is performed on M = A + A' - * 2 - Symbolic ordering and analisis is performed on M = A' * A. Dense columns from A' are dropped, A recreated from A'. - * This is appropriatefor LU factorization of unsymmetric matrices. - * 3 - Symbolic ordering and analisis is performed on M = A' * A. This is best used for LU factorization is matrix M has no dense rows. - * A dense row is a row with more than 10*sqr(columns) entries. - * @param {Number} threshold Partial pivoting threshold (1 for partial pivoting) - * - * @return {Object} The lower triangular matrix, the upper triangular matrix and the permutation vectors. - */ - var slu = typed('slu', { - - 'SparseMatrix, number, number': function (a, order, threshold) { - // verify order - if (!isInteger$8(order) || order < 0 || order > 3) - throw new Error('Symbolic Ordering and Analysis order must be an integer number in the interval [0, 3]'); - // verify threshold - if (threshold < 0 || threshold > 1) - throw new Error('Partial pivoting threshold must be a number from 0 to 1'); - - // perform symbolic ordering and analysis - var s = cs_sqr$$1(order, a, false); - - // perform lu decomposition - var f = cs_lu$$1(a, s, threshold); - - // return decomposition - return { - L: f.L, - U: f.U, - p: f.pinv, - q: s.q, - toString: function () { - return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\np: ' + this.p.toString() + (this.q ? '\nq: ' + this.q.toString() : '') + '\n'; - } - }; - } - }); + if (constantTerms.length > 0) { + var nonConstantTerms = node.args.filter(function(arg) { + return constNodes[arg] === undefined; + }); - return slu; -} + var nonConstantNode = nonConstantTerms.length === 1 + ? nonConstantTerms[0] + : new OperatorNode$$1('*', 'multiply', nonConstantTerms); -var name$126 = 'slu'; -var factory_1$136 = factory$137; + var newArgs = constantTerms.concat(_derivative(nonConstantNode, constNodes)); -var slu$1 = { - name: name$126, - factory: factory_1$136 -}; + return new OperatorNode$$1('*', 'multiply', newArgs); + } -var string$9 = utils.string; -var array$3 = utils.array; + // Product Rule, d/dx(f(x)*g(x)) = f'(x)*g(x) + f(x)*g'(x) + return new OperatorNode$$1('+', 'add', node.args.map(function(argOuter) { + return new OperatorNode$$1('*', 'multiply', node.args.map(function(argInner) { + return (argInner === argOuter) + ? _derivative(argInner, constNodes) + : argInner.clone(); + })); + })); + } -var isArray$3 = Array.isArray; + if (node.op === '/' && node.isBinary()) { + var arg0 = node.args[0]; + var arg1 = node.args[1]; -function factory$138 (type) { - - var DenseMatrix = type.DenseMatrix; + // d/dx(f(x) / c) = f'(x) / c + if (constNodes[arg1] !== undefined) { + return new OperatorNode$$1('/', 'divide', [_derivative(arg0, constNodes), arg1]); + } - /** - * Validates matrix and column vector b for backward/forward substitution algorithms. - * - * @param {Matrix} m An N x N matrix - * @param {Array | Matrix} b A column vector - * @param {Boolean} copy Return a copy of vector b - * - * @return {DenseMatrix} Dense column vector b - */ - var solveValidation = function (m, b, copy) { - // matrix size - var size = m.size(); - // validate matrix dimensions - if (size.length !== 2) - throw new RangeError('Matrix must be two dimensional (size: ' + string$9.format(size) + ')'); - // rows & columns - var rows = size[0]; - var columns = size[1]; - // validate rows & columns - if (rows !== columns) - throw new RangeError('Matrix must be square (size: ' + string$9.format(size) + ')'); - // vars - var data, i, bdata; - // check b is matrix - if (type.isMatrix(b)) { - // matrix size - var msize = b.size(); - // vector - if (msize.length === 1) { - // check vector length - if (msize[0] !== rows) - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - // create data array - data = []; - // matrix data (DenseMatrix) - bdata = b._data; - // loop b data - for (i = 0; i < rows; i++) { - // row array - data[i] = [bdata[i]]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1], - datatype: b._datatype - }); - } - // two dimensions - if (msize.length === 2) { - // array must be a column vector - if (msize[0] !== rows || msize[1] !== 1) - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - // check matrix type - if (type.isDenseMatrix(b)) { - // check a copy is needed - if (copy) { - // create data array - data = []; - // matrix data (DenseMatrix) - bdata = b._data; - // loop b data - for (i = 0; i < rows; i++) { - // row array - data[i] = [bdata[i][0]]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1], - datatype: b._datatype - }); + // Reciprocal Rule, d/dx(c / f(x)) = -c(f'(x)/f(x)^2) + if (constNodes[arg0] !== undefined) { + return new OperatorNode$$1('*', 'multiply', [ + new OperatorNode$$1('-', 'unaryMinus', [arg0]), + new OperatorNode$$1('/', 'divide', [ + _derivative(arg1, constNodes), + new OperatorNode$$1('^', 'pow', [arg1.clone(), createConstantNode(2)]) + ]) + ]); } - // b is already a column vector - return b; - } - // create data array - data = []; - for (i = 0; i < rows; i++) - data[i] = [0]; - // sparse matrix arrays - var values = b._values; - var index = b._index; - var ptr = b._ptr; - // loop values in column 0 - for (var k1 = ptr[1], k = ptr[0]; k < k1; k++) { - // row - i = index[k]; - // add to data - data[i][0] = values[k]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1], - datatype: b._datatype - }); - } - // throw error - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - } - // check b is array - if (isArray$3(b)) { - // size - var asize = array$3.size(b); - // check matrix dimensions, vector - if (asize.length === 1) { - // check vector length - if (asize[0] !== rows) - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - // create data array - data = []; - // loop b - for (i = 0; i < rows; i++) { - // row array - data[i] = [b[i]]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1] - }); - } - if (asize.length === 2) { - // array must be a column vector - if (asize[0] !== rows || asize[1] !== 1) - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - // create data array - data = []; - // loop b data - for (i = 0; i < rows; i++) { - // row array - data[i] = [b[i][0]]; + + // Quotient rule, d/dx(f(x) / g(x)) = (f'(x)g(x) - f(x)g'(x)) / g(x)^2 + return new OperatorNode$$1('/', 'divide', [ + new OperatorNode$$1('-', 'subtract', [ + new OperatorNode$$1('*', 'multiply', [_derivative(arg0, constNodes), arg1.clone()]), + new OperatorNode$$1('*', 'multiply', [arg0.clone(), _derivative(arg1, constNodes)]) + ]), + new OperatorNode$$1('^', 'pow', [arg1.clone(), createConstantNode(2)]) + ]); } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1] - }); - } - // throw error - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - } - }; - - return solveValidation; -} -var factory_1$137 = factory$138; + if (node.op === '^' && node.isBinary()) { + var arg0 = node.args[0]; + var arg1 = node.args[1]; -var solveValidation = { - factory: factory_1$137 -}; + if (constNodes[arg0] !== undefined) { + // If is secretly constant; 0^f(x) = 1 (in JS), 1^f(x) = 1 + if (type.isConstantNode(arg0) && (isZero(arg0.value) || equal(arg0.value, 1))) { + return createConstantNode(0); + } -function factory$139 (type, config, load, typed) { + // d/dx(c^f(x)) = c^f(x)*ln(c)*f'(x) + return new OperatorNode$$1('*', 'multiply', [ + node, + new OperatorNode$$1('*', 'multiply', [ + new FunctionNode$$1('log', [arg0.clone()]), + _derivative(arg1.clone(), constNodes) + ]) + ]); + } - var matrix$$1 = load(matrix); - var divideScalar$$1 = load(divideScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var subtract = load(subtract$1); - var equalScalar$$1 = load(equalScalar); + if (constNodes[arg1] !== undefined) { + if (type.isConstantNode(arg1)) { + // If is secretly constant; f(x)^0 = 1 -> d/dx(1) = 0 + if (isZero(arg1.value)) { + return createConstantNode(0); + } + // Ignore exponent; f(x)^1 = f(x) + if (equal(arg1.value,1)) { + return _derivative(arg0, constNodes); + } + } - var solveValidation$$1 = load(solveValidation); + // Elementary Power Rule, d/dx(f(x)^c) = c*f'(x)*f(x)^(c-1) + var powMinusOne = new OperatorNode$$1('^', 'pow', [ + arg0.clone(), + new OperatorNode$$1('-', 'subtract', [ + arg1, + createConstantNode(1) + ]) + ]); - var DenseMatrix = type.DenseMatrix; + return new OperatorNode$$1('*', 'multiply', [ + arg1.clone(), + new OperatorNode$$1('*', 'multiply', [ + _derivative(arg0, constNodes), + powMinusOne + ]) + ]); + } - /** - * Solves the linear equation system by forwards substitution. Matrix must be a lower triangular matrix. - * - * `L * x = b` - * - * Syntax: - * - * math.lsolve(L, b); - * - * Examples: - * - * var a = [[-2, 3], [2, 1]]; - * var b = [11, 9]; - * var x = lsolve(a, b); // [[-5.5], [20]] - * - * See also: - * - * lup, slu, usolve, lusolve - * - * @param {Matrix, Array} L A N x N matrix or array (L) - * @param {Matrix, Array} b A column vector with the b values - * - * @return {DenseMatrix | Array} A column vector with the linear system solution (x) - */ - var lsolve = typed('lsolve', { + // Functional Power Rule, d/dx(f^g) = f^g*[f'*(g/f) + g'ln(f)] + return new OperatorNode$$1('*', 'multiply', [ + new OperatorNode$$1('^', 'pow', [arg0.clone(), arg1.clone()]), + new OperatorNode$$1('+', 'add', [ + new OperatorNode$$1('*', 'multiply', [ + _derivative(arg0, constNodes), + new OperatorNode$$1('/', 'divide', [arg1.clone(), arg0.clone()]) + ]), + new OperatorNode$$1('*', 'multiply', [ + _derivative(arg1, constNodes), + new FunctionNode$$1('log', [arg0.clone()]) + ]) + ]) + ]); + } - 'SparseMatrix, Array | Matrix': function (m, b) { - // process matrix - return _sparseForwardSubstitution(m, b); - }, - - 'DenseMatrix, Array | Matrix': function (m, b) { - // process matrix - return _denseForwardSubstitution(m, b); - }, - - 'Array, Array | Matrix': function (a, b) { - // create dense matrix from array - var m = matrix$$1(a); - // use matrix implementation - var r = _denseForwardSubstitution(m, b); - // result - return r.valueOf(); - } - }); - - var _denseForwardSubstitution = function (m, b) { - // validate matrix and vector, return copy of column vector b - b = solveValidation$$1(m, b, true); - // column vector data - var bdata = b._data; - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // result - var x = []; - // data - var data = m._data; - // forward solve m * x = b, loop columns - for (var j = 0; j < columns; j++) { - // b[j] - var bj = bdata[j][0] || 0; - // x[j] - var xj; - // forward substitution (outer product) avoids inner looping when bj == 0 - if (!equalScalar$$1(bj, 0)) { - // value @ [j, j] - var vjj = data[j][j]; - // check vjj - if (equalScalar$$1(vjj, 0)) { - // system cannot be solved - throw new Error('Linear system cannot be solved since matrix is singular'); - } - // calculate xj - xj = divideScalar$$1(bj, vjj); - // loop rows - for (var i = j + 1; i < rows; i++) { - // update copy of b - bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, data[i][j]))]; - } - } - else { - // zero @ j - xj = 0; + throw new Error('Operator "' + node.op + '" is not supported by derivative, or a wrong number of arguments is passed'); } - // update x - x[j] = [xj]; - } - // return vector - return new DenseMatrix({ - data: x, - size: [rows, 1] }); - }; - var _sparseForwardSubstitution = function (m, b) { - // validate matrix and vector, return copy of column vector b - b = solveValidation$$1(m, b, true); - // column vector data - var bdata = b._data; - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // matrix arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // vars - var i, k; - // result - var x = []; - // forward solve m * x = b, loop columns - for (var j = 0; j < columns; j++) { - // b[j] - var bj = bdata[j][0] || 0; - // forward substitution (outer product) avoids inner looping when bj == 0 - if (!equalScalar$$1(bj, 0)) { - // value @ [j, j] - var vjj = 0; - // lower triangular matrix values & index (column j) - var jvalues = []; - var jindex = []; - // last index in column - var l = ptr[j + 1]; - // values in column, find value @ [j, j] - for (k = ptr[j]; k < l; k++) { - // row - i = index[k]; - // check row (rows are not sorted!) - if (i === j) { - // update vjj - vjj = values[k]; - } - else if (i > j) { - // store lower triangular - jvalues.push(values[k]); - jindex.push(i); - } - } - // at this point we must have a value @ [j, j] - if (equalScalar$$1(vjj, 0)) { - // system cannot be solved, there is no value @ [j, j] - throw new Error('Linear system cannot be solved since matrix is singular'); - } - // calculate xj - var xj = divideScalar$$1(bj, vjj); - // loop lower triangular - for (k = 0, l = jindex.length; k < l; k++) { - // row - i = jindex[k]; - // update copy of b - bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, jvalues[k]))]; - } - // update x - x[j] = [xj]; + /** + * Ensures the number of arguments for a function are correct, + * and will throw an error otherwise. + * + * @param {FunctionNode} node + */ + function funcArgsCheck(node) { + //TODO add min, max etc + if ((node.name === 'log' || node.name === 'nthRoot') && node.args.length === 2) { + return; } - else { - // update x - x[j] = [0]; + + // There should be an incorrect number of arguments if we reach here + + // Change all args to constants to avoid unidentified + // symbol error when compiling function + for (var i = 0; i < node.args.length; ++i) { + node.args[i] = createConstantNode(0); } - } - // return vector - return new DenseMatrix({ - data: x, - size: [rows, 1] - }); - }; - return lsolve; -} + node.compile().eval(); + throw new Error('Expected TypeError, but none found'); + } -var name$127 = 'lsolve'; -var factory_1$138 = factory$139; + /** + * Helper function to create a constant node with a specific type + * (number, BigNumber, Fraction) + * @param {number} value + * @param {string} [valueType] + * @return {ConstantNode} + */ + function createConstantNode(value, valueType) { + return new ConstantNode$$1(numeric$$1(value, valueType || config.number)); + } -var lsolve$1 = { - name: name$127, - factory: factory_1$138 -}; + return derivative; + } -function factory$140 () { + var name$97 = 'derivative'; + var factory_1$107 = factory$108; - /** - * Permutes a vector; x = P'b. In MATLAB notation, x(p)=b. - * - * @param {Array} p The permutation vector of length n. null value denotes identity - * @param {Array} b The input vector - * - * @return {Array} The output vector x = P'b - */ - var cs_ipvec = function (p, b, n) { - // vars - var k; - var n = b.length; - var x = []; - // check permutation vector was provided, p = null denotes identity - if (p) { - // loop vector - for (k = 0; k < n; k++) { - // apply permutation - x[p[k]] = b[k]; - } - } - else { - // loop vector - for (k = 0; k < n; k++) { - // x[i] = b[i] - x[k] = b[k]; - } - } - return x; + var derivative$1 = { + name: name$97, + factory: factory_1$107 }; - return cs_ipvec; -} + function factory$109 (type, config, load, typed) { + var simplify = load(simplify$1); + var simplifyCore$$1 = load(simplifyCore); + var simplifyConstant$$1 = load(simplifyConstant); + var ArgumentsError = ArgumentsError_1; + var parse = load(parse$1); + var number$$1 = number; + var ConstantNode$$1 = load(ConstantNode); + var OperatorNode$$1 = load(OperatorNode); + var SymbolNode$$1 = load(SymbolNode); + + /** + * Transform a rationalizable expression in a rational fraction. + * If rational fraction is one variable polynomial then converts + * the numerator and denominator in canonical form, with decreasing + * exponents, returning the coefficients of numerator. + * + * Syntax: + * + * rationalize(expr) + * rationalize(expr, detailed) + * rationalize(expr, scope) + * rationalize(expr, scope, detailed) + * + * Examples: + * + * math.rationalize('sin(x)+y') // Error: There is an unsolved function call + * math.rationalize('2x/y - y/(x+1)') // (2*x^2-y^2+2*x)/(x*y+y) + * math.rationalize('(2x+1)^6') + * // 64*x^6+192*x^5+240*x^4+160*x^3+60*x^2+12*x+1 + * math.rationalize('2x/( (2x-1) / (3x+2) ) - 5x/ ( (3x+4) / (2x^2-5) ) + 3') + * // -20*x^4+28*x^3+104*x^2+6*x-12)/(6*x^2+5*x-4) + * math.rationalize('x/(1-x)/(x-2)/(x-3)/(x-4) + 2x/ ( (1-2x)/(2-3x) )/ ((3-4x)/(4-5x) )') = + * // (-30*x^7+344*x^6-1506*x^5+3200*x^4-3472*x^3+1846*x^2-381*x)/ + * // (-8*x^6+90*x^5-383*x^4+780*x^3-797*x^2+390*x-72) + * + * math.rationalize('x+x+x+y',{y:1}) // 3*x+1 + * math.rationalize('x+x+x+y',{}) // 3*x+y + * ret = math.rationalize('x+x+x+y',{},true) + * // ret.expression=3*x+y, ret.variables = ["x","y"] + * ret = math.rationalize('-2+5x^2',{},true) + * // ret.expression=5*x^2-2, ret.variables = ["x"], ret.coefficients=[-2,0,5] + * + * See also: + * + * simplify + * + * @param {Node|string} expr The expression to check if is a polynomial expression + * @param {Object|boolean} optional scope of expression or true for already evaluated rational expression at input + * @param {Boolean} detailed optional True if return an object, false if return expression node (default) + * + * @return {Object | Expression Node} The rational polynomial of `expr` or na object + * {Object} + * {Expression Node} expression: node simplified expression + * {Expression Node} numerator: simplified numerator of expression + * {Expression Node | boolean} denominator: simplified denominator or false (if there is no denominator) + * {Array} variables: variable names + * {Array} coefficients: coefficients of numerator sorted by increased exponent + * {Expression Node} node simplified expression + * + */ + var rationalize = typed('rationalize', { + 'string': function (expr) { + return rationalize(parse(expr), {}, false); + }, -var name$128 = 'cs_ipvec'; -var path$63 = 'sparse'; -var factory_1$139 = factory$140; + 'string, boolean': function (expr, detailed) { + return rationalize(parse(expr), {} , detailed); + }, -var cs_ipvec = { - name: name$128, - path: path$63, - factory: factory_1$139 -}; + 'string, Object': function (expr, scope) { + return rationalize(parse(expr), scope, false); + }, -function factory$141 (type, config, load, typed) { + 'string, Object, boolean': function (expr, scope, detailed) { + return rationalize(parse(expr), scope, detailed); + }, - var matrix$$1 = load(matrix); - var divideScalar$$1 = load(divideScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var subtract = load(subtract$1); - var equalScalar$$1 = load(equalScalar); + 'Node': function (expr) { + return rationalize(expr, {}, false); + }, - var solveValidation$$1 = load(solveValidation); - - var DenseMatrix = type.DenseMatrix; + 'Node, boolean': function (expr, detailed) { + return rationalize(expr, {}, detailed); + }, - /** - * Solves the linear equation system by backward substitution. Matrix must be an upper triangular matrix. - * - * `U * x = b` - * - * Syntax: - * - * math.usolve(U, b); - * - * Examples: - * - * var a = [[-2, 3], [2, 1]]; - * var b = [11, 9]; - * var x = usolve(a, b); // [[8], [9]] - * - * See also: - * - * lup, slu, usolve, lusolve - * - * @param {Matrix, Array} U A N x N matrix or array (U) - * @param {Matrix, Array} b A column vector with the b values - * - * @return {DenseMatrix | Array} A column vector with the linear system solution (x) - */ - var usolve = typed('usolve', { - - 'SparseMatrix, Array | Matrix': function (m, b) { - // process matrix - return _sparseBackwardSubstitution(m, b); - }, + 'Node, Object': function (expr, scope) { + return rationalize(expr, scope, false); + }, - 'DenseMatrix, Array | Matrix': function (m, b) { - // process matrix - return _denseBackwardSubstitution(m, b); - }, + 'Node, Object, boolean': function (expr, scope, detailed) { + + var polyRet = polynomial(expr, scope, true); // Check if expression is a rationalizable polynomial + var nVars = polyRet.variables.length; + var expr = polyRet.expression; + + if (nVars>=1) { // If expression in not a constant + var setRules = rulesRationalize(); // Rules for change polynomial in near canonical form + expr = expandPower(expr); // First expand power of polynomials (cannot be made from rules!) + var redoInic = true; // If has change after start, redo the beginning + var s = ""; // New expression + var sBefore; // Previous expression + var rules; + var eDistrDiv = true; + + expr = simplify(expr, setRules.firstRules); // Apply the initial rules, including succ div rules + s = expr.toString(); - 'Array, Array | Matrix': function (a, b) { - // create dense matrix from array - var m = matrix$$1(a); - // use matrix implementation - var r = _denseBackwardSubstitution(m, b); - // result - return r.valueOf(); - } - }); - var _denseBackwardSubstitution = function (m, b) { - // validate matrix and vector, return copy of column vector b - b = solveValidation$$1(m, b, true); - // column vector data - var bdata = b._data; - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // result - var x = []; - // arrays - var data = m._data; - // backward solve m * x = b, loop columns (backwards) - for (var j = columns - 1; j >= 0 ; j--) { - // b[j] - var bj = bdata[j][0] || 0; - // x[j] - var xj; - // backward substitution (outer product) avoids inner looping when bj == 0 - if (!equalScalar$$1(bj, 0)) { - // value @ [j, j] - var vjj = data[j][j]; - // check vjj - if (equalScalar$$1(vjj, 0)) { - // system cannot be solved - throw new Error('Linear system cannot be solved since matrix is singular'); - } - // calculate xj - xj = divideScalar$$1(bj, vjj); - // loop rows - for (var i = j - 1; i >= 0; i--) { - // update copy of b - bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, data[i][j]))]; - } - } - else { - // zero value @ j - xj = 0; - } - // update x - x[j] = [xj]; - } - // return column vector - return new DenseMatrix({ - data: x, - size: [rows, 1] - }); - }; - - var _sparseBackwardSubstitution = function (m, b) { - // validate matrix and vector, return copy of column vector b - b = solveValidation$$1(m, b, true); - // column vector data - var bdata = b._data; - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // matrix arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // vars - var i, k; - // result - var x = []; - // backward solve m * x = b, loop columns (backwards) - for (var j = columns - 1; j >= 0 ; j--) { - // b[j] - var bj = bdata[j][0] || 0; - // backward substitution (outer product) avoids inner looping when bj == 0 - if (!equalScalar$$1(bj, 0)) { - // value @ [j, j] - var vjj = 0; - // upper triangular matrix values & index (column j) - var jvalues = []; - var jindex = []; - // first & last indeces in column - var f = ptr[j]; - var l = ptr[j + 1]; - // values in column, find value @ [j, j], loop backwards - for (k = l - 1; k >= f; k--) { - // row - i = index[k]; - // check row - if (i === j) { - // update vjj - vjj = values[k]; - } - else if (i < j) { - // store upper triangular - jvalues.push(values[k]); - jindex.push(i); + while (true) { // Apply alternately successive division rules and distr.div.rules + rules = eDistrDiv ? setRules.distrDivRules : setRules.sucDivRules; + expr = simplify(expr,rules); // until no more changes + eDistrDiv = ! eDistrDiv; // Swap between Distr.Div and Succ. Div. Rules + + s = expr.toString(); + if (s===sBefore) break // No changes : end of the loop + + redoInic = true; + sBefore = s; + } + + if (redoInic) { // Apply first rules again without succ div rules (if there are changes) + expr = simplify(expr,setRules.firstRulesAgain); } - } - // at this point we must have a value @ [j, j] - if (equalScalar$$1(vjj, 0)) { - // system cannot be solved, there is no value @ [j, j] - throw new Error('Linear system cannot be solved since matrix is singular'); - } - // calculate xj - var xj = divideScalar$$1(bj, vjj); - // loop upper triangular - for (k = 0, l = jindex.length; k < l; k++) { - // row - i = jindex[k]; - // update copy of b - bdata[i] = [subtract(bdata[i][0], multiplyScalar$$1(xj, jvalues[k]))]; - } - // update x - x[j] = [xj]; - } - else { - // update x - x[j] = [0]; - } - } - // return vector - return new DenseMatrix({ - data: x, - size: [rows, 1] - }); - }; - - return usolve; -} + expr = simplify(expr,setRules.finalRules); // Aplly final rules -var name$129 = 'usolve'; -var factory_1$140 = factory$141; + } // NVars >= 1 -var usolve$1 = { - name: name$129, - factory: factory_1$140 -}; + var coefficients=[]; + var retRationalize = {}; -var isArray$4 = Array.isArray; - -function factory$142 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var lup = load(lup$1); - var slu = load(slu$1); - var cs_ipvec$$1 = load(cs_ipvec); + if (expr.type === 'OperatorNode' && expr.isBinary() && expr.op === '/') { // Separate numerator from denominator + if (nVars==1) { + expr.args[0] = polyToCanonical(expr.args[0],coefficients); + expr.args[1] = polyToCanonical(expr.args[1]); + } + if (detailed) { + retRationalize.numerator = expr.args[0]; + retRationalize.denominator = expr.args[1]; + } + } else { + if (nVars==1) expr = polyToCanonical(expr,coefficients); + if (detailed) { + retRationalize.numerator = expr; + retRationalize.denominator = null; + } + } + // nVars - var solveValidation$$1 = load(solveValidation); + if (! detailed) return expr; + retRationalize.coefficients = coefficients; + retRationalize.variables = polyRet.variables; + retRationalize.expression = expr; + return retRationalize; + } // ^^^^^^^ end of rationalize ^^^^^^^^ + }); // end of typed rationalize - var usolve = load(usolve$1); - var lsolve = load(lsolve$1); + /** + * Function to simplify an expression using an optional scope and + * return it if the expression is a polynomial expression, i.e. + * an expression with one or more variables and the operators + * +, -, *, and ^, where the exponent can only be a positive integer. + * + * Syntax: + * + * polynomial(expr,scope,extended) + * + * @param {Node | string} expr The expression to simplify and check if is polynomial expression + * @param {object} scope Optional scope for expression simplification + * @param {boolean} extended Optional. Default is false. When true allows divide operator. + * + * + * @return {Object} + * {Object} node: node simplified expression + * {Array} variables: variable names + */ + function polynomial (expr, scope, extended) { + var variables = []; + var node = simplify(expr,scope); // Resolves any variables and functions with all defined parameters + extended = !! extended; + + var oper = '+-*' + (extended ? '/' : ''); + recPoly(node); + var retFunc ={}; + retFunc.expression = node; + retFunc.variables = variables; + return retFunc; + + //------------------------------------------------------------------------------------------------------- - /** - * Solves the linear system `A * x = b` where `A` is an [n x n] matrix and `b` is a [n] column vector. - * - * Syntax: - * - * math.lusolve(A, b) // returns column vector with the solution to the linear system A * x = b - * math.lusolve(lup, b) // returns column vector with the solution to the linear system A * x = b, lup = math.lup(A) - * - * Examples: - * - * var m = [[1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 3, 0], [0, 0, 0, 4]]; - * - * var x = math.lusolve(m, [-1, -1, -1, -1]); // x = [[-1], [-0.5], [-1/3], [-0.25]] - * - * var f = math.lup(m); - * var x1 = math.lusolve(f, [-1, -1, -1, -1]); // x1 = [[-1], [-0.5], [-1/3], [-0.25]] - * var x2 = math.lusolve(f, [1, 2, 1, -1]); // x2 = [[1], [1], [1/3], [-0.25]] - * - * var a = [[-2, 3], [2, 1]]; - * var b = [11, 9]; - * var x = math.lusolve(a, b); // [[2], [5]] - * - * See also: - * - * lup, slu, lsolve, usolve - * - * @param {Matrix | Array | Object} A Invertible Matrix or the Matrix LU decomposition - * @param {Matrix | Array} b Column Vector - * @param {number} [order] The Symbolic Ordering and Analysis order, see slu for details. Matrix must be a SparseMatrix - * @param {Number} [threshold] Partial pivoting threshold (1 for partial pivoting), see slu for details. Matrix must be a SparseMatrix. - * - * @return {DenseMatrix | Array} Column vector with the solution to the linear system A * x = b - */ - var lusolve = typed('lusolve', { - - 'Array, Array | Matrix': function (a, b) { - // convert a to matrix - a = matrix$$1(a); - // matrix lup decomposition - var d = lup(a); - // solve - var x = _lusolve(d.L, d.U, d.p, null, b); - // convert result to array - return x.valueOf(); - }, - - 'DenseMatrix, Array | Matrix': function (a, b) { - // matrix lup decomposition - var d = lup(a); - // solve - return _lusolve(d.L, d.U, d.p, null, b); - }, - - 'SparseMatrix, Array | Matrix': function (a, b) { - // matrix lup decomposition - var d = lup(a); - // solve - return _lusolve(d.L, d.U, d.p, null, b); - }, - - 'SparseMatrix, Array | Matrix, number, number': function (a, b, order, threshold) { - // matrix lu decomposition - var d = slu(a, order, threshold); - // solve - return _lusolve(d.L, d.U, d.p, d.q, b); - }, + /** + * Function to simplify an expression using an optional scope and + * return it if the expression is a polynomial expression, i.e. + * an expression with one or more variables and the operators + * +, -, *, and ^, where the exponent can only be a positive integer. + * + * Syntax: + * + * recPoly(node) + * + * + * @param {Node} node The current sub tree expression in recursion + * + * @return nothing, throw an exception if error + */ + function recPoly(node) { + var tp = node.type; // node type + if (tp==='FunctionNode') + throw new ArgumentsError('There is an unsolved function call') // No function call in polynomial expression + else if (tp==='OperatorNode') { + if (node.op === '^' && node.isBinary()) { + if (node.args[1].type!=='ConstantNode' || ! number$$1.isInteger(parseFloat(node.args[1].value))) + throw new ArgumentsError('There is a non-integer exponent'); + else + recPoly(node.args[0]); + } else { + if (oper.indexOf(node.op) === -1) throw new ArgumentsError('Operator ' + node.op + ' invalid in polynomial expression'); + for (var i=0;i infinite loop + // setRules.allRules =oldRules.concat(rulesFirst,rulesDistrDiv,rulesSucDiv); + + setRules.firstRules =oldRules.concat(rulesFirst,rulesSucDiv); // First rule set + setRules.distrDivRules = rulesDistrDiv; // Just distr. div. rules + setRules.sucDivRules = rulesSucDiv; // Jus succ. div. rules + setRules.firstRulesAgain = oldRules.concat(rulesFirst); // Last rules set without succ. div. + + // Division simplification + + // Second rule set. + // There is no aggregate expression with parentesis, but the only variable can be scattered. + setRules.finalRules=[ simplifyCore$$1, // simplify.rules[0] + { l: 'n*-n', r: '-n^2' }, // Joining multiply with power 1 + { l: 'n*n', r: 'n^2' }, // Joining multiply with power 2 + simplifyConstant$$1, // simplify.rules[14] old 3rd index in oldRules + { l: 'n*-n^n1', r: '-n^(n1+1)' }, // Joining multiply with power 3 + { l: 'n*n^n1', r: 'n^(n1+1)' }, // Joining multiply with power 4 + { l: 'n^n1*-n^n2', r: '-n^(n1+n2)' }, // Joining multiply with power 5 + { l: 'n^n1*n^n2', r: 'n^(n1+n2)' }, // Joining multiply with power 6 + { l: 'n^n1*-n', r: '-n^(n1+1)' }, // Joining multiply with power 7 + { l: 'n^n1*n', r: 'n^(n1+1)' }, // Joining multiply with power 8 + { l: 'n^n1/-n', r: '-n^(n1-1)' }, // Joining multiply with power 8 + { l: 'n^n1/n', r: 'n^(n1-1)' }, // Joining division with power 1 + { l: 'n/-n^n1', r: '-n^(1-n1)' }, // Joining division with power 2 + { l: 'n/n^n1', r: 'n^(1-n1)' }, // Joining division with power 3 + { l: 'n^n1/-n^n2', r: 'n^(n1-n2)' }, // Joining division with power 4 + { l: 'n^n1/n^n2', r: 'n^(n1-n2)' }, // Joining division with power 5 + { l: 'n1+(-n2*n3)', r: 'n1-n2*n3' }, // Solving useless parenthesis 1 + { l: 'v*(-c)', r: '-c*v' }, // Solving useless unary 2 + { l: 'n1+-n2', r: 'n1-n2' }, // Solving +- together (new!) + { l: 'v*c', r: 'c*v' }, // inversion constant with variable + { l: '(n1^n2)^n3', r:'(n1^(n2*n3))'}, // Power to Power + + ]; + return setRules; + } // End rulesRationalize - // polynomial - rationalize$1, - - - // decomposition - qr$1, - lup$1, - slu$1, - - // solver - lsolve$1, - lusolve$1, - usolve$1 -]; - -function factory$143 (type, config, load, typed) { - /** - * Test whether a value is negative: smaller than zero. - * The function supports types `number`, `BigNumber`, `Fraction`, and `Unit`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isNegative(x) - * - * Examples: - * - * math.isNegative(3); // returns false - * math.isNegative(-2); // returns true - * math.isNegative(0); // returns false - * math.isNegative(-0); // returns false - * math.isNegative(math.bignumber(2)); // returns false - * math.isNegative(math.fraction(-2, 5)); // returns true - * math.isNegative('-2'); // returns true - * math.isNegative([2, 0, -3]'); // returns [false, false, true] - * - * See also: - * - * isNumeric, isPositive, isZero, isInteger - * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is larger than zero. - * Throws an error in case of an unknown data type. - */ - var isNegative = typed('isNegative', { - 'number': function (x) { - return x < 0; - }, + //--------------------------------------------------------------------------------------- + /** + * Expand recursively a tree node for handling with expressions with exponents + * (it's not for constants, symbols or functions with exponents) + * PS: The other parameters are internal for recursion + * + * Syntax: + * + * expandPower(node) + * + * @param {Node} node Current expression node + * @param {node} parent Parent current node inside the recursion + * @param (int} Parent number of chid inside the rercursion + * + * @return {node} node expression with all powers expanded. + */ + function expandPower(node,parent,indParent) { + var tp = node.type; + var internal = (arguments.length>1); // TRUE in internal calls + + if (tp === 'OperatorNode' && node.isBinary()) { + var does = false; + if (node.op==='^') { // First operator: Parenthesis or UnaryMinus + if ( ( node.args[0].type==='ParenthesisNode' || + node.args[0].type==='OperatorNode' ) + && (node.args[1].type==='ConstantNode') ) { // Second operator: Constant + var val = parseFloat(node.args[1].value); + does = (val>=2 && number$$1.isInteger(val)); + } + } - 'BigNumber': function (x) { - return x.isNeg() && !x.isZero() && !x.isNaN(); - }, + if (does) { // Exponent >= 2 + //Before: + // operator A --> Subtree + // parent pow + // constant + // + if (val>2) { // Exponent > 2, + //AFTER: (exponent > 2) + // operator A --> Subtree + // parent * + // deep clone (operator A --> Subtree + // pow + // constant - 1 + // + var nEsqTopo = node.args[0]; + var nDirTopo = new OperatorNode$$1('^', 'pow', [node.args[0].cloneDeep(),new ConstantNode$$1(val-1)]); + node = new OperatorNode$$1('*', 'multiply', [nEsqTopo, nDirTopo]); + } else // Expo = 2 - no power + + //AFTER: (exponent = 2) + // operator A --> Subtree + // parent oper + // deep clone (operator A --> Subtree) + // + node = new OperatorNode$$1('*', 'multiply', [node.args[0], node.args[0].cloneDeep()]); + + if (internal) // Change parent references in internal recursive calls + if (indParent==='content') + parent.content = node; + else + parent.args[indParent] = node; + } // does + } // binary OperatorNode + + if (tp==='ParenthesisNode' ) // Recursion + expandPower(node.content,node,'content'); + else if (tp!=='ConstantNode' && tp!=='SymbolNode') + for (var i=0;i=0 ;i--) { + if (coefficients[i]===0) continue; + var n1 = new ConstantNode$$1( + first ? coefficients[i] : Math.abs(coefficients[i])); + var op = coefficients[i]<0 ? '-' : '+'; - 'Complex, boolean': _cbrtComplex, + if (i>0) { // Is not a constant without variable + var n2 = new SymbolNode$$1(varname); + if (i>1) { + var n3 = new ConstantNode$$1(i); + n2 = new OperatorNode$$1('^', 'pow', [n2, n3]); + } + if (coefficients[i]===-1 && first) + n1 = new OperatorNode$$1('-', 'unaryMinus', [n2]); + else if (Math.abs(coefficients[i])===1) + n1 = n2; + else + n1 = new OperatorNode$$1('*', 'multiply', [n1, n2]); + } - 'BigNumber': function (x) { - return x.cbrt(); - }, + var no; + if (first) + no = n1; + else if (op==='+') + no = new OperatorNode$$1('+', 'add', [no, n1]); + else + no = new OperatorNode$$1('-', 'subtract', [no, n1]); - 'Unit': _cbrtUnit, + first = false; + } // for - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since cbrt(0) = 0 - return deepMap(x, cbrt, true); - } - }); + if (first) + return new ConstantNode$$1(0); + else + return no; - /** - * Calculate the cubic root for a complex number - * @param {Complex} x - * @param {boolean} [allRoots] If true, the function will return an array - * with all three roots. If false or undefined, - * the principal root is returned. - * @returns {Complex | Array. | Matrix.} Returns the cubic root(s) of x - * @private - */ - function _cbrtComplex(x, allRoots) { - // https://www.wikiwand.com/en/Cube_root#/Complex_numbers - - var arg_3 = x.arg() / 3; - var abs = x.abs(); - - // principal root: - var principal = new type.Complex(_cbrtNumber(abs), 0).mul( - new type.Complex(0, arg_3).exp()); - - if (allRoots) { - var all = [ - principal, - new type.Complex(_cbrtNumber(abs), 0).mul( - new type.Complex(0, arg_3 + Math.PI * 2 / 3).exp()), - new type.Complex(_cbrtNumber(abs), 0).mul( - new type.Complex(0, arg_3 - Math.PI * 2 / 3).exp()) - ]; - - return (config.matrix === 'Array') ? all : matrix$$1(all); - } - else { - return principal; - } - } + /** + * Recursive auxilary function inside polyToCanonical for + * converting expression in canonical form + * + * Syntax: + * + * recurPol(node, noPai, obj) + * + * @param {Node} node The current subpolynomial expression + * @param {Node | Null} noPai The current parent node + * @param {object} obj Object with many internal flags + * + * @return {} No return. If error, throws an exception + */ + function recurPol(node,noPai,o) { + + var tp = node.type; + if (tp==='FunctionNode') // ***** FunctionName ***** + // No function call in polynomial expression + throw new ArgumentsError('There is an unsolved function call') + + else if (tp==='OperatorNode') { // ***** OperatorName ***** + if ('+-*^'.indexOf(node.op) === -1) throw new ArgumentsError('Operator ' + node.op + ' invalid'); + + if (noPai!==null) { + // -(unary),^ : children of *,+,- + if ( (node.fn==='unaryMinus' || node.fn==='pow') && noPai.fn !=='add' && + noPai.fn!=='subtract' && noPai.fn!=='multiply' ) + throw new ArgumentsError('Invalid ' + node.op + ' placing') + + // -,+,* : children of +,- + if ((node.fn==='subtract' || node.fn==='add' || node.fn==='multiply') && + noPai.fn!=='add' && noPai.fn!=='subtract' ) + throw new ArgumentsError('Invalid ' + node.op + ' placing'); + + // -,+ : first child + if ((node.fn==='subtract' || node.fn==='add' || + node.fn==='unaryMinus' ) && o.noFil!==0 ) + throw new ArgumentsError('Invalid ' + node.op + ' placing') + } // Has parent + + // Firers: ^,* Old: ^,&,-(unary): firers + if (node.op==='^' || node.op==='*') o.fire = node.op; + + for (var i=0;i it means there is no exponent above, so it's 1 (cte * var) + if (o.fire==='' || o.fire==='*' ) { + if (maxExpo<1) coefficients[1]=0; + coefficients[1] += o.cte* (o.oper==='+' ? 1 : -1); + maxExpo = Math.max(1,maxExpo); + } - /** - * Calculate the cubic root for a Unit - * @param {Unit} x - * @return {Unit} Returns the cubic root of x - * @private - */ - function _cbrtUnit(x) { - if(x.value && type.isComplex(x.value)) { - var result = x.clone(); - result.value = 1.0; - result = result.pow(1.0/3); // Compute the units - result.value = _cbrtComplex(x.value); // Compute the value - return result; - } - else { - var negate = isNegative(x.value); - if (negate) { - x.value = unaryMinus(x.value); - } + } else if (tp==='ConstantNode') { + var valor = parseFloat(node.value); + if (noPai === null) { + coefficients[0] = valor; + return; + } + if (noPai.op==='^') { + // cte: second child of power + if (o.noFil!==1) throw new ArgumentsError('Constant cannot be powered') + + if (! number$$1.isInteger(valor) || valor<=0 ) + throw new ArgumentsError('Non-integer exponent is not allowed'); + + for (var i=maxExpo+1;imaxExpo) coefficients[valor]=0; + coefficients[valor] += o.cte * (o.oper==='+' ? 1 : -1); + maxExpo = Math.max(valor,maxExpo); + return; + } + o.cte = valor; - // TODO: create a helper function for this - var third; - if (type.isBigNumber(x.value)) { - third = new type.BigNumber(1).div(3); - } - else if (type.isFraction(x.value)) { - third = new type.Fraction(1, 3); - } - else { - third = 1/3; - } + // Cte: firer '' => There is no exponent and no multiplication, so the exponent is 0. + if (o.fire==='') + coefficients[0] += o.cte * (o.oper==='+'? 1 : -1); - var result = x.pow(third); - if (negate) { - result.value = unaryMinus(result.value); - } + } else + throw new ArgumentsError('Type ' + tp + ' is not allowed'); + return; + } // End of recurPol + + } // End of polyToCanonical - return result; - } - } + return rationalize; + } // end of factory - cbrt.toTex = {1: '\\sqrt[3]{${args[0]}}'}; + var name$98 = 'rationalize'; + var factory_1$108 = factory$109; - return cbrt; -} + var rationalize$1 = { + name: name$98, + factory: factory_1$108 + }; -/** - * Calculate cbrt for a number - * - * Code from es6-shim.js: - * https://github.com/paulmillr/es6-shim/blob/master/es6-shim.js#L1564-L1577 - * - * @param {number} x - * @returns {number | Complex} Returns the cubic root of x - * @private - */ -var _cbrtNumber = Math.cbrt || function (x) { - if (x === 0) { - return x; - } + var isInteger$7 = number.isInteger; + var resize$1 = array.resize; - var negate = x < 0; - var result; - if (negate) { - x = -x; - } + function factory$110 (type, config, load, typed) { + var matrix$$1 = load(matrix); - if (isFinite(x)) { - result = Math.exp(Math.log(x) / 3); - // from http://en.wikipedia.org/wiki/Cube_root#Numerical_methods - result = (x / (result * result) + (2 * result)) / 3; - } else { - result = x; - } + /** + * Create a matrix filled with zeros. The created matrix can have one or + * multiple dimensions. + * + * Syntax: + * + * math.zeros(m) + * math.zeros(m, format) + * math.zeros(m, n) + * math.zeros(m, n, format) + * math.zeros([m, n]) + * math.zeros([m, n], format) + * + * Examples: + * + * math.zeros(3); // returns [0, 0, 0] + * math.zeros(3, 2); // returns [[0, 0], [0, 0], [0, 0]] + * math.zeros(3, 'dense'); // returns [0, 0, 0] + * + * var A = [[1, 2, 3], [4, 5, 6]]; + * math.zeros(math.size(A)); // returns [[0, 0, 0], [0, 0, 0]] + * + * See also: + * + * ones, eye, size, range + * + * @param {...number | Array} size The size of each dimension of the matrix + * @param {string} [format] The Matrix storage format + * + * @return {Array | Matrix} A matrix filled with zeros + */ + var zeros = typed('zeros', { + '': function () { + return (config.matrix === 'Array') + ? _zeros([]) + : _zeros([], 'default'); + }, - return negate ? -result : result; -}; + // math.zeros(m, n, p, ..., format) + // TODO: more accurate signature '...number | BigNumber, string' as soon as typed-function supports this + '...number | BigNumber | string': function (size) { + var last = size[size.length - 1]; + if (typeof last === 'string') { + var format = size.pop(); + return _zeros(size, format); + } + else if (config.matrix === 'Array') { + return _zeros(size); + } + else { + return _zeros(size, 'default'); + } + }, -var name$132 = 'cbrt'; -var factory_1$143 = factory$144; + 'Array': _zeros, -var cbrt$1 = { - name: name$132, - factory: factory_1$143 -}; + 'Matrix': function (size) { + var format = size.storage(); + return _zeros(size.valueOf(), format); + }, -function factory$145 (type, config, load, typed) { - /** - * Round a value towards plus infinity - * If `x` is complex, both real and imaginary part are rounded towards plus infinity. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.ceil(x) - * - * Examples: - * - * math.ceil(3.2); // returns number 4 - * math.ceil(3.8); // returns number 4 - * math.ceil(-4.2); // returns number -4 - * math.ceil(-4.7); // returns number -4 - * - * var c = math.complex(3.2, -2.7); - * math.ceil(c); // returns Complex 4 - 2i - * - * math.ceil([3.2, 3.8, -4.7]); // returns Array [4, 4, -4] - * - * See also: - * - * floor, fix, round - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded - * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value - */ - var ceil = typed('ceil', { - 'number': Math.ceil, + 'Array | Matrix, string': function (size, format) { + return _zeros (size.valueOf(), format); + } + }); - 'Complex': function (x) { - return x.ceil(); - }, + zeros.toTex = undefined; // use default template - 'BigNumber': function (x) { - return x.ceil(); - }, + return zeros; - 'Fraction': function (x) { - return x.ceil(); - }, + /** + * Create an Array or Matrix with zeros + * @param {Array} size + * @param {string} [format='default'] + * @return {Array | Matrix} + * @private + */ + function _zeros(size, format) { + var hasBigNumbers = _normalize(size); + var defaultValue = hasBigNumbers ? new type.BigNumber(0) : 0; + _validate(size); - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since ceil(0) = 0 - return deepMap(x, ceil, true); + if (format) { + // return a matrix + var m = matrix$$1(format); + if (size.length > 0) { + return m.resize(size, defaultValue); + } + return m; + } + else { + // return an Array + var arr = []; + if (size.length > 0) { + return resize$1(arr, size, defaultValue); + } + return arr; + } } - }); - ceil.toTex = {1: '\\left\\lceil${args[0]}\\right\\rceil'}; + // replace BigNumbers with numbers, returns true if size contained BigNumbers + function _normalize(size) { + var hasBigNumbers = false; + size.forEach(function (value, index, arr) { + if (type.isBigNumber(value)) { + hasBigNumbers = true; + arr[index] = value.toNumber(); + } + }); + return hasBigNumbers; + } - return ceil; -} + // validate arguments + function _validate (size) { + size.forEach(function (value) { + if (typeof value !== 'number' || !isInteger$7(value) || value < 0) { + throw new Error('Parameters in function zeros must be positive integers'); + } + }); + } + } -var name$133 = 'ceil'; -var factory_1$144 = factory$145; + // TODO: zeros contains almost the same code as ones. Reuse this? -var ceil$1 = { - name: name$133, - factory: factory_1$144 -}; + var name$99 = 'zeros'; + var factory_1$109 = factory$110; -function factory$146 (type, config, load, typed) { + var zeros$1 = { + name: name$99, + factory: factory_1$109 + }; - /** - * Compute the cube of a value, `x * x * x`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cube(x) - * - * Examples: - * - * math.cube(2); // returns number 8 - * math.pow(2, 3); // returns number 8 - * math.cube(4); // returns number 64 - * 4 * 4 * 4; // returns number 64 - * - * math.cube([1, 2, 3, 4]); // returns Array [1, 8, 27, 64] - * - * See also: - * - * multiply, square, pow, cbrt - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x Number for which to calculate the cube - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} Cube of x - */ - var cube = typed('cube', { - 'number': function (x) { - return x * x * x; - }, + function factory$111 (type, config, load, typed) { + /** + * Clone an object. + * + * Syntax: + * + * math.clone(x) + * + * Examples: + * + * math.clone(3.5); // returns number 3.5 + * math.clone(math.complex('2-4i'); // returns Complex 2 - 4i + * math.clone(math.unit(45, 'deg')); // returns Unit 45 deg + * math.clone([[1, 2], [3, 4]]); // returns Array [[1, 2], [3, 4]] + * math.clone("hello world"); // returns string "hello world" + * + * @param {*} x Object to be cloned + * @return {*} A clone of object x + */ + var clone = typed('clone', { + 'any': object.clone + }); - 'Complex': function (x) { - return x.mul(x).mul(x); // Is faster than pow(x, 3) - }, + clone.toTex = undefined; // use default template - 'BigNumber': function (x) { - return x.times(x).times(x); - }, + return clone; + } - 'Fraction': function (x) { - return x.pow(3); // Is faster than mul()mul()mul() - }, + var name$100 = 'clone'; + var factory_1$110 = factory$111; - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since cube(0) = 0 - return deepMap(x, cube, true); - }, + var clone$5 = { + name: name$100, + factory: factory_1$110 + }; - 'Unit': function(x) { - return x.pow(3); - } - }); + function factory$112 (type, config, load, typed) { + /** + * Test whether a value is positive: larger than zero. + * The function supports types `number`, `BigNumber`, `Fraction`, and `Unit`. + * + * The function is evaluated element-wise in case of Array or Matrix input. + * + * Syntax: + * + * math.isPositive(x) + * + * Examples: + * + * math.isPositive(3); // returns true + * math.isPositive(-2); // returns false + * math.isPositive(0); // returns false + * math.isPositive(-0); // returns false + * math.isPositive(0.5); // returns true + * math.isPositive(math.bignumber(2)); // returns true + * math.isPositive(math.fraction(-2, 5)); // returns false + * math.isPositive(math.fraction(1,3)); // returns false + * math.isPositive('2'); // returns true + * math.isPositive([2, 0, -3]'); // returns [true, false, false] + * + * See also: + * + * isNumeric, isZero, isNegative, isInteger + * + * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested + * @return {boolean} Returns true when `x` is larger than zero. + * Throws an error in case of an unknown data type. + */ + var isPositive = typed('isPositive', { + 'number': function (x) { + return x > 0; + }, - cube.toTex = {1: '\\left(${args[0]}\\right)^3'}; + 'BigNumber': function (x) { + return !x.isNeg() && !x.isZero() && !x.isNaN(); + }, - return cube; -} + 'Fraction': function (x) { + return x.s > 0 && x.n > 0; + }, -var name$134 = 'cube'; -var factory_1$145 = factory$146; + 'Unit': function (x) { + return isPositive(x.value); + }, -var cube$1 = { - name: name$134, - factory: factory_1$145 -}; + 'Array | Matrix': function (x) { + return deepMap(x, isPositive); + } + }); -function factory$147 (type, config, load, typed) { + return isPositive; + } - var equalScalar$$1 = load(equalScalar); + var name$101 = 'isPositive'; + var factory_1$111 = factory$112; - var SparseMatrix = type.SparseMatrix; + var isPositive$1 = { + name: name$101, + factory: factory_1$111 + }; - /** - * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). - * Callback function invoked NNZ times (number of nonzero items in SparseMatrix). - * - * - * ┌ f(Dij, Sij) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} denseMatrix The DenseMatrix instance (D) - * @param {Matrix} sparseMatrix The SparseMatrix instance (S) - * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) - * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 - */ - var algorithm02 = function (denseMatrix, sparseMatrix, callback, inverse) { - // dense matrix arrays - var adata = denseMatrix._data; - var asize = denseMatrix._size; - var adt = denseMatrix._datatype; - // sparse matrix arrays - var bvalues = sparseMatrix._values; - var bindex = sparseMatrix._index; - var bptr = sparseMatrix._ptr; - var bsize = sparseMatrix._size; - var bdt = sparseMatrix._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // sparse matrix cannot be a Pattern matrix - if (!bvalues) - throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result (SparseMatrix) - var cvalues = []; - var cindex = []; - var cptr = []; - - // loop columns in b - for (var j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // values in column j - for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - var i = bindex[k]; - // update C(i,j) - var cij = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); - // check for nonzero - if (!eq(cij, zero)) { - // push i & v - cindex.push(i); - cvalues.push(cij); - } - } - } - // update cptr - cptr[columns] = cindex.length; + var nearlyEqual$4 = number.nearlyEqual; - // return sparse matrix - return new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - }; - - return algorithm02; -} -var name$135 = 'algorithm02'; -var factory_1$146 = factory$147; + function factory$113 (type, config, load, typed) { -var algorithm02 = { - name: name$135, - factory: factory_1$146 -}; + var matrix$$1 = load(matrix); -function factory$148 (type, config, load, typed) { + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - var matrix$$1 = load(matrix); - var divideScalar$$1 = load(divideScalar); - var latex$$1 = latex; - - var algorithm02$$1 = load(algorithm02); - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + var latex$$1 = latex; - /** - * Divide two matrices element wise. The function accepts both matrices and - * scalar values. - * - * Syntax: - * - * math.dotDivide(x, y) - * - * Examples: - * - * math.dotDivide(2, 4); // returns 0.5 - * - * a = [[9, 5], [6, 1]]; - * b = [[3, 2], [5, 2]]; - * - * math.dotDivide(a, b); // returns [[3, 2.5], [1.2, 0.5]] - * math.divide(a, b); // returns [[1.75, 0.75], [-1.75, 2.25]] - * - * See also: - * - * divide, multiply, dotMultiply - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Numerator - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Denominator - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Quotient, `x ./ y` - */ - var dotDivide = typed('dotDivide', { - - 'any, any': divideScalar$$1, + /** + * Test whether two values are unequal. + * + * The function tests whether the relative difference between x and y is + * larger than the configured epsilon. The function cannot be used to compare + * values smaller than approximately 2.22e-16. + * + * For matrices, the function is evaluated element wise. + * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im. + * Strings are compared by their numerical value. + * + * Values `null` and `undefined` are compared strictly, thus `null` is unequal + * with everything except `null`, and `undefined` is unequal with everything + * except `undefined`. + * + * Syntax: + * + * math.unequal(x, y) + * + * Examples: + * + * math.unequal(2 + 2, 3); // returns true + * math.unequal(2 + 2, 4); // returns false + * + * var a = math.unit('50 cm'); + * var b = math.unit('5 m'); + * math.unequal(a, b); // returns false + * + * var c = [2, 5, 1]; + * var d = [2, 7, 1]; + * + * math.unequal(c, d); // returns [false, true, false] + * math.deepEqual(c, d); // returns false + * + * math.unequal(0, null); // returns true + * See also: + * + * equal, deepEqual, smaller, smallerEq, larger, largerEq, compare + * + * @param {number | BigNumber | Fraction | boolean | Complex | Unit | string | Array | Matrix | undefined} x First value to compare + * @param {number | BigNumber | Fraction | boolean | Complex | Unit | string | Array | Matrix | undefined} y Second value to compare + * @return {boolean | Array | Matrix} Returns true when the compared values are unequal, else returns false + */ + var unequal = typed('unequal', { + + 'any, any': function (x, y) { + // strict equality for null and undefined? + if (x === null) { return y !== null; } + if (y === null) { return x !== null; } + if (x === undefined) { return y !== undefined; } + if (y === undefined) { return x !== undefined; } + + return _unequal(x, y); + }, - 'SparseMatrix, SparseMatrix': function (x, y) { - return algorithm07$$1(x, y, divideScalar$$1, false); - }, + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm07$$1(x, y, _unequal); + }, - 'SparseMatrix, DenseMatrix': function (x, y) { - return algorithm02$$1(y, x, divideScalar$$1, true); - }, + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, _unequal, true); + }, - 'DenseMatrix, SparseMatrix': function (x, y) { - return algorithm03$$1(x, y, divideScalar$$1, false); - }, + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, _unequal, false); + }, - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, divideScalar$$1); - }, + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, _unequal); + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return dotDivide(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'Array, Array': function (x, y) { + // use matrix implementation + return unequal(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - 'Array, Matrix': function (x, y) { - // use matrix implementation - return dotDivide(matrix$$1(x), y); - }, + 'Array, Matrix': function (x, y) { + // use matrix implementation + return unequal(matrix$$1(x), y); + }, - 'Matrix, Array': function (x, y) { - // use matrix implementation - return dotDivide(x, matrix$$1(y)); - }, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return unequal(x, matrix$$1(y)); + }, - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, divideScalar$$1, false); - }, + 'SparseMatrix, any': function (x, y) { + return algorithm12$$1(x, y, _unequal, false); + }, - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, divideScalar$$1, false); - }, + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, _unequal, false); + }, - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, divideScalar$$1, true); - }, + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, _unequal, true); + }, - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, divideScalar$$1, true); - }, + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, _unequal, true); + }, - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, divideScalar$$1, false).valueOf(); - }, + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, _unequal, false).valueOf(); + }, - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, divideScalar$$1, true).valueOf(); - } - }); + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, _unequal, true).valueOf(); + } + }); - dotDivide.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['dotDivide'] + '${args[1]}\\right)' - }; - - return dotDivide; -} + var _unequal = typed('_unequal', { -var name$136 = 'dotDivide'; -var factory_1$147 = factory$148; + 'boolean, boolean': function (x, y) { + return x !== y; + }, -var dotDivide$1 = { - name: name$136, - factory: factory_1$147 -}; + 'number, number': function (x, y) { + return !nearlyEqual$4(x, y, config.epsilon); + }, -function factory$149 (type, config, load, typed) { + 'BigNumber, BigNumber': function (x, y) { + return !nearlyEqual(x, y, config.epsilon); + }, - var equalScalar$$1 = load(equalScalar); + 'Fraction, Fraction': function (x, y) { + return !x.equals(y); + }, - var SparseMatrix = type.SparseMatrix; + 'Complex, Complex': function (x, y) { + return !x.equals(y); + }, - /** - * Iterates over SparseMatrix A and invokes the callback function f(Aij, Bij). - * Callback function invoked NZA times, number of nonzero elements in A. - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm09 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = avalues && bvalues ? [] : undefined; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt + 'Unit, Unit': function (x, y) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return unequal(x.value, y.value); + } }); - // workspaces - var x = cvalues ? [] : undefined; - // marks indicating we have a value in x for a given column - var w = []; + unequal.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['unequal'] + '${args[1]}\\right)' + }; - // vars - var i, j, k, k0, k1; - - // loop columns - for (j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // column mark - var mark = j + 1; - // check we need to process values - if (x) { - // loop B(:,j) - for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - i = bindex[k]; - // update workspace - w[i] = mark; - x[i] = bvalues[k]; - } - } - // loop A(:,j) - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // check we need to process values - if (x) { - // b value @ i,j - var vb = w[i] === mark ? x[i] : zero; - // invoke f - var vc = cf(avalues[k], vb); - // check zero value - if (!eq(vc, zero)) { - // push index - cindex.push(i); - // push value - cvalues.push(vc); - } - } - else { - // push index - cindex.push(i); - } - } - } - // update cptr - cptr[columns] = cindex.length; + return unequal; + } - // return sparse matrix - return c; + var name$102 = 'unequal'; + var factory_1$112 = factory$113; + + var unequal$1 = { + name: name$102, + factory: factory_1$112 }; - return algorithm09; -} + function factory$114 (type, config, load, typed) { + /** + * Compute the sign of a value. The sign of a value x is: + * + * - 1 when x > 1 + * - -1 when x < 0 + * - 0 when x == 0 + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.sign(x) + * + * Examples: + * + * math.sign(3.5); // returns 1 + * math.sign(-4.2); // returns -1 + * math.sign(0); // returns 0 + * + * math.sign([3, 5, -2, 0, 2]); // returns [1, 1, -1, 0, 1] + * + * See also: + * + * abs + * + * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x + * The number for which to determine the sign + * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit}e + * The sign of `x` + */ + var sign = typed('sign', { + 'number': number.sign, -var name$137 = 'algorithm09'; -var factory_1$148 = factory$149; + 'Complex': function (x) { + return x.sign(); + }, -var algorithm09 = { - name: name$137, - factory: factory_1$148 -}; + 'BigNumber': function (x) { + return new type.BigNumber(x.cmp(0)); + }, -function factory$150 (type, config, load, typed) { + 'Fraction': function (x) { + return new type.Fraction(x.s, 1); + }, - var matrix$$1 = load(matrix); - var multiplyScalar$$1 = load(multiplyScalar); - var latex$$1 = latex; + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since sign(0) = 0 + return deepMap(x, sign, true); + }, - var algorithm02$$1 = load(algorithm02); - var algorithm09$$1 = load(algorithm09); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + 'Unit': function(x) { + return sign(x.value); + } + }); - /** - * Multiply two matrices element wise. The function accepts both matrices and - * scalar values. - * - * Syntax: - * - * math.dotMultiply(x, y) - * - * Examples: - * - * math.dotMultiply(2, 4); // returns 8 - * - * a = [[9, 5], [6, 1]]; - * b = [[3, 2], [5, 2]]; - * - * math.dotMultiply(a, b); // returns [[27, 10], [30, 2]] - * math.multiply(a, b); // returns [[52, 28], [23, 14]] - * - * See also: - * - * multiply, divide, dotDivide - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Left hand value - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Right hand value - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` - */ - var dotMultiply = typed('dotMultiply', { - - 'any, any': multiplyScalar$$1, + sign.toTex = {1: '\\mathrm{${name}}\\left(${args[0]}\\right)'}; - 'SparseMatrix, SparseMatrix': function (x, y) { - return algorithm09$$1(x, y, multiplyScalar$$1, false); - }, + return sign; + } - 'SparseMatrix, DenseMatrix': function (x, y) { - return algorithm02$$1(y, x, multiplyScalar$$1, true); - }, + var name$103 = 'sign'; + var factory_1$113 = factory$114; - 'DenseMatrix, SparseMatrix': function (x, y) { - return algorithm02$$1(x, y, multiplyScalar$$1, false); - }, + var sign$1 = { + name: name$103, + factory: factory_1$113 + }; - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, multiplyScalar$$1); - }, + function factory$115 (type, config, load, typed) { + /** + * Calculate the square root of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.sqrt(x) + * + * Examples: + * + * math.sqrt(25); // returns 5 + * math.square(5); // returns 25 + * math.sqrt(-4); // returns Complex 2i + * + * See also: + * + * square, multiply, cube, cbrt, sqrtm + * + * @param {number | BigNumber | Complex | Array | Matrix | Unit} x + * Value for which to calculate the square root. + * @return {number | BigNumber | Complex | Array | Matrix | Unit} + * Returns the square root of `x` + */ + var sqrt = typed('sqrt', { + 'number': _sqrtNumber, - 'Array, Array': function (x, y) { - // use matrix implementation - return dotMultiply(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return dotMultiply(matrix$$1(x), y); - }, + 'Complex': function (x) { + return x.sqrt(); + }, - 'Matrix, Array': function (x, y) { - // use matrix implementation - return dotMultiply(x, matrix$$1(y)); - }, + 'BigNumber': function (x) { + if (!x.isNegative() || config.predictable) { + return x.sqrt(); + } + else { + // negative value -> downgrade to number to do complex value computation + return _sqrtNumber(x.toNumber()); + } + }, - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, multiplyScalar$$1, false); - }, + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since sqrt(0) = 0 + return deepMap(x, sqrt, true); + }, - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, multiplyScalar$$1, false); - }, + 'Unit': function (x) { + // Someday will work for complex units when they are implemented + return x.pow(0.5); + } - 'any, SparseMatrix': function (x, y) { - return algorithm11$$1(y, x, multiplyScalar$$1, true); - }, + }); - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, multiplyScalar$$1, true); - }, + /** + * Calculate sqrt for a number + * @param {number} x + * @returns {number | Complex} Returns the square root of x + * @private + */ + function _sqrtNumber(x) { + if (x >= 0 || config.predictable) { + return Math.sqrt(x); + } + else { + return new type.Complex(x, 0).sqrt(); + } + } - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, multiplyScalar$$1, false).valueOf(); - }, + sqrt.toTex = {1: '\\sqrt{${args[0]}}'}; - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, multiplyScalar$$1, true).valueOf(); - } - }); + return sqrt; + } + + var name$104 = 'sqrt'; + var factory_1$114 = factory$115; - dotMultiply.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['dotMultiply'] + '${args[1]}\\right)' + var sqrt$1 = { + name: name$104, + factory: factory_1$114 }; - - return dotMultiply; -} -var name$138 = 'dotMultiply'; -var factory_1$149 = factory$150; + function factory$116 (type, config, load, typed) { + /** + * Compute the complex conjugate of a complex value. + * If `x = a+bi`, the complex conjugate of `x` is `a - bi`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.conj(x) + * + * Examples: + * + * math.conj(math.complex('2 + 3i')); // returns Complex 2 - 3i + * math.conj(math.complex('2 - 3i')); // returns Complex 2 + 3i + * math.conj(math.complex('-5.2i')); // returns Complex 5.2i + * + * See also: + * + * re, im, arg, abs + * + * @param {number | BigNumber | Complex | Array | Matrix} x + * A complex number or array with complex numbers + * @return {number | BigNumber | Complex | Array | Matrix} + * The complex conjugate of x + */ + var conj = typed('conj', { + 'number': function (x) { + return x; + }, + + 'BigNumber': function (x) { + return x; + }, -var dotMultiply$1 = { - name: name$138, - factory: factory_1$149 -}; + 'Complex': function (x) { + return x.conjugate(); + }, -function factory$151 (type, config, load, typed) { + 'Array | Matrix': function (x) { + return deepMap(x, conj); + } + }); - var matrix$$1 = load(matrix); - var pow = load(pow$1); - var latex$$1 = latex; + conj.toTex = {1: '\\left(${args[0]}\\right)^*'}; - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + return conj; + } - /** - * Calculates the power of x to y element wise. - * - * Syntax: - * - * math.dotPow(x, y) - * - * Examples: - * - * math.dotPow(2, 3); // returns number 8 - * - * var a = [[1, 2], [4, 3]]; - * math.dotPow(a, 2); // returns Array [[1, 4], [16, 9]] - * math.pow(a, 2); // returns Array [[9, 8], [16, 17]] - * - * See also: - * - * pow, sqrt, multiply - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x The base - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y The exponent - * @return {number | BigNumber | Complex | Unit | Array | Matrix} The value of `x` to the power `y` - */ - var dotPow = typed('dotPow', { - - 'any, any': pow, + var name$105 = 'conj'; + var factory_1$115 = factory$116; - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, pow, false); - }, + var conj$1 = { + name: name$105, + factory: factory_1$115 + }; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, pow, true); - }, + function factory$117 (type, config, load, typed) { - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, pow, false); - }, + var matrix$$1 = load(matrix); + var zeros = load(zeros$1); + var eye = load(eye$1); + var clone = load(clone$5); + + var isZero = load(isZero$1); + var isPositive = load(isPositive$1); + var unequal = load(unequal$1); + + var abs = load(abs$1); + var sign = load(sign$1); + var sqrt = load(sqrt$1); + var conj = load(conj$1); + + var unaryMinus = load(unaryMinus$1); + var addScalar$$1 = load(addScalar); + var divideScalar$$1 = load(divideScalar); + var multiplyScalar$$1 = load(multiplyScalar); + var subtract = load(subtract$1); + + + /** + * Calculate the Matrix QR decomposition. Matrix `A` is decomposed in + * two matrices (`Q`, `R`) where `Q` is an + * orthogonal matrix and `R` is an upper triangular matrix. + * + * Syntax: + * + * math.qr(A); + * + * Example: + * + * var m = [ + * [1, -1, 4], + * [1, 4, -2], + * [1, 4, 2], + * [1, -1, 0] + * ]; + * var result = math.qr(m); + * // r = { + * // Q: [ + * // [0.5, -0.5, 0.5], + * // [0.5, 0.5, -0.5], + * // [0.5, 0.5, 0.5], + * // [0.5, -0.5, -0.5], + * // ], + * // R: [ + * // [2, 3, 2], + * // [0, 5, -2], + * // [0, 0, 4], + * // [0, 0, 0] + * // ] + * // } + * + * See also: + * + * lu + * + * @param {Matrix | Array} A A two dimensional matrix or array + * for which to get the QR decomposition. + * + * @return {{Q: Array | Matrix, R: Array | Matrix}} Q: the orthogonal + * matrix and R: the upper triangular matrix + */ + var qr = typed('qr', { - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, pow); - }, + 'DenseMatrix': function (m) { + return _denseQR(m); + }, + + 'SparseMatrix': function (m) { + return _sparseQR(m); + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return dotPow(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'Array': function (a) { + // create dense matrix from array + var m = matrix$$1(a); + // lup, use matrix implementation + var r = _denseQR(m); + // result + return { + Q: r.Q.valueOf(), + R: r.R.valueOf() + }; + } + }); - 'Array, Matrix': function (x, y) { - // use matrix implementation - return dotPow(matrix$$1(x), y); - }, + var _denseQR = function (m) { + + // rows & columns (m x n) + var rows = m._size[0]; // m + var cols = m._size[1]; // n + + var Q = eye([rows], 'dense'); + var Qdata = Q._data; + + var R = m.clone(); + var Rdata = R._data; + + // vars + var i, j, k; + + var w = zeros([rows], ''); + + for (k = 0; k < Math.min(cols, rows); ++k) { + + /* + * **k-th Household matrix** + * + * The matrix I - 2*v*transpose(v) + * x = first column of A + * x1 = first element of x + * alpha = x1 / |x1| * |x| + * e1 = tranpose([1, 0, 0, ...]) + * u = x - alpha * e1 + * v = u / |u| + * + * Household matrix = I - 2 * v * tranpose(v) + * + * * Initially Q = I and R = A. + * * Household matrix is a reflection in a plane normal to v which + * will zero out all but the top right element in R. + * * Appplying reflection to both Q and R will not change product. + * * Repeat this process on the (1,1) minor to get R as an upper + * triangular matrix. + * * Reflections leave the magnitude of the columns of Q unchanged + * so Q remains othoganal. + * + */ + + var pivot = Rdata[k][k]; + var sgn = unaryMinus(sign(pivot)); + var conjSgn = conj(sgn); + + var alphaSquared = 0; - 'Matrix, Array': function (x, y) { - // use matrix implementation - return dotPow(x, matrix$$1(y)); - }, + for(i = k; i < rows; i++) { + alphaSquared = addScalar$$1(alphaSquared, multiplyScalar$$1(Rdata[i][k], conj(Rdata[i][k]))); + } + + var alpha = multiplyScalar$$1(sgn, sqrt(alphaSquared)); + + + if (!isZero(alpha)) { + + // first element in vector u + var u1 = subtract(pivot, alpha); + + // w = v * u1 / |u| (only elements k to (rows-1) are used) + w[k] = 1; + + for (i = k+1; i < rows; i++) { + w[i] = divideScalar$$1(Rdata[i][k], u1); + } + + // tau = - conj(u1 / alpha) + var tau = unaryMinus(conj(divideScalar$$1(u1, alpha))); + + var s; + + /* + * tau and w have been choosen so that + * + * 2 * v * tranpose(v) = tau * w * tranpose(w) + */ + + /* + * -- calculate R = R - tau * w * tranpose(w) * R -- + * Only do calculation with rows k to (rows-1) + * Additionally columns 0 to (k-1) will not be changed by this + * multiplication so do not bother recalculating them + */ + for (j = k; j < cols; j++) { + s = 0.0; + + // calculate jth element of [tranpose(w) * R] + for (i = k; i < rows; i++) { + s = addScalar$$1(s, multiplyScalar$$1(conj(w[i]), Rdata[i][j])); + } + + // calculate the jth element of [tau * transpose(w) * R] + s = multiplyScalar$$1(s, tau); + + for (i = k; i < rows; i++) { + Rdata[i][j] = multiplyScalar$$1( + subtract(Rdata[i][j], multiplyScalar$$1(w[i], s)), + conjSgn + ); + } + } + /* + * -- calculate Q = Q - tau * Q * w * transpose(w) -- + * Q is a square matrix (rows x rows) + * Only do calculation with columns k to (rows-1) + * Additionally rows 0 to (k-1) will not be changed by this + * multiplication so do not bother recalculating them + */ + for (i = 0; i < rows; i++) { + s = 0.0; + + // calculate ith element of [Q * w] + for (j = k; j < rows; j++) { + s = addScalar$$1(s, multiplyScalar$$1(Qdata[i][j], w[j])); + } + + // calculate the ith element of [tau * Q * w] + s = multiplyScalar$$1(s, tau); + + for (j = k; j < rows; ++j) { + Qdata[i][j] = divideScalar$$1( + subtract(Qdata[i][j], multiplyScalar$$1(s, conj(w[j]))), + conjSgn + ); + } + + } + } + + } + + // coerse almost zero elements to zero + // TODO I feel uneasy just zeroing these values + for (i = 0; i < rows; ++i) { + for (j = 0; j < i && j < cols; ++j) { + if (unequal(0, divideScalar$$1(Rdata[i][j], 1e5))) { + throw new Error('math.qr(): unknown error - ' + + 'R is not lower triangular (element (' + + i + ', ' + j + ') = ' + Rdata[i][j] + ')' + ); + } + Rdata[i][j] = multiplyScalar$$1(Rdata[i][j], 0); + } + } + + // return matrices + return { + Q: Q, + R: R, + toString: function () { + return 'Q: ' + this.Q.toString() + '\nR: ' + this.R.toString(); + } + }; + }; + + var _sparseQR = function (m) { + + throw new Error('qr not implemented for sparse matrices yet'); + + }; + + return qr; + } - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, dotPow, false); - }, + var name$106 = 'qr'; + var factory_1$116 = factory$117; - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, dotPow, false); - }, + var qr$1 = { + name: name$106, + factory: factory_1$116 + }; - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, dotPow, true); - }, + function factory$118 () { - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, dotPow, true); - }, + /** + * This function "flips" its input about the integer -1. + * + * @param {Number} i The value to flip + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_flip = function (i) { + // flip the value + return -i - 2; + }; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, dotPow, false).valueOf(); - }, + return cs_flip; + } - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, dotPow, true).valueOf(); - } - }); + var name$107 = 'cs_flip'; + var path$46 = 'sparse'; + var factory_1$117 = factory$118; - dotPow.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['dotPow'] + '${args[1]}\\right)' + var cs_flip = { + name: name$107, + path: path$46, + factory: factory_1$117 }; - - return dotPow; -} -var name$139 = 'dotPow'; -var factory_1$150 = factory$151; + function factory$119 () { -var dotPow$1 = { - name: name$139, - factory: factory_1$150 -}; - -function factory$152 (type, config, load, typed) { - /** - * Calculate the exponent of a value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.exp(x) - * - * Examples: - * - * math.exp(2); // returns number 7.3890560989306495 - * math.pow(math.e, 2); // returns number 7.3890560989306495 - * math.log(math.exp(2)); // returns number 2 - * - * math.exp([1, 2, 3]); - * // returns Array [ - * // 2.718281828459045, - * // 7.3890560989306495, - * // 20.085536923187668 - * // ] - * - * See also: - * - * expm1, log, pow - * - * @param {number | BigNumber | Complex | Array | Matrix} x A number or matrix to exponentiate - * @return {number | BigNumber | Complex | Array | Matrix} Exponent of `x` - */ - var exp = typed('exp', { - 'number': Math.exp, - - 'Complex': function (x) { - return x.exp(); - }, - - 'BigNumber': function (x) { - return x.exp(); - }, - - 'Array | Matrix': function (x) { - // TODO: exp(sparse) should return a dense matrix since exp(0)==1 - return deepMap(x, exp); - } - }); + /** + * Keeps entries in the matrix when the callback function returns true, removes the entry otherwise + * + * @param {Matrix} a The sparse matrix + * @param {function} callback The callback function, function will be invoked with the following args: + * - The entry row + * - The entry column + * - The entry value + * - The state parameter + * @param {any} other The state + * + * @return The number of nonzero elements in the matrix + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_fkeep = function (a, callback, other) { + // a arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + // columns + var n = asize[1]; + // nonzero items + var nz = 0; + // loop columns + for (var j = 0; j < n; j++) { + // get current location of col j + var p = aptr[j]; + // record new location of col j + aptr[j] = nz; + for (; p < aptr[j+1]; p++) { + // check we need to keep this item + if (callback(aindex[p], j, avalues ? avalues[p] : 1, other)) { + // keep A(i,j) + aindex[nz] = aindex[p]; + // check we need to process values (pattern only) + if (avalues) + avalues[nz] = avalues[p]; + // increment nonzero items + nz++; + } + } + } + // finalize A + aptr[n] = nz; + // trim arrays + aindex.splice(nz, aindex.length - nz); + // check we need to process values (pattern only) + if (avalues) + avalues.splice(nz, avalues.length - nz); + // return number of nonzero items + return (nz); + }; + + return cs_fkeep; + } - exp.toTex = {1: '\\exp\\left(${args[0]}\\right)'}; + var name$108 = 'cs_fkeep'; + var path$47 = 'sparse'; + var factory_1$118 = factory$119; - return exp; -} + var cs_fkeep = { + name: name$108, + path: path$47, + factory: factory_1$118 + }; -var name$140 = 'exp'; -var factory_1$151 = factory$152; + function factory$120 () { -var exp$1 = { - name: name$140, - factory: factory_1$151 -}; + /** + * Depth-first search and postorder of a tree rooted at node j + * + * @param {Number} j The tree node + * @param {Number} k + * @param {Array} w The workspace array + * @param {Number} head The index offset within the workspace for the head array + * @param {Number} next The index offset within the workspace for the next array + * @param {Array} post The post ordering array + * @param {Number} stack The index offset within the workspace for the stack array + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_tdfs = function (j, k, w, head, next, post, stack) { + // variables + var top = 0; + // place j on the stack + w[stack] = j; + // while (stack is not empty) + while (top >= 0) { + // p = top of stack + var p = w[stack + top]; + // i = youngest child of p + var i = w[head + p]; + if (i == -1) { + // p has no unordered children left + top--; + // node p is the kth postordered node + post[k++] = p; + } + else { + // remove i from children of p + w[head + p] = w[next + i]; + // increment top + ++top; + // start dfs on child node i + w[stack + top] = i; + } + } + return k; + }; -function factory$153 (type, config, load, typed) { - var latex$$1 = latex; + return cs_tdfs; + } - /** - * Calculate the value of subtracting 1 from the exponential value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.expm1(x) - * - * Examples: - * - * math.expm1(2); // returns number 6.38905609893065 - * math.pow(math.e, 2) - 1; // returns number 6.3890560989306495 - * math.log(math.expm1(2) + 1); // returns number 2 - * - * math.expm1([1, 2, 3]); - * // returns Array [ - * // 1.718281828459045, - * // 6.3890560989306495, - * // 19.085536923187668 - * // ] - * - * See also: - * - * exp, log, pow - * - * @param {number | BigNumber | Complex | Array | Matrix} x A number or matrix to apply expm1 - * @return {number | BigNumber | Complex | Array | Matrix} Exponent of `x` - */ - var expm1 = typed('expm1', { - 'number': Math.expm1 || _expm1, - - 'Complex': function (x) { - var r = Math.exp(x.re); - return new type.Complex( - r * Math.cos(x.im) - 1, - r * Math.sin(x.im) - ); - }, + var name$109 = 'cs_tdfs'; + var path$48 = 'sparse'; + var factory_1$119 = factory$120; - 'BigNumber': function (x) { - return x.exp().minus(1); - }, + var cs_tdfs = { + name: name$109, + path: path$48, + factory: factory_1$119 + }; - 'Array | Matrix': function (x) { - return deepMap(x, expm1); - } - }); + var clone$6 = object.clone; + var format$4 = string.format; - /** - * Calculates exponentiation minus 1. - * @param {number} x - * @return {number} res - * @private - */ - function _expm1(x) { - return (x >= 2e-4 || x <= -2e-4) - ? Math.exp(x) - 1 - : x + x*x/2 + x*x*x/6; - } + function factory$121 (type, config, load, typed) { + var latex$$1 = latex; - expm1.toTex = '\\left(e' + latex$$1.operators['pow'] + '{${args[0]}}-1\\right)'; + var matrix$$1 = load(matrix); - return expm1; -} + var DenseMatrix = type.DenseMatrix, + SparseMatrix = type.SparseMatrix; -var name$141 = 'expm1'; -var factory_1$152 = factory$153; + /** + * Transpose a matrix. All values of the matrix are reflected over its + * main diagonal. Only applicable to two dimensional matrices containing + * a vector (i.e. having size `[1,n]` or `[n,1]`). One dimensional + * vectors and scalars return the input unchanged. + * + * Syntax: + * + * math.transpose(x) + * + * Examples: + * + * var A = [[1, 2, 3], [4, 5, 6]]; + * math.transpose(A); // returns [[1, 4], [2, 5], [3, 6]] + * + * See also: + * + * diag, inv, subset, squeeze + * + * @param {Array | Matrix} x Matrix to be transposed + * @return {Array | Matrix} The transposed matrix + */ + var transpose = typed('transpose', { -var expm1$1 = { - name: name$141, - factory: factory_1$152 -}; + 'Array': function (x) { + // use dense matrix implementation + return transpose(matrix$$1(x)).valueOf(); + }, -function factory$154 (type, config, load, typed) { - /** - * Round a value towards zero. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.fix(x) - * - * Examples: - * - * math.fix(3.2); // returns number 3 - * math.fix(3.8); // returns number 3 - * math.fix(-4.2); // returns number -4 - * math.fix(-4.7); // returns number -4 - * - * var c = math.complex(3.2, -2.7); - * math.fix(c); // returns Complex 3 - 2i - * - * math.fix([3.2, 3.8, -4.7]); // returns Array [3, 3, -4] - * - * See also: - * - * ceil, floor, round - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded - * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value - */ - var fix = typed('fix', { - 'number': function (x) { - return (x > 0) ? Math.floor(x) : Math.ceil(x); - }, + 'Matrix': function (x) { + // matrix size + var size = x.size(); - 'Complex': function (x) { - return new type.Complex( - (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re), - (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im) - ); - }, + // result + var c; + + // process dimensions + switch (size.length) { + case 1: + // vector + c = x.clone(); + break; - 'BigNumber': function (x) { - return x.isNegative() ? x.ceil() : x.floor(); - }, + case 2: + // rows and columns + var rows = size[0]; + var columns = size[1]; + + // check columns + if (columns === 0) { + // throw exception + throw new RangeError('Cannot transpose a 2D matrix with no columns (size: ' + format$4(size) + ')'); + } - 'Fraction': function (x) { - return x.s < 0 ? x.ceil() : x.floor(); - }, + // process storage format + switch (x.storage()) { + case 'dense': + c = _denseTranspose(x, rows, columns); + break; + case 'sparse': + c = _sparseTranspose(x, rows, columns); + break; + } + break; + + default: + // multi dimensional + throw new RangeError('Matrix must be a vector or two dimensional (size: ' + format$4(this._size) + ')'); + } + return c; + }, - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since fix(0) = 0 - return deepMap(x, fix, true); - } - }); + // scalars + 'any': function (x) { + return clone$6(x); + } + }); - fix.toTex = {1: '\\mathrm{${name}}\\left(${args[0]}\\right)'}; + var _denseTranspose = function (m, rows, columns) { + // matrix array + var data = m._data; + // transposed matrix data + var transposed = []; + var transposedRow; + // loop columns + for (var j = 0; j < columns; j++) { + // initialize row + transposedRow = transposed[j] = []; + // loop rows + for (var i = 0; i < rows; i++) { + // set data + transposedRow[i] = clone$6(data[i][j]); + } + } + // return matrix + return new DenseMatrix({ + data: transposed, + size: [columns, rows], + datatype: m._datatype + }); + }; - return fix; -} + var _sparseTranspose = function (m, rows, columns) { + // matrix arrays + var values = m._values; + var index = m._index; + var ptr = m._ptr; + // result matrices + var cvalues = values ? [] : undefined; + var cindex = []; + var cptr = []; + // row counts + var w = []; + for (var x = 0; x < rows; x++) + w[x] = 0; + // vars + var p, l, j; + // loop values in matrix + for (p = 0, l = index.length; p < l; p++) { + // number of values in row + w[index[p]]++; + } + // cumulative sum + var sum = 0; + // initialize cptr with the cummulative sum of row counts + for (var i = 0; i < rows; i++) { + // update cptr + cptr.push(sum); + // update sum + sum += w[i]; + // update w + w[i] = cptr[i]; + } + // update cptr + cptr.push(sum); + // loop columns + for (j = 0; j < columns; j++) { + // values & index in column + for (var k0 = ptr[j], k1 = ptr[j + 1], k = k0; k < k1; k++) { + // C values & index + var q = w[index[k]]++; + // C[j, i] = A[i, j] + cindex[q] = j; + // check we need to process values (pattern matrix) + if (values) + cvalues[q] = clone$6(values[k]); + } + } + // return matrix + return new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [columns, rows], + datatype: m._datatype + }); + }; -var name$142 = 'fix'; -var factory_1$153 = factory$154; + transpose.toTex = {1: '\\left(${args[0]}\\right)' + latex$$1.operators['transpose']}; -var fix$1 = { - name: name$142, - factory: factory_1$153 -}; + return transpose; + } -function factory$155 (type, config, load, typed) { - /** - * Round a value towards minus infinity. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.floor(x) - * - * Examples: - * - * math.floor(3.2); // returns number 3 - * math.floor(3.8); // returns number 3 - * math.floor(-4.2); // returns number -5 - * math.floor(-4.7); // returns number -5 - * - * var c = math.complex(3.2, -2.7); - * math.floor(c); // returns Complex 3 - 3i - * - * math.floor([3.2, 3.8, -4.7]); // returns Array [3, 3, -5] - * - * See also: - * - * ceil, fix, round - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded - * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value - */ - var floor = typed('floor', { - 'number': Math.floor, + var name$110 = 'transpose'; + var factory_1$120 = factory$121; - 'Complex': function (x) { - return x.floor(); - }, + var transpose$1 = { + name: name$110, + factory: factory_1$120 + }; - 'BigNumber': function (x) { - return x.floor(); - }, + function factory$122 (type, config, load) { - 'Fraction': function (x) { - return x.floor(); - }, + var cs_flip$$1 = load(cs_flip); + var cs_fkeep$$1 = load(cs_fkeep); + var cs_tdfs$$1 = load(cs_tdfs); + + var add$$1 = load(add); + var multiply = load(multiply$1); + var transpose = load(transpose$1); - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since floor(0) = 0 - return deepMap(x, floor, true); - } - }); + /** + * Approximate minimum degree ordering. The minimum degree algorithm is a widely used + * heuristic for finding a permutation P so that P*A*P' has fewer nonzeros in its factorization + * than A. It is a gready method that selects the sparsest pivot row and column during the course + * of a right looking sparse Cholesky factorization. + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + * + * @param {Number} order 0: Natural, 1: Cholesky, 2: LU, 3: QR + * @param {Matrix} m Sparse Matrix + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_amd = function (order, a) { + // check input parameters + if (!a || order <= 0 || order > 3) + return null; + // a matrix arrays + var asize = a._size; + // rows and columns + var m = asize[0]; + var n = asize[1]; + // initialize vars + var lemax = 0; + // dense threshold + var dense = Math.max(16, 10 * Math.sqrt(n)); + dense = Math.min(n - 2, dense); + // create target matrix C + var cm = _createTargetMatrix(order, a, m, n, dense); + // drop diagonal entries + cs_fkeep$$1(cm, _diag, null); + // C matrix arrays + var cindex = cm._index; + var cptr = cm._ptr; + + // number of nonzero elements in C + var cnz = cptr[n]; + + // allocate result (n+1) + var P = []; + + // create workspace (8 * (n + 1)) + var W = []; + var len = 0; // first n + 1 entries + var nv = n + 1; // next n + 1 entries + var next = 2 * (n + 1); // next n + 1 entries + var head = 3 * (n + 1); // next n + 1 entries + var elen = 4 * (n + 1); // next n + 1 entries + var degree = 5 * (n + 1); // next n + 1 entries + var w = 6 * (n + 1); // next n + 1 entries + var hhead = 7 * (n + 1); // last n + 1 entries + + // use P as workspace for last + var last = P; + + // initialize quotient graph + var mark = _initializeQuotientGraph(n, cptr, W, len, head, last, next, hhead, nv, w, elen, degree); + + // initialize degree lists + var nel = _initializeDegreeLists(n, cptr, W, degree, elen, w, dense, nv, head, last, next); + + // minimum degree node + var mindeg = 0; + + // vars + var i, j, k, k1, k2, e, pj, ln, nvi, pk, eln, p1, p2, pn, h, d; + + // while (selecting pivots) do + while (nel < n) { + // select node of minimum approximate degree. amd() is now ready to start eliminating the graph. It first + // finds a node k of minimum degree and removes it from its degree list. The variable nel keeps track of thow + // many nodes have been eliminated. + for (k = -1; mindeg < n && (k = W[head + mindeg]) == -1; mindeg++); + if (W[next + k] != -1) + last[W[next + k]] = -1; + // remove k from degree list + W[head + mindeg] = W[next + k]; + // elenk = |Ek| + var elenk = W[elen + k]; + // # of nodes k represents + var nvk = W[nv + k]; + // W[nv + k] nodes of A eliminated + nel += nvk; + + // Construct a new element. The new element Lk is constructed in place if |Ek| = 0. nv[i] is + // negated for all nodes i in Lk to flag them as members of this set. Each node i is removed from the + // degree lists. All elements e in Ek are absorved into element k. + var dk = 0; + // flag k as in Lk + W[nv + k] = -nvk; + var p = cptr[k]; + // do in place if W[elen + k] == 0 + var pk1 = (elenk === 0) ? p : cnz; + var pk2 = pk1; + for (k1 = 1; k1 <= elenk + 1; k1++) { + if (k1 > elenk) { + // search the nodes in k + e = k; + // list of nodes starts at cindex[pj] + pj = p; + // length of list of nodes in k + ln = W[len + k] - elenk; + } + else { + // search the nodes in e + e = cindex[p++]; + pj = cptr[e]; + // length of list of nodes in e + ln = W[len + e]; + } + for (k2 = 1; k2 <= ln; k2++) { + i = cindex[pj++]; + // check node i dead, or seen + if ((nvi = W[nv + i]) <= 0) + continue; + // W[degree + Lk] += size of node i + dk += nvi; + // negate W[nv + i] to denote i in Lk + W[nv + i] = -nvi; + // place i in Lk + cindex[pk2++] = i; + if (W[next + i] != -1) + last[W[next + i]] = last[i]; + // check we need to remove i from degree list + if (last[i] != -1) + W[next + last[i]] = W[next + i]; + else + W[head + W[degree + i]] = W[next + i]; + } + if (e != k) { + // absorb e into k + cptr[e] = cs_flip$$1(k); + // e is now a dead element + W[w + e] = 0; + } + } + // cindex[cnz...nzmax] is free + if (elenk !== 0) + cnz = pk2; + // external degree of k - |Lk\i| + W[degree + k] = dk; + // element k is in cindex[pk1..pk2-1] + cptr[k] = pk1; + W[len + k] = pk2 - pk1; + // k is now an element + W[elen + k] = -2; + + // Find set differences. The scan1 function now computes the set differences |Le \ Lk| for all elements e. At the start of the + // scan, no entry in the w array is greater than or equal to mark. + + // clear w if necessary + mark = _wclear(mark, lemax, W, w, n); + // scan 1: find |Le\Lk| + for (pk = pk1; pk < pk2; pk++) { + i = cindex[pk]; + // check if W[elen + i] empty, skip it + if ((eln = W[elen + i]) <= 0) + continue; + // W[nv + i] was negated + nvi = -W[nv + i]; + var wnvi = mark - nvi; + // scan Ei + for (p = cptr[i], p1 = cptr[i] + eln - 1; p <= p1; p++) { + e = cindex[p]; + if (W[w + e] >= mark) { + // decrement |Le\Lk| + W[w + e] -= nvi; + } + else if (W[w + e] !== 0) { + // ensure e is a live element, 1st time e seen in scan 1 + W[w + e] = W[degree + e] + wnvi; + } + } + } + + // degree update + // The second pass computes the approximate degree di, prunes the sets Ei and Ai, and computes a hash + // function h(i) for all nodes in Lk. + + // scan2: degree update + for (pk = pk1; pk < pk2; pk++) { + // consider node i in Lk + i = cindex[pk]; + p1 = cptr[i]; + p2 = p1 + W[elen + i] - 1; + pn = p1; + // scan Ei + for (h = 0, d = 0, p = p1; p <= p2; p++) { + e = cindex[p]; + // check e is an unabsorbed element + if (W[w + e] !== 0) { + // dext = |Le\Lk| + var dext = W[w + e] - mark; + if (dext > 0) { + // sum up the set differences + d += dext; + // keep e in Ei + cindex[pn++] = e; + // compute the hash of node i + h += e; + } + else { + // aggressive absorb. e->k + cptr[e] = cs_flip$$1(k); + // e is a dead element + W[w + e] = 0; + } + } + } + // W[elen + i] = |Ei| + W[elen + i] = pn - p1 + 1; + var p3 = pn; + var p4 = p1 + W[len + i]; + // prune edges in Ai + for (p = p2 + 1; p < p4; p++) { + j = cindex[p]; + // check node j dead or in Lk + var nvj = W[nv + j]; + if (nvj <= 0) + continue; + // degree(i) += |j| + d += nvj; + // place j in node list of i + cindex[pn++] = j; + // compute hash for node i + h += j; + } + // check for mass elimination + if (d === 0) { + // absorb i into k + cptr[i] = cs_flip$$1(k); + nvi = -W[nv + i]; + // |Lk| -= |i| + dk -= nvi; + // |k| += W[nv + i] + nvk += nvi; + nel += nvi; + W[nv + i] = 0; + // node i is dead + W[elen + i] = -1; + } + else { + // update degree(i) + W[degree + i] = Math.min(W[degree + i], d); + // move first node to end + cindex[pn] = cindex[p3]; + // move 1st el. to end of Ei + cindex[p3] = cindex[p1]; + // add k as 1st element in of Ei + cindex[p1] = k; + // new len of adj. list of node i + W[len + i] = pn - p1 + 1; + // finalize hash of i + h = (h < 0 ? -h : h) % n; + // place i in hash bucket + W[next + i] = W[hhead + h]; + W[hhead + h] = i; + // save hash of i in last[i] + last[i] = h; + } + } + // finalize |Lk| + W[degree + k] = dk; + lemax = Math.max(lemax, dk); + // clear w + mark = _wclear(mark + lemax, lemax, W, w, n); + + // Supernode detection. Supernode detection relies on the hash function h(i) computed for each node i. + // If two nodes have identical adjacency lists, their hash functions wil be identical. + for (pk = pk1; pk < pk2; pk++) { + i = cindex[pk]; + // check i is dead, skip it + if (W[nv + i] >= 0) + continue; + // scan hash bucket of node i + h = last[i]; + i = W[hhead + h]; + // hash bucket will be empty + W[hhead + h] = -1; + for (; i != -1 && W[next + i] != -1; i = W[next + i], mark++) { + ln = W[len + i]; + eln = W[elen + i]; + for (p = cptr[i] + 1; p <= cptr[i] + ln - 1; p++) + W[w + cindex[p]] = mark; + var jlast = i; + // compare i with all j + for (j = W[next + i]; j != -1; ) { + var ok = W[len + j] === ln && W[elen + j] === eln; + for (p = cptr[j] + 1; ok && p <= cptr[j] + ln - 1; p++) { + // compare i and j + if (W[w + cindex[p]] != mark) + ok = 0; + } + // check i and j are identical + if (ok) { + // absorb j into i + cptr[j] = cs_flip$$1(i); + W[nv + i] += W[nv + j]; + W[nv + j] = 0; + // node j is dead + W[elen + j] = -1; + // delete j from hash bucket + j = W[next + j]; + W[next + jlast] = j; + } + else { + // j and i are different + jlast = j; + j = W[next + j]; + } + } + } + } + + // Finalize new element. The elimination of node k is nearly complete. All nodes i in Lk are scanned one last time. + // Node i is removed from Lk if it is dead. The flagged status of nv[i] is cleared. + for (p = pk1, pk = pk1; pk < pk2; pk++) { + i = cindex[pk]; + // check i is dead, skip it + if ((nvi = -W[nv + i]) <= 0) + continue; + // restore W[nv + i] + W[nv + i] = nvi; + // compute external degree(i) + d = W[degree + i] + dk - nvi; + d = Math.min(d, n - nel - nvi); + if (W[head + d] != -1) + last[W[head + d]] = i; + // put i back in degree list + W[next + i] = W[head + d]; + last[i] = -1; + W[head + d] = i; + // find new minimum degree + mindeg = Math.min(mindeg, d); + W[degree + i] = d; + // place i in Lk + cindex[p++] = i; + } + // # nodes absorbed into k + W[nv + k] = nvk; + // length of adj list of element k + if ((W[len + k] = p - pk1) === 0) { + // k is a root of the tree + cptr[k] = -1; + // k is now a dead element + W[w + k] = 0; + } + if (elenk !== 0) { + // free unused space in Lk + cnz = p; + } + } + + // Postordering. The elimination is complete, but no permutation has been computed. All that is left + // of the graph is the assembly tree (ptr) and a set of dead nodes and elements (i is a dead node if + // nv[i] is zero and a dead element if nv[i] > 0). It is from this information only that the final permutation + // is computed. The tree is restored by unflipping all of ptr. + + // fix assembly tree + for (i = 0; i < n; i++) + cptr[i] = cs_flip$$1(cptr[i]); + for (j = 0; j <= n; j++) + W[head + j] = -1; + // place unordered nodes in lists + for (j = n; j >= 0; j--) { + // skip if j is an element + if (W[nv + j] > 0) + continue; + // place j in list of its parent + W[next + j] = W[head + cptr[j]]; + W[head + cptr[j]] = j; + } + // place elements in lists + for (e = n; e >= 0; e--) { + // skip unless e is an element + if (W[nv + e] <= 0) + continue; + if (cptr[e] != -1) { + // place e in list of its parent + W[next + e] = W[head + cptr[e]]; + W[head + cptr[e]] = e; + } + } + // postorder the assembly tree + for (k = 0, i = 0; i <= n; i++) { + if (cptr[i] == -1) + k = cs_tdfs$$1(i, k, W, head, next, P, w); + } + // remove last item in array + P.splice(P.length - 1, 1); + // return P + return P; + }; + + /** + * Creates the matrix that will be used by the approximate minimum degree ordering algorithm. The function accepts the matrix M as input and returns a permutation + * vector P. The amd algorithm operates on a symmetrix matrix, so one of three symmetric matrices is formed. + * + * Order: 0 + * A natural ordering P=null matrix is returned. + * + * Order: 1 + * Matrix must be square. This is appropriate for a Cholesky or LU factorization. + * P = M + M' + * + * Order: 2 + * Dense columns from M' are dropped, M recreated from M'. This is appropriatefor LU factorization of unsymmetric matrices. + * P = M' * M + * + * Order: 3 + * This is best used for QR factorization or LU factorization is matrix M has no dense rows. A dense row is a row with more than 10*sqr(columns) entries. + * P = M' * M + */ + var _createTargetMatrix = function (order, a, m, n, dense) { + // compute A' + var at = transpose(a); - floor.toTex = {1: '\\left\\lfloor${args[0]}\\right\\rfloor'}; + // check order = 1, matrix must be square + if (order === 1 && n === m) { + // C = A + A' + return add$$1(a, at); + } + + // check order = 2, drop dense columns from M' + if (order == 2) { + // transpose arrays + var tindex = at._index; + var tptr = at._ptr; + // new column index + var p2 = 0; + // loop A' columns (rows) + for (var j = 0; j < m; j++) { + // column j of AT starts here + var p = tptr[j]; + // new column j starts here + tptr[j] = p2; + // skip dense col j + if (tptr[j + 1] - p > dense) + continue; + // map rows in column j of A + for (var p1 = tptr[j + 1]; p < p1; p++) + tindex[p2++] = tindex[p]; + } + // finalize AT + tptr[m] = p2; + // recreate A from new transpose matrix + a = transpose(at); + // use A' * A + return multiply(at, a); + } + + // use A' * A, square or rectangular matrix + return multiply(at, a); + }; - return floor; -} + /** + * Initialize quotient graph. There are four kind of nodes and elements that must be represented: + * + * - A live node is a node i (or a supernode) that has not been selected as a pivot nad has not been merged into another supernode. + * - A dead node i is one that has been removed from the graph, having been absorved into r = flip(ptr[i]). + * - A live element e is one that is in the graph, having been formed when node e was selected as the pivot. + * - A dead element e is one that has benn absorved into a subsequent element s = flip(ptr[e]). + */ + var _initializeQuotientGraph = function (n, cptr, W, len, head, last, next, hhead, nv, w, elen, degree) { + // Initialize quotient graph + for (var k = 0; k < n; k++) + W[len + k] = cptr[k + 1] - cptr[k]; + W[len + n] = 0; + // initialize workspace + for (var i = 0; i <= n; i++) { + // degree list i is empty + W[head + i] = -1; + last[i] = -1; + W[next + i] = -1; + // hash list i is empty + W[hhead + i] = -1; + // node i is just one node + W[nv + i] = 1; + // node i is alive + W[w + i] = 1; + // Ek of node i is empty + W[elen + i] = 0; + // degree of node i + W[degree + i] = W[len + i]; + } + // clear w + var mark = _wclear(0, 0, W, w, n); + // n is a dead element + W[elen + n] = -2; + // n is a root of assembly tree + cptr[n] = -1; + // n is a dead element + W[w + n] = 0; + // return mark + return mark; + }; -var name$143 = 'floor'; -var factory_1$154 = factory$155; + /** + * Initialize degree lists. Each node is placed in its degree lists. Nodes of zero degree are eliminated immediately. Nodes with + * degree >= dense are alsol eliminated and merged into a placeholder node n, a dead element. Thes nodes will appera last in the + * output permutation p. + */ + var _initializeDegreeLists = function (n, cptr, W, degree, elen, w, dense, nv, head, last, next) { + // result + var nel = 0; + // loop columns + for (var i = 0; i < n; i++) { + // degree @ i + var d = W[degree + i]; + // check node i is empty + if (d === 0) { + // element i is dead + W[elen + i] = -2; + nel++; + // i is a root of assembly tree + cptr[i] = -1; + W[w + i] = 0; + } + else if (d > dense) { + // absorb i into element n + W[nv + i] = 0; + // node i is dead + W[elen + i] = -1; + nel++; + cptr[i] = cs_flip$$1(n); + W[nv + n]++; + } + else { + var h = W[head + d]; + if (h != -1) + last[h] = i; + // put node i in degree list d + W[next + i] = W[head + d]; + W[head + d] = i; + } + } + return nel; + }; -var floor$1 = { - name: name$143, - factory: factory_1$154 -}; + var _wclear = function(mark, lemax, W, w, n) { + if (mark < 2 || (mark + lemax < 0)) { + for (var k = 0; k < n; k++) { + if (W[w + k] !== 0) + W[w + k] = 1; + } + mark = 2 ; + } + // at this point, W [0..n-1] < mark holds + return mark; + }; + + var _diag = function (i, j) { + return i != j; + }; + + return cs_amd; + } -var isInteger$9 = number.isInteger; + var name$111 = 'cs_amd'; + var path$49 = 'sparse'; + var factory_1$121 = factory$122; -function factory$156 (type, config, load, typed) { + var cs_amd = { + name: name$111, + path: path$49, + factory: factory_1$121 + }; - var matrix$$1 = load(matrix); + function factory$123 (type) { - var algorithm01$$1 = load(algorithm01); - var algorithm04$$1 = load(algorithm04); - var algorithm10$$1 = load(algorithm10); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + var SparseMatrix = type.SparseMatrix; - /** - * Calculate the greatest common divisor for two or more values or arrays. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.gcd(a, b) - * math.gcd(a, b, c, ...) - * - * Examples: - * - * math.gcd(8, 12); // returns 4 - * math.gcd(-4, 6); // returns 2 - * math.gcd(25, 15, -10); // returns 5 - * - * math.gcd([8, -4], [12, 6]); // returns [4, 2] - * - * See also: - * - * lcm, xgcd - * - * @param {... number | BigNumber | Fraction | Array | Matrix} args Two or more integer numbers - * @return {number | BigNumber | Fraction | Array | Matrix} The greatest common divisor - */ - var gcd = typed('gcd', { - - 'number, number': _gcd, - - 'BigNumber, BigNumber': _gcdBigNumber, - - 'Fraction, Fraction': function (x, y) { - return x.gcd(y); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm04$$1(x, y, gcd); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm01$$1(y, x, gcd, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, gcd, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, gcd); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return gcd(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return gcd(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return gcd(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm10$$1(x, y, gcd, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, gcd, false); - }, + /** + * Permutes a sparse matrix C = P * A * Q + * + * @param {Matrix} a The Matrix A + * @param {Array} pinv The row permutation vector + * @param {Array} q The column permutation vector + * @param {boolean} values Create a pattern matrix (false), values and pattern otherwise + * + * @return {Matrix} C = P * A * Q, null on error + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_permute = function (a, pinv, q, values) { + // a arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + // rows & columns + var m = asize[0]; + var n = asize[1]; + // c arrays + var cvalues = values && a._values ? [] : null; + var cindex = []; // (aptr[n]); + var cptr = []; // (n + 1); + // initialize vars + var nz = 0; + // loop columns + for (var k = 0; k < n; k++) { + // column k of C is column q[k] of A + cptr[k] = nz; + // apply column permutation + var j = q ? (q[k]) : k; + // loop values in column j of A + for (var t0 = aptr[j], t1 = aptr[j + 1], t = t0; t < t1; t++) { + // row i of A is row pinv[i] of C + var r = pinv ? pinv[aindex[t]] : aindex[t]; + // index + cindex[nz] = r; + // check we need to populate values + if (cvalues) + cvalues[nz] = avalues[t]; + // increment number of nonzero elements + nz++; + } + } + // finalize the last column of C + cptr[n] = nz; + // return C matrix + return new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [m, n], + datatype: adt + }); + }; - 'number | BigNumber, SparseMatrix': function (x, y) { - return algorithm10$$1(y, x, gcd, true); - }, + return cs_permute; + } - 'number | BigNumber, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, gcd, true); - }, + var name$112 = 'cs_permute'; + var path$50 = 'sparse'; + var factory_1$122 = factory$123; - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, gcd, false).valueOf(); - }, + var cs_permute = { + name: name$112, + path: path$50, + factory: factory_1$122 + }; - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, gcd, true).valueOf(); - }, + function factory$124 () { - // TODO: need a smarter notation here - 'Array | Matrix | number | BigNumber, Array | Matrix | number | BigNumber, ...Array | Matrix | number | BigNumber': function (a, b, args) { - var res = gcd(a, b); - for (var i = 0; i < args.length; i++) { - res = gcd(res, args[i]); + /** + * Computes the elimination tree of Matrix A (using triu(A)) or the + * elimination tree of A'A without forming A'A. + * + * @param {Matrix} a The A Matrix + * @param {boolean} ata A value of true the function computes the etree of A'A + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_etree = function (a, ata) { + // check inputs + if (!a) + return null; + // a arrays + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + // rows & columns + var m = asize[0]; + var n = asize[1]; + + // allocate result + var parent = []; // (n) + + // allocate workspace + var w = []; // (n + (ata ? m : 0)) + var ancestor = 0; // first n entries in w + var prev = n; // last m entries (ata = true) + + var i, inext; + + // check we are calculating A'A + if (ata) { + // initialize workspace + for (i = 0; i < m; i++) + w[prev + i] = -1; } - return res; - } - }); - - gcd.toTex = '\\gcd\\left(${args}\\right)'; - - return gcd; - - /** - * Calculate gcd for BigNumbers - * @param {BigNumber} a - * @param {BigNumber} b - * @returns {BigNumber} Returns greatest common denominator of a and b - * @private - */ - function _gcdBigNumber(a, b) { - if (!a.isInt() || !b.isInt()) { - throw new Error('Parameters in function gcd must be integer numbers'); - } + // loop columns + for (var k = 0; k < n; k++) { + // node k has no parent yet + parent[k] = -1; + // nor does k have an ancestor + w[ancestor + k] = -1; + // values in column k + for (var p0 = aptr[k], p1 = aptr[k + 1], p = p0; p < p1; p++) { + // row + var r = aindex[p]; + // node + i = ata ? (w[prev + r]) : r; + // traverse from i to k + for (; i != -1 && i < k; i = inext) { + // inext = ancestor of i + inext = w[ancestor + i]; + // path compression + w[ancestor + i] = k; + // check no anc., parent is k + if (inext == -1) + parent[i] = k; + } + if (ata) + w[prev + r] = k; + } + } + return parent; + }; - // http://en.wikipedia.org/wiki/Euclidean_algorithm - var zero = new type.BigNumber(0); - while (!b.isZero()) { - var r = a.mod(b); - a = b; - b = r; - } - return a.lt(zero) ? a.neg() : a; + return cs_etree; } -} -/** - * Calculate gcd for numbers - * @param {number} a - * @param {number} b - * @returns {number} Returns the greatest common denominator of a and b - * @private - */ -function _gcd(a, b) { - if (!isInteger$9(a) || !isInteger$9(b)) { - throw new Error('Parameters in function gcd must be integer numbers'); - } + var name$113 = 'cs_etree'; + var path$51 = 'sparse'; + var factory_1$123 = factory$124; - // http://en.wikipedia.org/wiki/Euclidean_algorithm - var r; - while (b != 0) { - r = a % b; - a = b; - b = r; - } - return (a < 0) ? -a : a; -} + var cs_etree = { + name: name$113, + path: path$51, + factory: factory_1$123 + }; -var name$144 = 'gcd'; -var factory_1$155 = factory$156; + function factory$125 (type, config, load) { -var gcd$1 = { - name: name$144, - factory: factory_1$155 -}; + var cs_tdfs$$1 = load(cs_tdfs); -var flatten$2 = array.flatten; + /** + * Post order a tree of forest + * + * @param {Array} parent The tree or forest + * @param {Number} n Number of columns + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_post = function (parent, n) { + // check inputs + if (!parent) + return null; + // vars + var k = 0; + var j; + // allocate result + var post = []; // (n); + // workspace, head: first n entries, next: next n entries, stack: last n entries + var w = []; // (3 * n); + var head = 0; + var next = n; + var stack = 2 * n; + // initialize workspace + for (j = 0; j < n; j++) { + // empty linked lists + w[head + j] = -1; + } + // traverse nodes in reverse order + for (j = n-1; j >= 0; j--) { + // check j is a root + if (parent[j] == -1) + continue; + // add j to list of its parent + w[next + j] = w[head + parent[j]]; + w[head + parent[j]] = j; + } + // loop nodes + for (j = 0; j < n; j++) { + // skip j if it is not a root + if (parent[j] != -1) + continue; + // depth-first search + k = cs_tdfs$$1(j, k, w, head, next, post, stack); + } + return post; + }; -function factory$157 (type, config, load, typed) { - var abs = load(abs$1); - var add = load(addScalar); - var divide = load(divideScalar); - var multiply = load(multiplyScalar); - var sqrt = load(sqrt$1); - var smaller$$1 = load(smaller); - var isPositive = load(isPositive$1); + return cs_post; + } - /** - * Calculate the hypotenusa of a list with values. The hypotenusa is defined as: - * - * hypot(a, b, c, ...) = sqrt(a^2 + b^2 + c^2 + ...) - * - * For matrix input, the hypotenusa is calculated for all values in the matrix. - * - * Syntax: - * - * math.hypot(a, b, ...) - * math.hypot([a, b, c, ...]) - * - * Examples: - * - * math.hypot(3, 4); // 5 - * math.hypot(3, 4, 5); // 7.0710678118654755 - * math.hypot([3, 4, 5]); // 7.0710678118654755 - * math.hypot(-2); // 2 - * - * See also: - * - * abs, norm - * - * @param {... number | BigNumber | Array | Matrix} args A list with numeric values or an Array or Matrix. - * Matrix and Array input is flattened and returns a - * single number for the whole matrix. - * @return {number | BigNumber} Returns the hypothenusa of the input values. - */ - var hypot = typed('hypot', { - '... number | BigNumber': _hypot, + var name$114 = 'cs_post'; + var path$52 = 'sparse'; + var factory_1$124 = factory$125; - 'Array': function (x) { - return hypot.apply(hypot, flatten$2(x)); - }, + var cs_post = { + name: name$114, + path: path$52, + factory: factory_1$124 + }; - 'Matrix': function (x) { - return hypot.apply(hypot, flatten$2(x.toArray())); - } - }); + function factory$126 () { - /** - * Calculate the hypotenusa for an Array with values - * @param {Array.} args - * @return {number | BigNumber} Returns the result - * @private - */ - function _hypot (args) { - // code based on `hypot` from es6-shim: - // https://github.com/paulmillr/es6-shim/blob/master/es6-shim.js#L1619-L1633 - var result = 0; - var largest = 0; - - for (var i = 0; i < args.length; i++) { - var value = abs(args[i]); - if (smaller$$1(largest, value)) { - result = multiply(result, multiply(divide(largest, value), divide(largest, value))); - result = add(result, 1); - largest = value; - } else { - result = add(result, isPositive(value) ? multiply(divide(value, largest), divide(value, largest)) : value); + /** + * This function determines if j is a leaf of the ith row subtree. + * Consider A(i,j), node j in ith row subtree and return lca(jprev,j) + * + * @param {Number} i The ith row subtree + * @param {Number} j The node to test + * @param {Array} w The workspace array + * @param {Number} first The index offset within the workspace for the first array + * @param {Number} maxfirst The index offset within the workspace for the maxfirst array + * @param {Number} prevleaf The index offset within the workspace for the prevleaf array + * @param {Number} ancestor The index offset within the workspace for the ancestor array + * + * @return {Object} + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_leaf = function (i, j, w, first, maxfirst, prevleaf, ancestor) { + + var s, sparent, jprev; + + // our result + var jleaf = 0; + var q; + + // check j is a leaf + if (i <= j || w[first + j] <= w[maxfirst + i]) + return (-1); + // update max first[j] seen so far + w[maxfirst + i] = w[first + j]; + // jprev = previous leaf of ith subtree + jprev = w[prevleaf + i]; + w[prevleaf + i] = j; + + // check j is first or subsequent leaf + if (jprev === -1) { + // 1st leaf, q = root of ith subtree + jleaf = 1; + q = i; } - } + else { + // update jleaf + jleaf = 2; + // q = least common ancester (jprev,j) + for (q = jprev; q != w[ancestor + q]; q = w[ancestor + q]); + for (s = jprev; s != q; s = sparent) { + // path compression + sparent = w[ancestor + s]; + w[ancestor + s] = q; + } + } + return { + jleaf: jleaf, + q: q + }; + }; - return multiply(largest, sqrt(result)); + return cs_leaf; } - hypot.toTex = '\\hypot\\left(${args}\\right)'; + var name$115 = 'cs_leaf'; + var path$53 = 'sparse'; + var factory_1$125 = factory$126; - return hypot; -} - -var name$145 = 'hypot'; -var factory_1$156 = factory$157; + var cs_leaf = { + name: name$115, + path: path$53, + factory: factory_1$125 + }; -var hypot$1 = { - name: name$145, - factory: factory_1$156 -}; + function factory$127 (type, config, load) { -var scatter = function scatter(a, j, w, x, u, mark, c, f, inverse, update, value) { - // a arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - // c arrays - var cindex = c._index; + var transpose = load(transpose$1); + + var cs_leaf$$1 = load(cs_leaf); - // vars - var k, k0, k1, i; + /** + * Computes the column counts using the upper triangular part of A. + * It transposes A internally, none of the input parameters are modified. + * + * @param {Matrix} a The sparse matrix A + * + * @param {Matrix} ata Count the columns of A'A instead + * + * @return An array of size n of the column counts or null on error + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_counts = function (a, parent, post, ata) { + // check inputs + if (!a || !parent || !post) + return null; + // a matrix arrays + var asize = a._size; + // rows and columns + var m = asize[0]; + var n = asize[1]; + // variables + var i, j, k, J, p, p0, p1; + + // workspace size + var s = 4 * n + (ata ? (n + m + 1) : 0); + // allocate workspace + var w = []; // (s) + var ancestor = 0; // first n entries + var maxfirst = n; // next n entries + var prevleaf = 2 * n; // next n entries + var first = 3 * n; // next n entries + var head = 4 * n; // next n + 1 entries (used when ata is true) + var next = 5 * n + 1; // last entries in workspace + // clear workspace w[0..s-1] + for (k = 0; k < s; k++) + w[k] = -1; + + // allocate result + var colcount = []; // (n); + + // AT = A' + var at = transpose(a); + // at arrays + var tindex = at._index; + var tptr = at._ptr; - // check we need to process values (pattern matrix) - if (x) { - // values in j - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // check value exists in current j - if (w[i] !== mark) { - // i is new entry in j - w[i] = mark; - // add i to pattern of C - cindex.push(i); - // x(i) = A, check we need to call function this time - if (update) { - // copy value to workspace calling callback function - x[i] = inverse ? f(avalues[k], value) : f(value, avalues[k]); - // function was called on current row - u[i] = mark; - } - else { - // copy value to workspace - x[i] = avalues[k]; + // find w[first + j] + for (k = 0; k < n; k++) { + j = post[k]; + // colcount[j]=1 if j is a leaf + colcount[j] = (w[first + j] == -1) ? 1 : 0; + for (; j != -1 && w[first + j] == -1; j = parent[j]) + w[first + j] = k; + } + + // initialize ata if needed + if (ata) { + // invert post + for (k = 0; k < n; k++) + w[post[k]] = k; + // loop rows (columns in AT) + for (i = 0; i < m; i++) { + // values in column i of AT + for (k = n, p0 = tptr[i], p1 = tptr[i + 1], p = p0; p < p1; p++) + k = Math.min(k, w[tindex[p]]); + // place row i in linked list k + w[next + i] = w[head + k]; + w[head + k] = i; } } - else { - // i exists in C already - x[i] = inverse ? f(avalues[k], x[i]) : f(x[i], avalues[k]); - // function was called on current row - u[i] = mark; - } - } - } - else { - // values in j - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // check value exists in current j - if (w[i] !== mark) { - // i is new entry in j - w[i] = mark; - // add i to pattern of C - cindex.push(i); + + // each node in its own set + for (i = 0; i < n; i++) + w[ancestor + i] = i; + + for (k = 0; k < n; k++) { + // j is the kth node in postordered etree + j = post[k]; + // check j is not a root + if (parent[j] != -1) + colcount[parent[j]]--; + + // J=j for LL'=A case + for (J = (ata ? w[head + k] : j); J != -1; J = (ata ? w[next + J] : -1)) { + for (p = tptr[J]; p < tptr[J+1]; p++) { + i = tindex[p]; + var r = cs_leaf$$1(i, j, w, first, maxfirst, prevleaf, ancestor); + // check A(i,j) is in skeleton + if (r.jleaf >= 1) + colcount[j]++; + // check account for overlap in q + if (r.jleaf == 2) + colcount[r.q]--; + } + } + if (parent[j] != -1) + w[ancestor + j] = parent[j]; } - else { - // indicate function was called on current row - u[i] = mark; + // sum up colcount's of each child + for (j = 0; j < n; j++) { + if (parent[j] != -1) + colcount[parent[j]] += colcount[j]; } - } - } -}; + return colcount; + }; -function factory$158 (type, config, load, typed) { + return cs_counts; + } - var equalScalar$$1 = load(equalScalar); + var name$116 = 'cs_counts'; + var path$54 = 'sparse'; + var factory_1$126 = factory$127; - var SparseMatrix = type.SparseMatrix; + var cs_counts = { + name: name$116, + path: path$54, + factory: factory_1$126 + }; - /** - * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). - * Callback function invoked (Anz U Bnz) times, where Anz and Bnz are the nonzero elements in both matrices. - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm06 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = avalues && bvalues ? [] : undefined; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); + function factory$128 (type, config, load) { - // workspaces - var x = cvalues ? [] : undefined; - // marks indicating we have a value in x for a given column - var w = []; - // marks indicating value in a given row has been updated - var u = []; + var cs_amd$$1 = load(cs_amd); + var cs_permute$$1 = load(cs_permute); + var cs_etree$$1 = load(cs_etree); + var cs_post$$1 = load(cs_post); + var cs_counts$$1 = load(cs_counts); - // loop columns - for (var j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // columns mark - var mark = j + 1; - // scatter the values of A(:,j) into workspace - scatter(a, j, w, x, u, mark, c, cf); - // scatter the values of B(:,j) into workspace - scatter(b, j, w, x, u, mark, c, cf); - // check we need to process values (non pattern matrix) - if (x) { - // initialize first index in j - var k = cptr[j]; - // loop index in j - while (k < cindex.length) { - // row - var i = cindex[k]; - // check function was invoked on current row (Aij !=0 && Bij != 0) - if (u[i] === mark) { - // value @ i - var v = x[i]; - // check for zero value - if (!eq(v, zero)) { - // push value - cvalues.push(v); - // increment pointer - k++; - } - else { - // remove value @ i, do not increment pointer - cindex.splice(k, 1); - } - } - else { - // remove value @ i, do not increment pointer - cindex.splice(k, 1); - } + /** + * Symbolic ordering and analysis for QR and LU decompositions. + * + * @param {Number} order The ordering strategy (see cs_amd for more details) + * @param {Matrix} a The A matrix + * @param {boolean} qr Symbolic ordering and analysis for QR decomposition (true) or + * symbolic ordering and analysis for LU decomposition (false) + * + * @return {Object} The Symbolic ordering and analysis for matrix A + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_sqr = function (order, a, qr) { + // a arrays + var aptr = a._ptr; + var asize = a._size; + // columns + var n = asize[1]; + // vars + var k; + // symbolic analysis result + var s = {}; + // fill-reducing ordering + s.q = cs_amd$$1(order, a); + // validate results + if (order && !s.q) + return null; + // QR symbolic analysis + if (qr) { + // apply permutations if needed + var c = order ? cs_permute$$1(a, null, s.q, 0) : a; + // etree of C'*C, where C=A(:,q) + s.parent = cs_etree$$1(c, 1); + // post order elimination tree + var post = cs_post$$1 (s.parent, n); + // col counts chol(C'*C) + s.cp = cs_counts$$1(c, s.parent, post, 1); + // check we have everything needed to calculate number of nonzero elements + if (c && s.parent && s.cp && _vcount(c, s)) { + // calculate number of nonzero elements + for (s.unz = 0, k = 0; k < n; k++) + s.unz += s.cp[k]; } } else { - // initialize first index in j - var p = cptr[j]; - // loop index in j - while (p < cindex.length) { - // row - var r = cindex[p]; - // check function was invoked on current row (Aij !=0 && Bij != 0) - if (u[r] !== mark) { - // remove value @ i, do not increment pointer - cindex.splice(p, 1); - } - else { - // increment pointer - p++; - } + // for LU factorization only, guess nnz(L) and nnz(U) + s.unz = 4 * (aptr[n]) + n; + s.lnz = s.unz; + } + // return result S + return s; + }; + + /** + * Compute nnz(V) = s.lnz, s.pinv, s.leftmost, s.m2 from A and s.parent + */ + var _vcount = function (a, s) { + // a arrays + var aptr = a._ptr; + var aindex = a._index; + var asize = a._size; + // rows & columns + var m = asize[0]; + var n = asize[1]; + // initialize s arrays + s.pinv = []; // (m + n); + s.leftmost = []; // (m); + // vars + var parent = s.parent; + var pinv = s.pinv; + var leftmost = s.leftmost; + // workspace, next: first m entries, head: next n entries, tail: next n entries, nque: next n entries + var w = []; // (m + 3 * n); + var next = 0; + var head = m; + var tail = m + n; + var nque = m + 2 * n; + // vars + var i, k, p, p0, p1; + // initialize w + for (k = 0; k < n; k++) { + // queue k is empty + w[head + k] = -1; + w[tail + k] = -1; + w[nque + k] = 0; + } + // initialize row arrays + for (i = 0; i < m; i++) + leftmost[i] = -1; + // loop columns backwards + for (k = n - 1; k >= 0; k--) { + // values & index for column k + for (p0 = aptr[k], p1 = aptr[k + 1], p = p0; p < p1; p++) { + // leftmost[i] = min(find(A(i,:))) + leftmost[aindex[p]] = k; + } + } + // scan rows in reverse order + for (i = m - 1; i >= 0; i--) { + // row i is not yet ordered + pinv[i] = -1; + k = leftmost[i]; + // check row i is empty + if (k == -1) + continue; + // first row in queue k + if (w[nque + k]++ === 0) + w[tail + k] = i; + // put i at head of queue k + w[next + i] = w[head + k]; + w[head + k] = i; + } + s.lnz = 0; + s.m2 = m; + // find row permutation and nnz(V) + for (k = 0; k < n; k++) { + // remove row i from queue k + i = w[head + k]; + // count V(k,k) as nonzero + s.lnz++; + // add a fictitious row + if (i < 0) + i = s.m2++; + // associate row i with V(:,k) + pinv[i] = k; + // skip if V(k+1:m,k) is empty + if (--nque[k] <= 0) + continue; + // nque[k] is nnz (V(k+1:m,k)) + s.lnz += w[nque + k]; + // move all rows to parent of k + var pa = parent[k]; + if (pa != -1) { + if (w[nque + pa] === 0) + w[tail + pa] = w[tail + k]; + w[next + w[tail + k]] = w[head + pa]; + w[head + pa] = w[next + i]; + w[nque + pa] += w[nque + k]; } } - } - // update cptr - cptr[columns] = cindex.length; + for (i = 0; i < m; i++) { + if (pinv[i] < 0) + pinv[i] = k++; + } + return true; + }; + + return cs_sqr; + } + + var name$117 = 'cs_sqr'; + var path$55 = 'sparse'; + var factory_1$127 = factory$128; - // return sparse matrix - return c; + var cs_sqr = { + name: name$117, + path: path$55, + factory: factory_1$127 }; - - return algorithm06; -} -var name$146 = 'algorithm06'; -var factory_1$157 = factory$158; + var nearlyEqual$5 = number.nearlyEqual; -var algorithm06 = { - name: name$146, - factory: factory_1$157 -}; -var isInteger$10 = number.isInteger; + function factory$129 (type, config, load, typed) { + + var matrix$$1 = load(matrix); -function factory$159 (type, config, load, typed) { - - var matrix$$1 = load(matrix); + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - var algorithm02$$1 = load(algorithm02); - var algorithm06$$1 = load(algorithm06); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + var latex$$1 = latex; - /** - * Calculate the least common multiple for two or more values or arrays. - * - * lcm is defined as: - * - * lcm(a, b) = abs(a * b) / gcd(a, b) - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.lcm(a, b) - * math.lcm(a, b, c, ...) - * - * Examples: - * - * math.lcm(4, 6); // returns 12 - * math.lcm(6, 21); // returns 42 - * math.lcm(6, 21, 5); // returns 210 - * - * math.lcm([4, 6], [6, 21]); // returns [12, 42] - * - * See also: - * - * gcd, xgcd - * - * @param {... number | BigNumber | Array | Matrix} args Two or more integer numbers - * @return {number | BigNumber | Array | Matrix} The least common multiple - */ - var lcm = typed('lcm', { - 'number, number': _lcm, - - 'BigNumber, BigNumber': _lcmBigNumber, - - 'Fraction, Fraction': function (x, y) { + /** + * Test whether value x is larger or equal to y. + * + * The function returns true when x is larger than y or the relative + * difference between x and y is smaller than the configured epsilon. The + * function cannot be used to compare values smaller than approximately 2.22e-16. + * + * For matrices, the function is evaluated element wise. + * Strings are compared by their numerical value. + * + * Syntax: + * + * math.largerEq(x, y) + * + * Examples: + * + * math.larger(2, 1 + 1); // returns false + * math.largerEq(2, 1 + 1); // returns true + * + * See also: + * + * equal, unequal, smaller, smallerEq, larger, compare + * + * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare + * @return {boolean | Array | Matrix} Returns true when the x is larger or equal to y, else returns false + */ + var largerEq = typed('largerEq', { - return x.lcm(y); - }, + 'boolean, boolean': function (x, y) { + return x >= y; + }, - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm06$$1(x, y, lcm); - }, + 'number, number': function (x, y) { + return x >= y || nearlyEqual$5(x, y, config.epsilon); + }, - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, lcm, true); - }, + 'BigNumber, BigNumber': function (x, y) { + return x.gte(y) || nearlyEqual(x, y, config.epsilon); + }, - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm02$$1(x, y, lcm, false); - }, + 'Fraction, Fraction': function (x, y) { + return x.compare(y) !== -1; + }, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, lcm); - }, + 'Complex, Complex': function () { + throw new TypeError('No ordering relation is defined for complex numbers'); + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return lcm(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'Unit, Unit': function (x, y) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); + } + return largerEq(x.value, y.value); + }, - 'Array, Matrix': function (x, y) { - // use matrix implementation - return lcm(matrix$$1(x), y); - }, + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm07$$1(x, y, largerEq); + }, - 'Matrix, Array': function (x, y) { - // use matrix implementation - return lcm(x, matrix$$1(y)); - }, + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, largerEq, true); + }, - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm11$$1(x, y, lcm, false); - }, + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, largerEq, false); + }, - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, lcm, false); - }, + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, largerEq); + }, - 'number | BigNumber, SparseMatrix': function (x, y) { - return algorithm11$$1(y, x, lcm, true); - }, + 'Array, Array': function (x, y) { + // use matrix implementation + return largerEq(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - 'number | BigNumber, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, lcm, true); - }, + 'Array, Matrix': function (x, y) { + // use matrix implementation + return largerEq(matrix$$1(x), y); + }, - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, lcm, false).valueOf(); - }, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return largerEq(x, matrix$$1(y)); + }, - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, lcm, true).valueOf(); - }, + 'SparseMatrix, any': function (x, y) { + return algorithm12$$1(x, y, largerEq, false); + }, - // TODO: need a smarter notation here - 'Array | Matrix | number | BigNumber, Array | Matrix | number | BigNumber, ...Array | Matrix | number | BigNumber': function (a, b, args) { - var res = lcm(a, b); - for (var i = 0; i < args.length; i++) { - res = lcm(res, args[i]); - } - return res; - } - }); + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, largerEq, false); + }, - lcm.toTex = undefined; // use default template + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, largerEq, true); + }, - return lcm; + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, largerEq, true); + }, - /** - * Calculate lcm for two BigNumbers - * @param {BigNumber} a - * @param {BigNumber} b - * @returns {BigNumber} Returns the least common multiple of a and b - * @private - */ - function _lcmBigNumber(a, b) { - if (!a.isInt() || !b.isInt()) { - throw new Error('Parameters in function lcm must be integer numbers'); - } + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, largerEq, false).valueOf(); + }, - if (a.isZero() || b.isZero()) { - return new type.BigNumber(0); - } + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, largerEq, true).valueOf(); + } + }); - // http://en.wikipedia.org/wiki/Euclidean_algorithm - // evaluate lcm here inline to reduce overhead - var prod = a.times(b); - while (!b.isZero()) { - var t = b; - b = a.mod(t); - a = t; - } - return prod.div(a).abs(); - } -} + largerEq.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['largerEq'] + '${args[1]}\\right)' + }; -/** - * Calculate lcm for two numbers - * @param {number} a - * @param {number} b - * @returns {number} Returns the least common multiple of a and b - * @private - */ -function _lcm (a, b) { - if (!isInteger$10(a) || !isInteger$10(b)) { - throw new Error('Parameters in function lcm must be integer numbers'); + return largerEq; } - if (a == 0 || b == 0) { - return 0; - } + var name$118 = 'largerEq'; + var factory_1$128 = factory$129; - // http://en.wikipedia.org/wiki/Euclidean_algorithm - // evaluate lcm here inline to reduce overhead - var t; - var prod = a * b; - while (b != 0) { - t = b; - b = a % t; - a = t; - } - return Math.abs(prod / a); -} + var largerEq$1 = { + name: name$118, + factory: factory_1$128 + }; -var name$147 = 'lcm'; -var factory_1$158 = factory$159; + function factory$130 () { -var lcm$1 = { - name: name$147, - factory: factory_1$158 -}; + /** + * Checks if the node at w[j] is marked + * + * @param {Array} w The array + * @param {Number} j The array index + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_marked = function (w, j) { + // check node is marked + return w[j] < 0; + }; -function factory$160 (type, config, load, typed) { - var divideScalar$$1 = load(divideScalar); + return cs_marked; + } - /** - * Calculate the logarithm of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.log(x) - * math.log(x, base) - * - * Examples: - * - * math.log(3.5); // returns 1.252762968495368 - * math.exp(math.log(2.4)); // returns 2.4 - * - * math.pow(10, 4); // returns 10000 - * math.log(10000, 10); // returns 4 - * math.log(10000) / math.log(10); // returns 4 - * - * math.log(1024, 2); // returns 10 - * math.pow(2, 10); // returns 1024 - * - * See also: - * - * exp, log2, log10, log1p - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the logarithm. - * @param {number | BigNumber | Complex} [base=e] - * Optional base for the logarithm. If not provided, the natural - * logarithm of `x` is calculated. - * @return {number | BigNumber | Complex | Array | Matrix} - * Returns the logarithm of `x` - */ - var log = typed('log', { - 'number': function (x) { - if (x >= 0 || config.predictable) { - return Math.log(x); - } - else { - // negative value -> complex value computation - return new type.Complex(x, 0).log(); - } - }, + var name$119 = 'cs_marked'; + var path$56 = 'sparse'; + var factory_1$129 = factory$130; - 'Complex': function (x) { - return x.log(); - }, + var cs_marked = { + name: name$119, + path: path$56, + factory: factory_1$129 + }; - 'BigNumber': function (x) { - if (!x.isNegative() || config.predictable) { - return x.ln(); - } - else { - // downgrade to number, return Complex valued result - return new type.Complex(x.toNumber(), 0).log(); - } - }, + function factory$131 (type, config, load) { - 'Array | Matrix': function (x) { - return deepMap(x, log); - }, + var cs_flip$$1 = load(cs_flip); - 'any, any': function (x, base) { - // calculate logarithm for a specified base, log(x, base) - return divideScalar$$1(log(x), log(base)); - } - }); + /** + * Marks the node at w[j] + * + * @param {Array} w The array + * @param {Number} j The array index + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_mark = function (w, j) { + // mark w[j] + w[j] = cs_flip$$1(w [j]); + }; - log.toTex = { - 1: '\\ln\\left(${args[0]}\\right)', - 2: '\\log_{${args[1]}}\\left(${args[0]}\\right)' - }; + return cs_mark; + } - return log; -} + var name$120 = 'cs_mark'; + var path$57 = 'sparse'; + var factory_1$130 = factory$131; -var name$148 = 'log'; -var factory_1$159 = factory$160; + var cs_mark = { + name: name$120, + path: path$57, + factory: factory_1$130 + }; -var log$1 = { - name: name$148, - factory: factory_1$159 -}; + function factory$132 (type, config, load) { -function factory$161 (type, config, load, typed) { - /** - * Calculate the 10-base logarithm of a value. This is the same as calculating `log(x, 10)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.log10(x) - * - * Examples: - * - * math.log10(0.00001); // returns -5 - * math.log10(10000); // returns 4 - * math.log(10000) / math.log(10); // returns 4 - * math.pow(10, 4); // returns 10000 - * - * See also: - * - * exp, log, log1p, log2 - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the logarithm. - * @return {number | BigNumber | Complex | Array | Matrix} - * Returns the 10-base logarithm of `x` - */ - var log10 = typed('log10', { - 'number': function (x) { - if (x >= 0 || config.predictable) { - return _log10(x); - } - else { - // negative value -> complex value computation - return new type.Complex(x, 0).log().div(Math.LN10); - } - }, + var cs_flip$$1 = load(cs_flip); + + /** + * Flips the value if it is negative of returns the same value otherwise. + * + * @param {Number} i The value to flip + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_unflip = function (i) { + // flip the value if it is negative + return i < 0 ? cs_flip$$1(i) : i; + }; - 'Complex': function (x) { - return new type.Complex(x).log().div(Math.LN10); - }, + return cs_unflip; + } - 'BigNumber': function (x) { - if (!x.isNegative() || config.predictable) { - return x.log(); - } - else { - // downgrade to number, return Complex valued result - return new type.Complex(x.toNumber(), 0).log().div(Math.LN10); - } - }, + var name$121 = 'cs_unflip'; + var path$58 = 'sparse'; + var factory_1$131 = factory$132; - 'Array | Matrix': function (x) { - return deepMap(x, log10); - } - }); + var cs_unflip = { + name: name$121, + path: path$58, + factory: factory_1$131 + }; - log10.toTex = {1: '\\log_{10}\\left(${args[0]}\\right)'}; + function factory$133 (type, config, load) { - return log10; -} + var cs_marked$$1 = load(cs_marked); + var cs_mark$$1 = load(cs_mark); + var cs_unflip$$1 = load(cs_unflip); -/** - * Calculate the 10-base logarithm of a number - * @param {number} x - * @return {number} - * @private - */ -var _log10 = Math.log10 || function (x) { - return Math.log(x) / Math.LN10; -}; + /** + * Depth-first search computes the nonzero pattern xi of the directed graph G (Matrix) starting + * at nodes in B (see cs_reach()). + * + * @param {Number} j The starting node for the DFS algorithm + * @param {Matrix} g The G matrix to search, ptr array modified, then restored + * @param {Number} top Start index in stack xi[top..n-1] + * @param {Number} k The kth column in B + * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n + * The first n entries is the nonzero pattern, the last n entries is the stack + * @param {Array} pinv The inverse row permutation vector, must be null for L * x = b + * + * @return {Number} New value of top + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_dfs = function (j, g, top, xi, pinv) { + // g arrays + var index = g._index; + var ptr = g._ptr; + var size = g._size; + // columns + var n = size[1]; + // vars + var i, p, p2; + // initialize head + var head = 0; + // initialize the recursion stack + xi[0] = j; + // loop + while (head >= 0) { + // get j from the top of the recursion stack + j = xi[head]; + // apply permutation vector + var jnew = pinv ? pinv[j] : j; + // check node j is marked + if (!cs_marked$$1(ptr, j)) { + // mark node j as visited + cs_mark$$1(ptr, j); + // update stack (last n entries in xi) + xi[n + head] = jnew < 0 ? 0 : cs_unflip$$1(ptr[jnew]); + } + // node j done if no unvisited neighbors + var done = 1; + // examine all neighbors of j, stack (last n entries in xi) + for (p = xi[n + head], p2 = jnew < 0 ? 0 : cs_unflip$$1(ptr[jnew+1]); p < p2; p++) { + // consider neighbor node i + i = index[p]; + // check we have visited node i, skip it + if (cs_marked$$1(ptr, i)) + continue; + // pause depth-first search of node j, update stack (last n entries in xi) + xi[n + head] = p; + // start dfs at node i + xi[++head] = i; + // node j is not done + done = 0; + // break, to start dfs(i) + break; + } + // check depth-first search at node j is done + if (done) { + // remove j from the recursion stack + head--; + // and place in the output stack + xi[--top] = j; + } + } + return top; + }; -var name$149 = 'log10'; -var factory_1$160 = factory$161; + return cs_dfs; + } -var log10$1 = { - name: name$149, - factory: factory_1$160 -}; + var name$122 = 'cs_dfs'; + var path$59 = 'sparse'; + var factory_1$132 = factory$133; -function factory$162 (type, config, load, typed) { - var divideScalar$$1 = load(divideScalar); - var log = load(log$1); + var cs_dfs = { + name: name$122, + path: path$59, + factory: factory_1$132 + }; - /** - * Calculate the logarithm of a `value+1`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.log1p(x) - * math.log1p(x, base) - * - * Examples: - * - * math.log1p(2.5); // returns 1.252762968495368 - * math.exp(math.log1p(1.4)); // returns 2.4 - * - * math.pow(10, 4); // returns 10000 - * math.log1p(9999, 10); // returns 4 - * math.log1p(9999) / math.log(10); // returns 4 - * - * See also: - * - * exp, log, log2, log10 - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the logarithm of `x+1`. - * @param {number | BigNumber | Complex} [base=e] - * Optional base for the logarithm. If not provided, the natural - * logarithm of `x+1` is calculated. - * @return {number | BigNumber | Complex | Array | Matrix} - * Returns the logarithm of `x+1` - */ - var log1p = typed('log1p', { - 'number': _log1pNumber, + function factory$134 (type, config, load) { - 'Complex': _log1pComplex, + var cs_dfs$$1 = load(cs_dfs); + var cs_marked$$1 = load(cs_marked); + var cs_mark$$1 = load(cs_mark); - 'BigNumber': function (x) { - var y = x.plus(1); - if (!y.isNegative() || config.predictable) { - return y.ln(); - } - else { - // downgrade to number, return Complex valued result - return _log1pComplex(new type.Complex(x.toNumber(), 0)); + /** + * The cs_reach function computes X = Reach(B), where B is the nonzero pattern of the n-by-1 + * sparse column of vector b. The function returns the set of nodes reachable from any node in B. The + * nonzero pattern xi of the solution x to the sparse linear system Lx=b is given by X=Reach(B). + * + * @param {Matrix} g The G matrix + * @param {Matrix} b The B matrix + * @param {Number} k The kth column in B + * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n + * The first n entries is the nonzero pattern, the last n entries is the stack + * @param {Array} pinv The inverse row permutation vector + * + * @return {Number} The index for the nonzero pattern + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_reach = function (g, b, k, xi, pinv) { + // g arrays + var gptr = g._ptr; + var gsize = g._size; + // b arrays + var bindex = b._index; + var bptr = b._ptr; + // columns + var n = gsize[1]; + // vars + var p, p0, p1; + // initialize top + var top = n; + // loop column indeces in B + for (p0 = bptr[k], p1 = bptr[k + 1], p = p0; p < p1; p++) { + // node i + var i = bindex[p]; + // check node i is marked + if (!cs_marked$$1(gptr, i)) { + // start a dfs at unmarked node i + top = cs_dfs$$1(i, g, top, xi, pinv); + } + } + // loop columns from top -> n - 1 + for (p = top; p < n; p++) { + // restore G + cs_mark$$1(gptr, xi[p]); } - }, - - 'Array | Matrix': function (x) { - return deepMap(x, log1p); - }, - - 'any, any': function (x, base) { - // calculate logarithm for a specified base, log1p(x, base) - return divideScalar$$1(log1p(x), log(base)); - } - }); + return top; + }; - /** - * Calculate the natural logarithm of a `number+1` - * @param {number} x - * @returns {number | Complex} - * @private - */ - function _log1pNumber(x) { - if (x >= -1 || config.predictable) { - return (Math.log1p) ? Math.log1p(x) : Math.log(x+1); - } - else { - // negative value -> complex value computation - return _log1pComplex(new type.Complex(x, 0)); - } + return cs_reach; } - /** - * Calculate the natural logarithm of a complex number + 1 - * @param {Complex} x - * @returns {Complex} - * @private - */ - function _log1pComplex(x) { - var x_re1p = x.re + 1; - return new type.Complex ( - Math.log(Math.sqrt(x_re1p * x_re1p + x.im * x.im)), - Math.atan2(x.im, x_re1p) - ); - } + var name$123 = 'cs_reach'; + var path$60 = 'sparse'; + var factory_1$133 = factory$134; - log1p.toTex = { - 1: '\\ln\\left(${args[0]}+1\\right)', - 2: '\\log_{${args[1]}}\\left(${args[0]}+1\\right)' + var cs_reach = { + name: name$123, + path: path$60, + factory: factory_1$133 }; - return log1p; -} - -var name$150 = 'log1p'; -var factory_1$161 = factory$162; - -var log1p$1 = { - name: name$150, - factory: factory_1$161 -}; + function factory$135 (type, config, load) { -function factory$163 (type, config, load, typed) { - /** - * Calculate the 2-base of a value. This is the same as calculating `log(x, 2)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.log2(x) - * - * Examples: - * - * math.log2(0.03125); // returns -5 - * math.log2(16); // returns 4 - * math.log2(16) / math.log2(2); // returns 4 - * math.pow(2, 4); // returns 16 - * - * See also: - * - * exp, log, log1p, log10 - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the logarithm. - * @return {number | BigNumber | Complex | Array | Matrix} - * Returns the 2-base logarithm of `x` - */ - var log2 = typed('log2', { - 'number': function (x) { - if (x >= 0 || config.predictable) { - return (Math.log2) - ? Math.log2(x) - : Math.log(x) / Math.LN2; - } - else { - // negative value -> complex value computation - return _log2Complex(new type.Complex(x, 0)); - } - }, + var divideScalar$$1 = load(divideScalar); + var multiply = load(multiply$1); + var subtract = load(subtract$1); - 'Complex': _log2Complex, + var cs_reach$$1 = load(cs_reach); - 'BigNumber': function (x) { - if (!x.isNegative() || config.predictable) { - return x.log(2); - } - else { - // downgrade to number, return Complex valued result - return _log2Complex(new type.Complex(x.toNumber(), 0)); + /** + * The function cs_spsolve() computes the solution to G * x = bk, where bk is the + * kth column of B. When lo is true, the function assumes G = L is lower triangular with the + * diagonal entry as the first entry in each column. When lo is true, the function assumes G = U + * is upper triangular with the diagonal entry as the last entry in each column. + * + * @param {Matrix} g The G matrix + * @param {Matrix} b The B matrix + * @param {Number} k The kth column in B + * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n + * The first n entries is the nonzero pattern, the last n entries is the stack + * @param {Array} x The soluton to the linear system G * x = b + * @param {Array} pinv The inverse row permutation vector, must be null for L * x = b + * @param {boolean} lo The lower (true) upper triangular (false) flag + * + * @return {Number} The index for the nonzero pattern + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_spsolve = function (g, b, k, xi, x, pinv, lo) { + // g arrays + var gvalues = g._values; + var gindex = g._index; + var gptr = g._ptr; + var gsize = g._size; + // columns + var n = gsize[1]; + // b arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + // vars + var p, p0, p1, q; + // xi[top..n-1] = cs_reach(B(:,k)) + var top = cs_reach$$1(g, b, k, xi, pinv); + // clear x + for (p = top; p < n; p++) + x[xi[p]] = 0; + // scatter b + for (p0 = bptr[k], p1 = bptr[k + 1], p = p0; p < p1; p++) + x[bindex[p]] = bvalues[p]; + // loop columns + for (var px = top; px < n; px++) { + // x array index for px + var j = xi[px]; + // apply permutation vector (U x = b), j maps to column J of G + var J = pinv ? pinv[j] : j; + // check column J is empty + if (J < 0) + continue; + // column value indeces in G, p0 <= p < p1 + p0 = gptr[J]; + p1 = gptr[J + 1]; + // x(j) /= G(j,j) + x[j] = divideScalar$$1(x[j], gvalues[lo ? p0 : (p1 - 1)]); + // first entry L(j,j) + p = lo ? (p0 + 1) : p0; + q = lo ? (p1) : (p1 - 1); + // loop + for ( ; p < q ; p++) { + // row + var i = gindex[p]; + // x(i) -= G(i,j) * x(j) + x[i] = subtract(x[i], multiply(gvalues[p], x[j])); + } } - }, - - 'Array | Matrix': function (x) { - return deepMap(x, log2); - } - }); - - /** - * Calculate log2 for a complex value - * @param {Complex} x - * @returns {Complex} - * @private - */ - function _log2Complex(x) { - var newX = Math.sqrt(x.re * x.re + x.im * x.im); - return new type.Complex ( - (Math.log2) ? Math.log2(newX) : Math.log(newX) / Math.LN2, - Math.atan2(x.im, x.re) / Math.LN2 - ); + // return top of stack + return top; + }; + + return cs_spsolve; } - log2.toTex = '\\log_{2}\\left(${args[0]}\\right)'; - - return log2; + var name$124 = 'cs_spsolve'; + var path$61 = 'sparse'; + var factory_1$134 = factory$135; -} - -var name$151 = 'log2'; -var factory_1$162 = factory$163; + var cs_spsolve = { + name: name$124, + path: path$61, + factory: factory_1$134 + }; -var log2$1 = { - name: name$151, - factory: factory_1$162 -}; + function factory$136 (type, config, load) { -function factory$164 (type, config, load, typed) { + var abs = load(abs$1); + var divideScalar$$1 = load(divideScalar); + var multiply = load(multiply$1); + + var larger$$1 = load(larger); + var largerEq = load(largerEq$1); + + var cs_spsolve$$1 = load(cs_spsolve); - var matrix$$1 = load(matrix); - var latex$$1 = latex; + var SparseMatrix = type.SparseMatrix; - var algorithm02$$1 = load(algorithm02); - var algorithm03$$1 = load(algorithm03); - var algorithm05$$1 = load(algorithm05); - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Calculates the modulus, the remainder of an integer division. - * - * For matrices, the function is evaluated element wise. - * - * The modulus is defined as: - * - * x - y * floor(x / y) - * - * See http://en.wikipedia.org/wiki/Modulo_operation. - * - * Syntax: - * - * math.mod(x, y) - * - * Examples: - * - * math.mod(8, 3); // returns 2 - * math.mod(11, 2); // returns 1 - * - * function isOdd(x) { - * return math.mod(x, 2) != 0; - * } - * - * isOdd(2); // returns false - * isOdd(3); // returns true - * - * See also: - * - * divide - * - * @param {number | BigNumber | Fraction | Array | Matrix} x Dividend - * @param {number | BigNumber | Fraction | Array | Matrix} y Divisor - * @return {number | BigNumber | Fraction | Array | Matrix} Returns the remainder of `x` divided by `y`. - */ - var mod = typed('mod', { - - 'number, number': _mod, + /** + * Computes the numeric LU factorization of the sparse matrix A. Implements a Left-looking LU factorization + * algorithm that computes L and U one column at a tume. At the kth step, it access columns 1 to k-1 of L + * and column k of A. Given the fill-reducing column ordering q (see parameter s) computes L, U and pinv so + * L * U = A(p, q), where p is the inverse of pinv. + * + * @param {Matrix} m The A Matrix to factorize + * @param {Object} s The symbolic analysis from cs_sqr(). Provides the fill-reducing + * column ordering q + * @param {Number} tol Partial pivoting threshold (1 for partial pivoting) + * + * @return {Number} The numeric LU factorization of A or null + * + * Reference: http://faculty.cse.tamu.edu/davis/publications.html + */ + var cs_lu = function (m, s, tol) { + // validate input + if (!m) + return null; + // m arrays + var size = m._size; + // columns + var n = size[1]; + // symbolic analysis result + var q; + var lnz = 100; + var unz = 100; + // update symbolic analysis parameters + if (s) { + q = s.q; + lnz = s.lnz || lnz; + unz = s.unz || unz; + } + // L arrays + var lvalues = []; // (lnz) + var lindex = []; // (lnz); + var lptr = []; // (n + 1); + // L + var L = new SparseMatrix({ + values: lvalues, + index: lindex, + ptr: lptr, + size: [n, n] + }); + // U arrays + var uvalues = []; // (unz); + var uindex = []; // (unz); + var uptr = []; // (n + 1); + // U + var U = new SparseMatrix({ + values: uvalues, + index: uindex, + ptr: uptr, + size: [n, n] + }); + // inverse of permutation vector + var pinv = []; // (n); + // vars + var i, p; + // allocate arrays + var x = []; // (n); + var xi = []; // (2 * n); + // initialize variables + for (i = 0; i < n; i++) { + // clear workspace + x[i] = 0; + // no rows pivotal yet + pinv[i] = -1; + // no cols of L yet + lptr[i + 1] = 0; + } + // reset number of nonzero elements in L and U + lnz = 0; + unz = 0; + // compute L(:,k) and U(:,k) + for (var k = 0; k < n; k++) { + // update ptr + lptr[k] = lnz; + uptr[k] = unz; + // apply column permutations if needed + var col = q ? q[k] : k; + // solve triangular system, x = L\A(:,col) + var top = cs_spsolve$$1(L, m, col, xi, x, pinv, 1); + // find pivot + var ipiv = -1; + var a = -1; + // loop xi[] from top -> n + for (p = top; p < n; p++) { + // x[i] is nonzero + i = xi[p]; + // check row i is not yet pivotal + if (pinv[i] < 0) { + // absolute value of x[i] + var xabs = abs(x[i]); + // check absoulte value is greater than pivot value + if (larger$$1(xabs, a)) { + // largest pivot candidate so far + a = xabs; + ipiv = i; + } + } + else { + // x(i) is the entry U(pinv[i],k) + uindex[unz] = pinv[i]; + uvalues[unz++] = x[i]; + } + } + // validate we found a valid pivot + if (ipiv == -1 || a <= 0) + return null; + // update actual pivot column, give preference to diagonal value + if (pinv[col] < 0 && largerEq(abs(x[col]), multiply(a, tol))) + ipiv = col; + // the chosen pivot + var pivot = x[ipiv]; + // last entry in U(:,k) is U(k,k) + uindex[unz] = k; + uvalues[unz++] = pivot; + // ipiv is the kth pivot row + pinv[ipiv] = k; + // first entry in L(:,k) is L(k,k) = 1 + lindex[lnz] = ipiv; + lvalues[lnz++] = 1; + // L(k+1:n,k) = x / pivot + for (p = top; p < n; p++) { + // row + i = xi[p]; + // check x(i) is an entry in L(:,k) + if (pinv[i] < 0) { + // save unpermuted row in L + lindex[lnz] = i; + // scale pivot column + lvalues[lnz++] = divideScalar$$1(x[i], pivot); + } + // x[0..n-1] = 0 for next k + x[i] = 0; + } + } + // update ptr + lptr[n] = lnz; + uptr[n] = unz; + // fix row indices of L for final pinv + for (p = 0; p < lnz; p++) + lindex[p] = pinv[lindex[p]]; + // trim arrays + lvalues.splice(lnz, lvalues.length - lnz); + lindex.splice(lnz, lindex.length - lnz); + uvalues.splice(unz, uvalues.length - unz); + uindex.splice(unz, uindex.length - unz); + // return LU factor + return { + L: L, + U: U, + pinv: pinv + }; + }; - 'BigNumber, BigNumber': function (x, y) { - return y.isZero() ? x : x.mod(y); - }, + return cs_lu; + } - 'Fraction, Fraction': function (x, y) { - return x.mod(y); - }, + var name$125 = 'cs_lu'; + var path$62 = 'sparse'; + var factory_1$135 = factory$136; - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm05$$1(x, y, mod, false); - }, + var cs_lu = { + name: name$125, + path: path$62, + factory: factory_1$135 + }; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, mod, true); - }, + var number$5 = utils.number, + + isInteger$8 = number$5.isInteger; - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, mod, false); - }, + function factory$137 (type, config, load, typed) { - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, mod); - }, + var cs_sqr$$1 = load(cs_sqr); + var cs_lu$$1 = load(cs_lu); - 'Array, Array': function (x, y) { - // use matrix implementation - return mod(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + /** + * Calculate the Sparse Matrix LU decomposition with full pivoting. Sparse Matrix `A` is decomposed in two matrices (`L`, `U`) and two permutation vectors (`pinv`, `q`) where + * + * `P * A * Q = L * U` + * + * Syntax: + * + * math.slu(A, order, threshold); + * + * Examples: + * + * var A = math.sparse([[4,3], [6, 3]]) + * math.slu(A, 1, 0.001) + * // returns: + * // { + * // L: [[1, 0], [1.5, 1]] + * // U: [[4, 3], [0, -1.5]] + * // p: [0, 1] + * // q: [0, 1] + * // } + * + * See also: + * + * lup, lsolve, usolve, lusolve + * + * @param {SparseMatrix} A A two dimensional sparse matrix for which to get the LU decomposition. + * @param {Number} order The Symbolic Ordering and Analysis order: + * 0 - Natural ordering, no permutation vector q is returned + * 1 - Matrix must be square, symbolic ordering and analisis is performed on M = A + A' + * 2 - Symbolic ordering and analisis is performed on M = A' * A. Dense columns from A' are dropped, A recreated from A'. + * This is appropriatefor LU factorization of unsymmetric matrices. + * 3 - Symbolic ordering and analisis is performed on M = A' * A. This is best used for LU factorization is matrix M has no dense rows. + * A dense row is a row with more than 10*sqr(columns) entries. + * @param {Number} threshold Partial pivoting threshold (1 for partial pivoting) + * + * @return {Object} The lower triangular matrix, the upper triangular matrix and the permutation vectors. + */ + var slu = typed('slu', { + + 'SparseMatrix, number, number': function (a, order, threshold) { + // verify order + if (!isInteger$8(order) || order < 0 || order > 3) + throw new Error('Symbolic Ordering and Analysis order must be an integer number in the interval [0, 3]'); + // verify threshold + if (threshold < 0 || threshold > 1) + throw new Error('Partial pivoting threshold must be a number from 0 to 1'); + + // perform symbolic ordering and analysis + var s = cs_sqr$$1(order, a, false); + + // perform lu decomposition + var f = cs_lu$$1(a, s, threshold); + + // return decomposition + return { + L: f.L, + U: f.U, + p: f.pinv, + q: s.q, + toString: function () { + return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\np: ' + this.p.toString() + (this.q ? '\nq: ' + this.q.toString() : '') + '\n'; + } + }; + } + }); - 'Array, Matrix': function (x, y) { - // use matrix implementation - return mod(matrix$$1(x), y); - }, + return slu; + } - 'Matrix, Array': function (x, y) { - // use matrix implementation - return mod(x, matrix$$1(y)); - }, + var name$126 = 'slu'; + var factory_1$136 = factory$137; - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, mod, false); - }, + var slu$1 = { + name: name$126, + factory: factory_1$136 + }; - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, mod, false); - }, + var string$9 = utils.string; + var array$3 = utils.array; - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, mod, true); - }, + var isArray$3 = Array.isArray; - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, mod, true); - }, + function factory$138 (type) { + + var DenseMatrix = type.DenseMatrix; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, mod, false).valueOf(); - }, + /** + * Validates matrix and column vector b for backward/forward substitution algorithms. + * + * @param {Matrix} m An N x N matrix + * @param {Array | Matrix} b A column vector + * @param {Boolean} copy Return a copy of vector b + * + * @return {DenseMatrix} Dense column vector b + */ + var solveValidation = function (m, b, copy) { + // matrix size + var size = m.size(); + // validate matrix dimensions + if (size.length !== 2) + throw new RangeError('Matrix must be two dimensional (size: ' + string$9.format(size) + ')'); + // rows & columns + var rows = size[0]; + var columns = size[1]; + // validate rows & columns + if (rows !== columns) + throw new RangeError('Matrix must be square (size: ' + string$9.format(size) + ')'); + // vars + var data, i, bdata; + // check b is matrix + if (type.isMatrix(b)) { + // matrix size + var msize = b.size(); + // vector + if (msize.length === 1) { + // check vector length + if (msize[0] !== rows) + throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); + // create data array + data = []; + // matrix data (DenseMatrix) + bdata = b._data; + // loop b data + for (i = 0; i < rows; i++) { + // row array + data[i] = [bdata[i]]; + } + // return Dense Matrix + return new DenseMatrix({ + data: data, + size: [rows, 1], + datatype: b._datatype + }); + } + // two dimensions + if (msize.length === 2) { + // array must be a column vector + if (msize[0] !== rows || msize[1] !== 1) + throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); + // check matrix type + if (type.isDenseMatrix(b)) { + // check a copy is needed + if (copy) { + // create data array + data = []; + // matrix data (DenseMatrix) + bdata = b._data; + // loop b data + for (i = 0; i < rows; i++) { + // row array + data[i] = [bdata[i][0]]; + } + // return Dense Matrix + return new DenseMatrix({ + data: data, + size: [rows, 1], + datatype: b._datatype + }); + } + // b is already a column vector + return b; + } + // create data array + data = []; + for (i = 0; i < rows; i++) + data[i] = [0]; + // sparse matrix arrays + var values = b._values; + var index = b._index; + var ptr = b._ptr; + // loop values in column 0 + for (var k1 = ptr[1], k = ptr[0]; k < k1; k++) { + // row + i = index[k]; + // add to data + data[i][0] = values[k]; + } + // return Dense Matrix + return new DenseMatrix({ + data: data, + size: [rows, 1], + datatype: b._datatype + }); + } + // throw error + throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); + } + // check b is array + if (isArray$3(b)) { + // size + var asize = array$3.size(b); + // check matrix dimensions, vector + if (asize.length === 1) { + // check vector length + if (asize[0] !== rows) + throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); + // create data array + data = []; + // loop b + for (i = 0; i < rows; i++) { + // row array + data[i] = [b[i]]; + } + // return Dense Matrix + return new DenseMatrix({ + data: data, + size: [rows, 1] + }); + } + if (asize.length === 2) { + // array must be a column vector + if (asize[0] !== rows || asize[1] !== 1) + throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); + // create data array + data = []; + // loop b data + for (i = 0; i < rows; i++) { + // row array + data[i] = [b[i][0]]; + } + // return Dense Matrix + return new DenseMatrix({ + data: data, + size: [rows, 1] + }); + } + // throw error + throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); + } + }; + + return solveValidation; + } - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, mod, true).valueOf(); - } - }); + var factory_1$137 = factory$138; - mod.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['mod'] + '${args[1]}\\right)' + var solveValidation = { + factory: factory_1$137 }; - return mod; - - /** - * Calculate the modulus of two numbers - * @param {number} x - * @param {number} y - * @returns {number} res - * @private - */ - function _mod(x, y) { - if (y > 0) { - // We don't use JavaScript's % operator here as this doesn't work - // correctly for x < 0 and x == 0 - // see http://en.wikipedia.org/wiki/Modulo_operation - return x - y * Math.floor(x / y); - } - else if (y === 0) { - return x; - } - else { // y < 0 - // TODO: implement mod for a negative divisor - throw new Error('Cannot calculate mod for a negative divisor'); - } - } -} - -var name$152 = 'mod'; -var factory_1$163 = factory$164; + function factory$139 (type, config, load, typed) { -var mod$1 = { - name: name$152, - factory: factory_1$163 -}; + var matrix$$1 = load(matrix); + var divideScalar$$1 = load(divideScalar); + var multiplyScalar$$1 = load(multiplyScalar); + var subtract = load(subtract$1); + var equalScalar$$1 = load(equalScalar); -var clone$7 = object.clone; -var format$5 = string.format; + var solveValidation$$1 = load(solveValidation); -function factory$165 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var add$$1 = load(add); + var DenseMatrix = type.DenseMatrix; - /** - * Calculate the trace of a matrix: the sum of the elements on the main - * diagonal of a square matrix. - * - * Syntax: - * - * math.trace(x) - * - * Examples: - * - * math.trace([[1, 2], [3, 4]]); // returns 5 - * - * var A = [ - * [1, 2, 3], - * [-1, 2, 3], - * [2, 0, 3] - * ] - * math.trace(A); // returns 6 - * - * See also: - * - * diag - * - * @param {Array | Matrix} x A matrix - * - * @return {number} The trace of `x` - */ - var trace = typed('trace', { - - 'Array': function _arrayTrace(x) { - // use dense matrix implementation - return _denseTrace(matrix$$1(x)); - }, + /** + * Solves the linear equation system by forwards substitution. Matrix must be a lower triangular matrix. + * + * `L * x = b` + * + * Syntax: + * + * math.lsolve(L, b); + * + * Examples: + * + * var a = [[-2, 3], [2, 1]]; + * var b = [11, 9]; + * var x = lsolve(a, b); // [[-5.5], [20]] + * + * See also: + * + * lup, slu, usolve, lusolve + * + * @param {Matrix, Array} L A N x N matrix or array (L) + * @param {Matrix, Array} b A column vector with the b values + * + * @return {DenseMatrix | Array} A column vector with the linear system solution (x) + */ + var lsolve = typed('lsolve', { - 'SparseMatrix': _sparseTrace, + 'SparseMatrix, Array | Matrix': function (m, b) { + // process matrix + return _sparseForwardSubstitution(m, b); + }, + + 'DenseMatrix, Array | Matrix': function (m, b) { + // process matrix + return _denseForwardSubstitution(m, b); + }, + + 'Array, Array | Matrix': function (a, b) { + // create dense matrix from array + var m = matrix$$1(a); + // use matrix implementation + var r = _denseForwardSubstitution(m, b); + // result + return r.valueOf(); + } + }); - 'DenseMatrix': _denseTrace, + var _denseForwardSubstitution = function (m, b) { + // validate matrix and vector, return copy of column vector b + b = solveValidation$$1(m, b, true); + // column vector data + var bdata = b._data; + // rows & columns + var rows = m._size[0]; + var columns = m._size[1]; + // result + var x = []; + // data + var data = m._data; + // forward solve m * x = b, loop columns + for (var j = 0; j < columns; j++) { + // b[j] + var bj = bdata[j][0] || 0; + // x[j] + var xj; + // forward substitution (outer product) avoids inner looping when bj == 0 + if (!equalScalar$$1(bj, 0)) { + // value @ [j, j] + var vjj = data[j][j]; + // check vjj + if (equalScalar$$1(vjj, 0)) { + // system cannot be solved + throw new Error('Linear system cannot be solved since matrix is singular'); + } + // calculate xj + xj = divideScalar$$1(bj, vjj); + // loop rows + for (var i = j + 1; i < rows; i++) { + // update copy of b + bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, data[i][j]))]; + } + } + else { + // zero @ j + xj = 0; + } + // update x + x[j] = [xj]; + } + // return vector + return new DenseMatrix({ + data: x, + size: [rows, 1] + }); + }; - 'any': clone$7 - }); - - function _denseTrace(m) { - // matrix size & data - var size = m._size; - var data = m._data; - - // process dimensions - switch (size.length) { - case 1: - // vector - if (size[0] === 1) { - // return data[0] - return clone$7(data[0]); - } - throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); - case 2: - // two dimensional - var rows = size[0]; - var cols = size[1]; - if (rows === cols) { - // calulate sum - var sum = 0; - // loop diagonal - for (var i = 0; i < rows; i++) - sum = add$$1(sum, data[i][i]); - // return trace - return sum; - } - throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); - default: - // multi dimensional - throw new RangeError('Matrix must be two dimensional (size: ' + format$5(size) + ')'); - } - } - - function _sparseTrace(m) { - // matrix arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - var size = m._size; - // check dimensions - var rows = size[0]; - var columns = size[1]; - // matrix must be square - if (rows === columns) { - // calulate sum - var sum = 0; - // check we have data (avoid looping columns) - if (values.length > 0) { - // loop columns - for (var j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // loop k within [k0, k1[ - for (var k = k0; k < k1; k++) { - // row index - var i = index[k]; - // check row + var _sparseForwardSubstitution = function (m, b) { + // validate matrix and vector, return copy of column vector b + b = solveValidation$$1(m, b, true); + // column vector data + var bdata = b._data; + // rows & columns + var rows = m._size[0]; + var columns = m._size[1]; + // matrix arrays + var values = m._values; + var index = m._index; + var ptr = m._ptr; + // vars + var i, k; + // result + var x = []; + // forward solve m * x = b, loop columns + for (var j = 0; j < columns; j++) { + // b[j] + var bj = bdata[j][0] || 0; + // forward substitution (outer product) avoids inner looping when bj == 0 + if (!equalScalar$$1(bj, 0)) { + // value @ [j, j] + var vjj = 0; + // lower triangular matrix values & index (column j) + var jvalues = []; + var jindex = []; + // last index in column + var l = ptr[j + 1]; + // values in column, find value @ [j, j] + for (k = ptr[j]; k < l; k++) { + // row + i = index[k]; + // check row (rows are not sorted!) if (i === j) { - // accumulate value - sum = add$$1(sum, values[k]); - // exit loop - break; + // update vjj + vjj = values[k]; } - if (i > j) { - // exit loop, no value on the diagonal for column j - break; + else if (i > j) { + // store lower triangular + jvalues.push(values[k]); + jindex.push(i); } } + // at this point we must have a value @ [j, j] + if (equalScalar$$1(vjj, 0)) { + // system cannot be solved, there is no value @ [j, j] + throw new Error('Linear system cannot be solved since matrix is singular'); + } + // calculate xj + var xj = divideScalar$$1(bj, vjj); + // loop lower triangular + for (k = 0, l = jindex.length; k < l; k++) { + // row + i = jindex[k]; + // update copy of b + bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, jvalues[k]))]; + } + // update x + x[j] = [xj]; + } + else { + // update x + x[j] = [0]; } } - // return trace - return sum; - } - throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); - } + // return vector + return new DenseMatrix({ + data: x, + size: [rows, 1] + }); + }; - trace.toTex = {1: '\\mathrm{tr}\\left(${args[0]}\\right)'}; - - return trace; -} + return lsolve; + } -var name$153 = 'trace'; -var factory_1$164 = factory$165; + var name$127 = 'lsolve'; + var factory_1$138 = factory$139; -var trace$1 = { - name: name$153, - factory: factory_1$164 -}; + var lsolve$1 = { + name: name$127, + factory: factory_1$138 + }; -function factory$166 (type, config, load, typed) { - - var abs = load(abs$1); - var add$$1 = load(add); - var pow = load(pow$1); - var conj = load(conj$1); - var sqrt = load(sqrt$1); - var multiply = load(multiply$1); - var equalScalar$$1 = load(equalScalar); - var larger$$1 = load(larger); - var smaller$$1 = load(smaller); - var matrix$$1 = load(matrix); - var trace = load(trace$1); - var transpose = load(transpose$1); + function factory$140 () { + /** + * Permutes a vector; x = P'b. In MATLAB notation, x(p)=b. + * + * @param {Array} p The permutation vector of length n. null value denotes identity + * @param {Array} b The input vector + * + * @return {Array} The output vector x = P'b + */ + var cs_ipvec = function (p, b, n) { + // vars + var k; + var n = b.length; + var x = []; + // check permutation vector was provided, p = null denotes identity + if (p) { + // loop vector + for (k = 0; k < n; k++) { + // apply permutation + x[p[k]] = b[k]; + } + } + else { + // loop vector + for (k = 0; k < n; k++) { + // x[i] = b[i] + x[k] = b[k]; + } + } + return x; + }; - /** - * Calculate the norm of a number, vector or matrix. - * - * The second parameter p is optional. If not provided, it defaults to 2. - * - * Syntax: - * - * math.norm(x) - * math.norm(x, p) - * - * Examples: - * - * math.abs(-3.5); // returns 3.5 - * math.norm(-3.5); // returns 3.5 - * - * math.norm(math.complex(3, -4)); // returns 5 - * - * math.norm([1, 2, -3], Infinity); // returns 3 - * math.norm([1, 2, -3], -Infinity); // returns 1 - * - * math.norm([3, 4], 2); // returns 5 - * - * math.norm([[1, 2], [3, 4]], 1) // returns 6 - * math.norm([[1, 2], [3, 4]], 'inf'); // returns 7 - * math.norm([[1, 2], [3, 4]], 'fro'); // returns 5.477225575051661 - * - * See also: - * - * abs, hypot - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the norm - * @param {number | BigNumber | string} [p=2] - * Vector space. - * Supported numbers include Infinity and -Infinity. - * Supported strings are: 'inf', '-inf', and 'fro' (The Frobenius norm) - * @return {number | BigNumber} the p-norm - */ - var norm = typed('norm', { - 'number': Math.abs, + return cs_ipvec; + } - 'Complex': function (x) { - return x.abs(); - }, + var name$128 = 'cs_ipvec'; + var path$63 = 'sparse'; + var factory_1$139 = factory$140; - 'BigNumber': function (x) { - // norm(x) = abs(x) - return x.abs(); - }, - - 'boolean' : function (x) { - // norm(x) = abs(x) - return Math.abs(x); - }, + var cs_ipvec = { + name: name$128, + path: path$63, + factory: factory_1$139 + }; - 'Array': function (x) { - return _norm(matrix$$1(x), 2); - }, - - 'Matrix': function (x) { - return _norm(x, 2); - }, + function factory$141 (type, config, load, typed) { - 'number | Complex | BigNumber | boolean, number | BigNumber | string': function (x) { - // ignore second parameter, TODO: remove the option of second parameter for these types - return norm(x); - }, + var matrix$$1 = load(matrix); + var divideScalar$$1 = load(divideScalar); + var multiplyScalar$$1 = load(multiplyScalar); + var subtract = load(subtract$1); + var equalScalar$$1 = load(equalScalar); - 'Array, number | BigNumber | string': function (x, p) { - return _norm(matrix$$1(x), p); - }, + var solveValidation$$1 = load(solveValidation); - 'Matrix, number | BigNumber | string': function (x, p) { - return _norm(x, p); - } - }); + var DenseMatrix = type.DenseMatrix; - /** - * Calculate the norm for an array - * @param {Array} x - * @param {number | string} p - * @returns {number} Returns the norm - * @private - */ - function _norm (x, p) { - // size - var sizeX = x.size(); - - // check if it is a vector - if (sizeX.length == 1) { - // check p - if (p === Number.POSITIVE_INFINITY || p === 'inf') { - // norm(x, Infinity) = max(abs(x)) - var pinf = 0; - // skip zeros since abs(0) == 0 - x.forEach( - function (value) { - var v = abs(value); - if (larger$$1(v, pinf)) - pinf = v; - }, - true); - return pinf; - } - if (p === Number.NEGATIVE_INFINITY || p === '-inf') { - // norm(x, -Infinity) = min(abs(x)) - var ninf; - // skip zeros since abs(0) == 0 - x.forEach( - function (value) { - var v = abs(value); - if (!ninf || smaller$$1(v, ninf)) - ninf = v; - }, - true); - return ninf || 0; - } - if (p === 'fro') { - return _norm(x, 2); - } - if (typeof p === 'number' && !isNaN(p)) { - // check p != 0 - if (!equalScalar$$1(p, 0)) { - // norm(x, p) = sum(abs(xi) ^ p) ^ 1/p - var n = 0; - // skip zeros since abs(0) == 0 - x.forEach( - function (value) { - n = add$$1(pow(abs(value), p), n); - }, - true); - return pow(n, 1 / p); - } - return Number.POSITIVE_INFINITY; - } - // invalid parameter value - throw new Error('Unsupported parameter value'); - } - // MxN matrix - if (sizeX.length == 2) { - // check p - if (p === 1) { - // norm(x) = the largest column sum - var c = []; + /** + * Solves the linear equation system by backward substitution. Matrix must be an upper triangular matrix. + * + * `U * x = b` + * + * Syntax: + * + * math.usolve(U, b); + * + * Examples: + * + * var a = [[-2, 3], [2, 1]]; + * var b = [11, 9]; + * var x = usolve(a, b); // [[8], [9]] + * + * See also: + * + * lup, slu, usolve, lusolve + * + * @param {Matrix, Array} U A N x N matrix or array (U) + * @param {Matrix, Array} b A column vector with the b values + * + * @return {DenseMatrix | Array} A column vector with the linear system solution (x) + */ + var usolve = typed('usolve', { + + 'SparseMatrix, Array | Matrix': function (m, b) { + // process matrix + return _sparseBackwardSubstitution(m, b); + }, + + 'DenseMatrix, Array | Matrix': function (m, b) { + // process matrix + return _denseBackwardSubstitution(m, b); + }, + + 'Array, Array | Matrix': function (a, b) { + // create dense matrix from array + var m = matrix$$1(a); + // use matrix implementation + var r = _denseBackwardSubstitution(m, b); // result - var maxc = 0; - // skip zeros since abs(0) == 0 - x.forEach( - function (value, index) { - var j = index[1]; - var cj = add$$1(c[j] || 0, abs(value)); - if (larger$$1(cj, maxc)) - maxc = cj; - c[j] = cj; - }, - true); - return maxc; + return r.valueOf(); } - if (p === Number.POSITIVE_INFINITY || p === 'inf') { - // norm(x) = the largest row sum - var r = []; - // result - var maxr = 0; - // skip zeros since abs(0) == 0 - x.forEach( - function (value, index) { - var i = index[0]; - var ri = add$$1(r[i] || 0, abs(value)); - if (larger$$1(ri, maxr)) - maxr = ri; - r[i] = ri; - }, - true); - return maxr; - } - if (p === 'fro') { - // norm(x) = sqrt(sum(diag(x'x))) - var fro = 0; - x.forEach( - function (value, index) { - fro = add$$1( fro, multiply( value, conj(value) ) ); - }); - return sqrt(fro); + }); + + var _denseBackwardSubstitution = function (m, b) { + // validate matrix and vector, return copy of column vector b + b = solveValidation$$1(m, b, true); + // column vector data + var bdata = b._data; + // rows & columns + var rows = m._size[0]; + var columns = m._size[1]; + // result + var x = []; + // arrays + var data = m._data; + // backward solve m * x = b, loop columns (backwards) + for (var j = columns - 1; j >= 0 ; j--) { + // b[j] + var bj = bdata[j][0] || 0; + // x[j] + var xj; + // backward substitution (outer product) avoids inner looping when bj == 0 + if (!equalScalar$$1(bj, 0)) { + // value @ [j, j] + var vjj = data[j][j]; + // check vjj + if (equalScalar$$1(vjj, 0)) { + // system cannot be solved + throw new Error('Linear system cannot be solved since matrix is singular'); + } + // calculate xj + xj = divideScalar$$1(bj, vjj); + // loop rows + for (var i = j - 1; i >= 0; i--) { + // update copy of b + bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, data[i][j]))]; + } + } + else { + // zero value @ j + xj = 0; + } + // update x + x[j] = [xj]; } - if (p === 2) { - // not implemented - throw new Error('Unsupported parameter value, missing implementation of matrix singular value decomposition'); + // return column vector + return new DenseMatrix({ + data: x, + size: [rows, 1] + }); + }; + + var _sparseBackwardSubstitution = function (m, b) { + // validate matrix and vector, return copy of column vector b + b = solveValidation$$1(m, b, true); + // column vector data + var bdata = b._data; + // rows & columns + var rows = m._size[0]; + var columns = m._size[1]; + // matrix arrays + var values = m._values; + var index = m._index; + var ptr = m._ptr; + // vars + var i, k; + // result + var x = []; + // backward solve m * x = b, loop columns (backwards) + for (var j = columns - 1; j >= 0 ; j--) { + // b[j] + var bj = bdata[j][0] || 0; + // backward substitution (outer product) avoids inner looping when bj == 0 + if (!equalScalar$$1(bj, 0)) { + // value @ [j, j] + var vjj = 0; + // upper triangular matrix values & index (column j) + var jvalues = []; + var jindex = []; + // first & last indeces in column + var f = ptr[j]; + var l = ptr[j + 1]; + // values in column, find value @ [j, j], loop backwards + for (k = l - 1; k >= f; k--) { + // row + i = index[k]; + // check row + if (i === j) { + // update vjj + vjj = values[k]; + } + else if (i < j) { + // store upper triangular + jvalues.push(values[k]); + jindex.push(i); + } + } + // at this point we must have a value @ [j, j] + if (equalScalar$$1(vjj, 0)) { + // system cannot be solved, there is no value @ [j, j] + throw new Error('Linear system cannot be solved since matrix is singular'); + } + // calculate xj + var xj = divideScalar$$1(bj, vjj); + // loop upper triangular + for (k = 0, l = jindex.length; k < l; k++) { + // row + i = jindex[k]; + // update copy of b + bdata[i] = [subtract(bdata[i][0], multiplyScalar$$1(xj, jvalues[k]))]; + } + // update x + x[j] = [xj]; + } + else { + // update x + x[j] = [0]; + } } - // invalid parameter value - throw new Error('Unsupported parameter value'); - } + // return vector + return new DenseMatrix({ + data: x, + size: [rows, 1] + }); + }; + + return usolve; } - norm.toTex = { - 1: '\\left\\|${args[0]}\\right\\|', - 2: undefined // use default template + var name$129 = 'usolve'; + var factory_1$140 = factory$141; + + var usolve$1 = { + name: name$129, + factory: factory_1$140 }; - return norm; -} + var isArray$4 = Array.isArray; + + function factory$142 (type, config, load, typed) { + + var matrix$$1 = load(matrix); + var lup = load(lup$1); + var slu = load(slu$1); + var cs_ipvec$$1 = load(cs_ipvec); + + var solveValidation$$1 = load(solveValidation); + + var usolve = load(usolve$1); + var lsolve = load(lsolve$1); + + /** + * Solves the linear system `A * x = b` where `A` is an [n x n] matrix and `b` is a [n] column vector. + * + * Syntax: + * + * math.lusolve(A, b) // returns column vector with the solution to the linear system A * x = b + * math.lusolve(lup, b) // returns column vector with the solution to the linear system A * x = b, lup = math.lup(A) + * + * Examples: + * + * var m = [[1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 3, 0], [0, 0, 0, 4]]; + * + * var x = math.lusolve(m, [-1, -1, -1, -1]); // x = [[-1], [-0.5], [-1/3], [-0.25]] + * + * var f = math.lup(m); + * var x1 = math.lusolve(f, [-1, -1, -1, -1]); // x1 = [[-1], [-0.5], [-1/3], [-0.25]] + * var x2 = math.lusolve(f, [1, 2, 1, -1]); // x2 = [[1], [1], [1/3], [-0.25]] + * + * var a = [[-2, 3], [2, 1]]; + * var b = [11, 9]; + * var x = math.lusolve(a, b); // [[2], [5]] + * + * See also: + * + * lup, slu, lsolve, usolve + * + * @param {Matrix | Array | Object} A Invertible Matrix or the Matrix LU decomposition + * @param {Matrix | Array} b Column Vector + * @param {number} [order] The Symbolic Ordering and Analysis order, see slu for details. Matrix must be a SparseMatrix + * @param {Number} [threshold] Partial pivoting threshold (1 for partial pivoting), see slu for details. Matrix must be a SparseMatrix. + * + * @return {DenseMatrix | Array} Column vector with the solution to the linear system A * x = b + */ + var lusolve = typed('lusolve', { + + 'Array, Array | Matrix': function (a, b) { + // convert a to matrix + a = matrix$$1(a); + // matrix lup decomposition + var d = lup(a); + // solve + var x = _lusolve(d.L, d.U, d.p, null, b); + // convert result to array + return x.valueOf(); + }, + + 'DenseMatrix, Array | Matrix': function (a, b) { + // matrix lup decomposition + var d = lup(a); + // solve + return _lusolve(d.L, d.U, d.p, null, b); + }, + + 'SparseMatrix, Array | Matrix': function (a, b) { + // matrix lup decomposition + var d = lup(a); + // solve + return _lusolve(d.L, d.U, d.p, null, b); + }, + + 'SparseMatrix, Array | Matrix, number, number': function (a, b, order, threshold) { + // matrix lu decomposition + var d = slu(a, order, threshold); + // solve + return _lusolve(d.L, d.U, d.p, d.q, b); + }, + + 'Object, Array | Matrix': function (d, b) { + // solve + return _lusolve(d.L, d.U, d.p, d.q, b); + } + }); + + var _toMatrix = function (a) { + // check it is a matrix + if (type.isMatrix(a)) + return a; + // check array + if (isArray$4(a)) + return matrix$$1(a); + // throw + throw new TypeError('Invalid Matrix LU decomposition'); + }; + + var _lusolve = function (l, u, p, q, b) { + // verify L, U, P + l = _toMatrix(l); + u = _toMatrix(u); + // validate matrix and vector + b = solveValidation$$1(l, b, false); + // apply row permutations if needed (b is a DenseMatrix) + if (p) + b._data = cs_ipvec$$1(p, b._data); + // use forward substitution to resolve L * y = b + var y = lsolve(l, b); + // use backward substitution to resolve U * x = y + var x = usolve(u, y); + // apply column permutations if needed (x is a DenseMatrix) + if (q) + x._data = cs_ipvec$$1(q, x._data); + // return solution + return x; + }; -var name$154 = 'norm'; -var factory_1$165 = factory$166; + return lusolve; + } -var norm$1 = { - name: name$154, - factory: factory_1$165 -}; + var name$130 = 'lusolve'; + var factory_1$141 = factory$142; -function factory$167 (type, config, load, typed) { + var lusolve$1 = { + name: name$130, + factory: factory_1$141 + }; - var matrix$$1 = load(matrix); + var algebra = [ + derivative$1, - var algorithm01$$1 = load(algorithm01); - var algorithm02$$1 = load(algorithm02); - var algorithm06$$1 = load(algorithm06); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + // simplify + simplify$1, - /** - * Calculate the nth root of a value. - * The principal nth root of a positive real number A, is the positive real - * solution of the equation - * - * x^root = A - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.nthRoot(a) - * math.nthRoot(a, root) - * - * Examples: - * - * math.nthRoot(9, 2); // returns 3, as 3^2 == 9 - * math.sqrt(9); // returns 3, as 3^2 == 9 - * math.nthRoot(64, 3); // returns 4, as 4^3 == 64 - * - * See also: - * - * sqrt, pow - * - * @param {number | BigNumber | Array | Matrix | Complex} a - * Value for which to calculate the nth root - * @param {number | BigNumber} [root=2] The root. - * @return {number | Complex | Array | Matrix} Returns the nth root of `a` - */ - var nthRoot = typed('nthRoot', { + // polynomial + rationalize$1, + - 'number': function (x) { - return _nthRoot(x, 2); - }, - 'number, number': _nthRoot, + // decomposition + qr$1, + lup$1, + slu$1, + + // solver + lsolve$1, + lusolve$1, + usolve$1 + ]; - 'BigNumber': function (x) { - return _bigNthRoot(x, new type.BigNumber(2)); - }, - 'Complex' : function(x) { - return _nthComplexRoot(x, 2); - }, - 'Complex, number' : _nthComplexRoot, - 'BigNumber, BigNumber': _bigNthRoot, - - 'Array | Matrix': function (x) { - return nthRoot(x, 2); - }, + function factory$143 (type, config, load, typed) { + /** + * Test whether a value is negative: smaller than zero. + * The function supports types `number`, `BigNumber`, `Fraction`, and `Unit`. + * + * The function is evaluated element-wise in case of Array or Matrix input. + * + * Syntax: + * + * math.isNegative(x) + * + * Examples: + * + * math.isNegative(3); // returns false + * math.isNegative(-2); // returns true + * math.isNegative(0); // returns false + * math.isNegative(-0); // returns false + * math.isNegative(math.bignumber(2)); // returns false + * math.isNegative(math.fraction(-2, 5)); // returns true + * math.isNegative('-2'); // returns true + * math.isNegative([2, 0, -3]'); // returns [false, false, true] + * + * See also: + * + * isNumeric, isPositive, isZero, isInteger + * + * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested + * @return {boolean} Returns true when `x` is larger than zero. + * Throws an error in case of an unknown data type. + */ + var isNegative = typed('isNegative', { + 'number': function (x) { + return x < 0; + }, - 'SparseMatrix, SparseMatrix': function (x, y) { - // density must be one (no zeros in matrix) - if (y.density() === 1) { - // sparse + sparse - return algorithm06$$1(x, y, nthRoot); - } - else { - // throw exception - throw new Error('Root must be non-zero'); - } - }, + 'BigNumber': function (x) { + return x.isNeg() && !x.isZero() && !x.isNaN(); + }, - 'SparseMatrix, DenseMatrix': function (x, y) { - return algorithm02$$1(y, x, nthRoot, true); - }, + 'Fraction': function (x) { + return x.s < 0; // It's enough to decide on the sign + }, - 'DenseMatrix, SparseMatrix': function (x, y) { - // density must be one (no zeros in matrix) - if (y.density() === 1) { - // dense + sparse - return algorithm01$$1(x, y, nthRoot, false); - } - else { - // throw exception - throw new Error('Root must be non-zero'); + 'Unit': function (x) { + return isNegative(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, isNegative); } - }, + }); - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, nthRoot); - }, + return isNegative; + } - 'Array, Array': function (x, y) { - // use matrix implementation - return nthRoot(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + var name$131 = 'isNegative'; + var factory_1$142 = factory$143; - 'Array, Matrix': function (x, y) { - // use matrix implementation - return nthRoot(matrix$$1(x), y); - }, + var isNegative$1 = { + name: name$131, + factory: factory_1$142 + }; - 'Matrix, Array': function (x, y) { - // use matrix implementation - return nthRoot(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm11$$1(x, y, nthRoot, false); - }, + function factory$144 (type, config, load, typed) { + var unaryMinus = load(unaryMinus$1); + var isNegative = load(isNegative$1); + var matrix$$1 = load(matrix); - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, nthRoot, false); - }, + /** + * Calculate the cubic root of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.cbrt(x) + * math.cbrt(x, allRoots) + * + * Examples: + * + * math.cbrt(27); // returns 3 + * math.cube(3); // returns 27 + * math.cbrt(-64); // returns -4 + * math.cbrt(math.unit('27 m^3')); // returns Unit 3 m + * math.cbrt([27, 64, 125]); // returns [3, 4, 5] + * + * var x = math.complex('8i'); + * math.cbrt(x); // returns Complex 1.7320508075689 + i + * math.cbrt(x, true); // returns Matrix [ + * // 1.7320508075689 + i + * // -1.7320508075689 + i + * // -2i + * // ] + * + * See also: + * + * square, sqrt, cube + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x + * Value for which to calculate the cubic root. + * @param {boolean} [allRoots] Optional, false by default. Only applicable + * when `x` is a number or complex number. If true, all complex + * roots are returned, if false (default) the principal root is + * returned. + * @return {number | BigNumber | Complex | Unit | Array | Matrix} + * Returns the cubic root of `x` + */ + var cbrt = typed('cbrt', { + 'number': _cbrtNumber, + // note: signature 'number, boolean' is also supported, + // created by typed as it knows how to convert number to Complex - 'number | BigNumber, SparseMatrix': function (x, y) { - // density must be one (no zeros in matrix) - if (y.density() === 1) { - // sparse - scalar - return algorithm11$$1(y, x, nthRoot, true); - } - else { - // throw exception - throw new Error('Root must be non-zero'); - } - }, + 'Complex': _cbrtComplex, - 'number | BigNumber, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, nthRoot, true); - }, + 'Complex, boolean': _cbrtComplex, - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return nthRoot(matrix$$1(x), y).valueOf(); - }, + 'BigNumber': function (x) { + return x.cbrt(); + }, - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return nthRoot(x, matrix$$1(y)).valueOf(); - } - }); + 'Unit': _cbrtUnit, - nthRoot.toTex = {2: '\\sqrt[${args[1]}]{${args[0]}}'}; + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since cbrt(0) = 0 + return deepMap(x, cbrt, true); + } + }); - return nthRoot; + /** + * Calculate the cubic root for a complex number + * @param {Complex} x + * @param {boolean} [allRoots] If true, the function will return an array + * with all three roots. If false or undefined, + * the principal root is returned. + * @returns {Complex | Array. | Matrix.} Returns the cubic root(s) of x + * @private + */ + function _cbrtComplex(x, allRoots) { + // https://www.wikiwand.com/en/Cube_root#/Complex_numbers - /** - * Calculate the nth root of a for BigNumbers, solve x^root == a - * http://rosettacode.org/wiki/Nth_root#JavaScript - * @param {BigNumber} a - * @param {BigNumber} root - * @private - */ - function _bigNthRoot(a, root) { - var precision = type.BigNumber.precision; - var Big = type.BigNumber.clone({precision: precision + 2}); - var zero = new type.BigNumber(0); + var arg_3 = x.arg() / 3; + var abs = x.abs(); - var one = new Big(1); - var inv = root.isNegative(); - if (inv) { - root = root.neg(); - } + // principal root: + var principal = new type.Complex(_cbrtNumber(abs), 0).mul( + new type.Complex(0, arg_3).exp()); - if (root.isZero()) { - throw new Error('Root must be non-zero'); - } - if (a.isNegative() && !root.abs().mod(2).equals(1)) { - throw new Error('Root must be odd when a is negative.'); - } + if (allRoots) { + var all = [ + principal, + new type.Complex(_cbrtNumber(abs), 0).mul( + new type.Complex(0, arg_3 + Math.PI * 2 / 3).exp()), + new type.Complex(_cbrtNumber(abs), 0).mul( + new type.Complex(0, arg_3 - Math.PI * 2 / 3).exp()) + ]; - // edge cases zero and infinity - if (a.isZero()) { - return inv ? new Big(Infinity) : 0; - } - if (!a.isFinite()) { - return inv ? zero : a; + return (config.matrix === 'Array') ? all : matrix$$1(all); + } + else { + return principal; + } } - var x = a.abs().pow(one.div(root)); - // If a < 0, we require that root is an odd integer, - // so (-1) ^ (1/root) = -1 - x = a.isNeg() ? x.neg() : x; - return new type.BigNumber((inv ? one.div(x) : x).toPrecision(precision)); - } -} + /** + * Calculate the cubic root for a Unit + * @param {Unit} x + * @return {Unit} Returns the cubic root of x + * @private + */ + function _cbrtUnit(x) { + if(x.value && type.isComplex(x.value)) { + var result = x.clone(); + result.value = 1.0; + result = result.pow(1.0/3); // Compute the units + result.value = _cbrtComplex(x.value); // Compute the value + return result; + } + else { + var negate = isNegative(x.value); + if (negate) { + x.value = unaryMinus(x.value); + } -/** - * Calculate the nth root of a, solve x^root == a - * http://rosettacode.org/wiki/Nth_root#JavaScript - * @param {number} a - * @param {number} root - * @private - */ -function _nthRoot(a, root) { - var inv = root < 0; - if (inv) { - root = -root; - } + // TODO: create a helper function for this + var third; + if (type.isBigNumber(x.value)) { + third = new type.BigNumber(1).div(3); + } + else if (type.isFraction(x.value)) { + third = new type.Fraction(1, 3); + } + else { + third = 1/3; + } - if (root === 0) { - throw new Error('Root must be non-zero'); - } - if (a < 0 && (Math.abs(root) % 2 != 1)) { - throw new Error('Root must be odd when a is negative.'); - } + var result = x.pow(third); - // edge cases zero and infinity - if (a == 0) { - return inv ? Infinity : 0; - } - if (!isFinite(a)) { - return inv ? 0 : a; - } + if (negate) { + result.value = unaryMinus(result.value); + } - var x = Math.pow(Math.abs(a), 1/root); - // If a < 0, we require that root is an odd integer, - // so (-1) ^ (1/root) = -1 - x = a < 0 ? -x : x; - return inv ? 1 / x : x; + return result; + } + } - // Very nice algorithm, but fails with nthRoot(-2, 3). - // Newton's method has some well-known problems at times: - // https://en.wikipedia.org/wiki/Newton%27s_method#Failure_analysis - /* - var x = 1; // Initial guess - var xPrev = 1; - var i = 0; - var iMax = 10000; - do { - var delta = (a / Math.pow(x, root - 1) - x) / root; - xPrev = x; - x = x + delta; - i++; - } - while (xPrev !== x && i < iMax); + cbrt.toTex = {1: '\\sqrt[3]{${args[0]}}'}; - if (xPrev !== x) { - throw new Error('Function nthRoot failed to converge'); + return cbrt; } - return inv ? 1 / x : x; - */ -} - -/** - * Calculate the nth root of a Complex Number a using De Moviers Theorem. - * @param {Complex} a - * @param {number} root - * @return {Array} array or n Complex Roots in Polar Form. - */ -function _nthComplexRoot(a, root) { - if (root < 0) throw new Error('Root must be greater than zero'); - if (root === 0) throw new Error('Root must be non-zero'); - if (root % 1 !== 0) throw new Error('Root must be an integer'); - var arg = a.arg(); - var abs = a.abs(); - var roots = []; - var r = Math.pow(abs, 1/root); - for(var k = 0; k < root; k++) { - roots.push({r: r, phi: (arg + 2 * Math.PI * k)/root}); - } - return roots; -} - -var name$155 = 'nthRoot'; -var factory_1$166 = factory$167; - -var nthRoot$1 = { - name: name$155, - factory: factory_1$166 -}; - -var isInteger$11 = number.isInteger; -var toFixed = number.toFixed; - - -var NO_INT = 'Number of decimals in function round must be an integer'; - -function factory$168 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - var zeros = load(zeros$1); - - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm14$$1 = load(algorithm14); - /** - * Round a value towards the nearest integer. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.round(x) - * math.round(x, n) - * - * Examples: - * - * math.round(3.2); // returns number 3 - * math.round(3.8); // returns number 4 - * math.round(-4.2); // returns number -4 - * math.round(-4.7); // returns number -5 - * math.round(math.pi, 3); // returns number 3.142 - * math.round(123.45678, 2); // returns number 123.46 - * - * var c = math.complex(3.2, -2.7); - * math.round(c); // returns Complex 3 - 3i + * Calculate cbrt for a number * - * math.round([3.2, 3.8, -4.7]); // returns Array [3, 4, -5] + * Code from es6-shim.js: + * https://github.com/paulmillr/es6-shim/blob/master/es6-shim.js#L1564-L1577 * - * See also: - * - * ceil, fix, floor - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded - * @param {number | BigNumber | Array} [n=0] Number of decimals - * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value + * @param {number} x + * @returns {number | Complex} Returns the cubic root of x + * @private */ - var round = typed('round', { + var _cbrtNumber = Math.cbrt || function (x) { + if (x === 0) { + return x; + } - 'number': Math.round, + var negate = x < 0; + var result; + if (negate) { + x = -x; + } - 'number, number': function (x, n) { - if (!isInteger$11(n)) {throw new TypeError(NO_INT);} - if (n < 0 || n > 15) {throw new Error('Number of decimals in function round must be in te range of 0-15');} + if (isFinite(x)) { + result = Math.exp(Math.log(x) / 3); + // from http://en.wikipedia.org/wiki/Cube_root#Numerical_methods + result = (x / (result * result) + (2 * result)) / 3; + } else { + result = x; + } - return _round(x, n); - }, + return negate ? -result : result; + }; - 'Complex': function (x) { - return x.round(); - }, + var name$132 = 'cbrt'; + var factory_1$143 = factory$144; - 'Complex, number': function (x, n) { - if (n % 1) {throw new TypeError(NO_INT);} - - return x.round(n); - }, + var cbrt$1 = { + name: name$132, + factory: factory_1$143 + }; - 'Complex, BigNumber': function (x, n) { - if (!n.isInteger()) {throw new TypeError(NO_INT);} - - var _n = n.toNumber(); - return x.round(_n); - }, - - 'number, BigNumber': function (x, n) { - if (!n.isInteger()) {throw new TypeError(NO_INT);} - - return new type.BigNumber(x).toDecimalPlaces(n.toNumber()); - }, - - 'BigNumber': function (x) { - return x.toDecimalPlaces(0); - }, - - 'BigNumber, BigNumber': function (x, n) { - if (!n.isInteger()) {throw new TypeError(NO_INT);} - - return x.toDecimalPlaces(n.toNumber()); - }, - - 'Fraction': function (x) { - return x.round(); - }, - - 'Fraction, number': function (x, n) { - if (n % 1) {throw new TypeError(NO_INT);} - return x.round(n); - }, + function factory$145 (type, config, load, typed) { + /** + * Round a value towards plus infinity + * If `x` is complex, both real and imaginary part are rounded towards plus infinity. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.ceil(x) + * + * Examples: + * + * math.ceil(3.2); // returns number 4 + * math.ceil(3.8); // returns number 4 + * math.ceil(-4.2); // returns number -4 + * math.ceil(-4.7); // returns number -4 + * + * var c = math.complex(3.2, -2.7); + * math.ceil(c); // returns Complex 4 - 2i + * + * math.ceil([3.2, 3.8, -4.7]); // returns Array [4, 4, -4] + * + * See also: + * + * floor, fix, round + * + * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded + * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value + */ + var ceil = typed('ceil', { + 'number': Math.ceil, - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since round(0) = 0 - return deepMap(x, round, true); - }, + 'Complex': function (x) { + return x.ceil(); + }, - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm11$$1(x, y, round, false); - }, + 'BigNumber': function (x) { + return x.ceil(); + }, - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, round, false); - }, + 'Fraction': function (x) { + return x.ceil(); + }, - 'number | Complex | BigNumber, SparseMatrix': function (x, y) { - // check scalar is zero - if (equalScalar$$1(x, 0)) { - // do not execute algorithm, result will be a zero matrix - return zeros(y.size(), y.storage()); + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since ceil(0) = 0 + return deepMap(x, ceil, true); } - return algorithm12$$1(y, x, round, true); - }, + }); - 'number | Complex | BigNumber, DenseMatrix': function (x, y) { - // check scalar is zero - if (equalScalar$$1(x, 0)) { - // do not execute algorithm, result will be a zero matrix - return zeros(y.size(), y.storage()); - } - return algorithm14$$1(y, x, round, true); - }, + ceil.toTex = {1: '\\left\\lceil${args[0]}\\right\\rceil'}; - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, round, false).valueOf(); - }, + return ceil; + } - 'number | Complex | BigNumber, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, round, true).valueOf(); - } - }); + var name$133 = 'ceil'; + var factory_1$144 = factory$145; - round.toTex = { - 1: '\\left\\lfloor${args[0]}\\right\\rceil', - 2: undefined // use default template + var ceil$1 = { + name: name$133, + factory: factory_1$144 }; - return round; -} - -/** - * round a number to the given number of decimals, or to zero if decimals is - * not provided - * @param {number} value - * @param {number} decimals number of decimals, between 0 and 15 (0 by default) - * @return {number} roundedValue - * @private - */ -function _round (value, decimals) { - return parseFloat(toFixed(value, decimals)); -} - -var name$156 = 'round'; -var factory_1$167 = factory$168; + function factory$146 (type, config, load, typed) { -var round$1 = { - name: name$156, - factory: factory_1$167 -}; + /** + * Compute the cube of a value, `x * x * x`. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.cube(x) + * + * Examples: + * + * math.cube(2); // returns number 8 + * math.pow(2, 3); // returns number 8 + * math.cube(4); // returns number 64 + * 4 * 4 * 4; // returns number 64 + * + * math.cube([1, 2, 3, 4]); // returns Array [1, 8, 27, 64] + * + * See also: + * + * multiply, square, pow, cbrt + * + * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x Number for which to calculate the cube + * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} Cube of x + */ + var cube = typed('cube', { + 'number': function (x) { + return x * x * x; + }, -function factory$169 (type, config, load, typed) { - /** - * Compute the square of a value, `x * x`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.square(x) - * - * Examples: - * - * math.square(2); // returns number 4 - * math.square(3); // returns number 9 - * math.pow(3, 2); // returns number 9 - * math.multiply(3, 3); // returns number 9 - * - * math.square([1, 2, 3, 4]); // returns Array [1, 4, 9, 16] - * - * See also: - * - * multiply, cube, sqrt, pow - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x - * Number for which to calculate the square - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} - * Squared value - */ - var square = typed('square', { - 'number': function (x) { - return x * x; - }, + 'Complex': function (x) { + return x.mul(x).mul(x); // Is faster than pow(x, 3) + }, - 'Complex': function (x) { - return x.mul(x); - }, + 'BigNumber': function (x) { + return x.times(x).times(x); + }, - 'BigNumber': function (x) { - return x.times(x); - }, + 'Fraction': function (x) { + return x.pow(3); // Is faster than mul()mul()mul() + }, - 'Fraction': function (x) { - return x.mul(x); - }, + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since cube(0) = 0 + return deepMap(x, cube, true); + }, - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since square(0) = 0 - return deepMap(x, square, true); - }, + 'Unit': function(x) { + return x.pow(3); + } + }); - 'Unit': function(x) { - return x.pow(2); - } - }); + cube.toTex = {1: '\\left(${args[0]}\\right)^3'}; - square.toTex = {1: '\\left(${args[0]}\\right)^2'}; + return cube; + } - return square; -} + var name$134 = 'cube'; + var factory_1$145 = factory$146; -var name$157 = 'square'; -var factory_1$168 = factory$169; + var cube$1 = { + name: name$134, + factory: factory_1$145 + }; -var square$1 = { - name: name$157, - factory: factory_1$168 -}; + function factory$147 (type, config, load, typed) { -function factory$170 (type, config, load, typed) { - var latex$$1 = latex; + var equalScalar$$1 = load(equalScalar); - /** - * Unary plus operation. - * Boolean values and strings will be converted to a number, numeric values will be returned as is. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.unaryPlus(x) - * - * Examples: - * - * math.unaryPlus(3.5); // returns 3.5 - * math.unaryPlus(1); // returns 1 - * - * See also: - * - * unaryMinus, add, subtract - * - * @param {number | BigNumber | Fraction | string | Complex | Unit | Array | Matrix} x - * Input value - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} - * Returns the input value when numeric, converts to a number when input is non-numeric. - */ - var unaryPlus = typed('unaryPlus', { - 'number': function (x) { - return x; - }, + var SparseMatrix = type.SparseMatrix; - 'Complex': function (x) { - return x; // complex numbers are immutable - }, + /** + * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). + * Callback function invoked NNZ times (number of nonzero items in SparseMatrix). + * + * + * ┌ f(Dij, Sij) ; S(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} denseMatrix The DenseMatrix instance (D) + * @param {Matrix} sparseMatrix The SparseMatrix instance (S) + * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) + * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 + */ + var algorithm02 = function (denseMatrix, sparseMatrix, callback, inverse) { + // dense matrix arrays + var adata = denseMatrix._data; + var asize = denseMatrix._size; + var adt = denseMatrix._datatype; + // sparse matrix arrays + var bvalues = sparseMatrix._values; + var bindex = sparseMatrix._index; + var bptr = sparseMatrix._ptr; + var bsize = sparseMatrix._size; + var bdt = sparseMatrix._datatype; - 'BigNumber': function (x) { - return x; // bignumbers are immutable - }, + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - 'Fraction': function (x) { - return x; // fractions are immutable - }, + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - 'Unit': function (x) { - return x.clone(); - }, + // sparse matrix cannot be a Pattern matrix + if (!bvalues) + throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since unaryPlus(0) = 0 - return deepMap(x, unaryPlus, true); - }, + // rows & columns + var rows = asize[0]; + var columns = asize[1]; + + // datatype + var dt; + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // find signature that matches (dt, dt) + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result (SparseMatrix) + var cvalues = []; + var cindex = []; + var cptr = []; + + // loop columns in b + for (var j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // values in column j + for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + var i = bindex[k]; + // update C(i,j) + var cij = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); + // check for nonzero + if (!eq(cij, zero)) { + // push i & v + cindex.push(i); + cvalues.push(cij); + } + } + } + // update cptr + cptr[columns] = cindex.length; + + // return sparse matrix + return new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); + }; + + return algorithm02; + } - 'boolean | string': function (x) { - // convert to a number or bignumber - return (config.number == 'BigNumber') ? new type.BigNumber(+x): +x; - } - }); + var name$135 = 'algorithm02'; + var factory_1$146 = factory$147; - unaryPlus.toTex = { - 1: latex$$1.operators['unaryPlus'] + '\\left(${args[0]}\\right)' + var algorithm02 = { + name: name$135, + factory: factory_1$146 }; - return unaryPlus; -} - -var name$158 = 'unaryPlus'; -var factory_1$169 = factory$170; - -var unaryPlus$1 = { - name: name$158, - factory: factory_1$169 -}; + function factory$148 (type, config, load, typed) { -var isInteger$12 = number.isInteger; + var matrix$$1 = load(matrix); + var divideScalar$$1 = load(divideScalar); + var latex$$1 = latex; + + var algorithm02$$1 = load(algorithm02); + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm11$$1 = load(algorithm11); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); -function factory$171 (type, config, load, typed) { - var matrix$$1 = load(matrix); + /** + * Divide two matrices element wise. The function accepts both matrices and + * scalar values. + * + * Syntax: + * + * math.dotDivide(x, y) + * + * Examples: + * + * math.dotDivide(2, 4); // returns 0.5 + * + * a = [[9, 5], [6, 1]]; + * b = [[3, 2], [5, 2]]; + * + * math.dotDivide(a, b); // returns [[3, 2.5], [1.2, 0.5]] + * math.divide(a, b); // returns [[1.75, 0.75], [-1.75, 2.25]] + * + * See also: + * + * divide, multiply, dotMultiply + * + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Numerator + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Denominator + * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Quotient, `x ./ y` + */ + var dotDivide = typed('dotDivide', { + + 'any, any': divideScalar$$1, - /** - * Calculate the extended greatest common divisor for two values. - * See http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm. - * - * Syntax: - * - * math.xgcd(a, b) - * - * Examples: - * - * math.xgcd(8, 12); // returns [4, -1, 1] - * math.gcd(8, 12); // returns 4 - * math.xgcd(36163, 21199); // returns [1247, -7, 12] - * - * See also: - * - * gcd, lcm - * - * @param {number | BigNumber} a An integer number - * @param {number | BigNumber} b An integer number - * @return {Array} Returns an array containing 3 integers `[div, m, n]` - * where `div = gcd(a, b)` and `a*m + b*n = div` - */ - var xgcd = typed('xgcd', { - 'number, number': _xgcd, - 'BigNumber, BigNumber': _xgcdBigNumber - // TODO: implement support for Fraction - }); + 'SparseMatrix, SparseMatrix': function (x, y) { + return algorithm07$$1(x, y, divideScalar$$1, false); + }, - xgcd.toTex = undefined; // use default template + 'SparseMatrix, DenseMatrix': function (x, y) { + return algorithm02$$1(y, x, divideScalar$$1, true); + }, - return xgcd; + 'DenseMatrix, SparseMatrix': function (x, y) { + return algorithm03$$1(x, y, divideScalar$$1, false); + }, - /** - * Calculate xgcd for two numbers - * @param {number} a - * @param {number} b - * @return {number} result - * @private - */ - function _xgcd (a, b) { - // source: http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - var t, // used to swap two variables - q, // quotient - r, // remainder - x = 0, lastx = 1, - y = 1, lasty = 0; + 'DenseMatrix, DenseMatrix': function (x, y) { + return algorithm13$$1(x, y, divideScalar$$1); + }, - if (!isInteger$12(a) || !isInteger$12(b)) { - throw new Error('Parameters in function xgcd must be integer numbers'); - } + 'Array, Array': function (x, y) { + // use matrix implementation + return dotDivide(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - while (b) { - q = Math.floor(a / b); - r = a - q*b; + 'Array, Matrix': function (x, y) { + // use matrix implementation + return dotDivide(matrix$$1(x), y); + }, - t = x; - x = lastx - q * x; - lastx = t; + 'Matrix, Array': function (x, y) { + // use matrix implementation + return dotDivide(x, matrix$$1(y)); + }, - t = y; - y = lasty - q * y; - lasty = t; + 'SparseMatrix, any': function (x, y) { + return algorithm11$$1(x, y, divideScalar$$1, false); + }, - a = b; - b = r; - } + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, divideScalar$$1, false); + }, - var res; - if (a < 0) { - res = [-a, -lastx, -lasty]; - } - else { - res = [a, a ? lastx : 0, lasty]; - } - return (config.matrix === 'Array') ? res : matrix$$1(res); - } + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, divideScalar$$1, true); + }, - /** - * Calculate xgcd for two BigNumbers - * @param {BigNumber} a - * @param {BigNumber} b - * @return {BigNumber[]} result - * @private - */ - function _xgcdBigNumber(a, b) { - // source: http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - var t, // used to swap two variables - q, // quotient - r, // remainder - zero = new type.BigNumber(0), - one = new type.BigNumber(1), - x = zero, - lastx = one, - y = one, - lasty = zero; - - if (!a.isInt() || !b.isInt()) { - throw new Error('Parameters in function xgcd must be integer numbers'); - } - - while (!b.isZero()) { - q = a.div(b).floor(); - r = a.mod(b); - - t = x; - x = lastx.minus(q.times(x)); - lastx = t; - - t = y; - y = lasty.minus(q.times(y)); - lasty = t; + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, divideScalar$$1, true); + }, - a = b; - b = r; - } + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, divideScalar$$1, false).valueOf(); + }, - var res; - if (a.lt(zero)) { - res = [a.neg(), lastx.neg(), lasty.neg()]; - } - else { - res = [a, !a.isZero() ? lastx : 0, lasty]; - } - return (config.matrix === 'Array') ? res : matrix$$1(res); - } -} - -var name$159 = 'xgcd'; -var factory_1$170 = factory$171; - -var xgcd$1 = { - name: name$159, - factory: factory_1$170 -}; - -var arithmetic = [ - abs$1, - add, - addScalar, - cbrt$1, - ceil$1, - cube$1, - divide$1, - dotDivide$1, - dotMultiply$1, - dotPow$1, - exp$1, - expm1$1, - fix$1, - floor$1, - gcd$1, - hypot$1, - lcm$1, - log$1, - log10$1, - log1p$1, - log2$1, - mod$1, - multiply$1, - norm$1, - nthRoot$1, - pow$1, - round$1, - sign$1, - sqrt$1, - square$1, - subtract$1, - unaryMinus$1, - unaryPlus$1, - xgcd$1 -]; - -/** - * Bitwise not - * @param {BigNumber} value - * @return {BigNumber} Result of ~`x`, fully precise - * - */ -var bitNot$1 = function bitNot (x) { - if (x.isFinite() && !x.isInteger()) { - throw new Error('Integer expected in function bitNot'); - } - - var BigNumber = x.constructor; - var prevPrec = BigNumber.precision; - BigNumber.config({precision: 1E9}); - - var x = x.plus(new BigNumber(1)); - x.s = -x.s || null; - - BigNumber.config({precision: prevPrec}); - return x; -}; - -/** - * Applies bitwise function to numbers - * @param {BigNumber} x - * @param {BigNumber} y - * @param {function (a, b)} func - * @return {BigNumber} - */ -var bitwise = function bitwise(x, y, func) { - var BigNumber = x.constructor; - - var xBits, yBits; - var xSign = +(x.s < 0); - var ySign = +(y.s < 0); - if (xSign) { - xBits = decCoefficientToBinaryString(bitNot$1(x)); - for (var i = 0; i < xBits.length; ++i) { - xBits[i] ^= 1; - } - } else { - xBits = decCoefficientToBinaryString(x); - } - if (ySign) { - yBits = decCoefficientToBinaryString(bitNot$1(y)); - for (var i = 0; i < yBits.length; ++i) { - yBits[i] ^= 1; - } - } else { - yBits = decCoefficientToBinaryString(y); - } + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, divideScalar$$1, true).valueOf(); + } + }); - var minBits, maxBits, minSign; - if (xBits.length <= yBits.length) { - minBits = xBits; - maxBits = yBits; - minSign = xSign; - } else { - minBits = yBits; - maxBits = xBits; - minSign = ySign; + dotDivide.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['dotDivide'] + '${args[1]}\\right)' + }; + + return dotDivide; } - var shortLen = minBits.length; - var longLen = maxBits.length; - var expFuncVal = func(xSign, ySign) ^ 1; - var outVal = new BigNumber(expFuncVal ^ 1); - var twoPower = new BigNumber(1); - var two = new BigNumber(2); + var name$136 = 'dotDivide'; + var factory_1$147 = factory$148; - var prevPrec = BigNumber.precision; - BigNumber.config({precision: 1E9}); + var dotDivide$1 = { + name: name$136, + factory: factory_1$147 + }; - while (shortLen > 0) { - if (func(minBits[--shortLen], maxBits[--longLen]) == expFuncVal) { - outVal = outVal.plus(twoPower); - } - twoPower = twoPower.times(two); - } - while (longLen > 0) { - if (func(minSign, maxBits[--longLen]) == expFuncVal) { - outVal = outVal.plus(twoPower); - } - twoPower = twoPower.times(two); - } + function factory$149 (type, config, load, typed) { - BigNumber.config({precision: prevPrec}); + var equalScalar$$1 = load(equalScalar); - if (expFuncVal == 0) { - outVal.s = -outVal.s; - } - return outVal; -}; + var SparseMatrix = type.SparseMatrix; -/* Extracted from decimal.js, and edited to specialize. */ -function decCoefficientToBinaryString (x) { - // Convert to string - var a = x.d; // array with digits - var r = a[0] + ''; + /** + * Iterates over SparseMatrix A and invokes the callback function f(Aij, Bij). + * Callback function invoked NZA times, number of nonzero elements in A. + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {Function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm09 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + // sparse matrix arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; - for (var i = 1; i < a.length; ++i) { - var s = a[i] + ''; - for (var z = 7 - s.length; z--; ) { - s = '0' + s; - } + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - r += s; - } + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - var j; - for (j = r.length - 1; r.charAt(j) == '0'; --j); + // rows & columns + var rows = asize[0]; + var columns = asize[1]; - var xe = x.e; - var str = r.slice(0, j + 1 || 1); - var strL = str.length; - if (xe > 0) { - if (++xe > strL) { - // Append zeros. - for (xe -= strL; xe--; str += '0'); - } else if (xe < strL) { - str = str.slice(0, xe) + '.' + str.slice(xe); - } - } + // datatype + var dt; + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // find signature that matches (dt, dt) + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result arrays + var cvalues = avalues && bvalues ? [] : undefined; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); - // Convert from base 10 (decimal) to base 2 - var arr = [0]; - for (var i = 0; i < str.length; ) { - for (var arrL = arr.length; arrL--; arr[arrL] *= 10); + // workspaces + var x = cvalues ? [] : undefined; + // marks indicating we have a value in x for a given column + var w = []; - arr[0] += str.charAt(i++) << 0; // convert to int - for (var j = 0; j < arr.length; ++j) { - if (arr[j] > 1) { - if (arr[j + 1] == null) { - arr[j + 1] = 0; + // vars + var i, j, k, k0, k1; + + // loop columns + for (j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // column mark + var mark = j + 1; + // check we need to process values + if (x) { + // loop B(:,j) + for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + i = bindex[k]; + // update workspace + w[i] = mark; + x[i] = bvalues[k]; + } + } + // loop A(:,j) + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // check we need to process values + if (x) { + // b value @ i,j + var vb = w[i] === mark ? x[i] : zero; + // invoke f + var vc = cf(avalues[k], vb); + // check zero value + if (!eq(vc, zero)) { + // push index + cindex.push(i); + // push value + cvalues.push(vc); + } + } + else { + // push index + cindex.push(i); + } } - - arr[j + 1] += arr[j] >> 1; - arr[j] &= 1; } - } - } + // update cptr + cptr[columns] = cindex.length; - return arr.reverse(); -} + // return sparse matrix + return c; + }; -/** - * Bitwise and for Bignumbers - * - * Special Cases: - * N & n = N - * n & 0 = 0 - * n & -1 = n - * n & n = n - * I & I = I - * -I & -I = -I - * I & -I = 0 - * I & n = n - * I & -n = I - * -I & n = 0 - * -I & -n = -I - * - * @param {BigNumber} x - * @param {BigNumber} y - * @return {BigNumber} Result of `x` & `y`, is fully precise - * @private - */ -var bitAnd$1 = function bitAnd(x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function bitAnd'); + return algorithm09; } - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN()) { - return new BigNumber(NaN); - } + var name$137 = 'algorithm09'; + var factory_1$148 = factory$149; - if (x.isZero() || y.eq(-1) || x.eq(y)) { - return x; - } - if (y.isZero() || x.eq(-1)) { - return y; - } + var algorithm09 = { + name: name$137, + factory: factory_1$148 + }; - if (!x.isFinite() || !y.isFinite()) { - if (!x.isFinite() && !y.isFinite()) { - if (x.isNegative() == y.isNegative()) { - return x; - } - return new BigNumber(0); - } - if (!x.isFinite()) { - if (y.isNegative()) { - return x; - } - if (x.isNegative()) { - return new BigNumber(0); - } - return y; - } - if (!y.isFinite()) { - if (x.isNegative()) { - return y; - } - if (y.isNegative()) { - return new BigNumber(0); - } - return x; - } - } - return bitwise(x, y, function (a, b) { return a & b }); -}; - -var isInteger$13 = number.isInteger; - - -function factory$172 (type, config, load, typed) { - var latex$$1 = latex; + function factory$150 (type, config, load, typed) { - var matrix$$1 = load(matrix); + var matrix$$1 = load(matrix); + var multiplyScalar$$1 = load(multiplyScalar); + var latex$$1 = latex; - var algorithm02$$1 = load(algorithm02); - var algorithm06$$1 = load(algorithm06); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise AND two values, `x & y`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.bitAnd(x, y) - * - * Examples: - * - * math.bitAnd(53, 131); // returns number 1 - * - * math.bitAnd([1, 12, 31], 42); // returns Array [0, 8, 10] - * - * See also: - * - * bitNot, bitOr, bitXor, leftShift, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x First value to and - * @param {number | BigNumber | Array | Matrix} y Second value to and - * @return {number | BigNumber | Array | Matrix} AND of `x` and `y` - */ - var bitAnd = typed('bitAnd', { + var algorithm02$$1 = load(algorithm02); + var algorithm09$$1 = load(algorithm09); + var algorithm11$$1 = load(algorithm11); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - 'number, number': function (x, y) { - if (!isInteger$13(x) || !isInteger$13(y)) { - throw new Error('Integers expected in function bitAnd'); - } + /** + * Multiply two matrices element wise. The function accepts both matrices and + * scalar values. + * + * Syntax: + * + * math.dotMultiply(x, y) + * + * Examples: + * + * math.dotMultiply(2, 4); // returns 8 + * + * a = [[9, 5], [6, 1]]; + * b = [[3, 2], [5, 2]]; + * + * math.dotMultiply(a, b); // returns [[27, 10], [30, 2]] + * math.multiply(a, b); // returns [[52, 28], [23, 14]] + * + * See also: + * + * multiply, divide, dotDivide + * + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Left hand value + * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Right hand value + * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` + */ + var dotMultiply = typed('dotMultiply', { + + 'any, any': multiplyScalar$$1, - return x & y; - }, + 'SparseMatrix, SparseMatrix': function (x, y) { + return algorithm09$$1(x, y, multiplyScalar$$1, false); + }, - 'BigNumber, BigNumber': bitAnd$1, + 'SparseMatrix, DenseMatrix': function (x, y) { + return algorithm02$$1(y, x, multiplyScalar$$1, true); + }, - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm06$$1(x, y, bitAnd, false); - }, + 'DenseMatrix, SparseMatrix': function (x, y) { + return algorithm02$$1(x, y, multiplyScalar$$1, false); + }, - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, bitAnd, true); - }, + 'DenseMatrix, DenseMatrix': function (x, y) { + return algorithm13$$1(x, y, multiplyScalar$$1); + }, - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm02$$1(x, y, bitAnd, false); - }, + 'Array, Array': function (x, y) { + // use matrix implementation + return dotMultiply(matrix$$1(x), matrix$$1(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return dotMultiply(matrix$$1(x), y); + }, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, bitAnd); - }, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return dotMultiply(x, matrix$$1(y)); + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return bitAnd(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'SparseMatrix, any': function (x, y) { + return algorithm11$$1(x, y, multiplyScalar$$1, false); + }, - 'Array, Matrix': function (x, y) { - // use matrix implementation - return bitAnd(matrix$$1(x), y); - }, + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, multiplyScalar$$1, false); + }, - 'Matrix, Array': function (x, y) { - // use matrix implementation - return bitAnd(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, bitAnd, false); - }, + 'any, SparseMatrix': function (x, y) { + return algorithm11$$1(y, x, multiplyScalar$$1, true); + }, - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, bitAnd, false); - }, + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, multiplyScalar$$1, true); + }, - 'any, SparseMatrix': function (x, y) { - return algorithm11$$1(y, x, bitAnd, true); - }, + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, multiplyScalar$$1, false).valueOf(); + }, - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, bitAnd, true); - }, + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, multiplyScalar$$1, true).valueOf(); + } + }); - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, bitAnd, false).valueOf(); - }, + dotMultiply.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['dotMultiply'] + '${args[1]}\\right)' + }; + + return dotMultiply; + } - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, bitAnd, true).valueOf(); - } - }); + var name$138 = 'dotMultiply'; + var factory_1$149 = factory$150; - bitAnd.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['bitAnd'] + '${args[1]}\\right)' + var dotMultiply$1 = { + name: name$138, + factory: factory_1$149 }; - return bitAnd; -} - -var name$160 = 'bitAnd'; -var factory_1$171 = factory$172; + function factory$151 (type, config, load, typed) { -var bitAnd$2 = { - name: name$160, - factory: factory_1$171 -}; + var matrix$$1 = load(matrix); + var pow = load(pow$1); + var latex$$1 = latex; -var isInteger$14 = number.isInteger; + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm11$$1 = load(algorithm11); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); -function factory$173 (type, config, load, typed) { - var latex$$1 = latex; + /** + * Calculates the power of x to y element wise. + * + * Syntax: + * + * math.dotPow(x, y) + * + * Examples: + * + * math.dotPow(2, 3); // returns number 8 + * + * var a = [[1, 2], [4, 3]]; + * math.dotPow(a, 2); // returns Array [[1, 4], [16, 9]] + * math.pow(a, 2); // returns Array [[9, 8], [16, 17]] + * + * See also: + * + * pow, sqrt, multiply + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x The base + * @param {number | BigNumber | Complex | Unit | Array | Matrix} y The exponent + * @return {number | BigNumber | Complex | Unit | Array | Matrix} The value of `x` to the power `y` + */ + var dotPow = typed('dotPow', { + + 'any, any': pow, - /** - * Bitwise NOT value, `~x`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the best prefix base. - * - * Syntax: - * - * math.bitNot(x) - * - * Examples: - * - * math.bitNot(1); // returns number -2 - * - * math.bitNot([2, -3, 4]); // returns Array [-3, 2, 5] - * - * See also: - * - * bitAnd, bitOr, bitXor, leftShift, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x Value to not - * @return {number | BigNumber | Array | Matrix} NOT of `x` - */ - var bitNot = typed('bitNot', { - 'number': function (x) { - if (!isInteger$14(x)) { - throw new Error('Integer expected in function bitNot'); - } + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm07$$1(x, y, pow, false); + }, - return ~x; - }, + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, pow, true); + }, - 'BigNumber': bitNot$1, + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, pow, false); + }, - 'Array | Matrix': function (x) { - return deepMap(x, bitNot); - } - }); + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, pow); + }, - bitNot.toTex = { - 1: latex$$1.operators['bitNot'] + '\\left(${args[0]}\\right)' - }; - - return bitNot; -} - -var name$161 = 'bitNot'; -var factory_1$172 = factory$173; - -var bitNot$2 = { - name: name$161, - factory: factory_1$172 -}; - -/** - * Bitwise OR for BigNumbers - * - * Special Cases: - * N | n = N - * n | 0 = n - * n | -1 = -1 - * n | n = n - * I | I = I - * -I | -I = -I - * I | -n = -1 - * I | -I = -1 - * I | n = I - * -I | n = -I - * -I | -n = -n - * - * @param {BigNumber} x - * @param {BigNumber} y - * @return {BigNumber} Result of `x` | `y`, fully precise - */ -var bitOr$1 = function bitOr (x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function bitOr'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN()) { - return new BigNumber(NaN); - } - - var negOne = new BigNumber(-1); - if (x.isZero() || y.eq(negOne) || x.eq(y)) { - return y; - } - if (y.isZero() || x.eq(negOne)) { - return x; - } + 'Array, Array': function (x, y) { + // use matrix implementation + return dotPow(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - if (!x.isFinite() || !y.isFinite()) { - if ((!x.isFinite() && !x.isNegative() && y.isNegative()) || - (x.isNegative() && !y.isNegative() && !y.isFinite())) { - return negOne; - } - if (x.isNegative() && y.isNegative()) { - return x.isFinite() ? x : y; - } - return x.isFinite() ? y : x; - } + 'Array, Matrix': function (x, y) { + // use matrix implementation + return dotPow(matrix$$1(x), y); + }, - return bitwise(x, y, function (a, b) { return a | b }); -}; + 'Matrix, Array': function (x, y) { + // use matrix implementation + return dotPow(x, matrix$$1(y)); + }, -var isInteger$15 = number.isInteger; + 'SparseMatrix, any': function (x, y) { + return algorithm11$$1(x, y, dotPow, false); + }, + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, dotPow, false); + }, -function factory$174 (type, config, load, typed) { - var latex$$1 = latex; + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, dotPow, true); + }, - var matrix$$1 = load(matrix); + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, dotPow, true); + }, - var algorithm01$$1 = load(algorithm01); - var algorithm04$$1 = load(algorithm04); - var algorithm10$$1 = load(algorithm10); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise OR two values, `x | y`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the lowest print base. - * - * Syntax: - * - * math.bitOr(x, y) - * - * Examples: - * - * math.bitOr(1, 2); // returns number 3 - * - * math.bitOr([1, 2, 3], 4); // returns Array [5, 6, 7] - * - * See also: - * - * bitAnd, bitNot, bitXor, leftShift, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x First value to or - * @param {number | BigNumber | Array | Matrix} y Second value to or - * @return {number | BigNumber | Array | Matrix} OR of `x` and `y` - */ - var bitOr = typed('bitOr', { + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, dotPow, false).valueOf(); + }, - 'number, number': function (x, y) { - if (!isInteger$15(x) || !isInteger$15(y)) { - throw new Error('Integers expected in function bitOr'); + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, dotPow, true).valueOf(); } + }); - return x | y; - }, - - 'BigNumber, BigNumber': bitOr$1, + dotPow.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['dotPow'] + '${args[1]}\\right)' + }; + + return dotPow; + } - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm04$$1(x, y, bitOr); - }, + var name$139 = 'dotPow'; + var factory_1$150 = factory$151; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm01$$1(y, x, bitOr, true); - }, + var dotPow$1 = { + name: name$139, + factory: factory_1$150 + }; - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, bitOr, false); - }, + function factory$152 (type, config, load, typed) { + /** + * Calculate the exponent of a value. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.exp(x) + * + * Examples: + * + * math.exp(2); // returns number 7.3890560989306495 + * math.pow(math.e, 2); // returns number 7.3890560989306495 + * math.log(math.exp(2)); // returns number 2 + * + * math.exp([1, 2, 3]); + * // returns Array [ + * // 2.718281828459045, + * // 7.3890560989306495, + * // 20.085536923187668 + * // ] + * + * See also: + * + * expm1, log, pow + * + * @param {number | BigNumber | Complex | Array | Matrix} x A number or matrix to exponentiate + * @return {number | BigNumber | Complex | Array | Matrix} Exponent of `x` + */ + var exp = typed('exp', { + 'number': Math.exp, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, bitOr); - }, + 'Complex': function (x) { + return x.exp(); + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return bitOr(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'BigNumber': function (x) { + return x.exp(); + }, - 'Array, Matrix': function (x, y) { - // use matrix implementation - return bitOr(matrix$$1(x), y); - }, + 'Array | Matrix': function (x) { + // TODO: exp(sparse) should return a dense matrix since exp(0)==1 + return deepMap(x, exp); + } + }); - 'Matrix, Array': function (x, y) { - // use matrix implementation - return bitOr(x, matrix$$1(y)); - }, + exp.toTex = {1: '\\exp\\left(${args[0]}\\right)'}; - 'SparseMatrix, any': function (x, y) { - return algorithm10$$1(x, y, bitOr, false); - }, + return exp; + } - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, bitOr, false); - }, + var name$140 = 'exp'; + var factory_1$151 = factory$152; - 'any, SparseMatrix': function (x, y) { - return algorithm10$$1(y, x, bitOr, true); - }, + var exp$1 = { + name: name$140, + factory: factory_1$151 + }; - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, bitOr, true); - }, + function factory$153 (type, config, load, typed) { + var latex$$1 = latex; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, bitOr, false).valueOf(); - }, + /** + * Calculate the value of subtracting 1 from the exponential value. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.expm1(x) + * + * Examples: + * + * math.expm1(2); // returns number 6.38905609893065 + * math.pow(math.e, 2) - 1; // returns number 6.3890560989306495 + * math.log(math.expm1(2) + 1); // returns number 2 + * + * math.expm1([1, 2, 3]); + * // returns Array [ + * // 1.718281828459045, + * // 6.3890560989306495, + * // 19.085536923187668 + * // ] + * + * See also: + * + * exp, log, pow + * + * @param {number | BigNumber | Complex | Array | Matrix} x A number or matrix to apply expm1 + * @return {number | BigNumber | Complex | Array | Matrix} Exponent of `x` + */ + var expm1 = typed('expm1', { + 'number': Math.expm1 || _expm1, + + 'Complex': function (x) { + var r = Math.exp(x.re); + return new type.Complex( + r * Math.cos(x.im) - 1, + r * Math.sin(x.im) + ); + }, - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, bitOr, true).valueOf(); - } - }); + 'BigNumber': function (x) { + return x.exp().minus(1); + }, - bitOr.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['bitOr'] + '${args[1]}\\right)' - }; - - return bitOr; -} - -var name$162 = 'bitOr'; -var factory_1$173 = factory$174; - -var bitOr$2 = { - name: name$162, - factory: factory_1$173 -}; - -/** - * Bitwise XOR for BigNumbers - * - * Special Cases: - * N ^ n = N - * n ^ 0 = n - * n ^ n = 0 - * n ^ -1 = ~n - * I ^ n = I - * I ^ -n = -I - * I ^ -I = -1 - * -I ^ n = -I - * -I ^ -n = I - * - * @param {BigNumber} x - * @param {BigNumber} y - * @return {BigNumber} Result of `x` ^ `y`, fully precise - * - */ -var bitXor$1 = function bitXor(x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function bitXor'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN()) { - return new BigNumber(NaN); - } - if (x.isZero()) { - return y; - } - if (y.isZero()) { - return x; - } + 'Array | Matrix': function (x) { + return deepMap(x, expm1); + } + }); - if (x.eq(y)) { - return new BigNumber(0); - } + /** + * Calculates exponentiation minus 1. + * @param {number} x + * @return {number} res + * @private + */ + function _expm1(x) { + return (x >= 2e-4 || x <= -2e-4) + ? Math.exp(x) - 1 + : x + x*x/2 + x*x*x/6; + } - var negOne = new BigNumber(-1); - if (x.eq(negOne)) { - return bitNot$1(y); - } - if (y.eq(negOne)) { - return bitNot$1(x); - } + expm1.toTex = '\\left(e' + latex$$1.operators['pow'] + '{${args[0]}}-1\\right)'; - if (!x.isFinite() || !y.isFinite()) { - if (!x.isFinite() && !y.isFinite()) { - return negOne; - } - return new BigNumber(x.isNegative() == y.isNegative() - ? Infinity - : -Infinity); + return expm1; } - return bitwise(x, y, function (a, b) { return a ^ b }); -}; -var isInteger$16 = number.isInteger; + var name$141 = 'expm1'; + var factory_1$152 = factory$153; + var expm1$1 = { + name: name$141, + factory: factory_1$152 + }; -function factory$175 (type, config, load, typed) { - var latex$$1 = latex; + function factory$154 (type, config, load, typed) { + /** + * Round a value towards zero. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.fix(x) + * + * Examples: + * + * math.fix(3.2); // returns number 3 + * math.fix(3.8); // returns number 3 + * math.fix(-4.2); // returns number -4 + * math.fix(-4.7); // returns number -4 + * + * var c = math.complex(3.2, -2.7); + * math.fix(c); // returns Complex 3 - 2i + * + * math.fix([3.2, 3.8, -4.7]); // returns Array [3, 3, -4] + * + * See also: + * + * ceil, floor, round + * + * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded + * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value + */ + var fix = typed('fix', { + 'number': function (x) { + return (x > 0) ? Math.floor(x) : Math.ceil(x); + }, - var matrix$$1 = load(matrix); + 'Complex': function (x) { + return new type.Complex( + (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re), + (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im) + ); + }, - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + 'BigNumber': function (x) { + return x.isNegative() ? x.ceil() : x.floor(); + }, - /** - * Bitwise XOR two values, `x ^ y`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.bitXor(x, y) - * - * Examples: - * - * math.bitXor(1, 2); // returns number 3 - * - * math.bitXor([2, 3, 4], 4); // returns Array [6, 7, 0] - * - * See also: - * - * bitAnd, bitNot, bitOr, leftShift, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x First value to xor - * @param {number | BigNumber | Array | Matrix} y Second value to xor - * @return {number | BigNumber | Array | Matrix} XOR of `x` and `y` - */ - var bitXor = typed('bitXor', { + 'Fraction': function (x) { + return x.s < 0 ? x.ceil() : x.floor(); + }, - 'number, number': function (x, y) { - if (!isInteger$16(x) || !isInteger$16(y)) { - throw new Error('Integers expected in function bitXor'); + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since fix(0) = 0 + return deepMap(x, fix, true); } + }); - return x ^ y; - }, + fix.toTex = {1: '\\mathrm{${name}}\\left(${args[0]}\\right)'}; - 'BigNumber, BigNumber': bitXor$1, + return fix; + } - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, bitXor); - }, + var name$142 = 'fix'; + var factory_1$153 = factory$154; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, bitXor, true); - }, + var fix$1 = { + name: name$142, + factory: factory_1$153 + }; - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, bitXor, false); - }, + function factory$155 (type, config, load, typed) { + /** + * Round a value towards minus infinity. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.floor(x) + * + * Examples: + * + * math.floor(3.2); // returns number 3 + * math.floor(3.8); // returns number 3 + * math.floor(-4.2); // returns number -5 + * math.floor(-4.7); // returns number -5 + * + * var c = math.complex(3.2, -2.7); + * math.floor(c); // returns Complex 3 - 3i + * + * math.floor([3.2, 3.8, -4.7]); // returns Array [3, 3, -5] + * + * See also: + * + * ceil, fix, round + * + * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded + * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value + */ + var floor = typed('floor', { + 'number': Math.floor, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, bitXor); - }, + 'Complex': function (x) { + return x.floor(); + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return bitXor(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'BigNumber': function (x) { + return x.floor(); + }, - 'Array, Matrix': function (x, y) { - // use matrix implementation - return bitXor(matrix$$1(x), y); - }, + 'Fraction': function (x) { + return x.floor(); + }, - 'Matrix, Array': function (x, y) { - // use matrix implementation - return bitXor(x, matrix$$1(y)); - }, + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since floor(0) = 0 + return deepMap(x, floor, true); + } + }); - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, bitXor, false); - }, + floor.toTex = {1: '\\left\\lfloor${args[0]}\\right\\rfloor'}; - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, bitXor, false); - }, + return floor; + } - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, bitXor, true); - }, + var name$143 = 'floor'; + var factory_1$154 = factory$155; - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, bitXor, true); - }, + var floor$1 = { + name: name$143, + factory: factory_1$154 + }; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, bitXor, false).valueOf(); - }, + var isInteger$9 = number.isInteger; - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, bitXor, true).valueOf(); - } - }); + function factory$156 (type, config, load, typed) { - bitXor.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['bitXor'] + '${args[1]}\\right)' - }; - - return bitXor; -} - -var name$163 = 'bitXor'; -var factory_1$174 = factory$175; - -var bitXor$2 = { - name: name$163, - factory: factory_1$174 -}; - -/** - * Bitwise left shift - * - * Special Cases: - * n << -n = N - * n << N = N - * N << n = N - * n << 0 = n - * 0 << n = 0 - * I << I = N - * I << n = I - * n << I = I - * - * @param {BigNumber} x - * @param {BigNumber} y - * @return {BigNumber} Result of `x` << `y` - * - */ -var leftShift$1 = function leftShift (x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function leftShift'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { - return new BigNumber(NaN); - } - if (x.isZero() || y.isZero()) { - return x; - } - if (!x.isFinite() && !y.isFinite()) { - return new BigNumber(NaN); - } + var matrix$$1 = load(matrix); - // Math.pow(2, y) is fully precise for y < 55, and fast - if (y.lt(55)) { - return x.times(Math.pow(2, y.toNumber()) + ''); - } - return x.times(new BigNumber(2).pow(y)); -}; + var algorithm01$$1 = load(algorithm01); + var algorithm04$$1 = load(algorithm04); + var algorithm10$$1 = load(algorithm10); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); -function factory$176 (type, config, load, typed) { + /** + * Calculate the greatest common divisor for two or more values or arrays. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.gcd(a, b) + * math.gcd(a, b, c, ...) + * + * Examples: + * + * math.gcd(8, 12); // returns 4 + * math.gcd(-4, 6); // returns 2 + * math.gcd(25, 15, -10); // returns 5 + * + * math.gcd([8, -4], [12, 6]); // returns [4, 2] + * + * See also: + * + * lcm, xgcd + * + * @param {... number | BigNumber | Fraction | Array | Matrix} args Two or more integer numbers + * @return {number | BigNumber | Fraction | Array | Matrix} The greatest common divisor + */ + var gcd = typed('gcd', { - var equalScalar$$1 = load(equalScalar); + 'number, number': _gcd, - var SparseMatrix = type.SparseMatrix; + 'BigNumber, BigNumber': _gcdBigNumber, - /** - * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). - * Callback function invoked MAX(NNZA, NNZB) times - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 - * C(i,j) = ┤ A(i,j) ; A(i,j) !== 0 - * └ 0 ; otherwise - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm08 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // sparse matrix cannot be a Pattern matrix - if (!avalues || !bvalues) - throw new Error('Cannot perform operation on Pattern Sparse Matrices'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = []; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); + 'Fraction, Fraction': function (x, y) { + return x.gcd(y); + }, - // workspace - var x = []; - // marks indicating we have a value in x for a given column - var w = []; + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm04$$1(x, y, gcd); + }, - // vars - var k, k0, k1, i; + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm01$$1(y, x, gcd, true); + }, - // loop columns - for (var j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // columns mark - var mark = j + 1; - // loop values in a - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // mark workspace - w[i] = mark; - // set value - x[i] = avalues[k]; - // add index - cindex.push(i); - } - // loop values in b - for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - i = bindex[k]; - // check value exists in workspace - if (w[i] === mark) { - // evaluate callback - x[i] = cf(x[i], bvalues[k]); - } - } - // initialize first index in j - k = cptr[j]; - // loop index in j - while (k < cindex.length) { - // row - i = cindex[k]; - // value @ i - var v = x[i]; - // check for zero value - if (!eq(v, zero)) { - // push value - cvalues.push(v); - // increment pointer - k++; - } - else { - // remove value @ i, do not increment pointer - cindex.splice(k, 1); - } - } - } - // update cptr - cptr[columns] = cindex.length; + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm01$$1(x, y, gcd, false); + }, - // return sparse matrix - return c; - }; + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, gcd); + }, - return algorithm08; -} + 'Array, Array': function (x, y) { + // use matrix implementation + return gcd(matrix$$1(x), matrix$$1(y)).valueOf(); + }, -var name$164 = 'algorithm08'; -var factory_1$175 = factory$176; + 'Array, Matrix': function (x, y) { + // use matrix implementation + return gcd(matrix$$1(x), y); + }, -var algorithm08 = { - name: name$164, - factory: factory_1$175 -}; + 'Matrix, Array': function (x, y) { + // use matrix implementation + return gcd(x, matrix$$1(y)); + }, + + 'SparseMatrix, number | BigNumber': function (x, y) { + return algorithm10$$1(x, y, gcd, false); + }, -var isInteger$17 = number.isInteger; + 'DenseMatrix, number | BigNumber': function (x, y) { + return algorithm14$$1(x, y, gcd, false); + }, + 'number | BigNumber, SparseMatrix': function (x, y) { + return algorithm10$$1(y, x, gcd, true); + }, -function factory$177 (type, config, load, typed) { - var latex$$1 = latex; + 'number | BigNumber, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, gcd, true); + }, - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - var zeros = load(zeros$1); + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, gcd, false).valueOf(); + }, - var algorithm01$$1 = load(algorithm01); - var algorithm02$$1 = load(algorithm02); - var algorithm08$$1 = load(algorithm08); - var algorithm10$$1 = load(algorithm10); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, gcd, true).valueOf(); + }, - /** - * Bitwise left logical shift of a value x by y number of bits, `x << y`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the best prefix base. - * - * Syntax: - * - * math.leftShift(x, y) - * - * Examples: - * - * math.leftShift(1, 2); // returns number 4 - * - * math.leftShift([1, 2, 3], 4); // returns Array [16, 32, 64] - * - * See also: - * - * leftShift, bitNot, bitOr, bitXor, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x Value to be shifted - * @param {number | BigNumber} y Amount of shifts - * @return {number | BigNumber | Array | Matrix} `x` shifted left `y` times - */ - var leftShift = typed('leftShift', { - - 'number, number': function (x, y) { - if (!isInteger$17(x) || !isInteger$17(y)) { - throw new Error('Integers expected in function leftShift'); + // TODO: need a smarter notation here + 'Array | Matrix | number | BigNumber, Array | Matrix | number | BigNumber, ...Array | Matrix | number | BigNumber': function (a, b, args) { + var res = gcd(a, b); + for (var i = 0; i < args.length; i++) { + res = gcd(res, args[i]); + } + return res; } + }); - return x << y; - }, + gcd.toTex = '\\gcd\\left(${args}\\right)'; - 'BigNumber, BigNumber': leftShift$1, + return gcd; - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm08$$1(x, y, leftShift, false); - }, + /** + * Calculate gcd for BigNumbers + * @param {BigNumber} a + * @param {BigNumber} b + * @returns {BigNumber} Returns greatest common denominator of a and b + * @private + */ + function _gcdBigNumber(a, b) { + if (!a.isInt() || !b.isInt()) { + throw new Error('Parameters in function gcd must be integer numbers'); + } - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, leftShift, true); - }, + // http://en.wikipedia.org/wiki/Euclidean_algorithm + var zero = new type.BigNumber(0); + while (!b.isZero()) { + var r = a.mod(b); + a = b; + b = r; + } + return a.lt(zero) ? a.neg() : a; + } + } - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, leftShift, false); - }, + /** + * Calculate gcd for numbers + * @param {number} a + * @param {number} b + * @returns {number} Returns the greatest common denominator of a and b + * @private + */ + function _gcd(a, b) { + if (!isInteger$9(a) || !isInteger$9(b)) { + throw new Error('Parameters in function gcd must be integer numbers'); + } - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, leftShift); - }, + // http://en.wikipedia.org/wiki/Euclidean_algorithm + var r; + while (b != 0) { + r = a % b; + a = b; + b = r; + } + return (a < 0) ? -a : a; + } - 'Array, Array': function (x, y) { - // use matrix implementation - return leftShift(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + var name$144 = 'gcd'; + var factory_1$155 = factory$156; - 'Array, Matrix': function (x, y) { - // use matrix implementation - return leftShift(matrix$$1(x), y); - }, + var gcd$1 = { + name: name$144, + factory: factory_1$155 + }; - 'Matrix, Array': function (x, y) { - // use matrix implementation - return leftShift(x, matrix$$1(y)); - }, + var flatten$2 = array.flatten; - 'SparseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm11$$1(x, y, leftShift, false); - }, + function factory$157 (type, config, load, typed) { + var abs = load(abs$1); + var add = load(addScalar); + var divide = load(divideScalar); + var multiply = load(multiplyScalar); + var sqrt = load(sqrt$1); + var smaller$$1 = load(smaller); + var isPositive = load(isPositive$1); - 'DenseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm14$$1(x, y, leftShift, false); - }, + /** + * Calculate the hypotenusa of a list with values. The hypotenusa is defined as: + * + * hypot(a, b, c, ...) = sqrt(a^2 + b^2 + c^2 + ...) + * + * For matrix input, the hypotenusa is calculated for all values in the matrix. + * + * Syntax: + * + * math.hypot(a, b, ...) + * math.hypot([a, b, c, ...]) + * + * Examples: + * + * math.hypot(3, 4); // 5 + * math.hypot(3, 4, 5); // 7.0710678118654755 + * math.hypot([3, 4, 5]); // 7.0710678118654755 + * math.hypot(-2); // 2 + * + * See also: + * + * abs, norm + * + * @param {... number | BigNumber | Array | Matrix} args A list with numeric values or an Array or Matrix. + * Matrix and Array input is flattened and returns a + * single number for the whole matrix. + * @return {number | BigNumber} Returns the hypothenusa of the input values. + */ + var hypot = typed('hypot', { + '... number | BigNumber': _hypot, - 'number | BigNumber, SparseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm10$$1(y, x, leftShift, true); - }, + 'Array': function (x) { + return hypot.apply(hypot, flatten$2(x)); + }, - 'number | BigNumber, DenseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); + 'Matrix': function (x) { + return hypot.apply(hypot, flatten$2(x.toArray())); } - return algorithm14$$1(y, x, leftShift, true); - }, + }); - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return leftShift(matrix$$1(x), y).valueOf(); - }, + /** + * Calculate the hypotenusa for an Array with values + * @param {Array.} args + * @return {number | BigNumber} Returns the result + * @private + */ + function _hypot (args) { + // code based on `hypot` from es6-shim: + // https://github.com/paulmillr/es6-shim/blob/master/es6-shim.js#L1619-L1633 + var result = 0; + var largest = 0; - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return leftShift(x, matrix$$1(y)).valueOf(); - } - }); + for (var i = 0; i < args.length; i++) { + var value = abs(args[i]); + if (smaller$$1(largest, value)) { + result = multiply(result, multiply(divide(largest, value), divide(largest, value))); + result = add(result, 1); + largest = value; + } else { + result = add(result, isPositive(value) ? multiply(divide(value, largest), divide(value, largest)) : value); + } + } - leftShift.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['leftShift'] + '${args[1]}\\right)' - }; - - return leftShift; -} - -var name$165 = 'leftShift'; -var factory_1$176 = factory$177; - -var leftShift$2 = { - name: name$165, - factory: factory_1$176 -}; - -/* - * Special Cases: - * n >> -n = N - * n >> N = N - * N >> n = N - * I >> I = N - * n >> 0 = n - * I >> n = I - * -I >> n = -I - * -I >> I = -I - * n >> I = I - * -n >> I = -1 - * 0 >> n = 0 - * - * @param {BigNumber} value - * @param {BigNumber} value - * @return {BigNumber} Result of `x` >> `y` - * - */ -var rightArithShift$1 = function rightArithShift (x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function rightArithShift'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { - return new BigNumber(NaN); - } - if (x.isZero() || y.isZero()) { - return x; - } - if (!y.isFinite()) { - if (x.isNegative()) { - return new BigNumber(-1); - } - if (!x.isFinite()) { - return new BigNumber(NaN); + return multiply(largest, sqrt(result)); } - return new BigNumber(0); - } - // Math.pow(2, y) is fully precise for y < 55, and fast - if (y.lt(55)) { - return x.div(Math.pow(2, y.toNumber()) + '').floor(); - } - return x.div(new BigNumber(2).pow(y)).floor(); -}; + hypot.toTex = '\\hypot\\left(${args}\\right)'; -var isInteger$18 = number.isInteger; + return hypot; + } + var name$145 = 'hypot'; + var factory_1$156 = factory$157; -function factory$178 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - var zeros = load(zeros$1); + var hypot$1 = { + name: name$145, + factory: factory_1$156 + }; - var algorithm01$$1 = load(algorithm01); - var algorithm02$$1 = load(algorithm02); - var algorithm08$$1 = load(algorithm08); - var algorithm10$$1 = load(algorithm10); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + var scatter = function scatter(a, j, w, x, u, mark, c, f, inverse, update, value) { + // a arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + // c arrays + var cindex = c._index; - /** - * Bitwise right arithmetic shift of a value x by y number of bits, `x >> y`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the best prefix base. - * - * Syntax: - * - * math.rightArithShift(x, y) - * - * Examples: - * - * math.rightArithShift(4, 2); // returns number 1 - * - * math.rightArithShift([16, -32, 64], 4); // returns Array [1, -2, 3] - * - * See also: - * - * bitAnd, bitNot, bitOr, bitXor, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x Value to be shifted - * @param {number | BigNumber} y Amount of shifts - * @return {number | BigNumber | Array | Matrix} `x` sign-filled shifted right `y` times - */ - var rightArithShift = typed('rightArithShift', { + // vars + var k, k0, k1, i; - 'number, number': function (x, y) { - if (!isInteger$18(x) || !isInteger$18(y)) { - throw new Error('Integers expected in function rightArithShift'); + // check we need to process values (pattern matrix) + if (x) { + // values in j + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // check value exists in current j + if (w[i] !== mark) { + // i is new entry in j + w[i] = mark; + // add i to pattern of C + cindex.push(i); + // x(i) = A, check we need to call function this time + if (update) { + // copy value to workspace calling callback function + x[i] = inverse ? f(avalues[k], value) : f(value, avalues[k]); + // function was called on current row + u[i] = mark; + } + else { + // copy value to workspace + x[i] = avalues[k]; + } + } + else { + // i exists in C already + x[i] = inverse ? f(avalues[k], x[i]) : f(x[i], avalues[k]); + // function was called on current row + u[i] = mark; + } + } + } + else { + // values in j + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // check value exists in current j + if (w[i] !== mark) { + // i is new entry in j + w[i] = mark; + // add i to pattern of C + cindex.push(i); + } + else { + // indicate function was called on current row + u[i] = mark; + } } + } + }; - return x >> y; - }, + function factory$158 (type, config, load, typed) { - 'BigNumber, BigNumber': rightArithShift$1, + var equalScalar$$1 = load(equalScalar); - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm08$$1(x, y, rightArithShift, false); - }, + var SparseMatrix = type.SparseMatrix; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, rightArithShift, true); - }, + /** + * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). + * Callback function invoked (Anz U Bnz) times, where Anz and Bnz are the nonzero elements in both matrices. + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 + * C(i,j) = ┤ + * └ 0 ; otherwise + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {Function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm06 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var asize = a._size; + var adt = a._datatype; + // sparse matrix arrays + var bvalues = b._values; + var bsize = b._size; + var bdt = b._datatype; - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, rightArithShift, false); - }, + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, rightArithShift); - }, + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - 'Array, Array': function (x, y) { - // use matrix implementation - return rightArithShift(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + // rows & columns + var rows = asize[0]; + var columns = asize[1]; - 'Array, Matrix': function (x, y) { - // use matrix implementation - return rightArithShift(matrix$$1(x), y); - }, + // datatype + var dt; + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // find signature that matches (dt, dt) + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result arrays + var cvalues = avalues && bvalues ? [] : undefined; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); - 'Matrix, Array': function (x, y) { - // use matrix implementation - return rightArithShift(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm11$$1(x, y, rightArithShift, false); - }, + // workspaces + var x = cvalues ? [] : undefined; + // marks indicating we have a value in x for a given column + var w = []; + // marks indicating value in a given row has been updated + var u = []; - 'DenseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); + // loop columns + for (var j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // columns mark + var mark = j + 1; + // scatter the values of A(:,j) into workspace + scatter(a, j, w, x, u, mark, c, cf); + // scatter the values of B(:,j) into workspace + scatter(b, j, w, x, u, mark, c, cf); + // check we need to process values (non pattern matrix) + if (x) { + // initialize first index in j + var k = cptr[j]; + // loop index in j + while (k < cindex.length) { + // row + var i = cindex[k]; + // check function was invoked on current row (Aij !=0 && Bij != 0) + if (u[i] === mark) { + // value @ i + var v = x[i]; + // check for zero value + if (!eq(v, zero)) { + // push value + cvalues.push(v); + // increment pointer + k++; + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + } + else { + // initialize first index in j + var p = cptr[j]; + // loop index in j + while (p < cindex.length) { + // row + var r = cindex[p]; + // check function was invoked on current row (Aij !=0 && Bij != 0) + if (u[r] !== mark) { + // remove value @ i, do not increment pointer + cindex.splice(p, 1); + } + else { + // increment pointer + p++; + } + } + } } - return algorithm14$$1(x, y, rightArithShift, false); - }, + // update cptr + cptr[columns] = cindex.length; - 'number | BigNumber, SparseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm10$$1(y, x, rightArithShift, true); - }, + // return sparse matrix + return c; + }; + + return algorithm06; + } - 'number | BigNumber, DenseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm14$$1(y, x, rightArithShift, true); - }, + var name$146 = 'algorithm06'; + var factory_1$157 = factory$158; - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return rightArithShift(matrix$$1(x), y).valueOf(); - }, + var algorithm06 = { + name: name$146, + factory: factory_1$157 + }; - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return rightArithShift(x, matrix$$1(y)).valueOf(); - } - }); + var isInteger$10 = number.isInteger; - rightArithShift.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['rightArithShift'] + '${args[1]}\\right)' - }; + function factory$159 (type, config, load, typed) { + + var matrix$$1 = load(matrix); - return rightArithShift; -} + var algorithm02$$1 = load(algorithm02); + var algorithm06$$1 = load(algorithm06); + var algorithm11$$1 = load(algorithm11); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); -var name$166 = 'rightArithShift'; -var factory_1$177 = factory$178; + /** + * Calculate the least common multiple for two or more values or arrays. + * + * lcm is defined as: + * + * lcm(a, b) = abs(a * b) / gcd(a, b) + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.lcm(a, b) + * math.lcm(a, b, c, ...) + * + * Examples: + * + * math.lcm(4, 6); // returns 12 + * math.lcm(6, 21); // returns 42 + * math.lcm(6, 21, 5); // returns 210 + * + * math.lcm([4, 6], [6, 21]); // returns [12, 42] + * + * See also: + * + * gcd, xgcd + * + * @param {... number | BigNumber | Array | Matrix} args Two or more integer numbers + * @return {number | BigNumber | Array | Matrix} The least common multiple + */ + var lcm = typed('lcm', { + 'number, number': _lcm, -var rightArithShift$2 = { - name: name$166, - factory: factory_1$177 -}; + 'BigNumber, BigNumber': _lcmBigNumber, -var isInteger$19 = number.isInteger; + 'Fraction, Fraction': function (x, y) { -function factory$179 (type, config, load, typed) { - var latex$$1 = latex; + return x.lcm(y); + }, - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - var zeros = load(zeros$1); + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm06$$1(x, y, lcm); + }, - var algorithm01$$1 = load(algorithm01); - var algorithm02$$1 = load(algorithm02); - var algorithm08$$1 = load(algorithm08); - var algorithm10$$1 = load(algorithm10); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise right logical shift of value x by y number of bits, `x >>> y`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the best prefix base. - * - * Syntax: - * - * math.rightLogShift(x, y) - * - * Examples: - * - * math.rightLogShift(4, 2); // returns number 1 - * - * math.rightLogShift([16, -32, 64], 4); // returns Array [1, 2, 3] - * - * See also: - * - * bitAnd, bitNot, bitOr, bitXor, leftShift, rightLogShift - * - * @param {number | Array | Matrix} x Value to be shifted - * @param {number} y Amount of shifts - * @return {number | Array | Matrix} `x` zero-filled shifted right `y` times - */ + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm02$$1(y, x, lcm, true); + }, - var rightLogShift = typed('rightLogShift', { + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm02$$1(x, y, lcm, false); + }, - 'number, number': function (x, y) { - if (!isInteger$19(x) || !isInteger$19(y)) { - throw new Error('Integers expected in function rightLogShift'); - } + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, lcm); + }, - return x >>> y; - }, + 'Array, Array': function (x, y) { + // use matrix implementation + return lcm(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - // 'BigNumber, BigNumber': ..., // TODO: implement BigNumber support for rightLogShift + 'Array, Matrix': function (x, y) { + // use matrix implementation + return lcm(matrix$$1(x), y); + }, - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm08$$1(x, y, rightLogShift, false); - }, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return lcm(x, matrix$$1(y)); + }, - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, rightLogShift, true); - }, + 'SparseMatrix, number | BigNumber': function (x, y) { + return algorithm11$$1(x, y, lcm, false); + }, - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, rightLogShift, false); - }, + 'DenseMatrix, number | BigNumber': function (x, y) { + return algorithm14$$1(x, y, lcm, false); + }, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, rightLogShift); - }, + 'number | BigNumber, SparseMatrix': function (x, y) { + return algorithm11$$1(y, x, lcm, true); + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return rightLogShift(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'number | BigNumber, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, lcm, true); + }, - 'Array, Matrix': function (x, y) { - // use matrix implementation - return rightLogShift(matrix$$1(x), y); - }, + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, lcm, false).valueOf(); + }, - 'Matrix, Array': function (x, y) { - // use matrix implementation - return rightLogShift(x, matrix$$1(y)); - }, + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, lcm, true).valueOf(); + }, - 'SparseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); + // TODO: need a smarter notation here + 'Array | Matrix | number | BigNumber, Array | Matrix | number | BigNumber, ...Array | Matrix | number | BigNumber': function (a, b, args) { + var res = lcm(a, b); + for (var i = 0; i < args.length; i++) { + res = lcm(res, args[i]); + } + return res; } - return algorithm11$$1(x, y, rightLogShift, false); - }, + }); - 'DenseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm14$$1(x, y, rightLogShift, false); - }, + lcm.toTex = undefined; // use default template - 'number | BigNumber, SparseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm10$$1(y, x, rightLogShift, true); - }, + return lcm; - 'number | BigNumber, DenseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); + /** + * Calculate lcm for two BigNumbers + * @param {BigNumber} a + * @param {BigNumber} b + * @returns {BigNumber} Returns the least common multiple of a and b + * @private + */ + function _lcmBigNumber(a, b) { + if (!a.isInt() || !b.isInt()) { + throw new Error('Parameters in function lcm must be integer numbers'); } - return algorithm14$$1(y, x, rightLogShift, true); - }, - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return rightLogShift(matrix$$1(x), y).valueOf(); - }, + if (a.isZero() || b.isZero()) { + return new type.BigNumber(0); + } - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return rightLogShift(x, matrix$$1(y)).valueOf(); + // http://en.wikipedia.org/wiki/Euclidean_algorithm + // evaluate lcm here inline to reduce overhead + var prod = a.times(b); + while (!b.isZero()) { + var t = b; + b = a.mod(t); + a = t; + } + return prod.div(a).abs(); } - }); - - rightLogShift.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['rightLogShift'] + '${args[1]}\\right)' - }; - - return rightLogShift; -} + } -var name$167 = 'rightLogShift'; -var factory_1$178 = factory$179; + /** + * Calculate lcm for two numbers + * @param {number} a + * @param {number} b + * @returns {number} Returns the least common multiple of a and b + * @private + */ + function _lcm (a, b) { + if (!isInteger$10(a) || !isInteger$10(b)) { + throw new Error('Parameters in function lcm must be integer numbers'); + } -var rightLogShift$1 = { - name: name$167, - factory: factory_1$178 -}; + if (a == 0 || b == 0) { + return 0; + } -var bitwise$1 = [ - bitAnd$2, - bitNot$2, - bitOr$2, - bitXor$2, - leftShift$2, - rightArithShift$2, - rightLogShift$1 -]; + // http://en.wikipedia.org/wiki/Euclidean_algorithm + // evaluate lcm here inline to reduce overhead + var t; + var prod = a * b; + while (b != 0) { + t = b; + b = a % t; + a = t; + } + return Math.abs(prod / a); + } -var isInteger$20 = number.isInteger; + var name$147 = 'lcm'; + var factory_1$158 = factory$159; -function factory$180 (type, config, load, typed) { - var multiply = load(multiply$1); - var pow = load(pow$1); + var lcm$1 = { + name: name$147, + factory: factory_1$158 + }; - /** - * Compute the gamma function of a value using Lanczos approximation for - * small values, and an extended Stirling approximation for large values. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.gamma(n) - * - * Examples: - * - * math.gamma(5); // returns 24 - * math.gamma(-0.5); // returns -3.5449077018110335 - * math.gamma(math.i); // returns -0.15494982830180973 - 0.49801566811835596i - * - * See also: - * - * combinations, factorial, permutations - * - * @param {number | Array | Matrix} n A real or complex number - * @return {number | Array | Matrix} The gamma of `n` - */ - var gamma = typed('gamma', { - 'number': function (n) { - var t, x; + function factory$160 (type, config, load, typed) { + var divideScalar$$1 = load(divideScalar); - if (isInteger$20(n)) { - if (n <= 0) { - return isFinite(n) ? Infinity : NaN; + /** + * Calculate the logarithm of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.log(x) + * math.log(x, base) + * + * Examples: + * + * math.log(3.5); // returns 1.252762968495368 + * math.exp(math.log(2.4)); // returns 2.4 + * + * math.pow(10, 4); // returns 10000 + * math.log(10000, 10); // returns 4 + * math.log(10000) / math.log(10); // returns 4 + * + * math.log(1024, 2); // returns 10 + * math.pow(2, 10); // returns 1024 + * + * See also: + * + * exp, log2, log10, log1p + * + * @param {number | BigNumber | Complex | Array | Matrix} x + * Value for which to calculate the logarithm. + * @param {number | BigNumber | Complex} [base=e] + * Optional base for the logarithm. If not provided, the natural + * logarithm of `x` is calculated. + * @return {number | BigNumber | Complex | Array | Matrix} + * Returns the logarithm of `x` + */ + var log = typed('log', { + 'number': function (x) { + if (x >= 0 || config.predictable) { + return Math.log(x); } - - if (n > 171) { - return Infinity; // Will overflow + else { + // negative value -> complex value computation + return new type.Complex(x, 0).log(); } + }, - var value = n - 2; - var res = n - 1; - while (value > 1) { - res *= value; - value--; - } + 'Complex': function (x) { + return x.log(); + }, - if (res == 0) { - res = 1; // 0! is per definition 1 + 'BigNumber': function (x) { + if (!x.isNegative() || config.predictable) { + return x.ln(); } + else { + // downgrade to number, return Complex valued result + return new type.Complex(x.toNumber(), 0).log(); + } + }, - return res; - } - - if (n < 0.5) { - return Math.PI / (Math.sin(Math.PI * n) * gamma(1-n)); - } - - if (n >= 171.35) { - return Infinity; // will overflow - } + 'Array | Matrix': function (x) { + return deepMap(x, log); + }, - if (n > 85.0) { // Extended Stirling Approx - var twoN = n*n; - var threeN = twoN*n; - var fourN = threeN*n; - var fiveN = fourN*n; - return Math.sqrt(2*Math.PI/n) * Math.pow((n/Math.E), n) * - (1 + 1/(12*n) + 1/(288*twoN) - 139/(51840*threeN) - - 571/(2488320*fourN) + 163879/(209018880*fiveN) + - 5246819/(75246796800*fiveN*n)); + 'any, any': function (x, base) { + // calculate logarithm for a specified base, log(x, base) + return divideScalar$$1(log(x), log(base)); } + }); - --n; - x = p[0]; - for (var i = 1; i < p.length; ++i) { - x += p[i] / (n+i); - } + log.toTex = { + 1: '\\ln\\left(${args[0]}\\right)', + 2: '\\log_{${args[1]}}\\left(${args[0]}\\right)' + }; - t = n + g + 0.5; - return Math.sqrt(2*Math.PI) * Math.pow(t, n+0.5) * Math.exp(-t) * x; - }, + return log; + } - 'Complex': function (n) { - var t, x; + var name$148 = 'log'; + var factory_1$159 = factory$160; - if (n.im == 0) { - return gamma(n.re); - } + var log$1 = { + name: name$148, + factory: factory_1$159 + }; - n = new type.Complex(n.re - 1, n.im); - x = new type.Complex(p[0], 0); - for (var i = 1; i < p.length; ++i) { - var real = n.re + i; // x += p[i]/(n+i) - var den = real*real + n.im*n.im; - if (den != 0) { - x.re += p[i] * real / den; - x.im += -(p[i] * n.im) / den; - } else { - x.re = p[i] < 0 - ? -Infinity - : Infinity; + function factory$161 (type, config, load, typed) { + /** + * Calculate the 10-base logarithm of a value. This is the same as calculating `log(x, 10)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.log10(x) + * + * Examples: + * + * math.log10(0.00001); // returns -5 + * math.log10(10000); // returns 4 + * math.log(10000) / math.log(10); // returns 4 + * math.pow(10, 4); // returns 10000 + * + * See also: + * + * exp, log, log1p, log2 + * + * @param {number | BigNumber | Complex | Array | Matrix} x + * Value for which to calculate the logarithm. + * @return {number | BigNumber | Complex | Array | Matrix} + * Returns the 10-base logarithm of `x` + */ + var log10 = typed('log10', { + 'number': function (x) { + if (x >= 0 || config.predictable) { + return _log10(x); } - } - - t = new type.Complex(n.re + g + 0.5, n.im); - var twoPiSqrt = Math.sqrt(2*Math.PI); - - n.re += 0.5; - var result = pow(t, n); - if (result.im == 0) { // sqrt(2*PI)*result - result.re *= twoPiSqrt; - } else if (result.re == 0) { - result.im *= twoPiSqrt; - } else { - result.re *= twoPiSqrt; - result.im *= twoPiSqrt; - } - - var r = Math.exp(-t.re); // exp(-t) - t.re = r * Math.cos(-t.im); - t.im = r * Math.sin(-t.im); + else { + // negative value -> complex value computation + return new type.Complex(x, 0).log().div(Math.LN10); + } + }, - return multiply(multiply(result, t), x); - }, + 'Complex': function (x) { + return new type.Complex(x).log().div(Math.LN10); + }, - 'BigNumber': function (n) { - if (n.isInteger()) { - return (n.isNegative() || n.isZero()) - ? new type.BigNumber(Infinity) - : bigFactorial(n.minus(1)); - } + 'BigNumber': function (x) { + if (!x.isNegative() || config.predictable) { + return x.log(); + } + else { + // downgrade to number, return Complex valued result + return new type.Complex(x.toNumber(), 0).log().div(Math.LN10); + } + }, - if (!n.isFinite()) { - return new type.BigNumber(n.isNegative() ? NaN : Infinity); + 'Array | Matrix': function (x) { + return deepMap(x, log10); } + }); - throw new Error('Integer BigNumber expected'); - }, + log10.toTex = {1: '\\log_{10}\\left(${args[0]}\\right)'}; - 'Array | Matrix': function (n) { - return deepMap(n, gamma); - } - }); + return log10; + } /** - * Calculate factorial for a BigNumber - * @param {BigNumber} n - * @returns {BigNumber} Returns the factorial of n + * Calculate the 10-base logarithm of a number + * @param {number} x + * @return {number} + * @private */ - function bigFactorial(n) { - if (n.isZero()) { - return new type.BigNumber(1); // 0! is per definition 1 - } - - var precision = config.precision + (Math.log(n.toNumber()) | 0); - var Big = type.BigNumber.clone({precision: precision}); - - var res = new Big(n); - var value = n.toNumber() - 1; // number - while (value > 1) { - res = res.times(value); - value--; - } - - return new type.BigNumber(res.toPrecision(type.BigNumber.precision)); - } + var _log10 = Math.log10 || function (x) { + return Math.log(x) / Math.LN10; + }; - gamma.toTex = {1: '\\Gamma\\left(${args[0]}\\right)'}; + var name$149 = 'log10'; + var factory_1$160 = factory$161; - return gamma; -} + var log10$1 = { + name: name$149, + factory: factory_1$160 + }; -// TODO: comment on the variables g and p + function factory$162 (type, config, load, typed) { + var divideScalar$$1 = load(divideScalar); + var log = load(log$1); -var g = 4.7421875; + /** + * Calculate the logarithm of a `value+1`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.log1p(x) + * math.log1p(x, base) + * + * Examples: + * + * math.log1p(2.5); // returns 1.252762968495368 + * math.exp(math.log1p(1.4)); // returns 2.4 + * + * math.pow(10, 4); // returns 10000 + * math.log1p(9999, 10); // returns 4 + * math.log1p(9999) / math.log(10); // returns 4 + * + * See also: + * + * exp, log, log2, log10 + * + * @param {number | BigNumber | Complex | Array | Matrix} x + * Value for which to calculate the logarithm of `x+1`. + * @param {number | BigNumber | Complex} [base=e] + * Optional base for the logarithm. If not provided, the natural + * logarithm of `x+1` is calculated. + * @return {number | BigNumber | Complex | Array | Matrix} + * Returns the logarithm of `x+1` + */ + var log1p = typed('log1p', { + 'number': _log1pNumber, -var p = [ - 0.99999999999999709182, - 57.156235665862923517, - -59.597960355475491248, - 14.136097974741747174, - -0.49191381609762019978, - 0.33994649984811888699e-4, - 0.46523628927048575665e-4, - -0.98374475304879564677e-4, - 0.15808870322491248884e-3, - -0.21026444172410488319e-3, - 0.21743961811521264320e-3, - -0.16431810653676389022e-3, - 0.84418223983852743293e-4, - -0.26190838401581408670e-4, - 0.36899182659531622704e-5 -]; + 'Complex': _log1pComplex, -var name$168 = 'gamma'; -var factory_1$179 = factory$180; + 'BigNumber': function (x) { + var y = x.plus(1); + if (!y.isNegative() || config.predictable) { + return y.ln(); + } + else { + // downgrade to number, return Complex valued result + return _log1pComplex(new type.Complex(x.toNumber(), 0)); + } + }, -var gamma$1 = { - name: name$168, - factory: factory_1$179 -}; + 'Array | Matrix': function (x) { + return deepMap(x, log1p); + }, -function factory$181 (type, config, load, typed) { - var gamma = load(gamma$1); - var latex$$1 = latex; + 'any, any': function (x, base) { + // calculate logarithm for a specified base, log1p(x, base) + return divideScalar$$1(log1p(x), log(base)); + } + }); - /** - * Compute the factorial of a value - * - * Factorial only supports an integer value as argument. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.factorial(n) - * - * Examples: - * - * math.factorial(5); // returns 120 - * math.factorial(3); // returns 6 - * - * See also: - * - * combinations, gamma, permutations - * - * @param {number | BigNumber | Array | Matrix} n An integer number - * @return {number | BigNumber | Array | Matrix} The factorial of `n` - */ - var factorial = typed('factorial', { - 'number': function (n) { - if (n < 0) { - throw new Error('Value must be non-negative'); + /** + * Calculate the natural logarithm of a `number+1` + * @param {number} x + * @returns {number | Complex} + * @private + */ + function _log1pNumber(x) { + if (x >= -1 || config.predictable) { + return (Math.log1p) ? Math.log1p(x) : Math.log(x+1); } - - return gamma(n + 1); - }, - - 'BigNumber': function (n) { - if (n.isNegative()) { - throw new Error('Value must be non-negative'); + else { + // negative value -> complex value computation + return _log1pComplex(new type.Complex(x, 0)); } - - return gamma(n.plus(1)); - }, - - 'Array | Matrix': function (n) { - return deepMap(n, factorial); } - }); - - factorial.toTex = { - 1: '\\left(${args[0]}\\right)' + latex$$1.operators['factorial'] - }; - - return factorial; -} -var name$169 = 'factorial'; -var factory_1$180 = factory$181; - -var factorial$1 = { - name: name$169, - factory: factory_1$180 -}; + /** + * Calculate the natural logarithm of a complex number + 1 + * @param {Complex} x + * @returns {Complex} + * @private + */ + function _log1pComplex(x) { + var x_re1p = x.re + 1; + return new type.Complex ( + Math.log(Math.sqrt(x_re1p * x_re1p + x.im * x.im)), + Math.atan2(x.im, x_re1p) + ); + } -var isInteger$21 = number.isInteger; + log1p.toTex = { + 1: '\\ln\\left(${args[0]}+1\\right)', + 2: '\\log_{${args[1]}}\\left(${args[0]}+1\\right)' + }; -function factory$182 (type, config, load, typed) { - /** - * Compute the number of ways of picking `k` unordered outcomes from `n` - * possibilities. - * - * Combinations only takes integer arguments. - * The following condition must be enforced: k <= n. - * - * Syntax: - * - * math.combinations(n, k) - * - * Examples: - * - * math.combinations(7, 5); // returns 21 - * - * See also: - * - * permutations, factorial - * - * @param {number | BigNumber} n Total number of objects in the set - * @param {number | BigNumber} k Number of objects in the subset - * @return {number | BigNumber} Number of possible combinations. - */ - var combinations = typed('combinations', { - 'number, number': function (n, k) { - var max, result, i; + return log1p; + } - if (!isInteger$21(n) || n < 0) { - throw new TypeError('Positive integer value expected in function combinations'); - } - if (!isInteger$21(k) || k < 0) { - throw new TypeError('Positive integer value expected in function combinations'); - } - if (k > n) { - throw new TypeError('k must be less than or equal to n'); - } + var name$150 = 'log1p'; + var factory_1$161 = factory$162; - max = Math.max(k, n - k); - result = 1; - for (i = 1; i <= n - max; i++) { - result = result * (max + i) / i; - } + var log1p$1 = { + name: name$150, + factory: factory_1$161 + }; - return result; - }, + function factory$163 (type, config, load, typed) { + /** + * Calculate the 2-base of a value. This is the same as calculating `log(x, 2)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.log2(x) + * + * Examples: + * + * math.log2(0.03125); // returns -5 + * math.log2(16); // returns 4 + * math.log2(16) / math.log2(2); // returns 4 + * math.pow(2, 4); // returns 16 + * + * See also: + * + * exp, log, log1p, log10 + * + * @param {number | BigNumber | Complex | Array | Matrix} x + * Value for which to calculate the logarithm. + * @return {number | BigNumber | Complex | Array | Matrix} + * Returns the 2-base logarithm of `x` + */ + var log2 = typed('log2', { + 'number': function (x) { + if (x >= 0 || config.predictable) { + return (Math.log2) + ? Math.log2(x) + : Math.log(x) / Math.LN2; + } + else { + // negative value -> complex value computation + return _log2Complex(new type.Complex(x, 0)); + } + }, - 'BigNumber, BigNumber': function (n, k) { - var max, result, i, ii; - var one = new type.BigNumber(1); + 'Complex': _log2Complex, - if (!isPositiveInteger(n) || !isPositiveInteger(k)) { - throw new TypeError('Positive integer value expected in function combinations'); - } - if (k.gt(n)) { - throw new TypeError('k must be less than n in function combinations'); - } + 'BigNumber': function (x) { + if (!x.isNegative() || config.predictable) { + return x.log(2); + } + else { + // downgrade to number, return Complex valued result + return _log2Complex(new type.Complex(x.toNumber(), 0)); + } + }, - max = n.minus(k); - if (k.lt(max)) max = k; - result = one; - for (i = one, ii = n.minus(max); i.lte(ii); i = i.plus(1)) { - result = result.times(max.plus(i)).dividedBy(i); + 'Array | Matrix': function (x) { + return deepMap(x, log2); } + }); - return result; + /** + * Calculate log2 for a complex value + * @param {Complex} x + * @returns {Complex} + * @private + */ + function _log2Complex(x) { + var newX = Math.sqrt(x.re * x.re + x.im * x.im); + return new type.Complex ( + (Math.log2) ? Math.log2(newX) : Math.log(newX) / Math.LN2, + Math.atan2(x.im, x.re) / Math.LN2 + ); } - // TODO: implement support for collection in combinations - }); + log2.toTex = '\\log_{2}\\left(${args[0]}\\right)'; - combinations.toTex = {2: '\\binom{${args[0]}}{${args[1]}}'}; + return log2; - return combinations; -} + } -/** - * Test whether BigNumber n is a positive integer - * @param {BigNumber} n - * @returns {boolean} isPositiveInteger - */ -function isPositiveInteger(n) { - return n.isInteger() && n.gte(0); -} + var name$151 = 'log2'; + var factory_1$162 = factory$163; -var name$170 = 'combinations'; -var factory_1$181 = factory$182; + var log2$1 = { + name: name$151, + factory: factory_1$162 + }; -var combinations$1 = { - name: name$170, - factory: factory_1$181 -}; + function factory$164 (type, config, load, typed) { -function factory$183 (type, config, load, typed) { - /** - * Test whether a value is an integer number. - * The function supports `number`, `BigNumber`, and `Fraction`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isInteger(x) - * - * Examples: - * - * math.isInteger(2); // returns true - * math.isInteger(0); // returns true - * math.isInteger(0.5); // returns false - * math.isInteger(math.bignumber(500)); // returns true - * math.isInteger(math.fraction(4)); // returns true - * math.isInteger('3'); // returns true - * math.isInteger([3, 0.5, -2]); // returns [true, false, true] - * math.isInteger(math.complex('2-4i'); // throws an error - * - * See also: - * - * isNumeric, isPositive, isNegative, isZero - * - * @param {number | BigNumber | Fraction | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` contains a numeric, integer value. - * Throws an error in case of an unknown data type. - */ - var isInteger = typed('isInteger', { - 'number': number.isInteger, // TODO: what to do with isInteger(add(0.1, 0.2)) ? + var matrix$$1 = load(matrix); + var latex$$1 = latex; + + var algorithm02$$1 = load(algorithm02); + var algorithm03$$1 = load(algorithm03); + var algorithm05$$1 = load(algorithm05); + var algorithm11$$1 = load(algorithm11); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + /** + * Calculates the modulus, the remainder of an integer division. + * + * For matrices, the function is evaluated element wise. + * + * The modulus is defined as: + * + * x - y * floor(x / y) + * + * See http://en.wikipedia.org/wiki/Modulo_operation. + * + * Syntax: + * + * math.mod(x, y) + * + * Examples: + * + * math.mod(8, 3); // returns 2 + * math.mod(11, 2); // returns 1 + * + * function isOdd(x) { + * return math.mod(x, 2) != 0; + * } + * + * isOdd(2); // returns false + * isOdd(3); // returns true + * + * See also: + * + * divide + * + * @param {number | BigNumber | Fraction | Array | Matrix} x Dividend + * @param {number | BigNumber | Fraction | Array | Matrix} y Divisor + * @return {number | BigNumber | Fraction | Array | Matrix} Returns the remainder of `x` divided by `y`. + */ + var mod = typed('mod', { - 'BigNumber': function (x) { - return x.isInt(); - }, + 'number, number': _mod, - 'Fraction': function (x) { - return x.d === 1 && isFinite(x.n); - }, + 'BigNumber, BigNumber': function (x, y) { + return y.isZero() ? x : x.mod(y); + }, - 'Array | Matrix': function (x) { - return deepMap(x, isInteger); - } - }); + 'Fraction, Fraction': function (x, y) { + return x.mod(y); + }, - return isInteger; -} - -var name$171 = 'isInteger'; -var factory_1$182 = factory$183; - -var isInteger$22 = { - name: name$171, - factory: factory_1$182 -}; - -function factory$184 (type, config, load, typed) { - var add$$1 = load(add); - var subtract = load(subtract$1); - var multiply = load(multiply$1); - var divide = load(divide$1); - var pow = load(pow$1); - var factorial = load(factorial$1); - var combinations = load(combinations$1); - var isNegative = load(isNegative$1); - var isInteger = load(isInteger$22); - var larger$$1 = load(larger); + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm05$$1(x, y, mod, false); + }, - /** - * The Stirling numbers of the second kind, counts the number of ways to partition - * a set of n labelled objects into k nonempty unlabelled subsets. - * stirlingS2 only takes integer arguments. - * The following condition must be enforced: k <= n. - * - * If n = k or k = 1, then s(n,k) = 1 - * - * Syntax: - * - * math.stirlingS2(n, k) - * - * Examples: - * - * math.stirlingS2(5, 3); //returns 25 - * - * See also: - * - * Bell numbers - * - * @param {Number | BigNumber} n Total number of objects in the set - * @param {Number | BigNumber} k Number of objects in the subset - * @return {Number | BigNumber} S(n,k) - */ - var stirlingS2 = typed('stirlingS2', { - 'number | BigNumber, number | BigNumber': function (n, k) { - if (!isInteger(n) || isNegative(n) || !isInteger(k) || isNegative(k)) { - throw new TypeError('Non-negative integer value expected in function stirlingS2'); - } - else if (larger$$1(k, n)) { - throw new TypeError('k must be less than or equal to n in function stirlingS2'); - } + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm02$$1(y, x, mod, true); + }, - // 1/k! Sum(i=0 -> k) [(-1)^(k-i)*C(k,j)* i^n] - var kFactorial = factorial(k); - var result = 0; - for(var i = 0; i <= k; i++) { - var negativeOne = pow(-1, subtract(k,i)); - var kChooseI = combinations(k,i); - var iPower = pow(i,n); + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, mod, false); + }, - result = add$$1(result, multiply(multiply(kChooseI, iPower), negativeOne)); - } + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, mod); + }, - return divide(result, kFactorial); - } - }); + 'Array, Array': function (x, y) { + // use matrix implementation + return mod(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - stirlingS2.toTex = {2: '\\mathrm{S}\\left(${args}\\right)'}; + 'Array, Matrix': function (x, y) { + // use matrix implementation + return mod(matrix$$1(x), y); + }, - return stirlingS2; -} + 'Matrix, Array': function (x, y) { + // use matrix implementation + return mod(x, matrix$$1(y)); + }, -var name$172 = 'stirlingS2'; -var factory_1$183 = factory$184; + 'SparseMatrix, any': function (x, y) { + return algorithm11$$1(x, y, mod, false); + }, -var stirlingS2$1 = { - name: name$172, - factory: factory_1$183 -}; + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, mod, false); + }, -function factory$185 (type, config, load, typed) { - var add$$1 = load(add); - var stirlingS2 = load(stirlingS2$1); - var isNegative = load(isNegative$1); - var isInteger = load(isInteger$22); + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, mod, true); + }, - /** - * The Bell Numbers count the number of partitions of a set. A partition is a pairwise disjoint subset of S whose union is S. - * bellNumbers only takes integer arguments. - * The following condition must be enforced: n >= 0 - * - * Syntax: - * - * math.bellNumbers(n) - * - * Examples: - * - * math.bellNumbers(3); // returns 5; - * math.bellNumbers(8); // returns 4140; - * - * See also: - * - * stirlingS2 - * - * @param {Number | BigNumber} n Total number of objects in the set - * @return {Number | BigNumber} B(n) - */ - var bellNumbers = typed('bellNumbers', { - 'number | BigNumber': function (n) { + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, mod, true); + }, - if (!isInteger(n) || isNegative(n)) { - throw new TypeError('Non-negative integer value expected in function bellNumbers'); - } + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, mod, false).valueOf(); + }, - // Sum (k=0, n) S(n,k). - var result = 0; - for(var i = 0; i <= n; i++) { - result = add$$1(result, stirlingS2(n, i)); + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, mod, true).valueOf(); } + }); - return result; - } - }); - - bellNumbers.toTex = {1: '\\mathrm{B}_{${args[0]}}'}; - - return bellNumbers; -} - -var name$173 = 'bellNumbers'; -var factory_1$184 = factory$185; - -var bellNumbers$1 = { - name: name$173, - factory: factory_1$184 -}; + mod.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['mod'] + '${args[1]}\\right)' + }; -function factory$186 (type, config, load, typed) { - var combinations = load(combinations$1); - var add = load(addScalar); - var isPositive = load(isPositive$1); - var isInteger = load(isInteger$22); - var larger$$1 = load(larger); + return mod; - /** - * The composition counts of n into k parts. - * - * composition only takes integer arguments. - * The following condition must be enforced: k <= n. - * - * Syntax: - * - * math.composition(n, k) - * - * Examples: - * - * math.composition(5, 3); // returns 6 - * - * See also: - * - * combinations - * - * @param {Number | BigNumber} n Total number of objects in the set - * @param {Number | BigNumber} k Number of objects in the subset - * @return {Number | BigNumber} Returns the composition counts of n into k parts. - */ - var composition = typed('composition', { - 'number | BigNumber, number | BigNumber': function (n, k) { - if (!isInteger(n) || !isPositive(n) || !isInteger(k) || !isPositive(k)) { - throw new TypeError('Positive integer value expected in function composition'); + /** + * Calculate the modulus of two numbers + * @param {number} x + * @param {number} y + * @returns {number} res + * @private + */ + function _mod(x, y) { + if (y > 0) { + // We don't use JavaScript's % operator here as this doesn't work + // correctly for x < 0 and x == 0 + // see http://en.wikipedia.org/wiki/Modulo_operation + return x - y * Math.floor(x / y); + } + else if (y === 0) { + return x; } - else if (larger$$1(k, n)) { - throw new TypeError('k must be less than or equal to n in function composition'); + else { // y < 0 + // TODO: implement mod for a negative divisor + throw new Error('Cannot calculate mod for a negative divisor'); } - - return combinations(add(n, -1), add(k, -1)); } - }); + } - composition.toTex = undefined; // use default template + var name$152 = 'mod'; + var factory_1$163 = factory$164; - return composition; -} + var mod$1 = { + name: name$152, + factory: factory_1$163 + }; -var name$174 = 'composition'; -var factory_1$185 = factory$186; + var clone$7 = object.clone; + var format$5 = string.format; -var composition$1 = { - name: name$174, - factory: factory_1$185 -}; + function factory$165 (type, config, load, typed) { + + var matrix$$1 = load(matrix); + var add$$1 = load(add); -function factory$187 (type, config, load, typed) { - var add$$1 = load(add); - var divide = load(divide$1); - var multiply = load(multiply$1); - var combinations = load(combinations$1); - var isNegative = load(isNegative$1); - var isInteger = load(isInteger$22); + /** + * Calculate the trace of a matrix: the sum of the elements on the main + * diagonal of a square matrix. + * + * Syntax: + * + * math.trace(x) + * + * Examples: + * + * math.trace([[1, 2], [3, 4]]); // returns 5 + * + * var A = [ + * [1, 2, 3], + * [-1, 2, 3], + * [2, 0, 3] + * ] + * math.trace(A); // returns 6 + * + * See also: + * + * diag + * + * @param {Array | Matrix} x A matrix + * + * @return {number} The trace of `x` + */ + var trace = typed('trace', { + + 'Array': function _arrayTrace(x) { + // use dense matrix implementation + return _denseTrace(matrix$$1(x)); + }, + 'SparseMatrix': _sparseTrace, - /** - * The Catalan Numbers enumerate combinatorial structures of many different types. - * catalan only takes integer arguments. - * The following condition must be enforced: n >= 0 - * - * Syntax: - * - * math.catalan(n) - * - * Examples: - * - * math.catalan(3); // returns 5; - * math.catalan(8); // returns 1430; - * - * See also: - * - * bellNumbers - * - * @param {Number | BigNumber} n nth Catalan number - * @return {Number | BigNumber} Cn(n) - */ - var catalan = typed('catalan', { - 'number | BigNumber': function (n) { + 'DenseMatrix': _denseTrace, - if (!isInteger(n) || isNegative(n)) { - throw new TypeError('Non-negative integer value expected in function catalan'); + 'any': clone$7 + }); + + function _denseTrace(m) { + // matrix size & data + var size = m._size; + var data = m._data; + + // process dimensions + switch (size.length) { + case 1: + // vector + if (size[0] === 1) { + // return data[0] + return clone$7(data[0]); + } + throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); + case 2: + // two dimensional + var rows = size[0]; + var cols = size[1]; + if (rows === cols) { + // calulate sum + var sum = 0; + // loop diagonal + for (var i = 0; i < rows; i++) + sum = add$$1(sum, data[i][i]); + // return trace + return sum; + } + throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); + default: + // multi dimensional + throw new RangeError('Matrix must be two dimensional (size: ' + format$5(size) + ')'); } - - return divide(combinations(multiply(n,2), n), add$$1(n,1)); - } - }); + + function _sparseTrace(m) { + // matrix arrays + var values = m._values; + var index = m._index; + var ptr = m._ptr; + var size = m._size; + // check dimensions + var rows = size[0]; + var columns = size[1]; + // matrix must be square + if (rows === columns) { + // calulate sum + var sum = 0; + // check we have data (avoid looping columns) + if (values.length > 0) { + // loop columns + for (var j = 0; j < columns; j++) { + // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] + var k0 = ptr[j]; + var k1 = ptr[j + 1]; + // loop k within [k0, k1[ + for (var k = k0; k < k1; k++) { + // row index + var i = index[k]; + // check row + if (i === j) { + // accumulate value + sum = add$$1(sum, values[k]); + // exit loop + break; + } + if (i > j) { + // exit loop, no value on the diagonal for column j + break; + } + } + } + } + // return trace + return sum; + } + throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); + } - catalan.toTex = {1: '\\mathrm{C}_{${args[0]}}'}; + trace.toTex = {1: '\\mathrm{tr}\\left(${args[0]}\\right)'}; + + return trace; + } - return catalan; -} + var name$153 = 'trace'; + var factory_1$164 = factory$165; -var name$175 = 'catalan'; -var factory_1$186 = factory$187; + var trace$1 = { + name: name$153, + factory: factory_1$164 + }; -var catalan$1 = { - name: name$175, - factory: factory_1$186 -}; + function factory$166 (type, config, load, typed) { + + var abs = load(abs$1); + var add$$1 = load(add); + var pow = load(pow$1); + var conj = load(conj$1); + var sqrt = load(sqrt$1); + var multiply = load(multiply$1); + var equalScalar$$1 = load(equalScalar); + var larger$$1 = load(larger); + var smaller$$1 = load(smaller); + var matrix$$1 = load(matrix); + var trace = load(trace$1); + var transpose = load(transpose$1); -var combinatorics = [ - bellNumbers$1, - composition$1, - stirlingS2$1, - catalan$1 -]; -function factory$188 (type, config, load, typed) { - /** - * Compute the argument of a complex value. - * For a complex number `a + bi`, the argument is computed as `atan2(b, a)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.arg(x) - * - * Examples: - * - * var a = math.complex(2, 2); - * math.arg(a) / math.pi; // returns number 0.25 - * - * var b = math.complex('2 + 3i'); - * math.arg(b); // returns number 0.982793723247329 - * math.atan2(3, 2); // returns number 0.982793723247329 - * - * See also: - * - * re, im, conj, abs - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * A complex number or array with complex numbers - * @return {number | BigNumber | Array | Matrix} The argument of x - */ - var arg = typed('arg', { - 'number': function (x) { - return Math.atan2(0, x); - }, + /** + * Calculate the norm of a number, vector or matrix. + * + * The second parameter p is optional. If not provided, it defaults to 2. + * + * Syntax: + * + * math.norm(x) + * math.norm(x, p) + * + * Examples: + * + * math.abs(-3.5); // returns 3.5 + * math.norm(-3.5); // returns 3.5 + * + * math.norm(math.complex(3, -4)); // returns 5 + * + * math.norm([1, 2, -3], Infinity); // returns 3 + * math.norm([1, 2, -3], -Infinity); // returns 1 + * + * math.norm([3, 4], 2); // returns 5 + * + * math.norm([[1, 2], [3, 4]], 1) // returns 6 + * math.norm([[1, 2], [3, 4]], 'inf'); // returns 7 + * math.norm([[1, 2], [3, 4]], 'fro'); // returns 5.477225575051661 + * + * See also: + * + * abs, hypot + * + * @param {number | BigNumber | Complex | Array | Matrix} x + * Value for which to calculate the norm + * @param {number | BigNumber | string} [p=2] + * Vector space. + * Supported numbers include Infinity and -Infinity. + * Supported strings are: 'inf', '-inf', and 'fro' (The Frobenius norm) + * @return {number | BigNumber} the p-norm + */ + var norm = typed('norm', { + 'number': Math.abs, - 'BigNumber': function (x) { - return type.BigNumber.atan2(0, x); - }, + 'Complex': function (x) { + return x.abs(); + }, - 'Complex': function (x) { - return x.arg(); - }, + 'BigNumber': function (x) { + // norm(x) = abs(x) + return x.abs(); + }, + + 'boolean' : function (x) { + // norm(x) = abs(x) + return Math.abs(x); + }, - // TODO: implement BigNumber support for function arg + 'Array': function (x) { + return _norm(matrix$$1(x), 2); + }, + + 'Matrix': function (x) { + return _norm(x, 2); + }, - 'Array | Matrix': function (x) { - return deepMap(x, arg); - } - }); + 'number | Complex | BigNumber | boolean, number | BigNumber | string': function (x) { + // ignore second parameter, TODO: remove the option of second parameter for these types + return norm(x); + }, - arg.toTex = {1: '\\arg\\left(${args[0]}\\right)'}; + 'Array, number | BigNumber | string': function (x, p) { + return _norm(matrix$$1(x), p); + }, + + 'Matrix, number | BigNumber | string': function (x, p) { + return _norm(x, p); + } + }); - return arg; -} + /** + * Calculate the norm for an array + * @param {Array} x + * @param {number | string} p + * @returns {number} Returns the norm + * @private + */ + function _norm (x, p) { + // size + var sizeX = x.size(); + + // check if it is a vector + if (sizeX.length == 1) { + // check p + if (p === Number.POSITIVE_INFINITY || p === 'inf') { + // norm(x, Infinity) = max(abs(x)) + var pinf = 0; + // skip zeros since abs(0) == 0 + x.forEach( + function (value) { + var v = abs(value); + if (larger$$1(v, pinf)) + pinf = v; + }, + true); + return pinf; + } + if (p === Number.NEGATIVE_INFINITY || p === '-inf') { + // norm(x, -Infinity) = min(abs(x)) + var ninf; + // skip zeros since abs(0) == 0 + x.forEach( + function (value) { + var v = abs(value); + if (!ninf || smaller$$1(v, ninf)) + ninf = v; + }, + true); + return ninf || 0; + } + if (p === 'fro') { + return _norm(x, 2); + } + if (typeof p === 'number' && !isNaN(p)) { + // check p != 0 + if (!equalScalar$$1(p, 0)) { + // norm(x, p) = sum(abs(xi) ^ p) ^ 1/p + var n = 0; + // skip zeros since abs(0) == 0 + x.forEach( + function (value) { + n = add$$1(pow(abs(value), p), n); + }, + true); + return pow(n, 1 / p); + } + return Number.POSITIVE_INFINITY; + } + // invalid parameter value + throw new Error('Unsupported parameter value'); + } + // MxN matrix + if (sizeX.length == 2) { + // check p + if (p === 1) { + // norm(x) = the largest column sum + var c = []; + // result + var maxc = 0; + // skip zeros since abs(0) == 0 + x.forEach( + function (value, index) { + var j = index[1]; + var cj = add$$1(c[j] || 0, abs(value)); + if (larger$$1(cj, maxc)) + maxc = cj; + c[j] = cj; + }, + true); + return maxc; + } + if (p === Number.POSITIVE_INFINITY || p === 'inf') { + // norm(x) = the largest row sum + var r = []; + // result + var maxr = 0; + // skip zeros since abs(0) == 0 + x.forEach( + function (value, index) { + var i = index[0]; + var ri = add$$1(r[i] || 0, abs(value)); + if (larger$$1(ri, maxr)) + maxr = ri; + r[i] = ri; + }, + true); + return maxr; + } + if (p === 'fro') { + // norm(x) = sqrt(sum(diag(x'x))) + var fro = 0; + x.forEach( + function (value, index) { + fro = add$$1( fro, multiply( value, conj(value) ) ); + }); + return sqrt(fro); + } + if (p === 2) { + // not implemented + throw new Error('Unsupported parameter value, missing implementation of matrix singular value decomposition'); + } + // invalid parameter value + throw new Error('Unsupported parameter value'); + } + } -var name$176 = 'arg'; -var factory_1$187 = factory$188; + norm.toTex = { + 1: '\\left\\|${args[0]}\\right\\|', + 2: undefined // use default template + }; -var arg$1 = { - name: name$176, - factory: factory_1$187 -}; + return norm; + } -function factory$189 (type, config, load, typed) { - /** - * Get the imaginary part of a complex number. - * For a complex number `a + bi`, the function returns `b`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.im(x) - * - * Examples: - * - * var a = math.complex(2, 3); - * math.re(a); // returns number 2 - * math.im(a); // returns number 3 - * - * math.re(math.complex('-5.2i')); // returns number -5.2 - * math.re(math.complex(2.4)); // returns number 0 - * - * See also: - * - * re, conj, abs, arg - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * A complex number or array with complex numbers - * @return {number | BigNumber | Array | Matrix} The imaginary part of x - */ - var im = typed('im', { - 'number': function (x) { - return 0; - }, + var name$154 = 'norm'; + var factory_1$165 = factory$166; - 'BigNumber': function (x) { - return new type.BigNumber(0); - }, + var norm$1 = { + name: name$154, + factory: factory_1$165 + }; - 'Complex': function (x) { - return x.im; - }, + function factory$167 (type, config, load, typed) { - 'Array | Matrix': function (x) { - return deepMap(x, im); - } - }); + var matrix$$1 = load(matrix); - im.toTex = {1: '\\Im\\left\\lbrace${args[0]}\\right\\rbrace'}; + var algorithm01$$1 = load(algorithm01); + var algorithm02$$1 = load(algorithm02); + var algorithm06$$1 = load(algorithm06); + var algorithm11$$1 = load(algorithm11); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - return im; -} + /** + * Calculate the nth root of a value. + * The principal nth root of a positive real number A, is the positive real + * solution of the equation + * + * x^root = A + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.nthRoot(a) + * math.nthRoot(a, root) + * + * Examples: + * + * math.nthRoot(9, 2); // returns 3, as 3^2 == 9 + * math.sqrt(9); // returns 3, as 3^2 == 9 + * math.nthRoot(64, 3); // returns 4, as 4^3 == 64 + * + * See also: + * + * sqrt, pow + * + * @param {number | BigNumber | Array | Matrix | Complex} a + * Value for which to calculate the nth root + * @param {number | BigNumber} [root=2] The root. + * @return {number | Complex | Array | Matrix} Returns the nth root of `a` + */ + var nthRoot = typed('nthRoot', { + + 'number': function (x) { + return _nthRoot(x, 2); + }, + 'number, number': _nthRoot, -var name$177 = 'im'; -var factory_1$188 = factory$189; + 'BigNumber': function (x) { + return _bigNthRoot(x, new type.BigNumber(2)); + }, + 'Complex' : function(x) { + return _nthComplexRoot(x, 2); + }, + 'Complex, number' : _nthComplexRoot, + 'BigNumber, BigNumber': _bigNthRoot, + + 'Array | Matrix': function (x) { + return nthRoot(x, 2); + }, -var im$1 = { - name: name$177, - factory: factory_1$188 -}; + 'SparseMatrix, SparseMatrix': function (x, y) { + // density must be one (no zeros in matrix) + if (y.density() === 1) { + // sparse + sparse + return algorithm06$$1(x, y, nthRoot); + } + else { + // throw exception + throw new Error('Root must be non-zero'); + } + }, -function factory$190 (type, config, load, typed) { - /** - * Get the real part of a complex number. - * For a complex number `a + bi`, the function returns `a`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.re(x) - * - * Examples: - * - * var a = math.complex(2, 3); - * math.re(a); // returns number 2 - * math.im(a); // returns number 3 - * - * math.re(math.complex('-5.2i')); // returns number 0 - * math.re(math.complex(2.4)); // returns number 2.4 - * - * See also: - * - * im, conj, abs, arg - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * A complex number or array with complex numbers - * @return {number | BigNumber | Array | Matrix} The real part of x - */ - var re = typed('re', { - 'number': function (x) { - return x; - }, + 'SparseMatrix, DenseMatrix': function (x, y) { + return algorithm02$$1(y, x, nthRoot, true); + }, - 'BigNumber': function (x) { - return x; - }, + 'DenseMatrix, SparseMatrix': function (x, y) { + // density must be one (no zeros in matrix) + if (y.density() === 1) { + // dense + sparse + return algorithm01$$1(x, y, nthRoot, false); + } + else { + // throw exception + throw new Error('Root must be non-zero'); + } + }, - 'Complex': function (x) { - return x.re; - }, + 'DenseMatrix, DenseMatrix': function (x, y) { + return algorithm13$$1(x, y, nthRoot); + }, - 'Array | Matrix': function (x) { - return deepMap(x, re); - } - }); + 'Array, Array': function (x, y) { + // use matrix implementation + return nthRoot(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - re.toTex = {1: '\\Re\\left\\lbrace${args[0]}\\right\\rbrace'}; + 'Array, Matrix': function (x, y) { + // use matrix implementation + return nthRoot(matrix$$1(x), y); + }, - return re; -} + 'Matrix, Array': function (x, y) { + // use matrix implementation + return nthRoot(x, matrix$$1(y)); + }, + + 'SparseMatrix, number | BigNumber': function (x, y) { + return algorithm11$$1(x, y, nthRoot, false); + }, -var name$178 = 're'; -var factory_1$189 = factory$190; + 'DenseMatrix, number | BigNumber': function (x, y) { + return algorithm14$$1(x, y, nthRoot, false); + }, -var re$1 = { - name: name$178, - factory: factory_1$189 -}; + 'number | BigNumber, SparseMatrix': function (x, y) { + // density must be one (no zeros in matrix) + if (y.density() === 1) { + // sparse - scalar + return algorithm11$$1(y, x, nthRoot, true); + } + else { + // throw exception + throw new Error('Root must be non-zero'); + } + }, -var complex$5 = [ - arg$1, - conj$1, - im$1, - re$1 -]; + 'number | BigNumber, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, nthRoot, true); + }, -function factory$191 (type, config, load, typed) { + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return nthRoot(matrix$$1(x), y).valueOf(); + }, - var abs = load(abs$1); - var add$$1 = load(add); - var addScalar$$1 = load(addScalar); - var matrix$$1 = load(matrix); - var multiply = load(multiply$1); - var multiplyScalar$$1 = load(multiplyScalar); - var divideScalar$$1 = load(divideScalar); - var subtract = load(subtract$1); - var smaller$$1 = load(smaller); - var equalScalar$$1 = load(equalScalar); + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return nthRoot(x, matrix$$1(y)).valueOf(); + } + }); - /** - * Calculates the point of intersection of two lines in two or three dimensions - * and of a line and a plane in three dimensions. The inputs are in the form of - * arrays or 1 dimensional matrices. The line intersection functions return null - * if the lines do not meet. - * - * Note: Fill the plane coefficients as `x + y + z = c` and not as `x + y + z + c = 0`. - * - * Syntax: - * - * math.intersect(endPoint1Line1, endPoint2Line1, endPoint1Line2, endPoint2Line2) - * math.intersect(endPoint1, endPoint2, planeCoefficients) - * - * Examples: - * - * math.intersect([0, 0], [10, 10], [10, 0], [0, 10]); // Returns [5, 5] - * math.intersect([0, 0, 0], [10, 10, 0], [10, 0, 0], [0, 10, 0]); // Returns [5, 5, 0] - * math.intersect([1, 0, 1], [4, -2, 2], [1, 1, 1, 6]); // Returns [7, -4, 3] - * - * @param {Array | Matrix} w Co-ordinates of first end-point of first line - * @param {Array | Matrix} x Co-ordinates of second end-point of first line - * @param {Array | Matrix} y Co-ordinates of first end-point of second line - * OR Co-efficients of the plane's equation - * @param {Array | Matrix} z Co-ordinates of second end-point of second line - * OR null if the calculation is for line and plane - * @return {Array} Returns the point of intersection of lines/lines-planes - */ - var intersect = typed('intersect', { - 'Array, Array, Array': function (x, y, plane) { - if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } - if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - if (!_4d(plane)) { throw new TypeError('Array with 4 numbers expected as third argument'); } + nthRoot.toTex = {2: '\\sqrt[${args[1]}]{${args[0]}}'}; - return _intersectLinePlane(x[0], x[1], x[2], y[0], y[1], y[2], plane[0], plane[1], plane[2], plane[3]); - }, + return nthRoot; - 'Array, Array, Array, Array': function (w, x, y, z) { - if (w.length === 2) { - if (!_2d(w)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } - if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } - if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for third argument'); } - if (!_2d(z)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for fourth argument'); } + /** + * Calculate the nth root of a for BigNumbers, solve x^root == a + * http://rosettacode.org/wiki/Nth_root#JavaScript + * @param {BigNumber} a + * @param {BigNumber} root + * @private + */ + function _bigNthRoot(a, root) { + var precision = type.BigNumber.precision; + var Big = type.BigNumber.clone({precision: precision + 2}); + var zero = new type.BigNumber(0); - return _intersect2d(w, x, y, z); + var one = new Big(1); + var inv = root.isNegative(); + if (inv) { + root = root.neg(); } - else if (w.length === 3) { - if (!_3d(w)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } - if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for third argument'); } - if (!_3d(z)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for fourth argument'); } - return _intersect3d(w[0], w[1], w[2], x[0], x[1], x[2], y[0], y[1], y[2], z[0], z[1], z[2]); + if (root.isZero()) { + throw new Error('Root must be non-zero'); } - else { - throw new TypeError('Arrays with two or thee dimensional points expected'); + if (a.isNegative() && !root.abs().mod(2).equals(1)) { + throw new Error('Root must be odd when a is negative.'); } - }, - 'Matrix, Matrix, Matrix': function (x, y, plane) { - return matrix$$1(intersect(x.valueOf(), y.valueOf(), plane.valueOf())); - }, + // edge cases zero and infinity + if (a.isZero()) { + return inv ? new Big(Infinity) : 0; + } + if (!a.isFinite()) { + return inv ? zero : a; + } - 'Matrix, Matrix, Matrix, Matrix': function (w, x, y, z) { - // TODO: output matrix type should match input matrix type - return matrix$$1(intersect(w.valueOf(), x.valueOf(), y.valueOf(), z.valueOf())); + var x = a.abs().pow(one.div(root)); + // If a < 0, we require that root is an odd integer, + // so (-1) ^ (1/root) = -1 + x = a.isNeg() ? x.neg() : x; + return new type.BigNumber((inv ? one.div(x) : x).toPrecision(precision)); } - }); - - function _isNumber(a) { - // intersect supports numbers and bignumbers - return (typeof a === 'number' || type.isBigNumber(a)); } - function _2d(x) { - return x.length === 2 && _isNumber(x[0]) && _isNumber(x[1]); - } + /** + * Calculate the nth root of a, solve x^root == a + * http://rosettacode.org/wiki/Nth_root#JavaScript + * @param {number} a + * @param {number} root + * @private + */ + function _nthRoot(a, root) { + var inv = root < 0; + if (inv) { + root = -root; + } - function _3d(x) { - return x.length === 3 && _isNumber(x[0]) && _isNumber(x[1]) && _isNumber(x[2]); - } + if (root === 0) { + throw new Error('Root must be non-zero'); + } + if (a < 0 && (Math.abs(root) % 2 != 1)) { + throw new Error('Root must be odd when a is negative.'); + } - function _4d(x) { - return x.length === 4 && _isNumber(x[0]) && _isNumber(x[1]) && _isNumber(x[2]) && _isNumber(x[3]); - } + // edge cases zero and infinity + if (a == 0) { + return inv ? Infinity : 0; + } + if (!isFinite(a)) { + return inv ? 0 : a; + } - function _intersect2d(p1a, p1b, p2a, p2b){ - var o1 = p1a; - var o2 = p2a; - var d1 = subtract(o1, p1b); - var d2 = subtract(o2, p2b); - var det = subtract(multiplyScalar$$1(d1[0], d2[1]), multiplyScalar$$1(d2[0], d1[1])); - if (smaller$$1(abs(det), config.epsilon)) { - return null; + var x = Math.pow(Math.abs(a), 1/root); + // If a < 0, we require that root is an odd integer, + // so (-1) ^ (1/root) = -1 + x = a < 0 ? -x : x; + return inv ? 1 / x : x; + + // Very nice algorithm, but fails with nthRoot(-2, 3). + // Newton's method has some well-known problems at times: + // https://en.wikipedia.org/wiki/Newton%27s_method#Failure_analysis + /* + var x = 1; // Initial guess + var xPrev = 1; + var i = 0; + var iMax = 10000; + do { + var delta = (a / Math.pow(x, root - 1) - x) / root; + xPrev = x; + x = x + delta; + i++; } - var d20o11 = multiplyScalar$$1(d2[0], o1[1]); - var d21o10 = multiplyScalar$$1(d2[1], o1[0]); - var d20o21 = multiplyScalar$$1(d2[0], o2[1]); - var d21o20 = multiplyScalar$$1(d2[1], o2[0]); - var t = divideScalar$$1(addScalar$$1(subtract(subtract(d20o11, d21o10), d20o21), d21o20), det); - return add$$1(multiply(d1, t), o1); - } - - function _intersect3dHelper(a, b, c, d, e, f, g, h, i, j, k, l){ - // (a - b)*(c - d) + (e - f)*(g - h) + (i - j)*(k - l) - var add1 = multiplyScalar$$1(subtract(a, b), subtract(c, d)); - var add2 = multiplyScalar$$1(subtract(e, f), subtract(g, h)); - var add3 = multiplyScalar$$1(subtract(i, j), subtract(k, l)); - return addScalar$$1(addScalar$$1(add1, add2), add3); - } - - function _intersect3d(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4){ - var d1343 = _intersect3dHelper(x1, x3, x4, x3, y1, y3, y4, y3, z1, z3, z4, z3); - var d4321 = _intersect3dHelper(x4, x3, x2, x1, y4, y3, y2, y1, z4, z3, z2, z1); - var d1321 = _intersect3dHelper(x1, x3, x2, x1, y1, y3, y2, y1, z1, z3, z2, z1); - var d4343 = _intersect3dHelper(x4, x3, x4, x3, y4, y3, y4, y3, z4, z3, z4, z3); - var d2121 = _intersect3dHelper(x2, x1, x2, x1, y2, y1, y2, y1, z2, z1, z2, z1); - var ta = divideScalar$$1( - subtract(multiplyScalar$$1(d1343, d4321), multiplyScalar$$1(d1321, d4343)), - subtract(multiplyScalar$$1(d2121, d4343), multiplyScalar$$1(d4321, d4321))); - var tb = divideScalar$$1(addScalar$$1(d1343, multiplyScalar$$1(ta, d4321)), d4343); - - var pax = addScalar$$1(x1, multiplyScalar$$1(ta, subtract(x2, x1))); - var pay = addScalar$$1(y1, multiplyScalar$$1(ta, subtract(y2, y1))); - var paz = addScalar$$1(z1, multiplyScalar$$1(ta, subtract(z2, z1))); - var pbx = addScalar$$1(x3, multiplyScalar$$1(tb, subtract(x4, x3))); - var pby = addScalar$$1(y3, multiplyScalar$$1(tb, subtract(y4, y3))); - var pbz = addScalar$$1(z3, multiplyScalar$$1(tb, subtract(z4, z3))); - if (equalScalar$$1(pax, pbx) && equalScalar$$1(pay, pby) && equalScalar$$1(paz, pbz)){ - return [pax, pay, paz]; - } - else{ - return null; + while (xPrev !== x && i < iMax); + + if (xPrev !== x) { + throw new Error('Function nthRoot failed to converge'); } - } - function _intersectLinePlane(x1, y1, z1, x2, y2, z2, x, y, z, c){ - var x1x = multiplyScalar$$1(x1, x); - var x2x = multiplyScalar$$1(x2, x); - var y1y = multiplyScalar$$1(y1, y); - var y2y = multiplyScalar$$1(y2, y); - var z1z = multiplyScalar$$1(z1, z); - var z2z = multiplyScalar$$1(z2, z); - var t = divideScalar$$1( - subtract(subtract(subtract(c, x1x), y1y), z1z), - subtract(subtract(subtract(addScalar$$1(addScalar$$1(x2x, y2y), z2z), x1x), y1y), z1z)); - var px = addScalar$$1(x1, multiplyScalar$$1(t, subtract(x2, x1))); - var py = addScalar$$1(y1, multiplyScalar$$1(t, subtract(y2, y1))); - var pz = addScalar$$1(z1, multiplyScalar$$1(t, subtract(z2, z1))); - return [px, py, pz]; - // TODO: Add cases when line is parallel to the plane: - // (a) no intersection, - // (b) line contained in plane - } - - return intersect; -} - -var name$179 = 'intersect'; -var factory_1$190 = factory$191; - -var intersect$1 = { - name: name$179, - factory: factory_1$190 -}; - -function factory$192 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var add = load(addScalar); - var subtract = load(subtract$1); - var multiply = load(multiplyScalar); - var divide = load(divideScalar); - var negate = load(unaryMinus$1); - var sqrt = load(sqrt$1); - var abs = load(abs$1); + return inv ? 1 / x : x; + */ + } /** - * Calculates: - * The eucledian distance between two points in 2 and 3 dimensional spaces. - * Distance between point and a line in 2 and 3 dimensional spaces. - * Pairwise distance between a set of 2D or 3D points - * NOTE: - * When substituting coefficients of a line(a, b and c), use ax + by + c = 0 instead of ax + by = c - * For parametric equation of a 3D line, x0, y0, z0, a, b, c are from: (x−x0, y−y0, z−z0) = t(a, b, c) - * - * Syntax: - * math.distance([x1, y1], [x2, y2]) - *- math.distance({pointOneX: 4, pointOneY: 5}, {pointTwoX: 2, pointTwoY: 7}) - * math.distance([x1, y1, z1], [x2, y2, z2]) - * math.distance({pointOneX: 4, pointOneY: 5, pointOneZ: 8}, {pointTwoX: 2, pointTwoY: 7, pointTwoZ: 9}) - * math.distance([[A], [B], [C]...]) - * math.distance([x1, y1], [LinePtX1, LinePtY1], [LinePtX2, LinePtY2]) - * math.distance({pointX: 1, pointY: 4}, {lineOnePtX: 6, lineOnePtY: 3}, {lineTwoPtX: 2, lineTwoPtY: 8}) - * math.distance([x1, y1, z1], [LinePtX1, LinePtY1, LinePtZ1], [LinePtX2, LinePtY2, LinePtZ2]) - * math.distance({pointX: 1, pointY: 4, pointZ: 7}, {lineOnePtX: 6, lineOnePtY: 3, lineOnePtZ: 4}, {lineTwoPtX: 2, lineTwoPtY: 8, lineTwoPtZ: 5}) - * math.distance([x1, y1], [xCoeffLine, yCoeffLine, constant]) - * math.distance({pointX: 10, pointY: 10}, {xCoeffLine: 8, yCoeffLine: 1, constant: 3}) - * math.distance([x1, y1, z1], [x0, y0, z0, a-tCoeff, b-tCoeff, c-tCoeff]) point and parametric equation of 3D line - * math.distance([x, y, z], [x0, y0, z0, a, b, c]) - * math.distance({pointX: 2, pointY: 5, pointZ: 9}, {x0: 4, y0: 6, z0: 3, a: 4, b: 2, c: 0}) - * - * Examples: - * math.distance([0,0], [4,4]) // Returns 5.6569 - * math.distance( - * {pointOneX: 0, pointOneY: 0}, - * {pointTwoX: 10, pointTwoY: 10}) // Returns 14.142135623730951 - * math.distance([1, 0, 1], [4, -2, 2]) // Returns 3.74166 - * math.distance( - * {pointOneX: 4, pointOneY: 5, pointOneZ: 8}, - * {pointTwoX: 2, pointTwoY: 7, pointTwoZ: 9}) // Returns 3 - * math.distance([[1, 2], [1, 2], [1, 3]]) // Returns [0, 1, 1] - * math.distance([[1,2,4], [1,2,6], [8,1,3]]) // Returns [2, 7.14142842854285, 7.681145747868608] - * math.distance([10, 10], [8, 1, 3]) // Returns 11.535230316796387 - * math.distance([10, 10], [2, 3], [-8, 0]) // Returns 8.759953130362847 - * math.distance( - * {pointX: 1, pointY: 4}, - * {lineOnePtX: 6, lineOnePtY: 3}, - * {lineTwoPtX: 2, lineTwoPtY: 8}) // Returns 2.720549372624744 - * math.distance([2, 3, 1], [1, 1, 2, 5, 0, 1]) // Returns 2.3204774044612857 - * math.distance( - * {pointX: 2, pointY: 3, pointZ: 1}, - * {x0: 1, y0: 1, z0: 2, a: 5, b: 0, c: 1} // Returns 2.3204774044612857 - * - * @param {Array | Matrix | Object} x Co-ordinates of first point - * @param {Array | Matrix | Object} y Co-ordinates of second point - * @return {Number | BigNumber} Returns the distance from two/three points - */ - - var distance = typed('distance', { - 'Array, Array, Array': function(x, y, z){ - // Point to Line 2D; (x=Point, y=LinePoint1, z=LinePoint2) - if (x.length == 2 && y.length == 2 && z.length == 2){ - if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } - if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } - if (!_2d(z)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for third argument'); } - var m = divide(subtract(z[1], z[0]), subtract(y[1], y[0])); - var xCoeff = multiply(multiply(m, m), y[0]); - var yCoeff = negate(multiply(m, y[0])); - var constant = x[1]; + * Calculate the nth root of a Complex Number a using De Moviers Theorem. + * @param {Complex} a + * @param {number} root + * @return {Array} array or n Complex Roots in Polar Form. + */ + function _nthComplexRoot(a, root) { + if (root < 0) throw new Error('Root must be greater than zero'); + if (root === 0) throw new Error('Root must be non-zero'); + if (root % 1 !== 0) throw new Error('Root must be an integer'); + var arg = a.arg(); + var abs = a.abs(); + var roots = []; + var r = Math.pow(abs, 1/root); + for(var k = 0; k < root; k++) { + roots.push({r: r, phi: (arg + 2 * Math.PI * k)/root}); + } + return roots; + } - return _distancePointLine2D(x[0], x[1], xCoeff, yCoeff, constant); - } - else{ - throw new TypeError('Invalid Arguments: Try again'); - } - }, - 'Object, Object, Object': function(x, y, z){ - if (Object.keys(x).length == 2 && Object.keys(y).length == 2 && Object.keys(z).length == 2){ - if (!_2d(x)) { throw new TypeError('Values of pointX and pointY should be numbers or BigNumbers'); } - if (!_2d(y)) { throw new TypeError('Values of lineOnePtX and lineOnePtY should be numbers or BigNumbers'); } - if (!_2d(z)) { throw new TypeError('Values of lineTwoPtX and lineTwoPtY should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('lineOnePtX') && - y.hasOwnProperty('lineOnePtY') && z.hasOwnProperty('lineTwoPtX') && z.hasOwnProperty('lineTwoPtY')){ - var m = divide(subtract(z.lineTwoPtY, z.lineTwoPtX), subtract(y.lineOnePtY, y.lineOnePtX)); - var xCoeff = multiply(multiply(m, m), y.lineOnePtX); - var yCoeff = negate(multiply(m, y.lineOnePtX)); - var constant = x.pointX; - - return _distancePointLine2D(x.pointX, x.pointY, xCoeff, yCoeff, constant); - } - else{ - throw new TypeError('Key names do not match'); - } - } - else{ - throw new TypeError('Invalid Arguments: Try again'); - } - }, - 'Array, Array': function(x, y){ - // Point to Line 2D; (x=[pointX, pointY], y=[x-coeff, y-coeff, const]) - if (x.length == 2 && y.length == 3){ - if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } - if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } + var name$155 = 'nthRoot'; + var factory_1$166 = factory$167; - return _distancePointLine2D(x[0], x[1], y[0], y[1], y[2]); - } - // Point to Line 3D - else if (x.length == 3 && y.length == 6){ - if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } - if (!_parametricLine(y)) { throw new TypeError('Array with 6 numbers or BigNumbers expected for second argument'); } + var nthRoot$1 = { + name: name$155, + factory: factory_1$166 + }; - return _distancePointLine3D(x[0], x[1], x[2], y[0], y[1], y[2], y[3], y[4], y[5]); - } - // Point to Point 2D - else if (x.length == 2 && y.length == 2){ - if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } - if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } + var isInteger$11 = number.isInteger; + var toFixed = number.toFixed; - return _distance2d(x[0], x[1], y[0], y[1]); - } - // Point to Point 3D - else if(x.length == 3 && y.length == 3){ - if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } - if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - return _distance3d(x[0], x[1], x[2], y[0], y[1], y[2]); - } - else{ - throw new TypeError('Invalid Arguments: Try again'); - } - }, - 'Object, Object': function(x, y){ - if (Object.keys(x).length == 2 && Object.keys(y).length == 3){ - if (!_2d(x)) { throw new TypeError('Values of pointX and pointY should be numbers or BigNumbers'); } - if (!_3d(y)) { throw new TypeError('Values of xCoeffLine, yCoeffLine and constant should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('xCoeffLine') && - y.hasOwnProperty('yCoeffLine') && y.hasOwnProperty('constant')){ + var NO_INT = 'Number of decimals in function round must be an integer'; - return _distancePointLine2D(x.pointX, x.pointY, y.xCoeffLine, y.yCoeffLine, y.constant); - } - else{ - throw new TypeError('Key names do not match'); - } - } - // Point to Line 3D - else if (Object.keys(x).length == 3 && Object.keys(y).length == 6){ - if (!_3d(x)) { throw new TypeError('Values of pointX, pointY and pointZ should be numbers or BigNumbers'); } - if (!_parametricLine(y)) { throw new TypeError('Values of x0, y0, z0, a, b and c should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('x0') && - y.hasOwnProperty('y0') && y.hasOwnProperty('z0') && y.hasOwnProperty('a') && - y.hasOwnProperty('b') && y.hasOwnProperty('c')){ + function factory$168 (type, config, load, typed) { + var matrix$$1 = load(matrix); + var equalScalar$$1 = load(equalScalar); + var zeros = load(zeros$1); - return _distancePointLine3D(x.pointX, x.pointY, x.pointZ, y.x0, y.y0, y.z0, y.a, y.b, y.c); - } - else{ - throw new TypeError('Key names do not match'); - } - } - // Point to Point 2D - else if (Object.keys(x).length == 2 && Object.keys(y).length == 2){ - if (!_2d(x)) { throw new TypeError('Values of pointOneX and pointOneY should be numbers or BigNumbers'); } - if (!_2d(y)) { throw new TypeError('Values of pointTwoX and pointTwoY should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointOneX') && x.hasOwnProperty('pointOneY') && - y.hasOwnProperty('pointTwoX') && y.hasOwnProperty('pointTwoY')){ + var algorithm11$$1 = load(algorithm11); + var algorithm12$$1 = load(algorithm12); + var algorithm14$$1 = load(algorithm14); + + /** + * Round a value towards the nearest integer. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.round(x) + * math.round(x, n) + * + * Examples: + * + * math.round(3.2); // returns number 3 + * math.round(3.8); // returns number 4 + * math.round(-4.2); // returns number -4 + * math.round(-4.7); // returns number -5 + * math.round(math.pi, 3); // returns number 3.142 + * math.round(123.45678, 2); // returns number 123.46 + * + * var c = math.complex(3.2, -2.7); + * math.round(c); // returns Complex 3 - 3i + * + * math.round([3.2, 3.8, -4.7]); // returns Array [3, 4, -5] + * + * See also: + * + * ceil, fix, floor + * + * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded + * @param {number | BigNumber | Array} [n=0] Number of decimals + * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value + */ + var round = typed('round', { - return _distance2d(x.pointOneX, x.pointOneY, y.pointTwoX, y.pointTwoY); - } - else{ - throw new TypeError('Key names do not match'); - } - } - // Point to Point 3D - else if(Object.keys(x).length == 3 && Object.keys(y).length == 3){ - if (!_3d(x)) { throw new TypeError('Values of pointOneX, pointOneY and pointOneZ should be numbers or BigNumbers'); } - if (!_3d(y)) { throw new TypeError('Values of pointTwoX, pointTwoY and pointTwoZ should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointOneX') && x.hasOwnProperty('pointOneY') && x.hasOwnProperty('pointOneZ') && - y.hasOwnProperty('pointTwoX') && y.hasOwnProperty('pointTwoY') && y.hasOwnProperty('pointTwoZ')){ + 'number': Math.round, - return _distance3d(x.pointOneX, x.pointOneY, x.pointOneZ, y.pointTwoX, y.pointTwoY, y.pointTwoZ); - } - else { - throw new TypeError('Key names do not match'); - } - } - else{ - throw new TypeError('Invalid Arguments: Try again'); - } - }, - 'Array': function(arr){ - if (!_pairwise(arr)) { throw new TypeError('Incorrect array format entered for pairwise distance calculation'); } + 'number, number': function (x, n) { + if (!isInteger$11(n)) {throw new TypeError(NO_INT);} + if (n < 0 || n > 15) {throw new Error('Number of decimals in function round must be in te range of 0-15');} - return _distancePairwise(arr); - } - }); + return _round(x, n); + }, - function _isNumber(a) { - // distance supports numbers and bignumbers - return (typeof a === 'number' || type.isBigNumber(a)); - } + 'Complex': function (x) { + return x.round(); + }, - function _2d(a){ - // checks if the number of arguments are correct in count and are valid (should be numbers) - if (a.constructor !== Array){ - a = _objectToArray(a); - } - return _isNumber(a[0]) && _isNumber(a[1]); - } + 'Complex, number': function (x, n) { + if (n % 1) {throw new TypeError(NO_INT);} + + return x.round(n); + }, - function _3d(a){ - // checks if the number of arguments are correct in count and are valid (should be numbers) - if (a.constructor !== Array){ - a = _objectToArray(a); - } - return _isNumber(a[0]) && _isNumber(a[1]) && _isNumber(a[2]); - } + 'Complex, BigNumber': function (x, n) { + if (!n.isInteger()) {throw new TypeError(NO_INT);} - function _parametricLine(a){ - if (a.constructor !== Array){ - a = _objectToArray(a); - } - return _isNumber(a[0]) && _isNumber(a[1]) && _isNumber(a[2]) && - _isNumber(a[3]) && _isNumber(a[4]) && _isNumber(a[5]); - } + var _n = n.toNumber(); + return x.round(_n); + }, - function _objectToArray(o){ - var keys = Object.keys(o); - var a = []; - for (var i = 0; i < keys.length; i++) { - a.push(o[keys[i]]); - } - return a; - } + 'number, BigNumber': function (x, n) { + if (!n.isInteger()) {throw new TypeError(NO_INT);} - function _pairwise(a){ - //checks for valid arguments passed to _distancePairwise(Array) - if (a[0].length == 2 && _isNumber(a[0][0]) && _isNumber(a[0][1])){ - for(var i in a){ - if (a[i].length != 2 || !_isNumber(a[i][0]) || !_isNumber(a[i][1])){ - return false; - } - } - } - else if (a[0].length == 3 && _isNumber(a[0][0]) && _isNumber(a[0][1]) && _isNumber(a[0][2])){ - for(var i in a){ - if (a[i].length != 3 || !_isNumber(a[i][0]) || !_isNumber(a[i][1]) || !_isNumber(a[i][2])){ - return false; - } - } - } - else{ - return false; - } - return true; - } + return new type.BigNumber(x).toDecimalPlaces(n.toNumber()); + }, - function _distancePointLine2D(x, y, a, b, c){ - var num = abs(add(add(multiply(a, x), multiply(b, y)), c)); - var den = sqrt(add(multiply(a, a), multiply(b, b))); - var result = divide(num, den); - return result; - } + 'BigNumber': function (x) { + return x.toDecimalPlaces(0); + }, - function _distancePointLine3D(x, y, z, x0, y0, z0, a, b, c){ - var num = [ subtract(multiply(subtract(y0, y), c), multiply(subtract(z0, z), b)), - subtract(multiply(subtract(z0, z), a), multiply(subtract(x0, x), c)), - subtract(multiply(subtract(x0, x), b), multiply(subtract(y0, y), a)) ]; - num = sqrt(add(add(multiply(num[0], num[0]), multiply(num[1], num[1])), multiply(num[2], num[2]))); - var den = sqrt(add(add(multiply(a, a), multiply(b, b)), multiply(c, c))); - var result = divide(num, den); - return result; - } + 'BigNumber, BigNumber': function (x, n) { + if (!n.isInteger()) {throw new TypeError(NO_INT);} - function _distance2d(x1, y1, x2, y2){ - var yDiff = subtract(y2, y1); - var xDiff = subtract(x2, x1); - var radicant = add(multiply(yDiff, yDiff), multiply(xDiff, xDiff)); - var result = sqrt(radicant); - return result; - } + return x.toDecimalPlaces(n.toNumber()); + }, - function _distance3d(x1, y1, z1, x2, y2, z2){ - var zDiff = subtract(z2, z1); - var yDiff = subtract(y2, y1); - var xDiff = subtract(x2, x1); - var radicant = add(add(multiply(zDiff, zDiff), multiply(yDiff, yDiff)), multiply(xDiff, xDiff)); - var result = sqrt(radicant); - return result; - } + 'Fraction': function (x) { + return x.round(); + }, - function _distancePairwise(a){ - var result = []; - for(var i = 0; i < a.length-1; i++){ - for(var j = i+1; j < a.length; j++){ - if (a[0].length == 2){ - result.push(_distance2d(a[i][0], a[i][1], a[j][0], a[j][1])); - } - else if (a[0].length == 3){ - result.push(_distance3d(a[i][0], a[i][1], a[i][2], a[j][0], a[j][1], a[j][2])); + 'Fraction, number': function (x, n) { + if (n % 1) {throw new TypeError(NO_INT);} + return x.round(n); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since round(0) = 0 + return deepMap(x, round, true); + }, + + 'SparseMatrix, number | BigNumber': function (x, y) { + return algorithm11$$1(x, y, round, false); + }, + + 'DenseMatrix, number | BigNumber': function (x, y) { + return algorithm14$$1(x, y, round, false); + }, + + 'number | Complex | BigNumber, SparseMatrix': function (x, y) { + // check scalar is zero + if (equalScalar$$1(x, 0)) { + // do not execute algorithm, result will be a zero matrix + return zeros(y.size(), y.storage()); } - } - } - return result; - } + return algorithm12$$1(y, x, round, true); + }, - return distance; -} + 'number | Complex | BigNumber, DenseMatrix': function (x, y) { + // check scalar is zero + if (equalScalar$$1(x, 0)) { + // do not execute algorithm, result will be a zero matrix + return zeros(y.size(), y.storage()); + } + return algorithm14$$1(y, x, round, true); + }, -var name$180 = 'distance'; -var factory_1$191 = factory$192; + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, round, false).valueOf(); + }, -var distance$1 = { - name: name$180, - factory: factory_1$191 -}; + 'number | Complex | BigNumber, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, round, true).valueOf(); + } + }); -var geometry = [ - intersect$1, - distance$1 -]; + round.toTex = { + 1: '\\left\\lfloor${args[0]}\\right\\rceil', + 2: undefined // use default template + }; -function factory$193 (type, config, load, typed) { - var latex$$1 = latex; + return round; + } /** - * Logical `not`. Flips boolean value of a given parameter. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.not(x) - * - * Examples: - * - * math.not(2); // returns false - * math.not(0); // returns true - * math.not(true); // returns false - * - * a = [2, -7, 0]; - * math.not(a); // returns [false, false, true] - * - * See also: - * - * and, or, xor - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @return {boolean | Array | Matrix} - * Returns true when input is a zero or empty value. + * round a number to the given number of decimals, or to zero if decimals is + * not provided + * @param {number} value + * @param {number} decimals number of decimals, between 0 and 15 (0 by default) + * @return {number} roundedValue + * @private */ - var not = typed('not', { - 'number': function (x) { - return !x; - }, + function _round (value, decimals) { + return parseFloat(toFixed(value, decimals)); + } - 'Complex': function (x) { - return x.re === 0 && x.im === 0; - }, + var name$156 = 'round'; + var factory_1$167 = factory$168; - 'BigNumber': function (x) { - return x.isZero() || x.isNaN(); - }, + var round$1 = { + name: name$156, + factory: factory_1$167 + }; - 'Unit': function (x) { - return x.value !== null ? not(x.value) : true; - }, + function factory$169 (type, config, load, typed) { + /** + * Compute the square of a value, `x * x`. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.square(x) + * + * Examples: + * + * math.square(2); // returns number 4 + * math.square(3); // returns number 9 + * math.pow(3, 2); // returns number 9 + * math.multiply(3, 3); // returns number 9 + * + * math.square([1, 2, 3, 4]); // returns Array [1, 4, 9, 16] + * + * See also: + * + * multiply, cube, sqrt, pow + * + * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x + * Number for which to calculate the square + * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} + * Squared value + */ + var square = typed('square', { + 'number': function (x) { + return x * x; + }, - 'Array | Matrix': function (x) { - return deepMap(x, not); - } - }); + 'Complex': function (x) { + return x.mul(x); + }, - not.toTex = { - 1: latex$$1.operators['not'] + '\\left(${args[0]}\\right)' - }; + 'BigNumber': function (x) { + return x.times(x); + }, - return not; -} + 'Fraction': function (x) { + return x.mul(x); + }, -var name$181 = 'not'; -var factory_1$192 = factory$193; + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since square(0) = 0 + return deepMap(x, square, true); + }, -var not$1 = { - name: name$181, - factory: factory_1$192 -}; + 'Unit': function(x) { + return x.pow(2); + } + }); -function factory$194 (type, config, load, typed) { - var latex$$1 = latex; + square.toTex = {1: '\\left(${args[0]}\\right)^2'}; - var matrix$$1 = load(matrix); - var zeros = load(zeros$1); - var not = load(not$1); - var isZero = load(isZero$1); + return square; + } - var algorithm02$$1 = load(algorithm02); - var algorithm06$$1 = load(algorithm06); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + var name$157 = 'square'; + var factory_1$168 = factory$169; - /** - * Logical `and`. Test whether two values are both defined with a nonzero/nonempty value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.and(x, y) - * - * Examples: - * - * math.and(2, 4); // returns true - * - * a = [2, 0, 0]; - * b = [3, 7, 0]; - * c = 0; - * - * math.and(a, b); // returns [true, false, false] - * math.and(a, c); // returns [false, false, false] - * - * See also: - * - * not, or, xor - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check - * @return {boolean | Array | Matrix} - * Returns true when both inputs are defined with a nonzero/nonempty value. - */ - var and = typed('and', { + var square$1 = { + name: name$157, + factory: factory_1$168 + }; - 'number, number': function (x, y) { - return !!(x && y); - }, + function factory$170 (type, config, load, typed) { + var latex$$1 = latex; - 'Complex, Complex': function (x, y) { - return (x.re !== 0 || x.im !== 0) && (y.re !== 0 || y.im !== 0); - }, + /** + * Unary plus operation. + * Boolean values and strings will be converted to a number, numeric values will be returned as is. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.unaryPlus(x) + * + * Examples: + * + * math.unaryPlus(3.5); // returns 3.5 + * math.unaryPlus(1); // returns 1 + * + * See also: + * + * unaryMinus, add, subtract + * + * @param {number | BigNumber | Fraction | string | Complex | Unit | Array | Matrix} x + * Input value + * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} + * Returns the input value when numeric, converts to a number when input is non-numeric. + */ + var unaryPlus = typed('unaryPlus', { + 'number': function (x) { + return x; + }, - 'BigNumber, BigNumber': function (x, y) { - return !x.isZero() && !y.isZero() && !x.isNaN() && !y.isNaN(); - }, + 'Complex': function (x) { + return x; // complex numbers are immutable + }, - 'Unit, Unit': function (x, y) { - return and(x.value || 0, y.value || 0); - }, + 'BigNumber': function (x) { + return x; // bignumbers are immutable + }, - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm06$$1(x, y, and, false); - }, + 'Fraction': function (x) { + return x; // fractions are immutable + }, - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, and, true); - }, + 'Unit': function (x) { + return x.clone(); + }, - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm02$$1(x, y, and, false); - }, + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since unaryPlus(0) = 0 + return deepMap(x, unaryPlus, true); + }, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, and); - }, + 'boolean | string': function (x) { + // convert to a number or bignumber + return (config.number == 'BigNumber') ? new type.BigNumber(+x): +x; + } + }); - 'Array, Array': function (x, y) { - // use matrix implementation - return and(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + unaryPlus.toTex = { + 1: latex$$1.operators['unaryPlus'] + '\\left(${args[0]}\\right)' + }; - 'Array, Matrix': function (x, y) { - // use matrix implementation - return and(matrix$$1(x), y); - }, + return unaryPlus; + } - 'Matrix, Array': function (x, y) { - // use matrix implementation - return and(x, matrix$$1(y)); - }, + var name$158 = 'unaryPlus'; + var factory_1$169 = factory$170; - 'SparseMatrix, any': function (x, y) { - // check scalar - if (not(y)) { - // return zero matrix - return zeros(x.size(), x.storage()); - } - return algorithm11$$1(x, y, and, false); - }, + var unaryPlus$1 = { + name: name$158, + factory: factory_1$169 + }; - 'DenseMatrix, any': function (x, y) { - // check scalar - if (not(y)) { - // return zero matrix - return zeros(x.size(), x.storage()); - } - return algorithm14$$1(x, y, and, false); - }, + var isInteger$12 = number.isInteger; - 'any, SparseMatrix': function (x, y) { - // check scalar - if (not(x)) { - // return zero matrix - return zeros(x.size(), x.storage()); - } - return algorithm11$$1(y, x, and, true); - }, + function factory$171 (type, config, load, typed) { + var matrix$$1 = load(matrix); + + /** + * Calculate the extended greatest common divisor for two values. + * See http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm. + * + * Syntax: + * + * math.xgcd(a, b) + * + * Examples: + * + * math.xgcd(8, 12); // returns [4, -1, 1] + * math.gcd(8, 12); // returns 4 + * math.xgcd(36163, 21199); // returns [1247, -7, 12] + * + * See also: + * + * gcd, lcm + * + * @param {number | BigNumber} a An integer number + * @param {number | BigNumber} b An integer number + * @return {Array} Returns an array containing 3 integers `[div, m, n]` + * where `div = gcd(a, b)` and `a*m + b*n = div` + */ + var xgcd = typed('xgcd', { + 'number, number': _xgcd, + 'BigNumber, BigNumber': _xgcdBigNumber + // TODO: implement support for Fraction + }); + + xgcd.toTex = undefined; // use default template - 'any, DenseMatrix': function (x, y) { - // check scalar - if (not(x)) { - // return zero matrix - return zeros(x.size(), x.storage()); + return xgcd; + + /** + * Calculate xgcd for two numbers + * @param {number} a + * @param {number} b + * @return {number} result + * @private + */ + function _xgcd (a, b) { + // source: http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm + var t, // used to swap two variables + q, // quotient + r, // remainder + x = 0, lastx = 1, + y = 1, lasty = 0; + + if (!isInteger$12(a) || !isInteger$12(b)) { + throw new Error('Parameters in function xgcd must be integer numbers'); } - return algorithm14$$1(y, x, and, true); - }, - 'Array, any': function (x, y) { - // use matrix implementation - return and(matrix$$1(x), y).valueOf(); - }, + while (b) { + q = Math.floor(a / b); + r = a - q*b; - 'any, Array': function (x, y) { - // use matrix implementation - return and(x, matrix$$1(y)).valueOf(); - } - }); + t = x; + x = lastx - q * x; + lastx = t; - and.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['and'] + '${args[1]}\\right)' - }; + t = y; + y = lasty - q * y; + lasty = t; - return and; -} + a = b; + b = r; + } -var name$182 = 'and'; -var factory_1$193 = factory$194; + var res; + if (a < 0) { + res = [-a, -lastx, -lasty]; + } + else { + res = [a, a ? lastx : 0, lasty]; + } + return (config.matrix === 'Array') ? res : matrix$$1(res); + } -var and$1 = { - name: name$182, - factory: factory_1$193 -}; + /** + * Calculate xgcd for two BigNumbers + * @param {BigNumber} a + * @param {BigNumber} b + * @return {BigNumber[]} result + * @private + */ + function _xgcdBigNumber(a, b) { + // source: http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm + var t, // used to swap two variables + q, // quotient + r, // remainder + zero = new type.BigNumber(0), + one = new type.BigNumber(1), + x = zero, + lastx = one, + y = one, + lasty = zero; + + if (!a.isInt() || !b.isInt()) { + throw new Error('Parameters in function xgcd must be integer numbers'); + } + + while (!b.isZero()) { + q = a.div(b).floor(); + r = a.mod(b); + + t = x; + x = lastx.minus(q.times(x)); + lastx = t; + + t = y; + y = lasty.minus(q.times(y)); + lasty = t; -function factory$195 (type, config, load, typed) { - var latex$$1 = latex; + a = b; + b = r; + } - var matrix$$1 = load(matrix); + var res; + if (a.lt(zero)) { + res = [a.neg(), lastx.neg(), lasty.neg()]; + } + else { + res = [a, !a.isZero() ? lastx : 0, lasty]; + } + return (config.matrix === 'Array') ? res : matrix$$1(res); + } + } + + var name$159 = 'xgcd'; + var factory_1$170 = factory$171; + + var xgcd$1 = { + name: name$159, + factory: factory_1$170 + }; + + var arithmetic = [ + abs$1, + add, + addScalar, + cbrt$1, + ceil$1, + cube$1, + divide$1, + dotDivide$1, + dotMultiply$1, + dotPow$1, + exp$1, + expm1$1, + fix$1, + floor$1, + gcd$1, + hypot$1, + lcm$1, + log$1, + log10$1, + log1p$1, + log2$1, + mod$1, + multiply$1, + norm$1, + nthRoot$1, + pow$1, + round$1, + sign$1, + sqrt$1, + square$1, + subtract$1, + unaryMinus$1, + unaryPlus$1, + xgcd$1 + ]; - var algorithm03$$1 = load(algorithm03); - var algorithm05$$1 = load(algorithm05); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - /** - * Logical `or`. Test if at least one value is defined with a nonzero/nonempty value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.or(x, y) - * - * Examples: - * - * math.or(2, 4); // returns true - * - * a = [2, 5, 0]; - * b = [0, 22, 0]; - * c = 0; - * - * math.or(a, b); // returns [true, true, false] - * math.or(b, c); // returns [false, true, false] + * Bitwise not + * @param {BigNumber} value + * @return {BigNumber} Result of ~`x`, fully precise * - * See also: - * - * and, not, xor - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check - * @return {boolean | Array | Matrix} - * Returns true when one of the inputs is defined with a nonzero/nonempty value. */ - var or = typed('or', { - - 'number, number': function (x, y) { - return !!(x || y); - }, - - 'Complex, Complex': function (x, y) { - return (x.re !== 0 || x.im !== 0) || (y.re !== 0 || y.im !== 0); - }, + var bitNot$1 = function bitNot (x) { + if (x.isFinite() && !x.isInteger()) { + throw new Error('Integer expected in function bitNot'); + } - 'BigNumber, BigNumber': function (x, y) { - return (!x.isZero() && !x.isNaN()) || (!y.isZero() && !y.isNaN()); - }, + var BigNumber = x.constructor; + var prevPrec = BigNumber.precision; + BigNumber.config({precision: 1E9}); - 'Unit, Unit': function (x, y) { - return or(x.value || 0, y.value || 0); - }, + var x = x.plus(new BigNumber(1)); + x.s = -x.s || null; - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm05$$1(x, y, or); - }, + BigNumber.config({precision: prevPrec}); + return x; + }; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, or, true); - }, + /** + * Applies bitwise function to numbers + * @param {BigNumber} x + * @param {BigNumber} y + * @param {function (a, b)} func + * @return {BigNumber} + */ + var bitwise = function bitwise(x, y, func) { + var BigNumber = x.constructor; - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, or, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, or); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return or(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return or(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return or(x, matrix$$1(y)); - }, + var xBits, yBits; + var xSign = +(x.s < 0); + var ySign = +(y.s < 0); + if (xSign) { + xBits = decCoefficientToBinaryString(bitNot$1(x)); + for (var i = 0; i < xBits.length; ++i) { + xBits[i] ^= 1; + } + } else { + xBits = decCoefficientToBinaryString(x); + } + if (ySign) { + yBits = decCoefficientToBinaryString(bitNot$1(y)); + for (var i = 0; i < yBits.length; ++i) { + yBits[i] ^= 1; + } + } else { + yBits = decCoefficientToBinaryString(y); + } - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, or, false); - }, + var minBits, maxBits, minSign; + if (xBits.length <= yBits.length) { + minBits = xBits; + maxBits = yBits; + minSign = xSign; + } else { + minBits = yBits; + maxBits = xBits; + minSign = ySign; + } - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, or, false); - }, + var shortLen = minBits.length; + var longLen = maxBits.length; + var expFuncVal = func(xSign, ySign) ^ 1; + var outVal = new BigNumber(expFuncVal ^ 1); + var twoPower = new BigNumber(1); + var two = new BigNumber(2); - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, or, true); - }, + var prevPrec = BigNumber.precision; + BigNumber.config({precision: 1E9}); - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, or, true); - }, + while (shortLen > 0) { + if (func(minBits[--shortLen], maxBits[--longLen]) == expFuncVal) { + outVal = outVal.plus(twoPower); + } + twoPower = twoPower.times(two); + } + while (longLen > 0) { + if (func(minSign, maxBits[--longLen]) == expFuncVal) { + outVal = outVal.plus(twoPower); + } + twoPower = twoPower.times(two); + } - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, or, false).valueOf(); - }, + BigNumber.config({precision: prevPrec}); - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, or, true).valueOf(); + if (expFuncVal == 0) { + outVal.s = -outVal.s; } - }); - - or.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['or'] + '${args[1]}\\right)' + return outVal; }; - return or; -} + /* Extracted from decimal.js, and edited to specialize. */ + function decCoefficientToBinaryString (x) { + // Convert to string + var a = x.d; // array with digits + var r = a[0] + ''; -var name$183 = 'or'; -var factory_1$194 = factory$195; + for (var i = 1; i < a.length; ++i) { + var s = a[i] + ''; + for (var z = 7 - s.length; z--; ) { + s = '0' + s; + } + + r += s; + } -var or$1 = { - name: name$183, - factory: factory_1$194 -}; + var j; + for (j = r.length - 1; r.charAt(j) == '0'; --j); + + var xe = x.e; + var str = r.slice(0, j + 1 || 1); + var strL = str.length; + if (xe > 0) { + if (++xe > strL) { + // Append zeros. + for (xe -= strL; xe--; str += '0'); + } else if (xe < strL) { + str = str.slice(0, xe) + '.' + str.slice(xe); + } + } + + // Convert from base 10 (decimal) to base 2 + var arr = [0]; + for (var i = 0; i < str.length; ) { + for (var arrL = arr.length; arrL--; arr[arrL] *= 10); + + arr[0] += str.charAt(i++) << 0; // convert to int + for (var j = 0; j < arr.length; ++j) { + if (arr[j] > 1) { + if (arr[j + 1] == null) { + arr[j + 1] = 0; + } -function factory$196 (type, config, load, typed) { - var latex$$1 = latex; + arr[j + 1] += arr[j] >> 1; + arr[j] &= 1; + } + } + } - var matrix$$1 = load(matrix); + return arr.reverse(); + } - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - /** - * Logical `xor`. Test whether one and only one value is defined with a nonzero/nonempty value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.xor(x, y) + * Bitwise and for Bignumbers * - * Examples: - * - * math.xor(2, 4); // returns false - * - * a = [2, 0, 0]; - * b = [2, 7, 0]; - * c = 0; - * - * math.xor(a, b); // returns [false, true, false] - * math.xor(a, c); // returns [true, false, false] + * Special Cases: + * N & n = N + * n & 0 = 0 + * n & -1 = n + * n & n = n + * I & I = I + * -I & -I = -I + * I & -I = 0 + * I & n = n + * I & -n = I + * -I & n = 0 + * -I & -n = -I * - * See also: - * - * and, not, or - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check - * @return {boolean | Array | Matrix} - * Returns true when one and only one input is defined with a nonzero/nonempty value. + * @param {BigNumber} x + * @param {BigNumber} y + * @return {BigNumber} Result of `x` & `y`, is fully precise + * @private */ - var xor = typed('xor', { - - 'number, number': function (x, y) { - return !!x !== !!y; - }, + var bitAnd$1 = function bitAnd(x, y) { + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Integers expected in function bitAnd'); + } - 'Complex, Complex': function (x, y) { - return ((x.re !== 0 || x.im !== 0) !== (y.re !== 0 || y.im !== 0)); - }, + var BigNumber = x.constructor; + if (x.isNaN() || y.isNaN()) { + return new BigNumber(NaN); + } - 'BigNumber, BigNumber': function (x, y) { - return ((!x.isZero() && !x.isNaN()) !== (!y.isZero() && !y.isNaN())); - }, + if (x.isZero() || y.eq(-1) || x.eq(y)) { + return x; + } + if (y.isZero() || x.eq(-1)) { + return y; + } - 'Unit, Unit': function (x, y) { - return xor(x.value || 0, y.value || 0); - }, + if (!x.isFinite() || !y.isFinite()) { + if (!x.isFinite() && !y.isFinite()) { + if (x.isNegative() == y.isNegative()) { + return x; + } + return new BigNumber(0); + } + if (!x.isFinite()) { + if (y.isNegative()) { + return x; + } + if (x.isNegative()) { + return new BigNumber(0); + } + return y; + } + if (!y.isFinite()) { + if (x.isNegative()) { + return y; + } + if (y.isNegative()) { + return new BigNumber(0); + } + return x; + } + } + return bitwise(x, y, function (a, b) { return a & b }); + }; - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, xor); - }, + var isInteger$13 = number.isInteger; - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, xor, true); - }, - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, xor, false); - }, + function factory$172 (type, config, load, typed) { + var latex$$1 = latex; - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, xor); - }, + var matrix$$1 = load(matrix); - 'Array, Array': function (x, y) { - // use matrix implementation - return xor(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + var algorithm02$$1 = load(algorithm02); + var algorithm06$$1 = load(algorithm06); + var algorithm11$$1 = load(algorithm11); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + /** + * Bitwise AND two values, `x & y`. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.bitAnd(x, y) + * + * Examples: + * + * math.bitAnd(53, 131); // returns number 1 + * + * math.bitAnd([1, 12, 31], 42); // returns Array [0, 8, 10] + * + * See also: + * + * bitNot, bitOr, bitXor, leftShift, rightArithShift, rightLogShift + * + * @param {number | BigNumber | Array | Matrix} x First value to and + * @param {number | BigNumber | Array | Matrix} y Second value to and + * @return {number | BigNumber | Array | Matrix} AND of `x` and `y` + */ + var bitAnd = typed('bitAnd', { - 'Array, Matrix': function (x, y) { - // use matrix implementation - return xor(matrix$$1(x), y); - }, + 'number, number': function (x, y) { + if (!isInteger$13(x) || !isInteger$13(y)) { + throw new Error('Integers expected in function bitAnd'); + } - 'Matrix, Array': function (x, y) { - // use matrix implementation - return xor(x, matrix$$1(y)); - }, + return x & y; + }, - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, xor, false); - }, + 'BigNumber, BigNumber': bitAnd$1, - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, xor, false); - }, + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm06$$1(x, y, bitAnd, false); + }, - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, xor, true); - }, + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm02$$1(y, x, bitAnd, true); + }, - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, xor, true); - }, + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm02$$1(x, y, bitAnd, false); + }, - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, xor, false).valueOf(); - }, + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, bitAnd); + }, - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, xor, true).valueOf(); - } - }); + 'Array, Array': function (x, y) { + // use matrix implementation + return bitAnd(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - xor.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['xor'] + '${args[1]}\\right)' - }; + 'Array, Matrix': function (x, y) { + // use matrix implementation + return bitAnd(matrix$$1(x), y); + }, - return xor; -} + 'Matrix, Array': function (x, y) { + // use matrix implementation + return bitAnd(x, matrix$$1(y)); + }, + + 'SparseMatrix, any': function (x, y) { + return algorithm11$$1(x, y, bitAnd, false); + }, -var name$184 = 'xor'; -var factory_1$195 = factory$196; + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, bitAnd, false); + }, -var xor$1 = { - name: name$184, - factory: factory_1$195 -}; + 'any, SparseMatrix': function (x, y) { + return algorithm11$$1(y, x, bitAnd, true); + }, -var logical = [ - and$1, - not$1, - or$1, - xor$1 -]; + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, bitAnd, true); + }, -function factory$197 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var subtract = load(subtract$1); - var multiply = load(multiply$1); + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, bitAnd, false).valueOf(); + }, - /** - * Calculate the cross product for two vectors in three dimensional space. - * The cross product of `A = [a1, a2, a3]` and `B = [b1, b2, b3]` is defined - * as: - * - * cross(A, B) = [ - * a2 * b3 - a3 * b2, - * a3 * b1 - a1 * b3, - * a1 * b2 - a2 * b1 - * ] - * - * If one of the input vectors has a dimension greater than 1, the output - * vector will be a 1x3 (2-dimensional) matrix. - * - * Syntax: - * - * math.cross(x, y) - * - * Examples: - * - * math.cross([1, 1, 0], [0, 1, 1]); // Returns [1, -1, 1] - * math.cross([3, -3, 1], [4, 9, 2]); // Returns [-15, -2, 39] - * math.cross([2, 3, 4], [5, 6, 7]); // Returns [-3, 6, -3] - * math.cross([[1, 2, 3]], [[4], [5], [6]]); // Returns [[-3, 6, -3]] - * - * See also: - * - * dot, multiply - * - * @param {Array | Matrix} x First vector - * @param {Array | Matrix} y Second vector - * @return {Array | Matrix} Returns the cross product of `x` and `y` - */ - var cross = typed('cross', { - 'Matrix, Matrix': function (x, y) { - return matrix$$1(_cross(x.toArray(), y.toArray())); - }, + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, bitAnd, true).valueOf(); + } + }); - 'Matrix, Array': function (x, y) { - return matrix$$1(_cross(x.toArray(), y)); - }, + bitAnd.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['bitAnd'] + '${args[1]}\\right)' + }; - 'Array, Matrix': function (x, y) { - return matrix$$1(_cross(x, y.toArray())); - }, + return bitAnd; + } - 'Array, Array': _cross - }); + var name$160 = 'bitAnd'; + var factory_1$171 = factory$172; - cross.toTex = { - 2: '\\left(${args[0]}\\right)\\times\\left(${args[1]}\\right)' + var bitAnd$2 = { + name: name$160, + factory: factory_1$171 }; - return cross; - - /** - * Calculate the cross product for two arrays - * @param {Array} x First vector - * @param {Array} y Second vector - * @returns {Array} Returns the cross product of x and y - * @private - */ - function _cross(x, y) { - var highestDimension = Math.max(array.size(x).length, array.size(y).length); + var isInteger$14 = number.isInteger; - x = array.squeeze(x); - y = array.squeeze(y); + function factory$173 (type, config, load, typed) { + var latex$$1 = latex; - var xSize = array.size(x); - var ySize = array.size(y); + /** + * Bitwise NOT value, `~x`. + * For matrices, the function is evaluated element wise. + * For units, the function is evaluated on the best prefix base. + * + * Syntax: + * + * math.bitNot(x) + * + * Examples: + * + * math.bitNot(1); // returns number -2 + * + * math.bitNot([2, -3, 4]); // returns Array [-3, 2, 5] + * + * See also: + * + * bitAnd, bitOr, bitXor, leftShift, rightArithShift, rightLogShift + * + * @param {number | BigNumber | Array | Matrix} x Value to not + * @return {number | BigNumber | Array | Matrix} NOT of `x` + */ + var bitNot = typed('bitNot', { + 'number': function (x) { + if (!isInteger$14(x)) { + throw new Error('Integer expected in function bitNot'); + } - if (xSize.length != 1 || ySize.length != 1 || xSize[0] != 3 || ySize[0] != 3) { - throw new RangeError('Vectors with length 3 expected ' + - '(Size A = [' + xSize.join(', ') + '], B = [' + ySize.join(', ') + '])'); - } + return ~x; + }, - var product = [ - subtract(multiply(x[1], y[2]), multiply(x[2], y[1])), - subtract(multiply(x[2], y[0]), multiply(x[0], y[2])), - subtract(multiply(x[0], y[1]), multiply(x[1], y[0])) - ]; + 'BigNumber': bitNot$1, - if (highestDimension > 1) { - return [product]; - } else { - return product; - } - } -} + 'Array | Matrix': function (x) { + return deepMap(x, bitNot); + } + }); -var name$185 = 'cross'; -var factory_1$196 = factory$197; + bitNot.toTex = { + 1: latex$$1.operators['bitNot'] + '\\left(${args[0]}\\right)' + }; -var cross$1 = { - name: name$185, - factory: factory_1$196 -}; + return bitNot; + } -var clone$8 = object.clone; -var isInteger$23 = number.isInteger; + var name$161 = 'bitNot'; + var factory_1$172 = factory$173; -function factory$198 (type, config, load, typed) { + var bitNot$2 = { + name: name$161, + factory: factory_1$172 + }; - var matrix$$1 = load(matrix); - /** - * Create a diagonal matrix or retrieve the diagonal of a matrix - * - * When `x` is a vector, a matrix with vector `x` on the diagonal will be returned. - * When `x` is a two dimensional matrix, the matrixes `k`th diagonal will be returned as vector. - * When k is positive, the values are placed on the super diagonal. - * When k is negative, the values are placed on the sub diagonal. - * - * Syntax: - * - * math.diag(X) - * math.diag(X, format) - * math.diag(X, k) - * math.diag(X, k, format) - * - * Examples: - * - * // create a diagonal matrix - * math.diag([1, 2, 3]); // returns [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * math.diag([1, 2, 3], 1); // returns [[0, 1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]] - * math.diag([1, 2, 3], -1); // returns [[0, 0, 0], [1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * // retrieve the diagonal from a matrix - * var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; - * math.diag(a); // returns [1, 5, 9] - * - * See also: - * - * ones, zeros, eye + * Bitwise OR for BigNumbers * - * @param {Matrix | Array} x A two dimensional matrix or a vector - * @param {number | BigNumber} [k=0] The diagonal where the vector will be filled - * in or retrieved. - * @param {string} [format='dense'] The matrix storage format. + * Special Cases: + * N | n = N + * n | 0 = n + * n | -1 = -1 + * n | n = n + * I | I = I + * -I | -I = -I + * I | -n = -1 + * I | -I = -1 + * I | n = I + * -I | n = -I + * -I | -n = -n * - * @returns {Matrix | Array} Diagonal matrix from input vector, or diagonal from input matrix. + * @param {BigNumber} x + * @param {BigNumber} y + * @return {BigNumber} Result of `x` | `y`, fully precise */ - var diag = typed('diag', { - // FIXME: simplify this huge amount of signatures as soon as typed-function supports optional arguments + var bitOr$1 = function bitOr (x, y) { + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Integers expected in function bitOr'); + } - 'Array': function (x) { - return _diag(x, 0, array.size(x), null); - }, + var BigNumber = x.constructor; + if (x.isNaN() || y.isNaN()) { + return new BigNumber(NaN); + } - 'Array, number': function (x, k) { - return _diag(x, k, array.size(x), null); - }, + var negOne = new BigNumber(-1); + if (x.isZero() || y.eq(negOne) || x.eq(y)) { + return y; + } + if (y.isZero() || x.eq(negOne)) { + return x; + } + + if (!x.isFinite() || !y.isFinite()) { + if ((!x.isFinite() && !x.isNegative() && y.isNegative()) || + (x.isNegative() && !y.isNegative() && !y.isFinite())) { + return negOne; + } + if (x.isNegative() && y.isNegative()) { + return x.isFinite() ? x : y; + } + return x.isFinite() ? y : x; + } + + return bitwise(x, y, function (a, b) { return a | b }); + }; + + var isInteger$15 = number.isInteger; + + + function factory$174 (type, config, load, typed) { + var latex$$1 = latex; + + var matrix$$1 = load(matrix); + + var algorithm01$$1 = load(algorithm01); + var algorithm04$$1 = load(algorithm04); + var algorithm10$$1 = load(algorithm10); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - 'Array, BigNumber': function (x, k) { - return _diag(x, k.toNumber(), array.size(x), null); - }, + /** + * Bitwise OR two values, `x | y`. + * For matrices, the function is evaluated element wise. + * For units, the function is evaluated on the lowest print base. + * + * Syntax: + * + * math.bitOr(x, y) + * + * Examples: + * + * math.bitOr(1, 2); // returns number 3 + * + * math.bitOr([1, 2, 3], 4); // returns Array [5, 6, 7] + * + * See also: + * + * bitAnd, bitNot, bitXor, leftShift, rightArithShift, rightLogShift + * + * @param {number | BigNumber | Array | Matrix} x First value to or + * @param {number | BigNumber | Array | Matrix} y Second value to or + * @return {number | BigNumber | Array | Matrix} OR of `x` and `y` + */ + var bitOr = typed('bitOr', { - 'Array, string': function (x, format) { - return _diag(x, 0, array.size(x), format); - }, + 'number, number': function (x, y) { + if (!isInteger$15(x) || !isInteger$15(y)) { + throw new Error('Integers expected in function bitOr'); + } - 'Array, number, string': function (x, k, format) { - return _diag(x, k, array.size(x), format); - }, + return x | y; + }, - 'Array, BigNumber, string': function (x, k, format) { - return _diag(x, k.toNumber(), array.size(x), format); - }, + 'BigNumber, BigNumber': bitOr$1, - 'Matrix': function (x) { - return _diag(x, 0, x.size(), x.storage()); - }, + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm04$$1(x, y, bitOr); + }, - 'Matrix, number': function (x, k) { - return _diag(x, k, x.size(), x.storage()); - }, + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm01$$1(y, x, bitOr, true); + }, - 'Matrix, BigNumber': function (x, k) { - return _diag(x, k.toNumber(), x.size(), x.storage()); - }, + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm01$$1(x, y, bitOr, false); + }, - 'Matrix, string': function (x, format) { - return _diag(x, 0, x.size(), format); - }, + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, bitOr); + }, - 'Matrix, number, string': function (x, k, format) { - return _diag(x, k, x.size(), format); - }, + 'Array, Array': function (x, y) { + // use matrix implementation + return bitOr(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - 'Matrix, BigNumber, string': function (x, k, format) { - return _diag(x, k.toNumber(), x.size(), format); - } - }); + 'Array, Matrix': function (x, y) { + // use matrix implementation + return bitOr(matrix$$1(x), y); + }, - diag.toTex = undefined; // use default template + 'Matrix, Array': function (x, y) { + // use matrix implementation + return bitOr(x, matrix$$1(y)); + }, - return diag; + 'SparseMatrix, any': function (x, y) { + return algorithm10$$1(x, y, bitOr, false); + }, - /** - * Creeate diagonal matrix from a vector or vice versa - * @param {Array | Matrix} x - * @param {number} k - * @param {string} format Storage format for matrix. If null, - * an Array is returned - * @returns {Array | Matrix} - * @private - */ - function _diag (x, k, size, format) { - if (!isInteger$23(k)) { - throw new TypeError ('Second parameter in function diag must be an integer'); - } - - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // check dimensions - switch (size.length) { - case 1: - return _createDiagonalMatrix(x, k, format, size[0], kSub, kSuper); - case 2: - return _getDiagonal(x, k, format, size, kSub, kSuper); - } - throw new RangeError('Matrix for function diag must be 2 dimensional'); - } - - function _createDiagonalMatrix(x, k, format, l, kSub, kSuper) { - // matrix size - var ms = [l + kSub, l + kSuper]; - // get matrix constructor - var F = type.Matrix.storage(format || 'dense'); - // create diagonal matrix - var m = F.diagonal(ms, x, k); - // check we need to return a matrix - return format !== null ? m : m.valueOf(); - } - - function _getDiagonal(x, k, format, s, kSub, kSuper) { - // check x is a Matrix - if (type.isMatrix(x)) { - // get diagonal matrix - var dm = x.diagonal(k); - // check we need to return a matrix - if (format !== null) { - // check we need to change matrix format - if (format !== dm.storage()) - return matrix$$1(dm, format); - return dm; + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, bitOr, false); + }, + + 'any, SparseMatrix': function (x, y) { + return algorithm10$$1(y, x, bitOr, true); + }, + + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, bitOr, true); + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, bitOr, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, bitOr, true).valueOf(); } - return dm.valueOf(); - } - // vector size - var n = Math.min(s[0] - kSub, s[1] - kSuper); - // diagonal values - var vector = []; - // loop diagonal - for (var i = 0; i < n; i++) { - vector[i] = x[i + kSub][i + kSuper]; - } - // check we need to return a matrix - return format !== null ? matrix$$1(vector) : vector; - } -} + }); -var name$186 = 'diag'; -var factory_1$197 = factory$198; + bitOr.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['bitOr'] + '${args[1]}\\right)' + }; -var diag$1 = { - name: name$186, - factory: factory_1$197 -}; + return bitOr; + } -var size$3 = array.size; + var name$162 = 'bitOr'; + var factory_1$173 = factory$174; -function factory$199 (type, config, load, typed) { - var add$$1 = load(add); - var multiply = load(multiply$1); + var bitOr$2 = { + name: name$162, + factory: factory_1$173 + }; /** - * Calculate the dot product of two vectors. The dot product of - * `A = [a1, a2, a3, ..., an]` and `B = [b1, b2, b3, ..., bn]` is defined as: + * Bitwise XOR for BigNumbers * - * dot(A, B) = a1 * b1 + a2 * b2 + a3 * b3 + ... + an * bn + * Special Cases: + * N ^ n = N + * n ^ 0 = n + * n ^ n = 0 + * n ^ -1 = ~n + * I ^ n = I + * I ^ -n = -I + * I ^ -I = -1 + * -I ^ n = -I + * -I ^ -n = I * - * Syntax: - * - * math.dot(x, y) - * - * Examples: + * @param {BigNumber} x + * @param {BigNumber} y + * @return {BigNumber} Result of `x` ^ `y`, fully precise * - * math.dot([2, 4, 1], [2, 2, 3]); // returns number 15 - * math.multiply([2, 4, 1], [2, 2, 3]); // returns number 15 - * - * See also: - * - * multiply, cross - * - * @param {Array | Matrix} x First vector - * @param {Array | Matrix} y Second vector - * @return {number} Returns the dot product of `x` and `y` */ - var dot = typed('dot', { - 'Matrix, Matrix': function (x, y) { - return _dot(x.toArray(), y.toArray()); - }, + var bitXor$1 = function bitXor(x, y) { + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Integers expected in function bitXor'); + } - 'Matrix, Array': function (x, y) { - return _dot(x.toArray(), y); - }, + var BigNumber = x.constructor; + if (x.isNaN() || y.isNaN()) { + return new BigNumber(NaN); + } + if (x.isZero()) { + return y; + } + if (y.isZero()) { + return x; + } - 'Array, Matrix': function (x, y) { - return _dot(x, y.toArray()); - }, + if (x.eq(y)) { + return new BigNumber(0); + } - 'Array, Array': _dot - }); - - dot.toTex = {2: '\\left(${args[0]}\\cdot${args[1]}\\right)'}; + var negOne = new BigNumber(-1); + if (x.eq(negOne)) { + return bitNot$1(y); + } + if (y.eq(negOne)) { + return bitNot$1(x); + } - return dot; + if (!x.isFinite() || !y.isFinite()) { + if (!x.isFinite() && !y.isFinite()) { + return negOne; + } + return new BigNumber(x.isNegative() == y.isNegative() + ? Infinity + : -Infinity); + } + return bitwise(x, y, function (a, b) { return a ^ b }); + }; - /** - * Calculate the dot product for two arrays - * @param {Array} x First vector - * @param {Array} y Second vector - * @returns {number} Returns the dot product of x and y - * @private - */ - // TODO: double code with math.multiply - function _dot(x, y) { - var xSize= size$3(x); - var ySize = size$3(y); - var len = xSize[0]; + var isInteger$16 = number.isInteger; - if (xSize.length !== 1 || ySize.length !== 1) throw new RangeError('Vector expected'); // TODO: better error message - if (xSize[0] != ySize[0]) throw new RangeError('Vectors must have equal length (' + xSize[0] + ' != ' + ySize[0] + ')'); - if (len == 0) throw new RangeError('Cannot calculate the dot product of empty vectors'); - var prod = 0; - for (var i = 0; i < len; i++) { - prod = add$$1(prod, multiply(x[i], y[i])); - } + function factory$175 (type, config, load, typed) { + var latex$$1 = latex; - return prod; - } -} + var matrix$$1 = load(matrix); -var name$187 = 'dot'; -var factory_1$198 = factory$199; + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); -var dot$1 = { - name: name$187, - factory: factory_1$198 -}; + /** + * Bitwise XOR two values, `x ^ y`. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.bitXor(x, y) + * + * Examples: + * + * math.bitXor(1, 2); // returns number 3 + * + * math.bitXor([2, 3, 4], 4); // returns Array [6, 7, 0] + * + * See also: + * + * bitAnd, bitNot, bitOr, leftShift, rightArithShift, rightLogShift + * + * @param {number | BigNumber | Array | Matrix} x First value to xor + * @param {number | BigNumber | Array | Matrix} y Second value to xor + * @return {number | BigNumber | Array | Matrix} XOR of `x` and `y` + */ + var bitXor = typed('bitXor', { -var format$6 = string.format; + 'number, number': function (x, y) { + if (!isInteger$16(x) || !isInteger$16(y)) { + throw new Error('Integers expected in function bitXor'); + } -function factory$200 (type, config, load, typed) { + return x ^ y; + }, - var abs = load(abs$1); - var add$$1 = load(add); - var eye = load(eye$1); - var inv = load(inv$1); - var multiply = load(multiply$1); + 'BigNumber, BigNumber': bitXor$1, - var SparseMatrix = type.SparseMatrix; + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm07$$1(x, y, bitXor); + }, - /** - * Compute the matrix exponential, expm(A) = e^A. The matrix must be square. - * Not to be confused with exp(a), which performs element-wise - * exponentiation. - * - * The exponential is calculated using the Padé approximant with scaling and - * squaring; see "Nineteen Dubious Ways to Compute the Exponential of a - * Matrix," by Moler and Van Loan. - * - * Syntax: - * - * math.expm(x) - * - * Examples: - * - * var A = [[0,2],[0,0]] - * math.expm(A); // returns [[1,2],[0,1]] - * - * See also: - * - * exp - * - * @param {Matrix} x A square Matrix - * @return {Matrix} The exponential of x - */ - var expm = typed('expm', { + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, bitXor, true); + }, - 'Matrix': function (A) { + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, bitXor, false); + }, - // Check matrix size - var size = A.size(); - - if(size.length !== 2 || size[0] !== size[1]) { - throw new RangeError('Matrix must be square ' + - '(size: ' + format$6(size) + ')'); - } - - var n = size[0]; + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, bitXor); + }, - // Desired accuracy of the approximant (The actual accuracy - // will be affected by round-off error) - var eps = 1e-15; - - // The Padé approximant is not so accurate when the values of A - // are "large", so scale A by powers of two. Then compute the - // exponential, and square the result repeatedly according to - // the identity e^A = (e^(A/m))^m - - // Compute infinity-norm of A, ||A||, to see how "big" it is - var infNorm = infinityNorm(A); - - // Find the optimal scaling factor and number of terms in the - // Padé approximant to reach the desired accuracy - var params = findParams(infNorm, eps); - var q = params.q; - var j = params.j; - - // The Pade approximation to e^A is: - // Rqq(A) = Dqq(A) ^ -1 * Nqq(A) - // where - // Nqq(A) = sum(i=0, q, (2q-i)!p! / [ (2q)!i!(q-i)! ] A^i - // Dqq(A) = sum(i=0, q, (2q-i)!q! / [ (2q)!i!(q-i)! ] (-A)^i - - // Scale A by 1 / 2^j - var Apos = multiply(A, Math.pow(2, -j)); - - // The i=0 term is just the identity matrix - var N = eye(n); - var D = eye(n); - - // Initialization (i=0) - var factor = 1; - - // Initialization (i=1) - var Apos_to_i = Apos; // Cloning not necessary - var alternate = -1; - - for(var i=1; i<=q; i++) { - if(i>1) { - Apos_to_i = multiply(Apos_to_i, Apos); - alternate = -alternate; - } - factor = factor*(q-i+1)/((2*q-i+1)*i); - - N = add$$1(N, multiply(factor, Apos_to_i)); - D = add$$1(D, multiply(factor*alternate, Apos_to_i)); - } - - var R = multiply(inv(D), N); - - // Square j times - for(var i=0; i 0; - * } - * math.filter([6, -2, -1, 4, 3], isPositive); // returns [6, 4, 3] + * Bitwise left shift * - * math.filter(["23", "foo", "100", "55", "bar"], /[0-9]+/); // returns ["23", "100", "55"] + * Special Cases: + * n << -n = N + * n << N = N + * N << n = N + * n << 0 = n + * 0 << n = 0 + * I << I = N + * I << n = I + * n << I = I * - * See also: + * @param {BigNumber} x + * @param {BigNumber} y + * @return {BigNumber} Result of `x` << `y` * - * forEach, map, sort - * - * @param {Matrix | Array} x A one dimensional matrix or array to filter - * @param {Function | RegExp} test - * A function or regular expression to test items. - * All entries for which `test` returns true are returned. - * When `test` is a function, it is invoked with three parameters: - * the value of the element, the index of the element, and the - * matrix/array being traversed. The function must return a boolean. - * @return {Matrix | Array} Returns the filtered matrix. */ - var filter = typed('filter', { - 'Array, function': _filterCallback, - - 'Matrix, function': function (x, test) { - return matrix$$1(_filterCallback(x.toArray(), test)); - }, - - 'Array, RegExp': filterRegExp$1, - - 'Matrix, RegExp': function (x, test) { - return matrix$$1(filterRegExp$1(x.toArray(), test)); + var leftShift$1 = function leftShift (x, y) { + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Integers expected in function leftShift'); } - }); - - filter.toTex = undefined; // use default template - - return filter; -} -/** - * Filter values in a callback given a callback function - * @param {Array} x - * @param {Function} callback - * @return {Array} Returns the filtered array - * @private - */ -function _filterCallback (x, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$4(callback); - - return filter$2(x, function (value, index, array$$1) { - // invoke the callback function with the right number of arguments - if (args === 1) { - return callback(value); + var BigNumber = x.constructor; + if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { + return new BigNumber(NaN); } - else if (args === 2) { - return callback(value, [index]); + if (x.isZero() || y.isZero()) { + return x; } - else { // 3 or -1 - return callback(value, [index], array$$1); + if (!x.isFinite() && !y.isFinite()) { + return new BigNumber(NaN); } - }); -} -var name$189 = 'filter'; -var factory_1$200 = factory$201; + // Math.pow(2, y) is fully precise for y < 55, and fast + if (y.lt(55)) { + return x.times(Math.pow(2, y.toNumber()) + ''); + } + return x.times(new BigNumber(2).pow(y)); + }; -var filter_1 = { - name: name$189, - factory: factory_1$200 -}; + function factory$176 (type, config, load, typed) { -var clone$9 = object.clone; -var _flatten = array.flatten; + var equalScalar$$1 = load(equalScalar); -function factory$202 (type, config, load, typed) { - var matrix$$1 = load(matrix); + var SparseMatrix = type.SparseMatrix; - /** - * Flatten a multi dimensional matrix into a single dimensional matrix. - * - * Syntax: - * - * math.flatten(x) - * - * Examples: - * - * math.flatten([[1,2], [3,4]]); // returns [1, 2, 3, 4] - * - * See also: - * - * concat, resize, size, squeeze - * - * @param {Matrix | Array} x Matrix to be flattened - * @return {Matrix | Array} Returns the flattened matrix - */ - var flatten = typed('flatten', { - 'Array': function (x) { - return _flatten(clone$9(x)); - }, + /** + * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). + * Callback function invoked MAX(NNZA, NNZB) times + * + * + * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 + * C(i,j) = ┤ A(i,j) ; A(i,j) !== 0 + * └ 0 ; otherwise + * + * + * @param {Matrix} a The SparseMatrix instance (A) + * @param {Matrix} b The SparseMatrix instance (B) + * @param {Function} callback The f(Aij,Bij) operation to invoke + * + * @return {Matrix} SparseMatrix (C) + * + * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 + */ + var algorithm08 = function (a, b, callback) { + // sparse matrix arrays + var avalues = a._values; + var aindex = a._index; + var aptr = a._ptr; + var asize = a._size; + var adt = a._datatype; + // sparse matrix arrays + var bvalues = b._values; + var bindex = b._index; + var bptr = b._ptr; + var bsize = b._size; + var bdt = b._datatype; - 'Matrix': function (x) { - var flat = _flatten(clone$9(x.toArray())); - // TODO: return the same matrix type as x - return matrix$$1(flat); - } - }); + // validate dimensions + if (asize.length !== bsize.length) + throw new DimensionError_1(asize.length, bsize.length); - flatten.toTex = undefined; // use default template + // check rows & columns + if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) + throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - return flatten; -} + // sparse matrix cannot be a Pattern matrix + if (!avalues || !bvalues) + throw new Error('Cannot perform operation on Pattern Sparse Matrices'); -var name$190 = 'flatten'; -var factory_1$201 = factory$202; + // rows & columns + var rows = asize[0]; + var columns = asize[1]; -var flatten$3 = { - name: name$190, - factory: factory_1$201 -}; + // datatype + var dt; + // equal signature to use + var eq = equalScalar$$1; + // zero value + var zero = 0; + // callback signature to use + var cf = callback; + + // process data types + if (typeof adt === 'string' && adt === bdt) { + // datatype + dt = adt; + // find signature that matches (dt, dt) + eq = typed.find(equalScalar$$1, [dt, dt]); + // convert 0 to the same datatype + zero = typed.convert(0, dt); + // callback + cf = typed.find(callback, [dt, dt]); + } + + // result arrays + var cvalues = []; + var cindex = []; + var cptr = []; + // matrix + var c = new SparseMatrix({ + values: cvalues, + index: cindex, + ptr: cptr, + size: [rows, columns], + datatype: dt + }); -var maxArgumentCount$5 = _function.maxArgumentCount; -var forEach$4 = array.forEach; + // workspace + var x = []; + // marks indicating we have a value in x for a given column + var w = []; -function factory$203 (type, config, load, typed) { - /** - * Iterate over all elements of a matrix/array, and executes the given callback function. - * - * Syntax: - * - * math.forEach(x, callback) - * - * Examples: - * - * math.forEach([1, 2, 3], function(value) { - * console.log(value); - * }); - * // outputs 1, 2, 3 - * - * See also: - * - * filter, map, sort - * - * @param {Matrix | Array} x The matrix to iterate on. - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix/array being traversed. - */ - var forEach = typed('forEach', { - 'Array, function': _forEach, + // vars + var k, k0, k1, i; - 'Matrix, function': function (x, callback) { - return x.forEach(callback); - } - }); + // loop columns + for (var j = 0; j < columns; j++) { + // update cptr + cptr[j] = cindex.length; + // columns mark + var mark = j + 1; + // loop values in a + for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { + // row + i = aindex[k]; + // mark workspace + w[i] = mark; + // set value + x[i] = avalues[k]; + // add index + cindex.push(i); + } + // loop values in b + for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { + // row + i = bindex[k]; + // check value exists in workspace + if (w[i] === mark) { + // evaluate callback + x[i] = cf(x[i], bvalues[k]); + } + } + // initialize first index in j + k = cptr[j]; + // loop index in j + while (k < cindex.length) { + // row + i = cindex[k]; + // value @ i + var v = x[i]; + // check for zero value + if (!eq(v, zero)) { + // push value + cvalues.push(v); + // increment pointer + k++; + } + else { + // remove value @ i, do not increment pointer + cindex.splice(k, 1); + } + } + } + // update cptr + cptr[columns] = cindex.length; - forEach.toTex = undefined; // use default template + // return sparse matrix + return c; + }; - return forEach; -} + return algorithm08; + } -/** - * forEach for a multi dimensional array - * @param {Array} array - * @param {Function} callback - * @private - */ -function _forEach (array$$1, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$5(callback); + var name$164 = 'algorithm08'; + var factory_1$175 = factory$176; - var recurse = function (value, index) { - if (Array.isArray(value)) { - forEach$4(value, function (child, i) { - // we create a copy of the index array and append the new index value - recurse(child, index.concat(i)); - }); - } - else { - // invoke the callback function with the right number of arguments - if (args === 1) { - callback(value); - } - else if (args === 2) { - callback(value, index); - } - else { // 3 or -1 - callback(value, index, array$$1); - } - } + var algorithm08 = { + name: name$164, + factory: factory_1$175 }; - recurse(array$$1, []); -} -var name$191 = 'forEach'; -var factory_1$202 = factory$203; + var isInteger$17 = number.isInteger; + + + function factory$177 (type, config, load, typed) { + var latex$$1 = latex; -var forEach_1 = { - name: name$191, - factory: factory_1$202 -}; + var matrix$$1 = load(matrix); + var equalScalar$$1 = load(equalScalar); + var zeros = load(zeros$1); -var size$4 = array.size; + var algorithm01$$1 = load(algorithm01); + var algorithm02$$1 = load(algorithm02); + var algorithm08$$1 = load(algorithm08); + var algorithm10$$1 = load(algorithm10); + var algorithm11$$1 = load(algorithm11); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); -function factory$204(type, config, load, typed) { - var matrix$$1 = load(matrix); - var multiplyScalar$$1 = load(multiplyScalar); /** - * Calculates the kronecker product of 2 matrices or vectors. - * - * NOTE: If a one dimensional vector / matrix is given, it will be - * wrapped so its two dimensions. - * See the examples. + * Bitwise left logical shift of a value x by y number of bits, `x << y`. + * For matrices, the function is evaluated element wise. + * For units, the function is evaluated on the best prefix base. * * Syntax: * - * math.kron(x, y) + * math.leftShift(x, y) * * Examples: * - * math.kron([[1, 0], [0, 1]], [[1, 2], [3, 4]]); - * // returns [ [ 1, 2, 0, 0 ], [ 3, 4, 0, 0 ], [ 0, 0, 1, 2 ], [ 0, 0, 3, 4 ] ] + * math.leftShift(1, 2); // returns number 4 * - * math.kron([1,1], [2,3,4]); - * // returns [ [ 2, 3, 4, 2, 3, 4 ] ] + * math.leftShift([1, 2, 3], 4); // returns Array [16, 32, 64] * * See also: * - * multiply, dot, cross + * leftShift, bitNot, bitOr, bitXor, rightArithShift, rightLogShift * - * @param {Array | Matrix} x First vector - * @param {Array | Matrix} y Second vector - * @return {Array | Matrix} Returns the kronecker product of `x` and `y` + * @param {number | BigNumber | Array | Matrix} x Value to be shifted + * @param {number | BigNumber} y Amount of shifts + * @return {number | BigNumber | Array | Matrix} `x` shifted left `y` times */ - var kron = typed('kron', { - 'Matrix, Matrix': function(x, y) { - return matrix$$1(_kron(x.toArray(), y.toArray())); - }, + var leftShift = typed('leftShift', { + + 'number, number': function (x, y) { + if (!isInteger$17(x) || !isInteger$17(y)) { + throw new Error('Integers expected in function leftShift'); + } - 'Matrix, Array': function(x, y) { - return matrix$$1(_kron(x.toArray(), y)); - }, + return x << y; + }, - 'Array, Matrix': function(x, y) { - return matrix$$1(_kron(x, y.toArray())); - }, + 'BigNumber, BigNumber': leftShift$1, - 'Array, Array': _kron - }); + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm08$$1(x, y, leftShift, false); + }, - return kron; + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm02$$1(y, x, leftShift, true); + }, - /** - * Calculate the kronecker product of two matrices / vectors - * @param {Array} a First vector - * @param {Array} b Second vector - * @returns {Array} Returns the kronecker product of x and y - * @private - */ - function _kron(a, b) { - // Deal with the dimensions of the matricies. - if (size$4(a).length === 1) { - // Wrap it in a 2D Matrix - a = [a]; - } - if (size$4(b).length === 1) { - // Wrap it in a 2D Matrix - b = [b]; - } - if (size$4(a).length > 2 || size$4(b).length > 2) { - throw new RangeError('Vectors with dimensions greater then 2 are not supported expected ' + - '(Size x = ' + JSON.stringify(a.length) + ', y = ' + JSON.stringify(b.length) + ')'); - } - var t = []; - var r = []; - - return a.map(function(a) { - return b.map(function(b) { - return a.map(function(y) { - return b.map(function(x) { - return r.push(multiplyScalar$$1(y, x)); - }); - }, t.push(r = [])); - }); - }, t = []) && t; - } -} + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm01$$1(x, y, leftShift, false); + }, -var name$192 = 'kron'; -var factory_1$203 = factory$204; + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, leftShift); + }, -var kron$1 = { - name: name$192, - factory: factory_1$203 -}; + 'Array, Array': function (x, y) { + // use matrix implementation + return leftShift(matrix$$1(x), matrix$$1(y)).valueOf(); + }, -var maxArgumentCount$6 = _function.maxArgumentCount; + 'Array, Matrix': function (x, y) { + // use matrix implementation + return leftShift(matrix$$1(x), y); + }, -function factory$205 (type, config, load, typed) { - /** - * Create a new matrix or array with the results of the callback function executed on - * each entry of the matrix/array. - * - * Syntax: - * - * math.map(x, callback) - * - * Examples: - * - * math.map([1, 2, 3], function(value) { - * return value * value; - * }); // returns [1, 4, 9] - * - * See also: - * - * filter, forEach, sort - * - * @param {Matrix | Array} x The matrix to iterate on. - * @param {Function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the matrix being traversed. - * @return {Matrix | array} Transformed map of x - */ - var map = typed('map', { - 'Array, function': _map$1, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return leftShift(x, matrix$$1(y)); + }, - 'Matrix, function': function (x, callback) { - return x.map(callback); - } - }); + 'SparseMatrix, number | BigNumber': function (x, y) { + // check scalar + if (equalScalar$$1(y, 0)) { + return x.clone(); + } + return algorithm11$$1(x, y, leftShift, false); + }, - map.toTex = undefined; // use default template + 'DenseMatrix, number | BigNumber': function (x, y) { + // check scalar + if (equalScalar$$1(y, 0)) { + return x.clone(); + } + return algorithm14$$1(x, y, leftShift, false); + }, - return map; -} + 'number | BigNumber, SparseMatrix': function (x, y) { + // check scalar + if (equalScalar$$1(x, 0)) { + return zeros(y.size(), y.storage()); + } + return algorithm10$$1(y, x, leftShift, true); + }, -/** - * Map for a multi dimensional array - * @param {Array} array - * @param {Function} callback - * @return {Array} - * @private - */ -function _map$1 (array, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$6(callback); + 'number | BigNumber, DenseMatrix': function (x, y) { + // check scalar + if (equalScalar$$1(x, 0)) { + return zeros(y.size(), y.storage()); + } + return algorithm14$$1(y, x, leftShift, true); + }, - var recurse = function (value, index) { - if (Array.isArray(value)) { - return value.map(function (child, i) { - // we create a copy of the index array and append the new index value - return recurse(child, index.concat(i)); - }); - } - else { - // invoke the callback function with the right number of arguments - if (args === 1) { - return callback(value); + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return leftShift(matrix$$1(x), y).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return leftShift(x, matrix$$1(y)).valueOf(); } - else if (args === 2) { - return callback(value, index); + }); + + leftShift.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['leftShift'] + '${args[1]}\\right)' + }; + + return leftShift; + } + + var name$165 = 'leftShift'; + var factory_1$176 = factory$177; + + var leftShift$2 = { + name: name$165, + factory: factory_1$176 + }; + + /* + * Special Cases: + * n >> -n = N + * n >> N = N + * N >> n = N + * I >> I = N + * n >> 0 = n + * I >> n = I + * -I >> n = -I + * -I >> I = -I + * n >> I = I + * -n >> I = -1 + * 0 >> n = 0 + * + * @param {BigNumber} value + * @param {BigNumber} value + * @return {BigNumber} Result of `x` >> `y` + * + */ + var rightArithShift$1 = function rightArithShift (x, y) { + if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { + throw new Error('Integers expected in function rightArithShift'); + } + + var BigNumber = x.constructor; + if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { + return new BigNumber(NaN); + } + if (x.isZero() || y.isZero()) { + return x; + } + if (!y.isFinite()) { + if (x.isNegative()) { + return new BigNumber(-1); } - else { // 3 or -1 - return callback(value, index, array); + if (!x.isFinite()) { + return new BigNumber(NaN); } + return new BigNumber(0); } + + // Math.pow(2, y) is fully precise for y < 55, and fast + if (y.lt(55)) { + return x.div(Math.pow(2, y.toNumber()) + '').floor(); + } + return x.div(new BigNumber(2).pow(y)).floor(); }; - return recurse(array, []); -} + var isInteger$18 = number.isInteger; -var name$193 = 'map'; -var factory_1$204 = factory$205; -var map$7 = { - name: name$193, - factory: factory_1$204 -}; + function factory$178 (type, config, load, typed) { + var latex$$1 = latex; + + var matrix$$1 = load(matrix); + var equalScalar$$1 = load(equalScalar); + var zeros = load(zeros$1); -var isInteger$24 = number.isInteger; -var resize$2 = array.resize; + var algorithm01$$1 = load(algorithm01); + var algorithm02$$1 = load(algorithm02); + var algorithm08$$1 = load(algorithm08); + var algorithm10$$1 = load(algorithm10); + var algorithm11$$1 = load(algorithm11); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); -function factory$206 (type, config, load, typed) { - var matrix$$1 = load(matrix); + /** + * Bitwise right arithmetic shift of a value x by y number of bits, `x >> y`. + * For matrices, the function is evaluated element wise. + * For units, the function is evaluated on the best prefix base. + * + * Syntax: + * + * math.rightArithShift(x, y) + * + * Examples: + * + * math.rightArithShift(4, 2); // returns number 1 + * + * math.rightArithShift([16, -32, 64], 4); // returns Array [1, -2, 3] + * + * See also: + * + * bitAnd, bitNot, bitOr, bitXor, rightArithShift, rightLogShift + * + * @param {number | BigNumber | Array | Matrix} x Value to be shifted + * @param {number | BigNumber} y Amount of shifts + * @return {number | BigNumber | Array | Matrix} `x` sign-filled shifted right `y` times + */ + var rightArithShift = typed('rightArithShift', { - /** - * Create a matrix filled with ones. The created matrix can have one or - * multiple dimensions. - * - * Syntax: - * - * math.ones(m) - * math.ones(m, format) - * math.ones(m, n) - * math.ones(m, n, format) - * math.ones([m, n]) - * math.ones([m, n], format) - * math.ones([m, n, p, ...]) - * math.ones([m, n, p, ...], format) - * - * Examples: - * - * math.ones(3); // returns [1, 1, 1] - * math.ones(3, 2); // returns [[1, 1], [1, 1], [1, 1]] - * math.ones(3, 2, 'dense'); // returns Dense Matrix [[1, 1], [1, 1], [1, 1]] - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.ones(math.size(A)); // returns [[1, 1, 1], [1, 1, 1]] - * - * See also: - * - * zeros, eye, size, range - * - * @param {...number | Array} size The size of each dimension of the matrix - * @param {string} [format] The Matrix storage format - * - * @return {Array | Matrix | number} A matrix filled with ones - */ - var ones = typed('ones', { - '': function () { - return (config.matrix === 'Array') - ? _ones([]) - : _ones([], 'default'); - }, + 'number, number': function (x, y) { + if (!isInteger$18(x) || !isInteger$18(y)) { + throw new Error('Integers expected in function rightArithShift'); + } - // math.ones(m, n, p, ..., format) - // TODO: more accurate signature '...number | BigNumber, string' as soon as typed-function supports this - '...number | BigNumber | string': function (size) { - var last = size[size.length - 1]; - if (typeof last === 'string') { - var format = size.pop(); - return _ones(size, format); - } - else if (config.matrix === 'Array') { - return _ones(size); - } - else { - return _ones(size, 'default'); - } - }, + return x >> y; + }, - 'Array': _ones, + 'BigNumber, BigNumber': rightArithShift$1, - 'Matrix': function (size) { - var format = size.storage(); - return _ones(size.valueOf(), format); - }, + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm08$$1(x, y, rightArithShift, false); + }, - 'Array | Matrix, string': function (size, format) { - return _ones (size.valueOf(), format); - } - }); + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm02$$1(y, x, rightArithShift, true); + }, - ones.toTex = undefined; // use default template + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm01$$1(x, y, rightArithShift, false); + }, - return ones; + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, rightArithShift); + }, - /** - * Create an Array or Matrix with ones - * @param {Array} size - * @param {string} [format='default'] - * @return {Array | Matrix} - * @private - */ - function _ones(size, format) { - var hasBigNumbers = _normalize(size); - var defaultValue = hasBigNumbers ? new type.BigNumber(1) : 1; - _validate(size); - - if (format) { - // return a matrix - var m = matrix$$1(format); - if (size.length > 0) { - return m.resize(size, defaultValue); - } - return m; - } - else { - // return an Array - var arr = []; - if (size.length > 0) { - return resize$2(arr, size, defaultValue); - } - return arr; - } - } + 'Array, Array': function (x, y) { + // use matrix implementation + return rightArithShift(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - // replace BigNumbers with numbers, returns true if size contained BigNumbers - function _normalize(size) { - var hasBigNumbers = false; - size.forEach(function (value, index, arr) { - if (type.isBigNumber(value)) { - hasBigNumbers = true; - arr[index] = value.toNumber(); - } - }); - return hasBigNumbers; - } + 'Array, Matrix': function (x, y) { + // use matrix implementation + return rightArithShift(matrix$$1(x), y); + }, - // validate arguments - function _validate (size) { - size.forEach(function (value) { - if (typeof value !== 'number' || !isInteger$24(value) || value < 0) { - throw new Error('Parameters in function ones must be positive integers'); - } - }); - } -} + 'Matrix, Array': function (x, y) { + // use matrix implementation + return rightArithShift(x, matrix$$1(y)); + }, -var name$194 = 'ones'; -var factory_1$205 = factory$206; + 'SparseMatrix, number | BigNumber': function (x, y) { + // check scalar + if (equalScalar$$1(y, 0)) { + return x.clone(); + } + return algorithm11$$1(x, y, rightArithShift, false); + }, -var ones$1 = { - name: name$194, - factory: factory_1$205 -}; + 'DenseMatrix, number | BigNumber': function (x, y) { + // check scalar + if (equalScalar$$1(y, 0)) { + return x.clone(); + } + return algorithm14$$1(x, y, rightArithShift, false); + }, -var nearlyEqual$6 = number.nearlyEqual; + 'number | BigNumber, SparseMatrix': function (x, y) { + // check scalar + if (equalScalar$$1(x, 0)) { + return zeros(y.size(), y.storage()); + } + return algorithm10$$1(y, x, rightArithShift, true); + }, + 'number | BigNumber, DenseMatrix': function (x, y) { + // check scalar + if (equalScalar$$1(x, 0)) { + return zeros(y.size(), y.storage()); + } + return algorithm14$$1(y, x, rightArithShift, true); + }, -function factory$207 (type, config, load, typed) { + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return rightArithShift(matrix$$1(x), y).valueOf(); + }, - var matrix$$1 = load(matrix); + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return rightArithShift(x, matrix$$1(y)).valueOf(); + } + }); - var algorithm03$$1 = load(algorithm03); - var algorithm05$$1 = load(algorithm05); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Compare two values. Returns 1 when x > y, -1 when x < y, and 0 when x == y. - * - * x and y are considered equal when the relative difference between x and y - * is smaller than the configured epsilon. The function cannot be used to - * compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.compare(x, y) - * - * Examples: - * - * math.compare(6, 1); // returns 1 - * math.compare(2, 3); // returns -1 - * math.compare(7, 7); // returns 0 - * math.compare('10', '2'); // returns 1 - * math.compare('1000', '1e3'); // returns 0 - * - * var a = math.unit('5 cm'); - * var b = math.unit('40 mm'); - * math.compare(a, b); // returns 1 - * - * math.compare(2, [1, 2, 3]); // returns [1, 0, -1] - * - * See also: - * - * equal, unequal, smaller, smallerEq, larger, largerEq, compareNatural, compareText - * - * @param {number | BigNumber | Fraction | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | Unit | string | Array | Matrix} y Second value to compare - * @return {number | BigNumber | Fraction | Array | Matrix} Returns the result of the comparison: - * 1 when x > y, -1 when x < y, and 0 when x == y. - */ - var compare = typed('compare', { + rightArithShift.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['rightArithShift'] + '${args[1]}\\right)' + }; - 'boolean, boolean': function (x, y) { - return x === y ? 0 : (x > y ? 1 : -1); - }, + return rightArithShift; + } - 'number, number': function (x, y) { - return (x === y || nearlyEqual$6(x, y, config.epsilon)) - ? 0 - : (x > y ? 1 : -1); - }, + var name$166 = 'rightArithShift'; + var factory_1$177 = factory$178; - 'BigNumber, BigNumber': function (x, y) { - return (x.eq(y) || nearlyEqual(x, y, config.epsilon)) - ? new type.BigNumber(0) - : new type.BigNumber(x.cmp(y)); - }, + var rightArithShift$2 = { + name: name$166, + factory: factory_1$177 + }; - 'Fraction, Fraction': function (x, y) { - return new type.Fraction(x.compare(y)); - }, + var isInteger$19 = number.isInteger; - 'Complex, Complex': function () { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, + function factory$179 (type, config, load, typed) { + var latex$$1 = latex; - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return compare(x.value, y.value); - }, + var matrix$$1 = load(matrix); + var equalScalar$$1 = load(equalScalar); + var zeros = load(zeros$1); + + var algorithm01$$1 = load(algorithm01); + var algorithm02$$1 = load(algorithm02); + var algorithm08$$1 = load(algorithm08); + var algorithm10$$1 = load(algorithm10); + var algorithm11$$1 = load(algorithm11); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + /** + * Bitwise right logical shift of value x by y number of bits, `x >>> y`. + * For matrices, the function is evaluated element wise. + * For units, the function is evaluated on the best prefix base. + * + * Syntax: + * + * math.rightLogShift(x, y) + * + * Examples: + * + * math.rightLogShift(4, 2); // returns number 1 + * + * math.rightLogShift([16, -32, 64], 4); // returns Array [1, 2, 3] + * + * See also: + * + * bitAnd, bitNot, bitOr, bitXor, leftShift, rightLogShift + * + * @param {number | Array | Matrix} x Value to be shifted + * @param {number} y Amount of shifts + * @return {number | Array | Matrix} `x` zero-filled shifted right `y` times + */ - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm05$$1(x, y, compare); - }, + var rightLogShift = typed('rightLogShift', { - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, compare, true); - }, + 'number, number': function (x, y) { + if (!isInteger$19(x) || !isInteger$19(y)) { + throw new Error('Integers expected in function rightLogShift'); + } - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, compare, false); - }, + return x >>> y; + }, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, compare); - }, + // 'BigNumber, BigNumber': ..., // TODO: implement BigNumber support for rightLogShift - 'Array, Array': function (x, y) { - // use matrix implementation - return compare(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm08$$1(x, y, rightLogShift, false); + }, - 'Array, Matrix': function (x, y) { - // use matrix implementation - return compare(matrix$$1(x), y); - }, + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm02$$1(y, x, rightLogShift, true); + }, - 'Matrix, Array': function (x, y) { - // use matrix implementation - return compare(x, matrix$$1(y)); - }, + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm01$$1(x, y, rightLogShift, false); + }, - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, compare, false); - }, + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, rightLogShift); + }, - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, compare, false); - }, + 'Array, Array': function (x, y) { + // use matrix implementation + return rightLogShift(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, compare, true); - }, + 'Array, Matrix': function (x, y) { + // use matrix implementation + return rightLogShift(matrix$$1(x), y); + }, - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, compare, true); - }, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return rightLogShift(x, matrix$$1(y)); + }, - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, compare, false).valueOf(); - }, + 'SparseMatrix, number | BigNumber': function (x, y) { + // check scalar + if (equalScalar$$1(y, 0)) { + return x.clone(); + } + return algorithm11$$1(x, y, rightLogShift, false); + }, - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, compare, true).valueOf(); - } - }); + 'DenseMatrix, number | BigNumber': function (x, y) { + // check scalar + if (equalScalar$$1(y, 0)) { + return x.clone(); + } + return algorithm14$$1(x, y, rightLogShift, false); + }, - compare.toTex = undefined; // use default template + 'number | BigNumber, SparseMatrix': function (x, y) { + // check scalar + if (equalScalar$$1(x, 0)) { + return zeros(y.size(), y.storage()); + } + return algorithm10$$1(y, x, rightLogShift, true); + }, - return compare; -} + 'number | BigNumber, DenseMatrix': function (x, y) { + // check scalar + if (equalScalar$$1(x, 0)) { + return zeros(y.size(), y.storage()); + } + return algorithm14$$1(y, x, rightLogShift, true); + }, -var name$195 = 'compare'; -var factory_1$206 = factory$207; + 'Array, number | BigNumber': function (x, y) { + // use matrix implementation + return rightLogShift(matrix$$1(x), y).valueOf(); + }, -var compare$1 = { - name: name$195, - factory: factory_1$206 -}; + 'number | BigNumber, Array': function (x, y) { + // use matrix implementation + return rightLogShift(x, matrix$$1(y)).valueOf(); + } + }); -var isInteger$25 = number.isInteger; + rightLogShift.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['rightLogShift'] + '${args[1]}\\right)' + }; -function factory$208 (type, config, load, typed) { - var asc = load(compare$1); - function desc(a, b) { - return -asc(a, b); + return rightLogShift; } - /** - * Partition-based selection of an array or 1D matrix. - * Will find the kth smallest value, and mutates the input array. - * Uses Quickselect. - * - * Syntax: - * - * math.partitionSelect(x, k) - * math.partitionSelect(x, k, compare) - * - * Examples: - * - * math.partitionSelect([5, 10, 1], 2); // returns 10 - * math.partitionSelect(['C', 'B', 'A', 'D'], 1); // returns 'B' - * - * function sortByLength (a, b) { - * return a.length - b.length; - * } - * math.partitionSelect(['Langdon', 'Tom', 'Sara'], 2, sortByLength); // returns 'Langdon' - * - * See also: - * - * sort - * - * @param {Matrix | Array} x A one dimensional matrix or array to sort - * @param {Number} k The kth smallest value to be retrieved; zero-based index - * @param {Function | 'asc' | 'desc'} [compare='asc'] - * An optional comparator function. The function is called as - * `compare(a, b)`, and must return 1 when a > b, -1 when a < b, - * and 0 when a == b. - * @return {*} Returns the kth lowest value. - */ - return typed('partitionSelect', { - 'Array | Matrix, number': function (x, k) { - return _partitionSelect(x, k, asc); - }, + var name$167 = 'rightLogShift'; + var factory_1$178 = factory$179; - 'Array | Matrix, number, string': function (x, k, compare) { - if (compare === 'asc') { - return _partitionSelect(x, k, asc); - } - else if (compare === 'desc') { - return _partitionSelect(x, k, desc); - } - else { - throw new Error('Compare string must be "asc" or "desc"'); - } - }, + var rightLogShift$1 = { + name: name$167, + factory: factory_1$178 + }; - 'Array | Matrix, number, function': _partitionSelect - }); + var bitwise$1 = [ + bitAnd$2, + bitNot$2, + bitOr$2, + bitXor$2, + leftShift$2, + rightArithShift$2, + rightLogShift$1 + ]; - function _partitionSelect(x, k, compare) { - if (!isInteger$25(k) || k < 0) { - throw new Error('k must be a non-negative integer'); - } + var isInteger$20 = number.isInteger; - if (type.isMatrix(x)) { - var size = x.size(); - if (size.length > 1) { - throw new Error('Only one dimensional matrices supported'); - } - return quickSelect(x.valueOf(), k, compare); - } + function factory$180 (type, config, load, typed) { + var multiply = load(multiply$1); + var pow = load(pow$1); - if (Array.isArray(x)) { - return quickSelect(x, k, compare); - } - } + /** + * Compute the gamma function of a value using Lanczos approximation for + * small values, and an extended Stirling approximation for large values. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.gamma(n) + * + * Examples: + * + * math.gamma(5); // returns 24 + * math.gamma(-0.5); // returns -3.5449077018110335 + * math.gamma(math.i); // returns -0.15494982830180973 - 0.49801566811835596i + * + * See also: + * + * combinations, factorial, permutations + * + * @param {number | Array | Matrix} n A real or complex number + * @return {number | Array | Matrix} The gamma of `n` + */ + var gamma = typed('gamma', { + 'number': function (n) { + var t, x; - /** - * Quickselect algorithm. - * Code adapted from: - * http://blog.teamleadnet.com/2012/07/quick-select-algorithm-find-kth-element.html - * - * @param {Array} arr - * @param {Number} k - * @param {Function} compare - * @private - */ - function quickSelect(arr, k, compare) { - if (k >= arr.length) { - throw new Error('k out of bounds'); - } + if (isInteger$20(n)) { + if (n <= 0) { + return isFinite(n) ? Infinity : NaN; + } + + if (n > 171) { + return Infinity; // Will overflow + } - var from = 0; - var to = arr.length - 1; + var value = n - 2; + var res = n - 1; + while (value > 1) { + res *= value; + value--; + } - // if from == to we reached the kth element - while (from < to) { - var r = from; - var w = to; - var pivot = arr[Math.floor(Math.random() * (to - from + 1)) + from]; + if (res == 0) { + res = 1; // 0! is per definition 1 + } - // stop if the reader and writer meets - while (r < w) { - // arr[r] >= pivot - if (compare(arr[r], pivot) >= 0) { // put the large values at the end - var tmp = arr[w]; - arr[w] = arr[r]; - arr[r] = tmp; - --w; - } else { // the value is smaller than the pivot, skip - ++r; + return res; } - } - // if we stepped up (r++) we need to step one down (arr[r] > pivot) - if (compare(arr[r], pivot) > 0) { - --r; - } - - // the r pointer is on the end of the first k elements - if (k <= r) { - to = r; - } else { - from = r + 1; - } - } + if (n < 0.5) { + return Math.PI / (Math.sin(Math.PI * n) * gamma(1-n)); + } - return arr[k]; - } -} + if (n >= 171.35) { + return Infinity; // will overflow + } -var name$196 = 'partitionSelect'; -var factory_1$207 = factory$208; + if (n > 85.0) { // Extended Stirling Approx + var twoN = n*n; + var threeN = twoN*n; + var fourN = threeN*n; + var fiveN = fourN*n; + return Math.sqrt(2*Math.PI/n) * Math.pow((n/Math.E), n) * + (1 + 1/(12*n) + 1/(288*twoN) - 139/(51840*threeN) - + 571/(2488320*fourN) + 163879/(209018880*fiveN) + + 5246819/(75246796800*fiveN*n)); + } -var partitionSelect$1 = { - name: name$196, - factory: factory_1$207 -}; + --n; + x = p[0]; + for (var i = 1; i < p.length; ++i) { + x += p[i] / (n+i); + } -var isInteger$26 = number.isInteger; + t = n + g + 0.5; + return Math.sqrt(2*Math.PI) * Math.pow(t, n+0.5) * Math.exp(-t) * x; + }, + 'Complex': function (n) { + var t, x; -function factory$209 (type, config, load, typed) { - var matrix$$1 = load(matrix); + if (n.im == 0) { + return gamma(n.re); + } - /** - * Reshape a multi dimensional array to fit the specified dimensions - * - * Syntax: - * - * math.reshape(x, sizes) - * - * Examples: - * - * math.reshape([1, 2, 3, 4, 5, 6], [2, 3]); - * // returns Array [[1, 2, 3], [4, 5, 6]] - * - * math.reshape([[1, 2], [3, 4]], [1, 4]); - * // returns Array [[1, 2, 3, 4]] - * - * math.reshape([[1, 2], [3, 4]], [4]); - * // returns Array [1, 2, 3, 4] - * - * var x = math.matrix([1, 2, 3, 4, 5, 6, 7, 8]); - * math.reshape(x, [2, 2, 2]); - * // returns Matrix [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] - * - * See also: - * - * size, squeeze, resize - * - * @param {Array | Matrix | *} x Matrix to be reshaped - * @param {number[]} sizes One dimensional array with integral sizes for - * each dimension - * - * @return {* | Array | Matrix} A reshaped clone of matrix `x` - * - * @throws {TypeError} If `sizes` does not contain solely integers - * @throws {DimensionError} If the product of the new dimension sizes does - * not equal that of the old ones - */ - var reshape = typed('reshape', { - - 'Matrix, Array': function (x, sizes) { - if(x.reshape) { - return x.reshape(sizes); - } else { - return matrix$$1(array.reshape(x.valueOf(), sizes)); - } - }, - - 'Array, Array': function (x, sizes) { - sizes.forEach(function (size) { - if (!isInteger$26(size)) { - throw new TypeError('Invalid size for dimension: ' + size); + n = new type.Complex(n.re - 1, n.im); + x = new type.Complex(p[0], 0); + for (var i = 1; i < p.length; ++i) { + var real = n.re + i; // x += p[i]/(n+i) + var den = real*real + n.im*n.im; + if (den != 0) { + x.re += p[i] * real / den; + x.im += -(p[i] * n.im) / den; + } else { + x.re = p[i] < 0 + ? -Infinity + : Infinity; + } } - }); - return array.reshape(x, sizes); - } - - }); - - reshape.toTex = undefined; // use default template - - return reshape; -} - -var name$197 = 'reshape'; -var factory_1$208 = factory$209; -var reshape$1 = { - name: name$197, - factory: factory_1$208 -}; + t = new type.Complex(n.re + g + 0.5, n.im); + var twoPiSqrt = Math.sqrt(2*Math.PI); -var isInteger$27 = number.isInteger; -var format$7 = string.format; -var clone$10 = object.clone; + n.re += 0.5; + var result = pow(t, n); + if (result.im == 0) { // sqrt(2*PI)*result + result.re *= twoPiSqrt; + } else if (result.re == 0) { + result.im *= twoPiSqrt; + } else { + result.re *= twoPiSqrt; + result.im *= twoPiSqrt; + } + var r = Math.exp(-t.re); // exp(-t) + t.re = r * Math.cos(-t.im); + t.im = r * Math.sin(-t.im); -function factory$210 (type, config, load, typed) { - var matrix$$1 = load(matrix); + return multiply(multiply(result, t), x); + }, - /** - * Resize a matrix - * - * Syntax: - * - * math.resize(x, size) - * math.resize(x, size, defaultValue) - * - * Examples: - * - * math.resize([1, 2, 3, 4, 5], [3]); // returns Array [1, 2, 3] - * math.resize([1, 2, 3], [5], 0); // returns Array [1, 2, 3, 0, 0] - * math.resize(2, [2, 3], 0); // returns Matrix [[2, 0, 0], [0, 0, 0]] - * math.resize("hello", [8], "!"); // returns string 'hello!!!' - * - * See also: - * - * size, squeeze, subset, reshape - * - * @param {Array | Matrix | *} x Matrix to be resized - * @param {Array | Matrix} size One dimensional array with numbers - * @param {number | string} [defaultValue=0] Zero by default, except in - * case of a string, in that case - * defaultValue = ' ' - * @return {* | Array | Matrix} A resized clone of matrix `x` - */ - // TODO: rework resize to a typed-function - var resize = function resize (x, size, defaultValue) { - if (arguments.length != 2 && arguments.length != 3) { - throw new ArgumentsError_1('resize', arguments.length, 2, 3); - } + 'BigNumber': function (n) { + if (n.isInteger()) { + return (n.isNegative() || n.isZero()) + ? new type.BigNumber(Infinity) + : bigFactorial(n.minus(1)); + } - if (type.isMatrix(size)) { - size = size.valueOf(); // get Array - } + if (!n.isFinite()) { + return new type.BigNumber(n.isNegative() ? NaN : Infinity); + } - if (type.isBigNumber(size[0])) { - // convert bignumbers to numbers - size = size.map(function (value) { - return type.isBigNumber(value) ? value.toNumber() : value; - }); - } - - // check x is a Matrix - if (type.isMatrix(x)) { - // use optimized matrix implementation, return copy - return x.resize(size, defaultValue, true); - } - - if (typeof x === 'string') { - // resize string - return _resizeString(x, size, defaultValue); - } - - // check result should be a matrix - var asMatrix = Array.isArray(x) ? false : (config.matrix !== 'Array'); + throw new Error('Integer BigNumber expected'); + }, - if (size.length == 0) { - // output a scalar - while (Array.isArray(x)) { - x = x[0]; + 'Array | Matrix': function (n) { + return deepMap(n, gamma); } + }); - return clone$10(x); - } - else { - // output an array/matrix - if (!Array.isArray(x)) { - x = [x]; + /** + * Calculate factorial for a BigNumber + * @param {BigNumber} n + * @returns {BigNumber} Returns the factorial of n + */ + function bigFactorial(n) { + if (n.isZero()) { + return new type.BigNumber(1); // 0! is per definition 1 } - x = clone$10(x); - var res = array.resize(x, size, defaultValue); - return asMatrix ? matrix$$1(res) : res; - } - }; - - resize.toTex = undefined; // use default template - - return resize; + var precision = config.precision + (Math.log(n.toNumber()) | 0); + var Big = type.BigNumber.clone({precision: precision}); - /** - * Resize a string - * @param {string} str - * @param {number[]} size - * @param {string} [defaultChar=' '] - * @private - */ - function _resizeString(str, size, defaultChar) { - if (defaultChar !== undefined) { - if (typeof defaultChar !== 'string' || defaultChar.length !== 1) { - throw new TypeError('Single character expected as defaultValue'); + var res = new Big(n); + var value = n.toNumber() - 1; // number + while (value > 1) { + res = res.times(value); + value--; } - } - else { - defaultChar = ' '; - } - - if (size.length !== 1) { - throw new DimensionError_1(size.length, 1); - } - var len = size[0]; - if (typeof len !== 'number' || !isInteger$27(len)) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + format$7(size) + ')'); - } - if (str.length > len) { - return str.substring(0, len); - } - else if (str.length < len) { - var res = str; - for (var i = 0, ii = len - str.length; i < ii; i++) { - res += defaultChar; - } - return res; + return new type.BigNumber(res.toPrecision(type.BigNumber.precision)); } - else { - return str; - } - } -} -var name$198 = 'resize'; -var factory_1$209 = factory$210; + gamma.toTex = {1: '\\Gamma\\left(${args[0]}\\right)'}; -var resize$3 = { - name: name$198, - factory: factory_1$209 -}; + return gamma; + } -function factory$211 (type, config, load, typed) { - var matrix$$1 = load(matrix); + // TODO: comment on the variables g and p - /** - * Calculate the size of a matrix or scalar. - * - * Syntax: - * - * math.size(x) - * - * Examples: - * - * math.size(2.3); // returns [] - * math.size('hello world'); // returns [11] - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.size(A); // returns [2, 3] - * math.size(math.range(1,6)); // returns [5] - * - * See also: - * - * resize, squeeze, subset - * - * @param {boolean | number | Complex | Unit | string | Array | Matrix} x A matrix - * @return {Array | Matrix} A vector with size of `x`. - */ - var size = typed('size', { - 'Matrix': function (x) { - // TODO: return the same matrix type as the input - return matrix$$1(x.size()); - }, + var g = 4.7421875; - 'Array': array.size, + var p = [ + 0.99999999999999709182, + 57.156235665862923517, + -59.597960355475491248, + 14.136097974741747174, + -0.49191381609762019978, + 0.33994649984811888699e-4, + 0.46523628927048575665e-4, + -0.98374475304879564677e-4, + 0.15808870322491248884e-3, + -0.21026444172410488319e-3, + 0.21743961811521264320e-3, + -0.16431810653676389022e-3, + 0.84418223983852743293e-4, + -0.26190838401581408670e-4, + 0.36899182659531622704e-5 + ]; - 'string': function (x) { - return (config.matrix === 'Array') ? [x.length] : matrix$$1([x.length]); - }, + var name$168 = 'gamma'; + var factory_1$179 = factory$180; - 'number | Complex | BigNumber | Unit | boolean | null': function (x) { - // scalar - return (config.matrix === 'Array') ? [] : matrix$$1([]); - } - }); + var gamma$1 = { + name: name$168, + factory: factory_1$179 + }; - size.toTex = undefined; // use default template - - return size; -} - -var name$199 = 'size'; -var factory_1$210 = factory$211; - -var size$5 = { - name: name$199, - factory: factory_1$210 -}; - -/* - * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license - * Author: Jim Palmer (based on chunking idea from Dave Koelle) - */ -/*jshint unused:false */ -var naturalSort = function naturalSort (a, b) { - var re = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, - sre = /(^[ ]*|[ ]*$)/g, - dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, - hre = /^0x[0-9a-f]+$/i, - ore = /^0/, - i = function(s) { return naturalSort.insensitive && ('' + s).toLowerCase() || '' + s; }, - // convert all to strings strip whitespace - x = i(a).replace(sre, '') || '', - y = i(b).replace(sre, '') || '', - // chunk/tokenize - xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), - yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), - // numeric, hex or date detection - xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && x.match(dre) && Date.parse(x)), - yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null, - oFxNcL, oFyNcL; - // first try and sort Hex codes or Dates - if (yD) { - if ( xD < yD ) { return -1; } - else if ( xD > yD ) { return 1; } - } - // natural sorting through split numeric strings and default strings - for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) { - // find floats not starting with '0', string or 0 if not defined (Clint Priest) - oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0; - oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0; - // handle numeric vs string comparison - number < string - (Kyle Adams) - if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; } - // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' - else if (typeof oFxNcL !== typeof oFyNcL) { - oFxNcL += ''; - oFyNcL += ''; - } - if (oFxNcL < oFyNcL) { return -1; } - if (oFxNcL > oFyNcL) { return 1; } - } - return 0; -}; - -function factory$212 (type, config, load, typed) { - var getTypeOf = load(_typeof$1); - var compare = load(compare$1); - - var compareBooleans = compare.signatures['boolean,boolean']; + function factory$181 (type, config, load, typed) { + var gamma = load(gamma$1); + var latex$$1 = latex; - /** - * Compare two values of any type in a deterministic, natural way. - * - * For numeric values, the function works the same as `math.compare`. - * For types of values that can't be compared mathematically, - * the function compares in a natural way. - * - * For numeric values, x and y are considered equal when the relative - * difference between x and y is smaller than the configured epsilon. - * The function cannot be used to compare values smaller than - * approximately 2.22e-16. - * - * For Complex numbers, first the real parts are compared. If equal, - * the imaginary parts are compared. - * - * Strings are compared with a natural sorting algorithm, which - * orders strings in a "logic" way following some heuristics. - * This differs from the function `compare`, which converts the string - * into a numeric value and compares that. The function `compareText` - * on the other hand compares text lexically. - * - * Arrays and Matrices are compared value by value until there is an - * unequal pair of values encountered. Objects are compared by sorted - * keys until the keys or their values are unequal. - * - * Syntax: - * - * math.compareNatural(x, y) - * - * Examples: - * - * math.compareNatural(6, 1); // returns 1 - * math.compareNatural(2, 3); // returns -1 - * math.compareNatural(7, 7); // returns 0 - * - * math.compareNatural('10', '2'); // returns 1 - * math.compareText('10', '2'); // returns -1 - * math.compare('10', '2'); // returns 1 - * - * math.compareNatural('Answer: 10', 'Answer: 2'); // returns 1 - * math.compareText('Answer: 10', 'Answer: 2'); // returns -1 - * math.compare('Answer: 10', 'Answer: 2'); - * // Error: Cannot convert "Answer: 10" to a number - * - * var a = math.unit('5 cm'); - * var b = math.unit('40 mm'); - * math.compareNatural(a, b); // returns 1 - * - * var c = math.complex('2 + 3i'); - * var d = math.complex('2 + 4i'); - * math.compareNatural(c, d); // returns -1 - * - * math.compareNatural([1, 2, 4], [1, 2, 3]); // returns 1 - * math.compareNatural([1, 2, 3], [1, 2]); // returns 1 - * math.compareNatural([1, 5], [1, 2, 3]); // returns 1 - * math.compareNatural([1, 2], [1, 2]); // returns 0 - * - * math.compareNatural({a: 2}, {a: 4}); // returns -1 - * - * See also: - * - * compare, compareText - * - * @param {*} x First value to compare - * @param {*} y Second value to compare - * @return {number} Returns the result of the comparison: - * 1 when x > y, -1 when x < y, and 0 when x == y. - */ - var compareNatural = typed('compareNatural', { - 'any, any': function (x, y) { - var typeX = getTypeOf(x); - var typeY = getTypeOf(y); - var c; - - // numeric types - if ((typeX === 'number' || typeX === 'BigNumber' || typeX === 'Fraction') && - (typeY === 'number' || typeY === 'BigNumber' || typeY === 'Fraction')) { - c = compare(x, y); - if (c.toString() !== '0') { - // c can be number, BigNumber, or Fraction - return c > 0 ? 1 : -1; // return a number - } - else { - return naturalSort(typeX, typeY); + /** + * Compute the factorial of a value + * + * Factorial only supports an integer value as argument. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.factorial(n) + * + * Examples: + * + * math.factorial(5); // returns 120 + * math.factorial(3); // returns 6 + * + * See also: + * + * combinations, gamma, permutations + * + * @param {number | BigNumber | Array | Matrix} n An integer number + * @return {number | BigNumber | Array | Matrix} The factorial of `n` + */ + var factorial = typed('factorial', { + 'number': function (n) { + if (n < 0) { + throw new Error('Value must be non-negative'); } - } - // matrix types - if (typeX === 'Array' || typeX === 'Matrix' || - typeY === 'Array' || typeY === 'Matrix') { - c = compareMatricesAndArrays (x, y); - if (c !== 0) { - return c; - } - else { - return naturalSort(typeX, typeY); + return gamma(n + 1); + }, + + 'BigNumber': function (n) { + if (n.isNegative()) { + throw new Error('Value must be non-negative'); } - } - // in case of different types, order by name of type, i.e. 'BigNumber' < 'Complex' - if (typeX !== typeY) { - return naturalSort(typeX, typeY); - } + return gamma(n.plus(1)); + }, - if (typeX === 'Complex') { - return compareComplexNumbers(x, y); + 'Array | Matrix': function (n) { + return deepMap(n, factorial); } + }); - if (typeX === 'Unit') { - if (x.equalBase(y)) { - return compareNatural(x.value, y.value); - } - - // compare by units - return compareArrays(x.formatUnits(), y.formatUnits()); - } + factorial.toTex = { + 1: '\\left(${args[0]}\\right)' + latex$$1.operators['factorial'] + }; - if (typeX === 'boolean') { - return compareBooleans(x, y); - } + return factorial; + } - if (typeX === 'string') { - return naturalSort(x, y); - } + var name$169 = 'factorial'; + var factory_1$180 = factory$181; - if (typeX === 'Object') { - return compareObjects(x, y); - } + var factorial$1 = { + name: name$169, + factory: factory_1$180 + }; - if (typeX === 'null') { - return 0; - } + var isInteger$21 = number.isInteger; - if (typeX === 'undefined') { - return 0; - } + function factory$182 (type, config, load, typed) { + /** + * Compute the number of ways of picking `k` unordered outcomes from `n` + * possibilities. + * + * Combinations only takes integer arguments. + * The following condition must be enforced: k <= n. + * + * Syntax: + * + * math.combinations(n, k) + * + * Examples: + * + * math.combinations(7, 5); // returns 21 + * + * See also: + * + * permutations, factorial + * + * @param {number | BigNumber} n Total number of objects in the set + * @param {number | BigNumber} k Number of objects in the subset + * @return {number | BigNumber} Number of possible combinations. + */ + var combinations = typed('combinations', { + 'number, number': function (n, k) { + var max, result, i; - // this should not occur... - throw new TypeError('Unsupported type of value "' + typeX + '"'); - } - }); + if (!isInteger$21(n) || n < 0) { + throw new TypeError('Positive integer value expected in function combinations'); + } + if (!isInteger$21(k) || k < 0) { + throw new TypeError('Positive integer value expected in function combinations'); + } + if (k > n) { + throw new TypeError('k must be less than or equal to n'); + } - compareNatural.toTex = undefined; // use default template + max = Math.max(k, n - k); + result = 1; + for (i = 1; i <= n - max; i++) { + result = result * (max + i) / i; + } - /** - * Compare mixed matrix/array types, by converting to same-shaped array. - * This comparator is non-deterministic regarding input types. - * @param {Array | SparseMatrix | DenseMatrix | *} x - * @param {Array | SparseMatrix | DenseMatrix | *} y - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ - function compareMatricesAndArrays (x, y) { - if (type.isSparseMatrix(x) && type.isSparseMatrix(y)) { - return compareArrays(x.toJSON().values, y.toJSON().values); - } - if (type.isSparseMatrix(x)) { - // note: convert to array is expensive - return compareMatricesAndArrays(x.toArray(), y); - } - if (type.isSparseMatrix(y)) { - // note: convert to array is expensive - return compareMatricesAndArrays(x, y.toArray()); - } + return result; + }, - // convert DenseArray into Array - if (type.isDenseMatrix(x)) { - return compareMatricesAndArrays(x.toJSON().data, y); - } - if (type.isDenseMatrix(y)) { - return compareMatricesAndArrays(x, y.toJSON().data); - } + 'BigNumber, BigNumber': function (n, k) { + var max, result, i, ii; + var one = new type.BigNumber(1); - // convert scalars to array - if (!Array.isArray(x)) { - return compareMatricesAndArrays([x], y); - } - if (!Array.isArray(y)) { - return compareMatricesAndArrays(x, [y]); - } + if (!isPositiveInteger(n) || !isPositiveInteger(k)) { + throw new TypeError('Positive integer value expected in function combinations'); + } + if (k.gt(n)) { + throw new TypeError('k must be less than n in function combinations'); + } - return compareArrays(x, y); - } + max = n.minus(k); + if (k.lt(max)) max = k; + result = one; + for (i = one, ii = n.minus(max); i.lte(ii); i = i.plus(1)) { + result = result.times(max.plus(i)).dividedBy(i); + } - /** - * Compare two Arrays - * - * - First, compares value by value - * - Next, if all corresponding values are equal, - * look at the length: longest array will be considered largest - * - * @param {Array} x - * @param {Array} y - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ - function compareArrays (x, y) { - // compare each value - for (var i = 0, ii = Math.min(x.length, y.length); i < ii; i++) { - var v = compareNatural(x[i], y[i]); - if (v !== 0) { - return v; + return result; } - } - // compare the size of the arrays - if (x.length > y.length) { return 1; } - if (x.length < y.length) { return -1; } + // TODO: implement support for collection in combinations + }); + + combinations.toTex = {2: '\\binom{${args[0]}}{${args[1]}}'}; - // both Arrays have equal size and content - return 0; + return combinations; } /** - * Compare two objects - * - * - First, compare sorted property names - * - Next, compare the property values - * - * @param {Object} x - * @param {Object} y - * @returns {number} Returns the comparison result: -1, 0, or 1 + * Test whether BigNumber n is a positive integer + * @param {BigNumber} n + * @returns {boolean} isPositiveInteger */ - function compareObjects (x, y) { - var keysX = Object.keys(x); - var keysY = Object.keys(y); - - // compare keys - keysX.sort(naturalSort); - keysY.sort(naturalSort); - var c = compareArrays(keysX, keysY); - if (c !== 0) { - return c; - } - - // compare values - for (var i = 0; i < keysX.length; i++) { - var v = compareNatural(x[keysX[i]], y[keysY[i]]); - if (v !== 0) { - return v; - } - } - - return 0; + function isPositiveInteger(n) { + return n.isInteger() && n.gte(0); } - return compareNatural; -} + var name$170 = 'combinations'; + var factory_1$181 = factory$182; + + var combinations$1 = { + name: name$170, + factory: factory_1$181 + }; -/** - * Compare two complex numbers, `x` and `y`: - * - * - First, compare the real values of `x` and `y` - * - If equal, compare the imaginary values of `x` and `y` - * - * @params {Complex} x - * @params {Complex} y - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ -function compareComplexNumbers (x, y) { - if (x.re > y.re) { return 1; } - if (x.re < y.re) { return -1; } + function factory$183 (type, config, load, typed) { + /** + * Test whether a value is an integer number. + * The function supports `number`, `BigNumber`, and `Fraction`. + * + * The function is evaluated element-wise in case of Array or Matrix input. + * + * Syntax: + * + * math.isInteger(x) + * + * Examples: + * + * math.isInteger(2); // returns true + * math.isInteger(0); // returns true + * math.isInteger(0.5); // returns false + * math.isInteger(math.bignumber(500)); // returns true + * math.isInteger(math.fraction(4)); // returns true + * math.isInteger('3'); // returns true + * math.isInteger([3, 0.5, -2]); // returns [true, false, true] + * math.isInteger(math.complex('2-4i'); // throws an error + * + * See also: + * + * isNumeric, isPositive, isNegative, isZero + * + * @param {number | BigNumber | Fraction | Array | Matrix} x Value to be tested + * @return {boolean} Returns true when `x` contains a numeric, integer value. + * Throws an error in case of an unknown data type. + */ + var isInteger = typed('isInteger', { + 'number': number.isInteger, // TODO: what to do with isInteger(add(0.1, 0.2)) ? - if (x.im > y.im) { return 1; } - if (x.im < y.im) { return -1; } + 'BigNumber': function (x) { + return x.isInt(); + }, - return 0; -} + 'Fraction': function (x) { + return x.d === 1 && isFinite(x.n); + }, -var name$200 = 'compareNatural'; -var factory_1$211 = factory$212; + 'Array | Matrix': function (x) { + return deepMap(x, isInteger); + } + }); -var compareNatural$1 = { - name: name$200, - factory: factory_1$211 -}; + return isInteger; + } -var size$6 = array.size; + var name$171 = 'isInteger'; + var factory_1$182 = factory$183; -function factory$213 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var compareAsc = load(compare$1); - var compareDesc = function (a, b) { - return -compareAsc(a, b); + var isInteger$22 = { + name: name$171, + factory: factory_1$182 }; - var compareNatural = load(compareNatural$1); - /** - * Sort the items in a matrix. - * - * Syntax: - * - * math.sort(x) - * math.sort(x, compare) - * - * Examples: - * - * math.sort([5, 10, 1]); // returns [1, 5, 10] - * math.sort(['C', 'B', 'A', 'D'], math.compareNatural); - * // returns ['A', 'B', 'C', 'D'] - * - * function sortByLength (a, b) { - * return a.length - b.length; - * } - * math.sort(['Langdon', 'Tom', 'Sara'], sortByLength); - * // returns ['Tom', 'Sara', 'Langdon'] - * - * See also: - * - * filter, forEach, map, compare, compareNatural - * - * @param {Matrix | Array} x A one dimensional matrix or array to sort - * @param {Function | 'asc' | 'desc' | 'natural'} [compare='asc'] - * An optional _comparator function or name. The function is called as - * `compare(a, b)`, and must return 1 when a > b, -1 when a < b, - * and 0 when a == b. - * @return {Matrix | Array} Returns the sorted matrix. - */ - var sort = typed('sort', { - 'Array': function (x) { - _arrayIsVector(x); - return x.sort(compareAsc); - }, - - 'Matrix': function (x) { - _matrixIsVector(x); - return matrix$$1(x.toArray().sort(compareAsc), x.storage()); - }, - - 'Array, function': function (x, _comparator) { - _arrayIsVector(x); - return x.sort(_comparator); - }, + function factory$184 (type, config, load, typed) { + var add$$1 = load(add); + var subtract = load(subtract$1); + var multiply = load(multiply$1); + var divide = load(divide$1); + var pow = load(pow$1); + var factorial = load(factorial$1); + var combinations = load(combinations$1); + var isNegative = load(isNegative$1); + var isInteger = load(isInteger$22); + var larger$$1 = load(larger); - 'Matrix, function': function (x, _comparator) { - _matrixIsVector(x); - return matrix$$1(x.toArray().sort(_comparator), x.storage()); - }, + /** + * The Stirling numbers of the second kind, counts the number of ways to partition + * a set of n labelled objects into k nonempty unlabelled subsets. + * stirlingS2 only takes integer arguments. + * The following condition must be enforced: k <= n. + * + * If n = k or k = 1, then s(n,k) = 1 + * + * Syntax: + * + * math.stirlingS2(n, k) + * + * Examples: + * + * math.stirlingS2(5, 3); //returns 25 + * + * See also: + * + * Bell numbers + * + * @param {Number | BigNumber} n Total number of objects in the set + * @param {Number | BigNumber} k Number of objects in the subset + * @return {Number | BigNumber} S(n,k) + */ + var stirlingS2 = typed('stirlingS2', { + 'number | BigNumber, number | BigNumber': function (n, k) { + if (!isInteger(n) || isNegative(n) || !isInteger(k) || isNegative(k)) { + throw new TypeError('Non-negative integer value expected in function stirlingS2'); + } + else if (larger$$1(k, n)) { + throw new TypeError('k must be less than or equal to n in function stirlingS2'); + } - 'Array, string': function (x, order) { - _arrayIsVector(x); - return x.sort(_comparator(order)); - }, + // 1/k! Sum(i=0 -> k) [(-1)^(k-i)*C(k,j)* i^n] + var kFactorial = factorial(k); + var result = 0; + for(var i = 0; i <= k; i++) { + var negativeOne = pow(-1, subtract(k,i)); + var kChooseI = combinations(k,i); + var iPower = pow(i,n); - 'Matrix, string': function (x, order) { - _matrixIsVector(x); - return matrix$$1(x.toArray().sort(_comparator(order)), x.storage()); - } - }); + result = add$$1(result, multiply(multiply(kChooseI, iPower), negativeOne)); + } - sort.toTex = undefined; // use default template + return divide(result, kFactorial); + } + }); - /** - * Get the comparator for given order ('asc', 'desc', 'natural') - * @param {'asc' | 'desc' | 'natural'} order - * @return {Function} Returns a _comparator function - */ - function _comparator (order) { - if (order === 'asc') { - return compareAsc; - } - else if (order === 'desc') { - return compareDesc; - } - else if (order === 'natural') { - return compareNatural; - } - else { - throw new Error('String "asc", "desc", or "natural" expected'); - } - } + stirlingS2.toTex = {2: '\\mathrm{S}\\left(${args}\\right)'}; - /** - * Validate whether an array is one dimensional - * Throws an error when this is not the case - * @param {Array} array - * @private - */ - function _arrayIsVector (array$$1) { - if (size$6(array$$1).length !== 1) { - throw new Error('One dimensional array expected'); - } + return stirlingS2; } - /** - * Validate whether a matrix is one dimensional - * Throws an error when this is not the case - * @param {Matrix} matrix - * @private - */ - function _matrixIsVector (matrix$$1) { - if (matrix$$1.size().length !== 1) { - throw new Error('One dimensional matrix expected'); - } - } + var name$172 = 'stirlingS2'; + var factory_1$183 = factory$184; - return sort; -} + var stirlingS2$1 = { + name: name$172, + factory: factory_1$183 + }; -var name$201 = 'sort'; -var factory_1$212 = factory$213; + function factory$185 (type, config, load, typed) { + var add$$1 = load(add); + var stirlingS2 = load(stirlingS2$1); + var isNegative = load(isNegative$1); + var isInteger = load(isInteger$22); -var sort$1 = { - name: name$201, - factory: factory_1$212 -}; + /** + * The Bell Numbers count the number of partitions of a set. A partition is a pairwise disjoint subset of S whose union is S. + * bellNumbers only takes integer arguments. + * The following condition must be enforced: n >= 0 + * + * Syntax: + * + * math.bellNumbers(n) + * + * Examples: + * + * math.bellNumbers(3); // returns 5; + * math.bellNumbers(8); // returns 4140; + * + * See also: + * + * stirlingS2 + * + * @param {Number | BigNumber} n Total number of objects in the set + * @return {Number | BigNumber} B(n) + */ + var bellNumbers = typed('bellNumbers', { + 'number | BigNumber': function (n) { -function factory$214(type, config, load, typed) { - var matrix$$1 = load(matrix); - var abs = load(abs$1); - var add$$1 = load(add); - var divide = load(divide$1); - var multiply = load(multiply$1); - var sqrt = load(sqrt$1); - var subtract = load(subtract$1); - var inv = load(inv$1); - var size = load(size$5); - var max = load(max$1); - var eye = load(eye$1); + if (!isInteger(n) || isNegative(n)) { + throw new TypeError('Non-negative integer value expected in function bellNumbers'); + } - /** - * Calculate the principal square root of a square matrix. - * The principal square root matrix `X` of another matrix `A` is such that `X * X = A`. - * - * https://en.wikipedia.org/wiki/Square_root_of_a_matrix - * - * Syntax: - * - * X = math.sqrtm(A) - * - * Examples: - * - * math.sqrtm([[1, 2], [3, 4]]); // returns [[-2, 1], [1.5, -0.5]] - * - * See also: - * - * sqrt, pow - * - * @param {Array | Matrix} A The square matrix `A` - * @return {Array | Matrix} The principal square root of matrix `A` - */ - var sqrtm = typed('sqrtm', { - 'Array | Matrix': function (A) { - var size = type.isMatrix(A) ? A.size() : array.size(A); - switch (size.length) { - case 1: - // Single element Array | Matrix - if (size[0] == 1) { - return sqrt(A); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); - } + // Sum (k=0, n) S(n,k). + var result = 0; + for(var i = 0; i <= n; i++) { + result = add$$1(result, stirlingS2(n, i)); + } - case 2: - // Two-dimensional Array | Matrix - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - return _denmanBeavers(A); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); - } + return result; } - } - }); + }); - var _maxIterations = 1e3; - var _tolerance = 1e-6; + bellNumbers.toTex = {1: '\\mathrm{B}_{${args[0]}}'}; - /** - * Calculate the principal square root matrix using the Denman–Beavers iterative method - * - * https://en.wikipedia.org/wiki/Square_root_of_a_matrix#By_Denman–Beavers_iteration - * - * @param {Array | Matrix} A The square matrix `A` - * @return {Array | Matrix} The principal square root of matrix `A` - * @private - */ - function _denmanBeavers(A) { - var error; - var iterations = 0; + return bellNumbers; + } - var Y = A; - var Z = eye(size(A)); + var name$173 = 'bellNumbers'; + var factory_1$184 = factory$185; - do { - var Y_k = Y; - Y = multiply(0.5, add$$1(Y_k, inv(Z))); - Z = multiply(0.5, add$$1(Z, inv(Y_k))); + var bellNumbers$1 = { + name: name$173, + factory: factory_1$184 + }; + + function factory$186 (type, config, load, typed) { + var combinations = load(combinations$1); + var add = load(addScalar); + var isPositive = load(isPositive$1); + var isInteger = load(isInteger$22); + var larger$$1 = load(larger); - error = max(abs(subtract(Y, Y_k))); + /** + * The composition counts of n into k parts. + * + * composition only takes integer arguments. + * The following condition must be enforced: k <= n. + * + * Syntax: + * + * math.composition(n, k) + * + * Examples: + * + * math.composition(5, 3); // returns 6 + * + * See also: + * + * combinations + * + * @param {Number | BigNumber} n Total number of objects in the set + * @param {Number | BigNumber} k Number of objects in the subset + * @return {Number | BigNumber} Returns the composition counts of n into k parts. + */ + var composition = typed('composition', { + 'number | BigNumber, number | BigNumber': function (n, k) { + if (!isInteger(n) || !isPositive(n) || !isInteger(k) || !isPositive(k)) { + throw new TypeError('Positive integer value expected in function composition'); + } + else if (larger$$1(k, n)) { + throw new TypeError('k must be less than or equal to n in function composition'); + } - if (error > _tolerance && ++iterations > _maxIterations) { - throw new Error('computing square root of matrix: iterative method could not converge'); + return combinations(add(n, -1), add(k, -1)); } - } while (error > _tolerance); + }); - return Y; + composition.toTex = undefined; // use default template + + return composition; } - sqrtm.toTex = {1: '{${args[0]}}' + latex.operators['pow'] + '{\\frac{1}{2}}'}; + var name$174 = 'composition'; + var factory_1$185 = factory$186; + + var composition$1 = { + name: name$174, + factory: factory_1$185 + }; - return sqrtm; -} + function factory$187 (type, config, load, typed) { + var add$$1 = load(add); + var divide = load(divide$1); + var multiply = load(multiply$1); + var combinations = load(combinations$1); + var isNegative = load(isNegative$1); + var isInteger = load(isInteger$22); -var name$202 = 'sqrtm'; -var factory_1$213 = factory$214; -var sqrtm$1 = { - name: name$202, - factory: factory_1$213 -}; + /** + * The Catalan Numbers enumerate combinatorial structures of many different types. + * catalan only takes integer arguments. + * The following condition must be enforced: n >= 0 + * + * Syntax: + * + * math.catalan(n) + * + * Examples: + * + * math.catalan(3); // returns 5; + * math.catalan(8); // returns 1430; + * + * See also: + * + * bellNumbers + * + * @param {Number | BigNumber} n nth Catalan number + * @return {Number | BigNumber} Cn(n) + */ + var catalan = typed('catalan', { + 'number | BigNumber': function (n) { -function factory$215 (type, config, load, typed) { - var matrix$$1 = load(matrix); + if (!isInteger(n) || isNegative(n)) { + throw new TypeError('Non-negative integer value expected in function catalan'); + } + + return divide(combinations(multiply(n,2), n), add$$1(n,1)); - /** - * Squeeze a matrix, remove inner and outer singleton dimensions from a matrix. - * - * Syntax: - * - * math.squeeze(x) - * - * Examples: - * - * math.squeeze([3]); // returns 3 - * math.squeeze([[3]]); // returns 3 - * - * var A = math.zeros(3, 1); // returns [[0], [0], [0]] (size 3x1) - * math.squeeze(A); // returns [0, 0, 0] (size 3) - * - * var B = math.zeros(1, 3); // returns [[0, 0, 0]] (size 1x3) - * math.squeeze(B); // returns [0, 0, 0] (size 3) - * - * // only inner and outer dimensions are removed - * var C = math.zeros(2, 1, 3); // returns [[[0, 0, 0]], [[0, 0, 0]]] (size 2x1x3) - * math.squeeze(C); // returns [[[0, 0, 0]], [[0, 0, 0]]] (size 2x1x3) - * - * See also: - * - * subset - * - * @param {Matrix | Array} x Matrix to be squeezed - * @return {Matrix | Array} Squeezed matrix - */ - var squeeze = typed('squeeze', { - 'Array': function (x) { - return array.squeeze(object.clone(x)); - }, + } + }); - 'Matrix': function (x) { - var res = array.squeeze(x.toArray()); - // FIXME: return the same type of matrix as the input - return Array.isArray(res) ? matrix$$1(res) : res; - }, + catalan.toTex = {1: '\\mathrm{C}_{${args[0]}}'}; - 'any': function (x) { - // scalar - return object.clone(x); - } - }); + return catalan; + } - squeeze.toTex = undefined; // use default template - - return squeeze; -} - -var name$203 = 'squeeze'; -var factory_1$214 = factory$215; - -var squeeze$1 = { - name: name$203, - factory: factory_1$214 -}; - -var matrix$3 = [ - concat$1, - cross$1, - det$1, - diag$1, - dot$1, - eye$1, - expm$1, - filter_1, - flatten$3, - forEach_1, - inv$1, - kron$1, - map$7, - ones$1, - partitionSelect$1, - range$1, - reshape$1, - resize$3, - size$5, - sort$1, - sqrtm$1, - squeeze$1, - subset$1, - trace$1, - transpose$1, - zeros$1 -]; - -function factory$216 (type, config, load, typed) { - var add = load(addScalar); - var improveErrorMessage$$1 = load(improveErrorMessage); + var name$175 = 'catalan'; + var factory_1$186 = factory$187; - /** - * Compute the sum of a matrix or a list with values. - * In case of a (multi dimensional) array or matrix, the sum of all - * elements will be calculated. - * - * Syntax: - * - * math.sum(a, b, c, ...) - * math.sum(A) - * - * Examples: - * - * math.sum(2, 1, 4, 3); // returns 10 - * math.sum([2, 1, 4, 3]); // returns 10 - * math.sum([[2, 5], [4, 3], [1, 7]]); // returns 22 - * - * See also: - * - * mean, median, min, max, prod, std, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The sum of all values - */ - var sum = typed('sum', { - 'Array | Matrix': function (args) { - // sum([a, b, c, d, ...]) - return _sum(args); - }, + var catalan$1 = { + name: name$175, + factory: factory_1$186 + }; - 'Array | Matrix, number | BigNumber': function () { - // sum([a, b, c, d, ...], dim) - // TODO: implement sum(A, dim) - throw new Error('sum(A, dim) is not yet supported'); - }, + var combinatorics = [ + bellNumbers$1, + composition$1, + stirlingS2$1, + catalan$1 + ]; - '...': function (args) { - // sum(a, b, c, d, ...) - return _sum(args); - } - }); + function factory$188 (type, config, load, typed) { + /** + * Compute the argument of a complex value. + * For a complex number `a + bi`, the argument is computed as `atan2(b, a)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.arg(x) + * + * Examples: + * + * var a = math.complex(2, 2); + * math.arg(a) / math.pi; // returns number 0.25 + * + * var b = math.complex('2 + 3i'); + * math.arg(b); // returns number 0.982793723247329 + * math.atan2(3, 2); // returns number 0.982793723247329 + * + * See also: + * + * re, im, conj, abs + * + * @param {number | BigNumber | Complex | Array | Matrix} x + * A complex number or array with complex numbers + * @return {number | BigNumber | Array | Matrix} The argument of x + */ + var arg = typed('arg', { + 'number': function (x) { + return Math.atan2(0, x); + }, - sum.toTex = undefined; // use default template + 'BigNumber': function (x) { + return type.BigNumber.atan2(0, x); + }, - return sum; + 'Complex': function (x) { + return x.arg(); + }, - /** - * Recursively calculate the sum of an n-dimensional array - * @param {Array} array - * @return {number} sum - * @private - */ - function _sum(array) { - var sum = undefined; + // TODO: implement BigNumber support for function arg - deepForEach(array, function (value) { - try { - sum = (sum === undefined) ? value : add(sum, value); - } - catch (err) { - throw improveErrorMessage$$1(err, 'sum', value); + 'Array | Matrix': function (x) { + return deepMap(x, arg); } }); - if (sum === undefined) { - switch (config.number) { - case 'number': - return 0; - case 'BigNumber': - return new type.BigNumber(0); - case 'Fraction': - return new type.Fraction(0); - default: - return 0; - } - } + arg.toTex = {1: '\\arg\\left(${args[0]}\\right)'}; - return sum; + return arg; } -} - -var name$204 = 'sum'; -var factory_1$215 = factory$216; -var sum$1 = { - name: name$204, - factory: factory_1$215 -}; + var name$176 = 'arg'; + var factory_1$187 = factory$188; -function factory$217(type, config, load, typed) { - var matrix$$1 = load(matrix); - var divide = load(divide$1); - var sum = load(sum$1); - var multiply = load(multiply$1); - var dotDivide = load(dotDivide$1); - var log = load(log$1); - var isNumeric = load(isNumeric$1); + var arg$1 = { + name: name$176, + factory: factory_1$187 + }; + function factory$189 (type, config, load, typed) { /** - * Calculate the Kullback-Leibler (KL) divergence between two distributions + * Get the imaginary part of a complex number. + * For a complex number `a + bi`, the function returns `b`. + * + * For matrices, the function is evaluated element wise. * * Syntax: * - * math.kldivergence(x, y) + * math.im(x) * * Examples: * - * math.kldivergence([0.7,0.5,0.4], [0.2,0.9,0.5]); //returns 0.24376698773121153 + * var a = math.complex(2, 3); + * math.re(a); // returns number 2 + * math.im(a); // returns number 3 + * + * math.re(math.complex('-5.2i')); // returns number -5.2 + * math.re(math.complex(2.4)); // returns number 0 + * + * See also: * + * re, conj, abs, arg * - * @param {Array | Matrix} q First vector - * @param {Array | Matrix} p Second vector - * @return {number} Returns distance between q and p + * @param {number | BigNumber | Complex | Array | Matrix} x + * A complex number or array with complex numbers + * @return {number | BigNumber | Array | Matrix} The imaginary part of x */ - var kldivergence = typed('kldivergence', { - 'Array, Array': function(q, p) { - return _kldiv(matrix$$1(q), matrix$$1(p)); - }, - - 'Matrix, Array': function(q, p) { - return _kldiv(q, matrix$$1(p)); - }, + var im = typed('im', { + 'number': function (x) { + return 0; + }, - 'Array, Matrix': function(q, p){ - return _kldiv(matrix$$1(q), p); - }, + 'BigNumber': function (x) { + return new type.BigNumber(0); + }, - 'Matrix, Matrix': function(q, p){ - return _kldiv(q, p); - } + 'Complex': function (x) { + return x.im; + }, + 'Array | Matrix': function (x) { + return deepMap(x, im); + } }); - function _kldiv(q, p) { - var plength = p.size().length; - var qlength = q.size().length; - if (plength > 1) { - throw new Error('first object must be one dimensional'); - } - - if (qlength > 1) { - throw new Error('second object must be one dimensional'); - } - - if(plength !== qlength){ - throw new Error("Length of two vectors must be equal"); - } - - //Before calculation, apply normalization - var sumq = sum(q); - if (sumq === 0) { - throw new Error("Sum of elements in first object must be non zero"); - } - - var sump = sum(p); - if (sump === 0) { - throw new Error("Sum of elements in second object must be non zero"); - } - var qnorm = divide(q, sum(q)); - var pnorm = divide(p, sum(p)); - - var result = sum(multiply(qnorm, log(dotDivide(qnorm, pnorm)))); - if (isNumeric(result)) { - return result; - } - else { - return Number.NaN; - } - } - - return kldivergence; -} + im.toTex = {1: '\\Im\\left\\lbrace${args[0]}\\right\\rbrace'}; + return im; + } -var name$205 = 'kldivergence'; -var factory_1$216 = factory$217; - -var kldivergence$1 = { - name: name$205, - factory: factory_1$216 -}; + var name$177 = 'im'; + var factory_1$188 = factory$189; -function factory$218 (type, config, load, typed) { - var add$$1 = load(add); - var multiply = load(multiply$1); - var divide = load(divide$1); - var factorial = load(factorial$1); - var isInteger = load(isInteger$22); - var isPositive = load(isPositive$1); + var im$1 = { + name: name$177, + factory: factory_1$188 + }; - /** - * Multinomial Coefficients compute the number of ways of picking a1, a2, ..., ai unordered outcomes from `n` possibilities. - * - * multinomial takes one array of integers as an argument. - * The following condition must be enforced: every ai <= 0 - * - * Syntax: - * - * math.multinomial(a) // a is an array type - * - * Examples: - * - * math.multinomial([1,2,1]); // returns 12 - * - * See also: - * - * combinations, factorial - * - * @param {number[] | BigNumber[]} a Integer numbers of objects in the subset - * @return {Number | BigNumber} Multinomial coefficient. - */ - return typed('multinomial', { - 'Array | Matrix': function (a) { - var sum = 0; - var denom = 1; - - deepForEach(a, function(ai) { - if(!isInteger(ai) || !isPositive(ai)) { - throw new TypeError('Positive integer value expected in function multinomial'); - } - sum = add$$1(sum, ai); - denom = multiply(denom, factorial(ai)); - }); - - return divide(factorial(sum), denom); - } - }); -} - -var name$206 = 'multinomial'; -var factory_1$217 = factory$218; - -var multinomial$1 = { - name: name$206, - factory: factory_1$217 -}; - -var isInteger$28 = number.isInteger; - -function factory$219 (type, config, load, typed) { - var factorial = load(factorial$1); - - /** - * Compute the number of ways of obtaining an ordered subset of `k` elements - * from a set of `n` elements. - * - * Permutations only takes integer arguments. - * The following condition must be enforced: k <= n. - * - * Syntax: - * - * math.permutations(n) - * math.permutations(n, k) - * - * Examples: - * - * math.permutations(5); // 120 - * math.permutations(5, 3); // 60 - * - * See also: - * - * combinations, factorial - * - * @param {number | BigNumber} n The number of objects in total - * @param {number | BigNumber} [k] The number of objects in the subset - * @return {number | BigNumber} The number of permutations - */ - var permutations = typed('permutations', { - 'number | BigNumber': factorial, + function factory$190 (type, config, load, typed) { + /** + * Get the real part of a complex number. + * For a complex number `a + bi`, the function returns `a`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.re(x) + * + * Examples: + * + * var a = math.complex(2, 3); + * math.re(a); // returns number 2 + * math.im(a); // returns number 3 + * + * math.re(math.complex('-5.2i')); // returns number 0 + * math.re(math.complex(2.4)); // returns number 2.4 + * + * See also: + * + * im, conj, abs, arg + * + * @param {number | BigNumber | Complex | Array | Matrix} x + * A complex number or array with complex numbers + * @return {number | BigNumber | Array | Matrix} The real part of x + */ + var re = typed('re', { + 'number': function (x) { + return x; + }, - 'number, number': function (n, k) { - var result, i; + 'BigNumber': function (x) { + return x; + }, - if (!isInteger$28(n) || n < 0) { - throw new TypeError('Positive integer value expected in function permutations'); - } - if (!isInteger$28(k) || k < 0) { - throw new TypeError('Positive integer value expected in function permutations'); - } - if (k > n) { - throw new TypeError('second argument k must be less than or equal to first argument n'); - } + 'Complex': function (x) { + return x.re; + }, - // Permute n objects, k at a time - result = 1; - for (i = n - k + 1; i <= n; i++) { - result = result * i; + 'Array | Matrix': function (x) { + return deepMap(x, re); } + }); - return result; - }, - - 'BigNumber, BigNumber': function (n, k) { - var result, i; - - if (!isPositiveInteger$1(n) || !isPositiveInteger$1(k)) { - throw new TypeError('Positive integer value expected in function permutations'); - } - if (k.gt(n)) { - throw new TypeError('second argument k must be less than or equal to first argument n'); - } + re.toTex = {1: '\\Re\\left\\lbrace${args[0]}\\right\\rbrace'}; - result = new type.BigNumber(1); - for (i = n.minus(k).plus(1); i.lte(n); i = i.plus(1)) { - result = result.times(i); - } + return re; + } - return result; - } + var name$178 = 're'; + var factory_1$189 = factory$190; - // TODO: implement support for collection in permutations - }); + var re$1 = { + name: name$178, + factory: factory_1$189 + }; - permutations.toTex = undefined; // use default template - - return permutations; -} - -/** - * Test whether BigNumber n is a positive integer - * @param {BigNumber} n - * @returns {boolean} isPositiveInteger - */ -function isPositiveInteger$1(n) { - return n.isInteger() && n.gte(0); -} - -var name$207 = 'permutations'; -var factory_1$218 = factory$219; - -var permutations$1 = { - name: name$207, - factory: factory_1$218 -}; - -var seedRandom = createCommonjsModule(function (module) { - -var width = 256;// each RC4 output is 0 <= x < 256 -var chunks = 6;// at least six RC4 outputs for each double -var digits = 52;// there are 52 significant digits in a double -var pool = [];// pool: entropy pool starts empty -var GLOBAL = typeof commonjsGlobal === 'undefined' ? window : commonjsGlobal; - -// -// The following constants are related to IEEE 754 limits. -// -var startdenom = Math.pow(width, chunks), - significance = Math.pow(2, digits), - overflow = significance * 2, - mask = width - 1; - - -var oldRandom = Math.random; - -// -// seedrandom() -// This is the seedrandom function described above. -// -module.exports = function(seed, options) { - if (options && options.global === true) { - options.global = false; - Math.random = module.exports(seed, options); - options.global = true; - return Math.random; - } - var use_entropy = (options && options.entropy) || false; - var key = []; - - // Flatten the seed string or build one from local entropy if needed. - var shortseed = mixkey(flatten( - use_entropy ? [seed, tostring(pool)] : - 0 in arguments ? seed : autoseed(), 3), key); - - // Use the seed to initialize an ARC4 generator. - var arc4 = new ARC4(key); - - // Mix the randomness into accumulated entropy. - mixkey(tostring(arc4.S), pool); - - // Override Math.random - - // This function returns a random double in [0, 1) that contains - // randomness in every bit of the mantissa of the IEEE 754 value. - - return function() { // Closure to return a random double: - var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 - d = startdenom, // and denominator d = 2 ^ 48. - x = 0; // and no 'extra last byte'. - while (n < significance) { // Fill up all significant digits by - n = (n + x) * width; // shifting numerator and - d *= width; // denominator and generating a - x = arc4.g(1); // new least-significant-byte. - } - while (n >= overflow) { // To avoid rounding up, before adding - n /= 2; // last byte, shift everything - d /= 2; // right using integer Math until - x >>>= 1; // we have exactly the desired bits. - } - return (n + x) / d; // Form the number within [0, 1). - }; -}; - -module.exports.resetGlobal = function () { - Math.random = oldRandom; -}; - -// -// ARC4 -// -// An ARC4 implementation. The constructor takes a key in the form of -// an array of at most (width) integers that should be 0 <= x < (width). -// -// The g(count) method returns a pseudorandom integer that concatenates -// the next (count) outputs from ARC4. Its return value is a number x -// that is in the range 0 <= x < (width ^ count). -// -/** @constructor */ -function ARC4(key) { - var t, keylen = key.length, - me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; - - // The empty key [] is treated as [0]. - if (!keylen) { key = [keylen++]; } - - // Set up S using the standard key scheduling algorithm. - while (i < width) { - s[i] = i++; - } - for (i = 0; i < width; i++) { - s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; - s[j] = t; - } - - // The "g" method returns the next (count) outputs as one number. - (me.g = function(count) { - // Using instance members instead of closure state nearly doubles speed. - var t, r = 0, - i = me.i, j = me.j, s = me.S; - while (count--) { - t = s[i = mask & (i + 1)]; - r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; - } - me.i = i; me.j = j; - return r; - // For robust unpredictability discard an initial batch of values. - // See http://www.rsa.com/rsalabs/node.asp?id=2009 - })(width); -} - -// -// flatten() -// Converts an object tree to nested arrays of strings. -// -function flatten(obj, depth) { - var result = [], typ = (typeof obj)[0], prop; - if (depth && typ == 'o') { - for (prop in obj) { - try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} - } - } - return (result.length ? result : typ == 's' ? obj : obj + '\0'); -} - -// -// mixkey() -// Mixes a string seed into a key that is an array of integers, and -// returns a shortened string seed that is equivalent to the result key. -// -function mixkey(seed, key) { - var stringseed = seed + '', smear, j = 0; - while (j < stringseed.length) { - key[mask & j] = - mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); - } - return tostring(key); -} - -// -// autoseed() -// Returns an object for autoseeding, using window.crypto if available. -// -/** @param {Uint8Array=} seed */ -function autoseed(seed) { - try { - GLOBAL.crypto.getRandomValues(seed = new Uint8Array(width)); - return tostring(seed); - } catch (e) { - return [+new Date, GLOBAL, GLOBAL.navigator && GLOBAL.navigator.plugins, - GLOBAL.screen, tostring(pool)]; - } -} - -// -// tostring() -// Converts an array of charcodes to a string -// -function tostring(a) { - return String.fromCharCode.apply(0, a); -} - -// -// When seedrandom.js is loaded, we immediately mix a few bits -// from the built-in RNG into the entropy pool. Because we do -// not want to intefere with determinstic PRNG state later, -// seedrandom will not call Math.random on its own again after -// initialization. -// -mixkey(Math.random(), pool); -}); -var seedRandom_1 = seedRandom.resetGlobal; - -// create a random seed here to prevent an infinite loop from seed-random -// inside the factory. Reason is that math.random is defined as a getter/setter -// and seed-random generates a seed from the local entropy by reading every -// defined object including `math` itself. That means that whilst getting -// math.random, it tries to get math.random, etc... an infinite loop. -// See https://github.com/ForbesLindesay/seed-random/issues/6 -var singletonRandom = seedRandom(); - -function factory$220 (type, config, load, typed, math) { - var random; - - // create a new random generator with given seed - function setSeed (seed) { - random = seed === null ? singletonRandom : seedRandom(String(seed)); - } - - // initialize a seeded pseudo random number generator with config's random seed - setSeed(config.randomSeed); - - // wrapper function so the rng can be updated via generator - function rng() { - return random(); - } - - // updates generator with a new instance of a seeded pseudo random number generator - math.on('config', function (curr, prev, changes) { - // if the user specified a randomSeed - if(changes.randomSeed !== undefined) { - // update generator with a new instance of a seeded pseudo random number generator - setSeed(curr.randomSeed); - } - }); + var complex$5 = [ + arg$1, + conj$1, + im$1, + re$1 + ]; - return rng; -} + function factory$191 (type, config, load, typed) { -var factory_1$219 = factory$220; -var math$17 = true; + var abs = load(abs$1); + var add$$1 = load(add); + var addScalar$$1 = load(addScalar); + var matrix$$1 = load(matrix); + var multiply = load(multiply$1); + var multiplyScalar$$1 = load(multiplyScalar); + var divideScalar$$1 = load(divideScalar); + var subtract = load(subtract$1); + var smaller$$1 = load(smaller); + var equalScalar$$1 = load(equalScalar); -var seededRNG = { - factory: factory_1$219, - math: math$17 -}; + /** + * Calculates the point of intersection of two lines in two or three dimensions + * and of a line and a plane in three dimensions. The inputs are in the form of + * arrays or 1 dimensional matrices. The line intersection functions return null + * if the lines do not meet. + * + * Note: Fill the plane coefficients as `x + y + z = c` and not as `x + y + z + c = 0`. + * + * Syntax: + * + * math.intersect(endPoint1Line1, endPoint2Line1, endPoint1Line2, endPoint2Line2) + * math.intersect(endPoint1, endPoint2, planeCoefficients) + * + * Examples: + * + * math.intersect([0, 0], [10, 10], [10, 0], [0, 10]); // Returns [5, 5] + * math.intersect([0, 0, 0], [10, 10, 0], [10, 0, 0], [0, 10, 0]); // Returns [5, 5, 0] + * math.intersect([1, 0, 1], [4, -2, 2], [1, 1, 1, 6]); // Returns [7, -4, 3] + * + * @param {Array | Matrix} w Co-ordinates of first end-point of first line + * @param {Array | Matrix} x Co-ordinates of second end-point of first line + * @param {Array | Matrix} y Co-ordinates of first end-point of second line + * OR Co-efficients of the plane's equation + * @param {Array | Matrix} z Co-ordinates of second end-point of second line + * OR null if the calculation is for line and plane + * @return {Array} Returns the point of intersection of lines/lines-planes + */ + var intersect = typed('intersect', { + 'Array, Array, Array': function (x, y, plane) { + if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } + if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } + if (!_4d(plane)) { throw new TypeError('Array with 4 numbers expected as third argument'); } -var isNumber$3 = number.isNumber; + return _intersectLinePlane(x[0], x[1], x[2], y[0], y[1], y[2], plane[0], plane[1], plane[2], plane[3]); + }, -// TODO: rethink math.distribution -// TODO: rework to a typed function -function factory$221 (type, config, load, typed, math) { - var matrix$$1 = load(matrix); - var array$$1 = array; + 'Array, Array, Array, Array': function (w, x, y, z) { + if (w.length === 2) { + if (!_2d(w)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } + if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } + if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for third argument'); } + if (!_2d(z)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for fourth argument'); } - // seeded pseudo random number generator - var rng = load(seededRNG); + return _intersect2d(w, x, y, z); + } + else if (w.length === 3) { + if (!_3d(w)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } + if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } + if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for third argument'); } + if (!_3d(z)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for fourth argument'); } - /** - * Create a distribution object with a set of random functions for given - * random distribution. - * - * Syntax: - * - * math.distribution(name) - * - * Examples: - * - * var normalDist = math.distribution('normal'); // create a normal distribution - * normalDist.random(0, 10); // get a random value between 0 and 10 - * - * See also: - * - * random, randomInt, pickRandom - * - * @param {string} name Name of a distribution. Choose from 'uniform', 'normal'. - * @return {Object} Returns a distribution object containing functions: - * `random([size] [, min] [, max])`, - * `randomInt([min] [, max])`, - * `pickRandom(array)` - */ - function distribution(name) { - if (!distributions.hasOwnProperty(name)) - throw new Error('Unknown distribution ' + name); + return _intersect3d(w[0], w[1], w[2], x[0], x[1], x[2], y[0], y[1], y[2], z[0], z[1], z[2]); + } + else { + throw new TypeError('Arrays with two or thee dimensional points expected'); + } + }, - var args = Array.prototype.slice.call(arguments, 1), - distribution = distributions[name].apply(this, args); + 'Matrix, Matrix, Matrix': function (x, y, plane) { + return matrix$$1(intersect(x.valueOf(), y.valueOf(), plane.valueOf())); + }, - return (function(distribution) { + 'Matrix, Matrix, Matrix, Matrix': function (w, x, y, z) { + // TODO: output matrix type should match input matrix type + return matrix$$1(intersect(w.valueOf(), x.valueOf(), y.valueOf(), z.valueOf())); + } + }); - // This is the public API for all distributions - var randFunctions = { + function _isNumber(a) { + // intersect supports numbers and bignumbers + return (typeof a === 'number' || type.isBigNumber(a)); + } - random: function(arg1, arg2, arg3) { - var size, min, max; + function _2d(x) { + return x.length === 2 && _isNumber(x[0]) && _isNumber(x[1]); + } - if (arguments.length > 3) { - throw new ArgumentsError_1('random', arguments.length, 0, 3); - } else if (arguments.length === 1) { - // `random(max)` or `random(size)` - if (isCollection(arg1)) { - size = arg1; - } else { - max = arg1; - } - } else if (arguments.length === 2) { - // `random(min, max)` or `random(size, max)` - if (isCollection(arg1)) { - size = arg1; - max = arg2; - } else { - min = arg1; - max = arg2; - } - } else { - // `random(size, min, max)` - size = arg1; - min = arg2; - max = arg3; - } + function _3d(x) { + return x.length === 3 && _isNumber(x[0]) && _isNumber(x[1]) && _isNumber(x[2]); + } - // TODO: validate type of size - if ((min !== undefined && !isNumber$3(min)) || (max !== undefined && !isNumber$3(max))) { - throw new TypeError('Invalid argument in function random'); - } + function _4d(x) { + return x.length === 4 && _isNumber(x[0]) && _isNumber(x[1]) && _isNumber(x[2]) && _isNumber(x[3]); + } - if (max === undefined) max = 1; - if (min === undefined) min = 0; - if (size !== undefined) { - var res = _randomDataForMatrix(size.valueOf(), min, max, _random); - return type.isMatrix(size) ? matrix$$1(res) : res; - } - return _random(min, max); - }, + function _intersect2d(p1a, p1b, p2a, p2b){ + var o1 = p1a; + var o2 = p2a; + var d1 = subtract(o1, p1b); + var d2 = subtract(o2, p2b); + var det = subtract(multiplyScalar$$1(d1[0], d2[1]), multiplyScalar$$1(d2[0], d1[1])); + if (smaller$$1(abs(det), config.epsilon)) { + return null; + } + var d20o11 = multiplyScalar$$1(d2[0], o1[1]); + var d21o10 = multiplyScalar$$1(d2[1], o1[0]); + var d20o21 = multiplyScalar$$1(d2[0], o2[1]); + var d21o20 = multiplyScalar$$1(d2[1], o2[0]); + var t = divideScalar$$1(addScalar$$1(subtract(subtract(d20o11, d21o10), d20o21), d21o20), det); + return add$$1(multiply(d1, t), o1); + } + + function _intersect3dHelper(a, b, c, d, e, f, g, h, i, j, k, l){ + // (a - b)*(c - d) + (e - f)*(g - h) + (i - j)*(k - l) + var add1 = multiplyScalar$$1(subtract(a, b), subtract(c, d)); + var add2 = multiplyScalar$$1(subtract(e, f), subtract(g, h)); + var add3 = multiplyScalar$$1(subtract(i, j), subtract(k, l)); + return addScalar$$1(addScalar$$1(add1, add2), add3); + } + + function _intersect3d(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4){ + var d1343 = _intersect3dHelper(x1, x3, x4, x3, y1, y3, y4, y3, z1, z3, z4, z3); + var d4321 = _intersect3dHelper(x4, x3, x2, x1, y4, y3, y2, y1, z4, z3, z2, z1); + var d1321 = _intersect3dHelper(x1, x3, x2, x1, y1, y3, y2, y1, z1, z3, z2, z1); + var d4343 = _intersect3dHelper(x4, x3, x4, x3, y4, y3, y4, y3, z4, z3, z4, z3); + var d2121 = _intersect3dHelper(x2, x1, x2, x1, y2, y1, y2, y1, z2, z1, z2, z1); + var ta = divideScalar$$1( + subtract(multiplyScalar$$1(d1343, d4321), multiplyScalar$$1(d1321, d4343)), + subtract(multiplyScalar$$1(d2121, d4343), multiplyScalar$$1(d4321, d4321))); + var tb = divideScalar$$1(addScalar$$1(d1343, multiplyScalar$$1(ta, d4321)), d4343); + + var pax = addScalar$$1(x1, multiplyScalar$$1(ta, subtract(x2, x1))); + var pay = addScalar$$1(y1, multiplyScalar$$1(ta, subtract(y2, y1))); + var paz = addScalar$$1(z1, multiplyScalar$$1(ta, subtract(z2, z1))); + var pbx = addScalar$$1(x3, multiplyScalar$$1(tb, subtract(x4, x3))); + var pby = addScalar$$1(y3, multiplyScalar$$1(tb, subtract(y4, y3))); + var pbz = addScalar$$1(z3, multiplyScalar$$1(tb, subtract(z4, z3))); + if (equalScalar$$1(pax, pbx) && equalScalar$$1(pay, pby) && equalScalar$$1(paz, pbz)){ + return [pax, pay, paz]; + } + else{ + return null; + } + } - randomInt: typed({ - 'number | Array': function(arg) { - var min = 0; + function _intersectLinePlane(x1, y1, z1, x2, y2, z2, x, y, z, c){ + var x1x = multiplyScalar$$1(x1, x); + var x2x = multiplyScalar$$1(x2, x); + var y1y = multiplyScalar$$1(y1, y); + var y2y = multiplyScalar$$1(y2, y); + var z1z = multiplyScalar$$1(z1, z); + var z2z = multiplyScalar$$1(z2, z); + var t = divideScalar$$1( + subtract(subtract(subtract(c, x1x), y1y), z1z), + subtract(subtract(subtract(addScalar$$1(addScalar$$1(x2x, y2y), z2z), x1x), y1y), z1z)); + var px = addScalar$$1(x1, multiplyScalar$$1(t, subtract(x2, x1))); + var py = addScalar$$1(y1, multiplyScalar$$1(t, subtract(y2, y1))); + var pz = addScalar$$1(z1, multiplyScalar$$1(t, subtract(z2, z1))); + return [px, py, pz]; + // TODO: Add cases when line is parallel to the plane: + // (a) no intersection, + // (b) line contained in plane + } - if (isCollection(arg)) { - var size = arg; - var max = 1; - var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); - return type.isMatrix(size) ? matrix$$1(res) : res; - } else { - var max = arg; - return _randomInt(min, max); - } - }, - 'number | Array, number': function(arg1, arg2) { - if (isCollection(arg1)) { - var size = arg1; - var max = arg2; - var min = 0; - var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); - return type.isMatrix(size) ? matrix$$1(res) : res; - } - else { - var min = arg1; - var max = arg2; - return _randomInt(min, max); - } - }, - 'Array, number, number': function(size, min, max) { - var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); - return (size && size.isMatrix === true) ? matrix$$1(res) : res; - } - }), + return intersect; + } - pickRandom: typed({ - 'Array': function(possibles) { - return _pickRandom(possibles); - }, - 'Array, number | Array': function(possibles, arg2) { - var number$$1, weights; + var name$179 = 'intersect'; + var factory_1$190 = factory$191; - if (Array.isArray(arg2)) { - weights = arg2; - } else if (isNumber$3(arg2)) { - number$$1 = arg2; - } else { - throw new TypeError('Invalid argument in function pickRandom') - } + var intersect$1 = { + name: name$179, + factory: factory_1$190 + }; - return _pickRandom(possibles, number$$1, weights); - }, - 'Array, number | Array, Array | number': function(possibles, arg2, arg3) { - var number$$1, weights; + function factory$192 (type, config, load, typed) { + var matrix$$1 = load(matrix); + var add = load(addScalar); + var subtract = load(subtract$1); + var multiply = load(multiplyScalar); + var divide = load(divideScalar); + var negate = load(unaryMinus$1); + var sqrt = load(sqrt$1); + var abs = load(abs$1); - if (Array.isArray(arg2)) { - weights = arg2; - number$$1 = arg3; - } else { - weights = arg3; - number$$1 = arg2; - } + /** + * Calculates: + * The eucledian distance between two points in 2 and 3 dimensional spaces. + * Distance between point and a line in 2 and 3 dimensional spaces. + * Pairwise distance between a set of 2D or 3D points + * NOTE: + * When substituting coefficients of a line(a, b and c), use ax + by + c = 0 instead of ax + by = c + * For parametric equation of a 3D line, x0, y0, z0, a, b, c are from: (x−x0, y−y0, z−z0) = t(a, b, c) + * + * Syntax: + * math.distance([x1, y1], [x2, y2]) + *- math.distance({pointOneX: 4, pointOneY: 5}, {pointTwoX: 2, pointTwoY: 7}) + * math.distance([x1, y1, z1], [x2, y2, z2]) + * math.distance({pointOneX: 4, pointOneY: 5, pointOneZ: 8}, {pointTwoX: 2, pointTwoY: 7, pointTwoZ: 9}) + * math.distance([[A], [B], [C]...]) + * math.distance([x1, y1], [LinePtX1, LinePtY1], [LinePtX2, LinePtY2]) + * math.distance({pointX: 1, pointY: 4}, {lineOnePtX: 6, lineOnePtY: 3}, {lineTwoPtX: 2, lineTwoPtY: 8}) + * math.distance([x1, y1, z1], [LinePtX1, LinePtY1, LinePtZ1], [LinePtX2, LinePtY2, LinePtZ2]) + * math.distance({pointX: 1, pointY: 4, pointZ: 7}, {lineOnePtX: 6, lineOnePtY: 3, lineOnePtZ: 4}, {lineTwoPtX: 2, lineTwoPtY: 8, lineTwoPtZ: 5}) + * math.distance([x1, y1], [xCoeffLine, yCoeffLine, constant]) + * math.distance({pointX: 10, pointY: 10}, {xCoeffLine: 8, yCoeffLine: 1, constant: 3}) + * math.distance([x1, y1, z1], [x0, y0, z0, a-tCoeff, b-tCoeff, c-tCoeff]) point and parametric equation of 3D line + * math.distance([x, y, z], [x0, y0, z0, a, b, c]) + * math.distance({pointX: 2, pointY: 5, pointZ: 9}, {x0: 4, y0: 6, z0: 3, a: 4, b: 2, c: 0}) + * + * Examples: + * math.distance([0,0], [4,4]) // Returns 5.6569 + * math.distance( + * {pointOneX: 0, pointOneY: 0}, + * {pointTwoX: 10, pointTwoY: 10}) // Returns 14.142135623730951 + * math.distance([1, 0, 1], [4, -2, 2]) // Returns 3.74166 + * math.distance( + * {pointOneX: 4, pointOneY: 5, pointOneZ: 8}, + * {pointTwoX: 2, pointTwoY: 7, pointTwoZ: 9}) // Returns 3 + * math.distance([[1, 2], [1, 2], [1, 3]]) // Returns [0, 1, 1] + * math.distance([[1,2,4], [1,2,6], [8,1,3]]) // Returns [2, 7.14142842854285, 7.681145747868608] + * math.distance([10, 10], [8, 1, 3]) // Returns 11.535230316796387 + * math.distance([10, 10], [2, 3], [-8, 0]) // Returns 8.759953130362847 + * math.distance( + * {pointX: 1, pointY: 4}, + * {lineOnePtX: 6, lineOnePtY: 3}, + * {lineTwoPtX: 2, lineTwoPtY: 8}) // Returns 2.720549372624744 + * math.distance([2, 3, 1], [1, 1, 2, 5, 0, 1]) // Returns 2.3204774044612857 + * math.distance( + * {pointX: 2, pointY: 3, pointZ: 1}, + * {x0: 1, y0: 1, z0: 2, a: 5, b: 0, c: 1} // Returns 2.3204774044612857 + * + * @param {Array | Matrix | Object} x Co-ordinates of first point + * @param {Array | Matrix | Object} y Co-ordinates of second point + * @return {Number | BigNumber} Returns the distance from two/three points + */ - if (!Array.isArray(weights) || !isNumber$3(number$$1)) { - throw new TypeError('Invalid argument in function pickRandom'); - } + var distance = typed('distance', { + 'Array, Array, Array': function(x, y, z){ + // Point to Line 2D; (x=Point, y=LinePoint1, z=LinePoint2) + if (x.length == 2 && y.length == 2 && z.length == 2){ + if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } + if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } + if (!_2d(z)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for third argument'); } + var m = divide(subtract(z[1], z[0]), subtract(y[1], y[0])); + var xCoeff = multiply(multiply(m, m), y[0]); + var yCoeff = negate(multiply(m, y[0])); + var constant = x[1]; - return _pickRandom(possibles, number$$1, weights); + return _distancePointLine2D(x[0], x[1], xCoeff, yCoeff, constant); + } + else{ + throw new TypeError('Invalid Arguments: Try again'); + } + }, + 'Object, Object, Object': function(x, y, z){ + if (Object.keys(x).length == 2 && Object.keys(y).length == 2 && Object.keys(z).length == 2){ + if (!_2d(x)) { throw new TypeError('Values of pointX and pointY should be numbers or BigNumbers'); } + if (!_2d(y)) { throw new TypeError('Values of lineOnePtX and lineOnePtY should be numbers or BigNumbers'); } + if (!_2d(z)) { throw new TypeError('Values of lineTwoPtX and lineTwoPtY should be numbers or BigNumbers'); } + if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('lineOnePtX') && + y.hasOwnProperty('lineOnePtY') && z.hasOwnProperty('lineTwoPtX') && z.hasOwnProperty('lineTwoPtY')){ + var m = divide(subtract(z.lineTwoPtY, z.lineTwoPtX), subtract(y.lineOnePtY, y.lineOnePtX)); + var xCoeff = multiply(multiply(m, m), y.lineOnePtX); + var yCoeff = negate(multiply(m, y.lineOnePtX)); + var constant = x.pointX; + + return _distancePointLine2D(x.pointX, x.pointY, xCoeff, yCoeff, constant); } - }) - }; - - var _pickRandom = function(possibles, number$$1, weights) { - var single = (typeof number$$1 === 'undefined'); + else{ + throw new TypeError('Key names do not match'); + } + } + else{ + throw new TypeError('Invalid Arguments: Try again'); + } + }, + 'Array, Array': function(x, y){ + // Point to Line 2D; (x=[pointX, pointY], y=[x-coeff, y-coeff, const]) + if (x.length == 2 && y.length == 3){ + if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } + if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - if (single) { - number$$1 = 1; + return _distancePointLine2D(x[0], x[1], y[0], y[1], y[2]); } + // Point to Line 3D + else if (x.length == 3 && y.length == 6){ + if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } + if (!_parametricLine(y)) { throw new TypeError('Array with 6 numbers or BigNumbers expected for second argument'); } - if (type.isMatrix(possibles)) { - possibles = possibles.valueOf(); // get Array - } else if (!Array.isArray(possibles)) { - throw new TypeError('Unsupported type of value in function pickRandom'); + return _distancePointLine3D(x[0], x[1], x[2], y[0], y[1], y[2], y[3], y[4], y[5]); } + // Point to Point 2D + else if (x.length == 2 && y.length == 2){ + if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } + if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } - if (array$$1.size(possibles).length > 1) { - throw new Error('Only one dimensional vectors supported'); + return _distance2d(x[0], x[1], y[0], y[1]); } + // Point to Point 3D + else if(x.length == 3 && y.length == 3){ + if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } + if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - if (typeof weights !== 'undefined') { - if (weights.length != possibles.length) { - throw new Error('Weights must have the same length as possibles'); + return _distance3d(x[0], x[1], x[2], y[0], y[1], y[2]); + } + else{ + throw new TypeError('Invalid Arguments: Try again'); + } + }, + 'Object, Object': function(x, y){ + if (Object.keys(x).length == 2 && Object.keys(y).length == 3){ + if (!_2d(x)) { throw new TypeError('Values of pointX and pointY should be numbers or BigNumbers'); } + if (!_3d(y)) { throw new TypeError('Values of xCoeffLine, yCoeffLine and constant should be numbers or BigNumbers'); } + if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('xCoeffLine') && + y.hasOwnProperty('yCoeffLine') && y.hasOwnProperty('constant')){ + + return _distancePointLine2D(x.pointX, x.pointY, y.xCoeffLine, y.yCoeffLine, y.constant); } - - var totalWeights = 0; - - for (var i = 0, len = weights.length; i < len; i++) { - if (!isNumber$3(weights[i]) || weights[i] < 0) { - throw new Error('Weights must be an array of positive numbers'); - } - - totalWeights += weights[i]; + else{ + throw new TypeError('Key names do not match'); } } + // Point to Line 3D + else if (Object.keys(x).length == 3 && Object.keys(y).length == 6){ + if (!_3d(x)) { throw new TypeError('Values of pointX, pointY and pointZ should be numbers or BigNumbers'); } + if (!_parametricLine(y)) { throw new TypeError('Values of x0, y0, z0, a, b and c should be numbers or BigNumbers'); } + if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('x0') && + y.hasOwnProperty('y0') && y.hasOwnProperty('z0') && y.hasOwnProperty('a') && + y.hasOwnProperty('b') && y.hasOwnProperty('c')){ - var length = possibles.length; - - if (length == 0) { - return []; - } else if (number$$1 >= length) { - return number$$1 > 1 ? possibles : possibles[0]; + return _distancePointLine3D(x.pointX, x.pointY, x.pointZ, y.x0, y.y0, y.z0, y.a, y.b, y.c); + } + else{ + throw new TypeError('Key names do not match'); + } } + // Point to Point 2D + else if (Object.keys(x).length == 2 && Object.keys(y).length == 2){ + if (!_2d(x)) { throw new TypeError('Values of pointOneX and pointOneY should be numbers or BigNumbers'); } + if (!_2d(y)) { throw new TypeError('Values of pointTwoX and pointTwoY should be numbers or BigNumbers'); } + if (x.hasOwnProperty('pointOneX') && x.hasOwnProperty('pointOneY') && + y.hasOwnProperty('pointTwoX') && y.hasOwnProperty('pointTwoY')){ - var result = []; - var pick; - - while (result.length < number$$1) { - if (typeof weights === 'undefined') { - pick = possibles[Math.floor(rng() * length)]; - } else { - var randKey = rng() * totalWeights; - - for (var i = 0, len = possibles.length; i < len; i++) { - randKey -= weights[i]; - - if (randKey < 0) { - pick = possibles[i]; - break; - } - } + return _distance2d(x.pointOneX, x.pointOneY, y.pointTwoX, y.pointTwoY); } + else{ + throw new TypeError('Key names do not match'); + } + } + // Point to Point 3D + else if(Object.keys(x).length == 3 && Object.keys(y).length == 3){ + if (!_3d(x)) { throw new TypeError('Values of pointOneX, pointOneY and pointOneZ should be numbers or BigNumbers'); } + if (!_3d(y)) { throw new TypeError('Values of pointTwoX, pointTwoY and pointTwoZ should be numbers or BigNumbers'); } + if (x.hasOwnProperty('pointOneX') && x.hasOwnProperty('pointOneY') && x.hasOwnProperty('pointOneZ') && + y.hasOwnProperty('pointTwoX') && y.hasOwnProperty('pointTwoY') && y.hasOwnProperty('pointTwoZ')){ - if (result.indexOf(pick) == -1) { - result.push(pick); + return _distance3d(x.pointOneX, x.pointOneY, x.pointOneZ, y.pointTwoX, y.pointTwoY, y.pointTwoZ); + } + else { + throw new TypeError('Key names do not match'); } } + else{ + throw new TypeError('Invalid Arguments: Try again'); + } + }, + 'Array': function(arr){ + if (!_pairwise(arr)) { throw new TypeError('Incorrect array format entered for pairwise distance calculation'); } + + return _distancePairwise(arr); + } + }); - return single ? result[0] : result; + function _isNumber(a) { + // distance supports numbers and bignumbers + return (typeof a === 'number' || type.isBigNumber(a)); + } - // TODO: add support for multi dimensional matrices - }; + function _2d(a){ + // checks if the number of arguments are correct in count and are valid (should be numbers) + if (a.constructor !== Array){ + a = _objectToArray(a); + } + return _isNumber(a[0]) && _isNumber(a[1]); + } - var _random = function(min, max) { - return min + distribution() * (max - min); - }; + function _3d(a){ + // checks if the number of arguments are correct in count and are valid (should be numbers) + if (a.constructor !== Array){ + a = _objectToArray(a); + } + return _isNumber(a[0]) && _isNumber(a[1]) && _isNumber(a[2]); + } - var _randomInt = function(min, max) { - return Math.floor(min + distribution() * (max - min)); - }; + function _parametricLine(a){ + if (a.constructor !== Array){ + a = _objectToArray(a); + } + return _isNumber(a[0]) && _isNumber(a[1]) && _isNumber(a[2]) && + _isNumber(a[3]) && _isNumber(a[4]) && _isNumber(a[5]); + } - // This is a function for generating a random matrix recursively. - var _randomDataForMatrix = function(size, min, max, randFunc) { - var data = [], length, i; - size = size.slice(0); + function _objectToArray(o){ + var keys = Object.keys(o); + var a = []; + for (var i = 0; i < keys.length; i++) { + a.push(o[keys[i]]); + } + return a; + } - if (size.length > 1) { - for (var i = 0, length = size.shift(); i < length; i++) { - data.push(_randomDataForMatrix(size, min, max, randFunc)); + function _pairwise(a){ + //checks for valid arguments passed to _distancePairwise(Array) + if (a[0].length == 2 && _isNumber(a[0][0]) && _isNumber(a[0][1])){ + for(var i in a){ + if (a[i].length != 2 || !_isNumber(a[i][0]) || !_isNumber(a[i][1])){ + return false; } - } else { - for (var i = 0, length = size.shift(); i < length; i++) { - data.push(randFunc(min, max)); + } + } + else if (a[0].length == 3 && _isNumber(a[0][0]) && _isNumber(a[0][1]) && _isNumber(a[0][2])){ + for(var i in a){ + if (a[i].length != 3 || !_isNumber(a[i][0]) || !_isNumber(a[i][1]) || !_isNumber(a[i][2])){ + return false; } } + } + else{ + return false; + } + return true; + } - return data; - }; - - return randFunctions; + function _distancePointLine2D(x, y, a, b, c){ + var num = abs(add(add(multiply(a, x), multiply(b, y)), c)); + var den = sqrt(add(multiply(a, a), multiply(b, b))); + var result = divide(num, den); + return result; + } - })(distribution); - } + function _distancePointLine3D(x, y, z, x0, y0, z0, a, b, c){ + var num = [ subtract(multiply(subtract(y0, y), c), multiply(subtract(z0, z), b)), + subtract(multiply(subtract(z0, z), a), multiply(subtract(x0, x), c)), + subtract(multiply(subtract(x0, x), b), multiply(subtract(y0, y), a)) ]; + num = sqrt(add(add(multiply(num[0], num[0]), multiply(num[1], num[1])), multiply(num[2], num[2]))); + var den = sqrt(add(add(multiply(a, a), multiply(b, b)), multiply(c, c))); + var result = divide(num, den); + return result; + } - // Each distribution is a function that takes no argument and when called returns - // a number between 0 and 1. - var distributions = { + function _distance2d(x1, y1, x2, y2){ + var yDiff = subtract(y2, y1); + var xDiff = subtract(x2, x1); + var radicant = add(multiply(yDiff, yDiff), multiply(xDiff, xDiff)); + var result = sqrt(radicant); + return result; + } - uniform: function() { - return rng; - }, + function _distance3d(x1, y1, z1, x2, y2, z2){ + var zDiff = subtract(z2, z1); + var yDiff = subtract(y2, y1); + var xDiff = subtract(x2, x1); + var radicant = add(add(multiply(zDiff, zDiff), multiply(yDiff, yDiff)), multiply(xDiff, xDiff)); + var result = sqrt(radicant); + return result; + } - // Implementation of normal distribution using Box-Muller transform - // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform - // We take : mean = 0.5, standard deviation = 1/6 - // so that 99.7% values are in [0, 1]. - normal: function() { - return function() { - var u1, u2, - picked = -1; - // We reject values outside of the interval [0, 1] - // TODO: check if it is ok to do that? - while (picked < 0 || picked > 1) { - u1 = rng(); - u2 = rng(); - picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; + function _distancePairwise(a){ + var result = []; + for(var i = 0; i < a.length-1; i++){ + for(var j = i+1; j < a.length; j++){ + if (a[0].length == 2){ + result.push(_distance2d(a[i][0], a[i][1], a[j][0], a[j][1])); + } + else if (a[0].length == 3){ + result.push(_distance3d(a[i][0], a[i][1], a[i][2], a[j][0], a[j][1], a[j][2])); + } } - return picked; } + return result; } - }; - distribution.toTex = undefined; // use default template + return distance; + } - return distribution; -} + var name$180 = 'distance'; + var factory_1$191 = factory$192; -var name$208 = 'distribution'; -var factory_1$220 = factory$221; + var distance$1 = { + name: name$180, + factory: factory_1$191 + }; -var distribution = { - name: name$208, - factory: factory_1$220 -}; + var geometry = [ + intersect$1, + distance$1 + ]; -function factory$222 (type, config, load, typed) { - var distribution$$1 = load(distribution); + function factory$193 (type, config, load, typed) { + var latex$$1 = latex; - /** - * Random pick one or more values from a one dimensional array. - * Array elements are picked using a random function with uniform or weighted distribution. - * - * Syntax: - * - * math.pickRandom(array) - * math.pickRandom(array, number) - * math.pickRandom(array, weights) - * math.pickRandom(array, number, weights) - * math.pickRandom(array, weights, number) - * - * Examples: - * - * math.pickRandom([3, 6, 12, 2]); // returns one of the values in the array - * math.pickRandom([3, 6, 12, 2], 2); // returns an array of two of the values in the array - * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1]); // returns one of the values in the array with weighted distribution - * math.pickRandom([3, 6, 12, 2], 2, [1, 3, 2, 1]); // returns an array of two of the values in the array with weighted distribution - * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1], 2); // returns an array of two of the values in the array with weighted distribution - * - * See also: - * - * random, randomInt - * - * @param {Array} array A one dimensional array - * @param {Int} number An int or float - * @param {Array} weights An array of ints or floats - * @return {number | Array} Returns a single random value from array when number is 1 or undefined. - * Returns an array with the configured number of elements when number is > 1. - */ - // TODO: rework pickRandom to a typed-function - var pickRandom = distribution$$1('uniform').pickRandom; - - pickRandom.toTex = undefined; // use default template - - return pickRandom; -} - -var name$209 = 'pickRandom'; -var factory_1$221 = factory$222; - -var pickRandom$1 = { - name: name$209, - factory: factory_1$221 -}; - -function factory$223 (type, config, load, typed) { - var distribution$$1 = load(distribution); - - /** - * Return a random number larger or equal to `min` and smaller than `max` - * using a uniform distribution. - * - * Syntax: - * - * math.random() // generate a random number between 0 and 1 - * math.random(max) // generate a random number between 0 and max - * math.random(min, max) // generate a random number between min and max - * math.random(size) // generate a matrix with random numbers between 0 and 1 - * math.random(size, max) // generate a matrix with random numbers between 0 and max - * math.random(size, min, max) // generate a matrix with random numbers between min and max - * - * Examples: - * - * math.random(); // returns a random number between 0 and 1 - * math.random(100); // returns a random number between 0 and 100 - * math.random(30, 40); // returns a random number between 30 and 40 - * math.random([2, 3]); // returns a 2x3 matrix with random numbers between 0 and 1 - * - * See also: - * - * randomInt, pickRandom - * - * @param {Array | Matrix} [size] If provided, an array or matrix with given - * size and filled with random values is returned - * @param {number} [min] Minimum boundary for the random value, included - * @param {number} [max] Maximum boundary for the random value, excluded - * @return {number | Array | Matrix} A random number - */ - // TODO: rework random to a typed-function - var random = distribution$$1('uniform').random; - - random.toTex = undefined; // use default template - - return random; -} + /** + * Logical `not`. Flips boolean value of a given parameter. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.not(x) + * + * Examples: + * + * math.not(2); // returns false + * math.not(0); // returns true + * math.not(true); // returns false + * + * a = [2, -7, 0]; + * math.not(a); // returns [false, false, true] + * + * See also: + * + * and, or, xor + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check + * @return {boolean | Array | Matrix} + * Returns true when input is a zero or empty value. + */ + var not = typed('not', { + 'number': function (x) { + return !x; + }, -var name$210 = 'random'; -var factory_1$222 = factory$223; + 'Complex': function (x) { + return x.re === 0 && x.im === 0; + }, -var random$1 = { - name: name$210, - factory: factory_1$222 -}; + 'BigNumber': function (x) { + return x.isZero() || x.isNaN(); + }, -function factory$224 (type, config, load, typed) { - var distribution$$1 = load(distribution); + 'Unit': function (x) { + return x.value !== null ? not(x.value) : true; + }, - /** - * Return a random integer number larger or equal to `min` and smaller than `max` - * using a uniform distribution. - * - * Syntax: - * - * math.randomInt(max) // generate a random integer between 0 and max - * math.randomInt(min, max) // generate a random integer between min and max - * math.randomInt(size) // generate a matrix with random integer between 0 and 1 - * math.randomInt(size, max) // generate a matrix with random integer between 0 and max - * math.randomInt(size, min, max) // generate a matrix with random integer between min and max - * - * Examples: - * - * math.randomInt(100); // returns a random integer between 0 and 100 - * math.randomInt(30, 40); // returns a random integer between 30 and 40 - * math.randomInt([2, 3]); // returns a 2x3 matrix with random integers between 0 and 1 - * - * See also: - * - * random, pickRandom - * - * @param {Array | Matrix} [size] If provided, an array or matrix with given - * size and filled with random values is returned - * @param {number} [min] Minimum boundary for the random value, included - * @param {number} [max] Maximum boundary for the random value, excluded - * @return {number | Array | Matrix} A random integer value - */ - // TODO: rework randomInt to a typed-function - var randomInt = distribution$$1('uniform').randomInt; - - randomInt.toTex = undefined; // use default template - - return randomInt; -} - -var name$211 = 'randomInt'; -var factory_1$223 = factory$224; - -var randomInt$1 = { - name: name$211, - factory: factory_1$223 -}; - -var probability = [ - //require('./distribution'), // TODO: rethink math.distribution - combinations$1, - factorial$1, - gamma$1, - kldivergence$1, - multinomial$1, - permutations$1, - pickRandom$1, - random$1, - randomInt$1 -]; - -function factory$225 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var _typeof = load(_typeof$1); - - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Compare two strings lexically. Comparison is case sensitive. - * Returns 1 when x > y, -1 when x < y, and 0 when x == y. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.compareText(x, y) - * - * Examples: - * - * math.compareText('B', 'A'); // returns 1 - * math.compareText('2', '10'); // returns 1 - * math.compare('2', '10'); // returns -1 - * math.compareNatural('2', '10'); // returns -1 - * - * math.compareText('B', ['A', 'B', 'C']); // returns [1, 0, -1] - * - * See also: - * - * equal, equalText, compare, compareNatural - * - * @param {string | Array | DenseMatrix} x First string to compare - * @param {string | Array | DenseMatrix} y Second string to compare - * @return {number | Array | DenseMatrix} Returns the result of the comparison: - * 1 when x > y, -1 when x < y, and 0 when x == y. - */ - var compareText = typed('compareText', { + 'Array | Matrix': function (x) { + return deepMap(x, not); + } + }); - 'any, any': _compareText, + not.toTex = { + 1: latex$$1.operators['not'] + '\\left(${args[0]}\\right)' + }; - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, _compareText); - }, + return not; + } - 'Array, Array': function (x, y) { - // use matrix implementation - return compareText(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + var name$181 = 'not'; + var factory_1$192 = factory$193; - 'Array, Matrix': function (x, y) { - // use matrix implementation - return compareText(matrix$$1(x), y); - }, + var not$1 = { + name: name$181, + factory: factory_1$192 + }; - 'Matrix, Array': function (x, y) { - // use matrix implementation - return compareText(x, matrix$$1(y)); - }, + function factory$194 (type, config, load, typed) { + var latex$$1 = latex; - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, _compareText, false); - }, + var matrix$$1 = load(matrix); + var zeros = load(zeros$1); + var not = load(not$1); + var isZero = load(isZero$1); - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, _compareText, true); - }, + var algorithm02$$1 = load(algorithm02); + var algorithm06$$1 = load(algorithm06); + var algorithm11$$1 = load(algorithm11); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, _compareText, false).valueOf(); - }, + /** + * Logical `and`. Test whether two values are both defined with a nonzero/nonempty value. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.and(x, y) + * + * Examples: + * + * math.and(2, 4); // returns true + * + * a = [2, 0, 0]; + * b = [3, 7, 0]; + * c = 0; + * + * math.and(a, b); // returns [true, false, false] + * math.and(a, c); // returns [false, false, false] + * + * See also: + * + * not, or, xor + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check + * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check + * @return {boolean | Array | Matrix} + * Returns true when both inputs are defined with a nonzero/nonempty value. + */ + var and = typed('and', { - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, _compareText, true).valueOf(); - } - }); + 'number, number': function (x, y) { + return !!(x && y); + }, - /** - * Compare two strings - * @param {string} x - * @param {string} y - * @returns {number} - * @private - */ - function _compareText(x, y) { - // we don't want to convert numbers to string, only accept string input - if (!type.isString(x)) { - throw new TypeError('Unexpected type of argument in function compareText ' + - '(expected: string or Array or Matrix, actual: ' + _typeof(x) + ', index: 0)'); - } - if (!type.isString(y)) { - throw new TypeError('Unexpected type of argument in function compareText ' + - '(expected: string or Array or Matrix, actual: ' + _typeof(y) + ', index: 1)'); - } + 'Complex, Complex': function (x, y) { + return (x.re !== 0 || x.im !== 0) && (y.re !== 0 || y.im !== 0); + }, - return (x === y) - ? 0 - : (x > y ? 1 : -1); - } + 'BigNumber, BigNumber': function (x, y) { + return !x.isZero() && !y.isZero() && !x.isNaN() && !y.isNaN(); + }, - compareText.toTex = undefined; // use default template + 'Unit, Unit': function (x, y) { + return and(x.value || 0, y.value || 0); + }, - return compareText; -} + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm06$$1(x, y, and, false); + }, -var name$212 = 'compareText'; -var factory_1$224 = factory$225; + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm02$$1(y, x, and, true); + }, -var compareText$1 = { - name: name$212, - factory: factory_1$224 -}; + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm02$$1(x, y, and, false); + }, -function factory$226 (type, config, load, typed) { - var equal = load(equal$1); + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, and); + }, - /** - * Test element wise whether two matrices are equal. - * The function accepts both matrices and scalar values. - * - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.deepEqual(x, y) - * - * Examples: - * - * math.deepEqual(2, 4); // returns false - * - * a = [2, 5, 1]; - * b = [2, 7, 1]; - * - * math.deepEqual(a, b); // returns false - * math.equal(a, b); // returns [true, false, true] - * - * See also: - * - * equal, unequal - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First matrix to compare - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second matrix to compare - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} - * Returns true when the input matrices have the same size and each of their elements is equal. - */ - var deepEqual = typed('deepEqual', { - 'any, any': function (x, y) { - return _deepEqual(x.valueOf(), y.valueOf()); - } - }); + 'Array, Array': function (x, y) { + // use matrix implementation + return and(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - deepEqual.toTex = undefined; // use default template + 'Array, Matrix': function (x, y) { + // use matrix implementation + return and(matrix$$1(x), y); + }, - return deepEqual; + 'Matrix, Array': function (x, y) { + // use matrix implementation + return and(x, matrix$$1(y)); + }, - /** - * Test whether two arrays have the same size and all elements are equal - * @param {Array | *} x - * @param {Array | *} y - * @return {boolean} Returns true if both arrays are deep equal - */ - function _deepEqual(x, y) { - if (Array.isArray(x)) { - if (Array.isArray(y)) { - var len = x.length; - if (len !== y.length) { - return false; + 'SparseMatrix, any': function (x, y) { + // check scalar + if (not(y)) { + // return zero matrix + return zeros(x.size(), x.storage()); } + return algorithm11$$1(x, y, and, false); + }, - for (var i = 0; i < len; i++) { - if (!_deepEqual(x[i], y[i])) { - return false; - } + 'DenseMatrix, any': function (x, y) { + // check scalar + if (not(y)) { + // return zero matrix + return zeros(x.size(), x.storage()); } + return algorithm14$$1(x, y, and, false); + }, - return true; - } - else { - return false; - } - } - else { - if (Array.isArray(y)) { - return false; - } - else { - return equal(x, y); - } - } - } -} - -var name$213 = 'deepEqual'; -var factory_1$225 = factory$226; - -var deepEqual$2 = { - name: name$213, - factory: factory_1$225 -}; - -function factory$227 (type, config, load, typed) { - var compareText = load(compareText$1); - var isZero = load(isZero$1); + 'any, SparseMatrix': function (x, y) { + // check scalar + if (not(x)) { + // return zero matrix + return zeros(x.size(), x.storage()); + } + return algorithm11$$1(y, x, and, true); + }, - /** - * Check equality of two strings. Comparison is case sensitive. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.equalText(x, y) - * - * Examples: - * - * math.equalText('Hello', 'Hello'); // returns true - * math.equalText('a', 'A'); // returns false - * math.equal('2e3', '2000'); // returns true - * math.equalText('2e3', '2000'); // returns false - * - * math.equalText('B', ['A', 'B', 'C']); // returns [false, true, false] - * - * See also: - * - * equal, compareText, compare, compareNatural - * - * @param {string | Array | DenseMatrix} x First string to compare - * @param {string | Array | DenseMatrix} y Second string to compare - * @return {number | Array | DenseMatrix} Returns true if the values are equal, and false if not. - */ - var equalText = typed('equalText', { + 'any, DenseMatrix': function (x, y) { + // check scalar + if (not(x)) { + // return zero matrix + return zeros(x.size(), x.storage()); + } + return algorithm14$$1(y, x, and, true); + }, - 'any, any': function (x, y) { - return isZero(compareText(x, y)); - } + 'Array, any': function (x, y) { + // use matrix implementation + return and(matrix$$1(x), y).valueOf(); + }, - }); + 'any, Array': function (x, y) { + // use matrix implementation + return and(x, matrix$$1(y)).valueOf(); + } + }); - equalText.toTex = undefined; // use default template + and.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['and'] + '${args[1]}\\right)' + }; - return equalText; -} + return and; + } -var name$214 = 'equalText'; -var factory_1$226 = factory$227; + var name$182 = 'and'; + var factory_1$193 = factory$194; -var equalText$1 = { - name: name$214, - factory: factory_1$226 -}; + var and$1 = { + name: name$182, + factory: factory_1$193 + }; -var nearlyEqual$7 = number.nearlyEqual; + function factory$195 (type, config, load, typed) { + var latex$$1 = latex; + var matrix$$1 = load(matrix); -function factory$228 (type, config, load, typed) { + var algorithm03$$1 = load(algorithm03); + var algorithm05$$1 = load(algorithm05); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + /** + * Logical `or`. Test if at least one value is defined with a nonzero/nonempty value. + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.or(x, y) + * + * Examples: + * + * math.or(2, 4); // returns true + * + * a = [2, 5, 0]; + * b = [0, 22, 0]; + * c = 0; + * + * math.or(a, b); // returns [true, true, false] + * math.or(b, c); // returns [false, true, false] + * + * See also: + * + * and, not, xor + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check + * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check + * @return {boolean | Array | Matrix} + * Returns true when one of the inputs is defined with a nonzero/nonempty value. + */ + var or = typed('or', { - var matrix$$1 = load(matrix); + 'number, number': function (x, y) { + return !!(x || y); + }, - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + 'Complex, Complex': function (x, y) { + return (x.re !== 0 || x.im !== 0) || (y.re !== 0 || y.im !== 0); + }, - var latex$$1 = latex; + 'BigNumber, BigNumber': function (x, y) { + return (!x.isZero() && !x.isNaN()) || (!y.isZero() && !y.isNaN()); + }, - /** - * Test whether value x is smaller or equal to y. - * - * The function returns true when x is smaller than y or the relative - * difference between x and y is smaller than the configured epsilon. The - * function cannot be used to compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.smallerEq(x, y) - * - * Examples: - * - * math.smaller(1 + 2, 3); // returns false - * math.smallerEq(1 + 2, 3); // returns true - * - * See also: - * - * equal, unequal, smaller, larger, largerEq, compare - * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false - */ - var smallerEq = typed('smallerEq', { + 'Unit, Unit': function (x, y) { + return or(x.value || 0, y.value || 0); + }, - 'boolean, boolean': function (x, y) { - return x <= y; - }, + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm05$$1(x, y, or); + }, - 'number, number': function (x, y) { - return x <= y || nearlyEqual$7(x, y, config.epsilon); - }, + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, or, true); + }, - 'BigNumber, BigNumber': function (x, y) { - return x.lte(y) || nearlyEqual(x, y, config.epsilon); - }, + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, or, false); + }, - 'Fraction, Fraction': function (x, y) { - return x.compare(y) !== 1; - }, + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, or); + }, - 'Complex, Complex': function () { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, + 'Array, Array': function (x, y) { + // use matrix implementation + return or(matrix$$1(x), matrix$$1(y)).valueOf(); + }, - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return smallerEq(x.value, y.value); - }, + 'Array, Matrix': function (x, y) { + // use matrix implementation + return or(matrix$$1(x), y); + }, - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, smallerEq); - }, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return or(x, matrix$$1(y)); + }, - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, smallerEq, true); - }, + 'SparseMatrix, any': function (x, y) { + return algorithm12$$1(x, y, or, false); + }, - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, smallerEq, false); - }, + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, or, false); + }, - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, smallerEq); - }, + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, or, true); + }, - 'Array, Array': function (x, y) { - // use matrix implementation - return smallerEq(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, or, true); + }, - 'Array, Matrix': function (x, y) { - // use matrix implementation - return smallerEq(matrix$$1(x), y); - }, + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, or, false).valueOf(); + }, - 'Matrix, Array': function (x, y) { - // use matrix implementation - return smallerEq(x, matrix$$1(y)); - }, + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, or, true).valueOf(); + } + }); - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, smallerEq, false); - }, + or.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['or'] + '${args[1]}\\right)' + }; - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, smallerEq, false); - }, + return or; + } - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, smallerEq, true); - }, + var name$183 = 'or'; + var factory_1$194 = factory$195; - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, smallerEq, true); - }, + var or$1 = { + name: name$183, + factory: factory_1$194 + }; - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, smallerEq, false).valueOf(); - }, + function factory$196 (type, config, load, typed) { + var latex$$1 = latex; - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, smallerEq, true).valueOf(); - } - }); + var matrix$$1 = load(matrix); - smallerEq.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['smallerEq'] + '${args[1]}\\right)' - }; - - return smallerEq; -} - -var name$215 = 'smallerEq'; -var factory_1$227 = factory$228; - -var smallerEq$1 = { - name: name$215, - factory: factory_1$227 -}; - -var relational = [ - compare$1, - compareNatural$1, - compareText$1, - deepEqual$2, - equal$1, - equalText$1, - larger, - largerEq$1, - smaller, - smallerEq$1, - unequal$1 -]; - -var flatten$4 = array.flatten; - -function factory$229 (type, config, load, typed) { - var index = load(MatrixIndex); - var matrix = load(DenseMatrix); - var size = load(size$5); - var subset = load(subset$1); - var compareNatural = load(compareNatural$1); - - /** - * Create the cartesian product of two (multi)sets. - * Multi-dimension arrays will be converted to single-dimension arrays before the operation. - * - * Syntax: - * - * math.setCartesian(set1, set2) - * - * Examples: - * - * math.setCartesian([1, 2], [3, 4]); // returns [[1, 3], [1, 4], [2, 3], [2, 4]] - * - * See also: - * - * setUnion, setIntersect, setDifference, setPowerset - * - * @param {Array | Matrix} a1 A (multi)set - * @param {Array | Matrix} a2 A (multi)set - * @return {Array | Matrix} The cartesian product of two (multi)sets - */ - var setCartesian = typed('setCartesian', { - 'Array | Matrix, Array | Matrix': function (a1, a2) { - if (subset(size(a1), new index(0)) === 0 || subset(size(a2), new index(0)) === 0) { // if any of them is empty, return empty - var result = []; - } - else { - var b1 = flatten$4(Array.isArray(a1) ? a1 : a1.toArray()).sort(compareNatural); - var b2 = flatten$4(Array.isArray(a2) ? a2 : a2.toArray()).sort(compareNatural); - var result = []; - for (var i=0; i0; i--) { - for (var j=0; j array$$1[j+1].length) { - temp = array$$1[j]; - array$$1[j] = array$$1[j+1]; - array$$1[j+1] = temp; - } + if (xSize.length != 1 || ySize.length != 1 || xSize[0] != 3 || ySize[0] != 3) { + throw new RangeError('Vectors with length 3 expected ' + + '(Size A = [' + xSize.join(', ') + '], B = [' + ySize.join(', ') + '])'); } - } - return array$$1; - } -} - -var name$222 = 'setPowerset'; -var factory_1$234 = factory$235; -var setPowerset$1 = { - name: name$222, - factory: factory_1$234 -}; - -var flatten$11 = array.flatten; + var product = [ + subtract(multiply(x[1], y[2]), multiply(x[2], y[1])), + subtract(multiply(x[2], y[0]), multiply(x[0], y[2])), + subtract(multiply(x[0], y[1]), multiply(x[1], y[0])) + ]; -function factory$236 (type, config, load, typed) { - var compareNatural = load(compareNatural$1); - - /** - * Count the number of elements of a (multi)set. When a second parameter is 'true', count only the unique values. - * A multi-dimension array will be converted to a single-dimension array before the operation. - * - * Syntax: - * - * math.setSize(set) - * math.setSize(set, unique) - * - * Examples: - * - * math.setSize([1, 2, 2, 4]); // returns 4 - * math.setSize([1, 2, 2, 4], true); // returns 3 - * - * See also: - * - * setUnion, setIntersect, setDifference - * - * @param {Array | Matrix} a A multiset - * @return {number} The number of elements of the (multi)set - */ - var setSize = typed('setSize', { - 'Array | Matrix': function (a) { - return Array.isArray(a) ? flatten$11(a).length : flatten$11(a.toArray()).length; - }, - 'Array | Matrix, boolean': function (a, unique) { - if (unique === false || a.length === 0) { - return Array.isArray(a) ? flatten$11(a).length : flatten$11(a.toArray()).length; - } - else { - var b = flatten$11(Array.isArray(a) ? a : a.toArray()).sort(compareNatural); - var count = 1; - for (var i=1; i 1) { + return [product]; + } else { + return product; } } - }); + } - return setSize; -} + var name$185 = 'cross'; + var factory_1$196 = factory$197; -var name$223 = 'setSize'; -var factory_1$235 = factory$236; + var cross$1 = { + name: name$185, + factory: factory_1$196 + }; -var setSize$1 = { - name: name$223, - factory: factory_1$235 -}; + var clone$8 = object.clone; + var isInteger$23 = number.isInteger; -var flatten$12 = array.flatten; + function factory$198 (type, config, load, typed) { -function factory$237 (type, config, load, typed) { - var index = load(MatrixIndex); - var concat = load(concat$1); - var size = load(size$5); - var subset = load(subset$1); - var setDifference = load(setDifference$1); - - /** - * Create the symmetric difference of two (multi)sets. - * Multi-dimension arrays will be converted to single-dimension arrays before the operation. - * - * Syntax: - * - * math.setSymDifference(set1, set2) - * - * Examples: - * - * math.setSymDifference([1, 2, 3, 4], [3, 4, 5, 6]); // returns [1, 2, 5, 6] - * math.setSymDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]]); // returns [1, 2, 5, 6] - * - * See also: - * - * setUnion, setIntersect, setDifference - * - * @param {Array | Matrix} a1 A (multi)set - * @param {Array | Matrix} a2 A (multi)set - * @return {Array | Matrix} The symmetric difference of two (multi)sets - */ - var setSymDifference = typed('setSymDifference', { - 'Array | Matrix, Array | Matrix': function (a1, a2) { - if (subset(size(a1), new index(0)) === 0) { // if any of them is empty, return the other one - return flatten$12(a2); - } - else if (subset(size(a2), new index(0)) === 0) { - return flatten$12(a1); - } - var b1 = flatten$12(a1); - var b2 = flatten$12(a2); - return concat(setDifference(b1, b2), setDifference(b2, b1)); - } - }); - - return setSymDifference; -} - -var name$224 = 'setSymDifference'; -var factory_1$236 = factory$237; + var matrix$$1 = load(matrix); + + /** + * Create a diagonal matrix or retrieve the diagonal of a matrix + * + * When `x` is a vector, a matrix with vector `x` on the diagonal will be returned. + * When `x` is a two dimensional matrix, the matrixes `k`th diagonal will be returned as vector. + * When k is positive, the values are placed on the super diagonal. + * When k is negative, the values are placed on the sub diagonal. + * + * Syntax: + * + * math.diag(X) + * math.diag(X, format) + * math.diag(X, k) + * math.diag(X, k, format) + * + * Examples: + * + * // create a diagonal matrix + * math.diag([1, 2, 3]); // returns [[1, 0, 0], [0, 2, 0], [0, 0, 3]] + * math.diag([1, 2, 3], 1); // returns [[0, 1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]] + * math.diag([1, 2, 3], -1); // returns [[0, 0, 0], [1, 0, 0], [0, 2, 0], [0, 0, 3]] + * + * // retrieve the diagonal from a matrix + * var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; + * math.diag(a); // returns [1, 5, 9] + * + * See also: + * + * ones, zeros, eye + * + * @param {Matrix | Array} x A two dimensional matrix or a vector + * @param {number | BigNumber} [k=0] The diagonal where the vector will be filled + * in or retrieved. + * @param {string} [format='dense'] The matrix storage format. + * + * @returns {Matrix | Array} Diagonal matrix from input vector, or diagonal from input matrix. + */ + var diag = typed('diag', { + // FIXME: simplify this huge amount of signatures as soon as typed-function supports optional arguments -var setSymDifference$1 = { - name: name$224, - factory: factory_1$236 -}; + 'Array': function (x) { + return _diag(x, 0, array.size(x), null); + }, -var flatten$13 = array.flatten; + 'Array, number': function (x, k) { + return _diag(x, k, array.size(x), null); + }, + + 'Array, BigNumber': function (x, k) { + return _diag(x, k.toNumber(), array.size(x), null); + }, -function factory$238 (type, config, load, typed) { - var index = load(MatrixIndex); - var concat = load(concat$1); - var size = load(size$5); - var subset = load(subset$1); - var setIntersect = load(setIntersect$1); - var setSymDifference = load(setSymDifference$1); - - /** - * Create the union of two (multi)sets. - * Multi-dimension arrays will be converted to single-dimension arrays before the operation. - * - * Syntax: - * - * math.setUnion(set1, set2) - * - * Examples: - * - * math.setUnion([1, 2, 3, 4], [3, 4, 5, 6]); // returns [1, 2, 3, 4, 5, 6] - * math.setUnion([[1, 2], [3, 4]], [[3, 4], [5, 6]]); // returns [1, 2, 3, 4, 5, 6] - * - * See also: - * - * setIntersect, setDifference - * - * @param {Array | Matrix} a1 A (multi)set - * @param {Array | Matrix} a2 A (multi)set - * @return {Array | Matrix} The union of two (multi)sets - */ - var setUnion = typed('setUnion', { - 'Array | Matrix, Array | Matrix': function (a1, a2) { - if (subset(size(a1), new index(0)) === 0) { // if any of them is empty, return the other one - return flatten$13(a2); - } - else if (subset(size(a2), new index(0)) === 0) { - return flatten$13(a1); - } - var b1 = flatten$13(a1); - var b2 = flatten$13(a2); - return concat(setSymDifference(b1, b2), setIntersect(b1, b2)); - } - }); + 'Array, string': function (x, format) { + return _diag(x, 0, array.size(x), format); + }, - return setUnion; -} + 'Array, number, string': function (x, k, format) { + return _diag(x, k, array.size(x), format); + }, -var name$225 = 'setUnion'; -var factory_1$237 = factory$238; + 'Array, BigNumber, string': function (x, k, format) { + return _diag(x, k.toNumber(), array.size(x), format); + }, -var setUnion$1 = { - name: name$225, - factory: factory_1$237 -}; + 'Matrix': function (x) { + return _diag(x, 0, x.size(), x.storage()); + }, -var set = [ - setCartesian$1, - setDifference$1, - setDistinct$1, - setIntersect$1, - setIsSubset$1, - setMultiplicity$1, - setPowerset$1, - setSize$1, - setSymDifference$1, - setUnion$1 -]; + 'Matrix, number': function (x, k) { + return _diag(x, k, x.size(), x.storage()); + }, -var sign$2 = number.sign; + 'Matrix, BigNumber': function (x, k) { + return _diag(x, k.toNumber(), x.size(), x.storage()); + }, + 'Matrix, string': function (x, format) { + return _diag(x, 0, x.size(), format); + }, -function factory$239 (type, config, load, typed) { - /** - * Compute the erf function of a value using a rational Chebyshev - * approximations for different intervals of x. - * - * This is a translation of W. J. Cody's Fortran implementation from 1987 - * ( http://www.netlib.org/specfun/erf ). See the AMS publication - * "Rational Chebyshev Approximations for the Error Function" by W. J. Cody - * for an explanation of this process. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.erf(x) - * - * Examples: - * - * math.erf(0.2); // returns 0.22270258921047847 - * math.erf(-0.5); // returns -0.5204998778130465 - * math.erf(4); // returns 0.9999999845827421 - * - * @param {number | Array | Matrix} x A real number - * @return {number | Array | Matrix} The erf of `x` - */ - var erf = typed('erf', { - 'number': function (x) { - var y = Math.abs(x); + 'Matrix, number, string': function (x, k, format) { + return _diag(x, k, x.size(), format); + }, - if (y >= MAX_NUM) { - return sign$2(x); - } - if (y <= THRESH) { - return sign$2(x) * erf1(y); + 'Matrix, BigNumber, string': function (x, k, format) { + return _diag(x, k.toNumber(), x.size(), format); } - if (y <= 4.0) { - return sign$2(x) * (1 - erfc2(y)); - } - return sign$2(x) * (1 - erfc3(y)); - }, - - // TODO: Not sure if there's a way to guarantee some degree of accuracy here. - // Perhaps it would be best to set the precision of the number to that which - // is guaranteed by erf() - 'BigNumber': function (n) { - return new type.BigNumber(erf(n.toNumber())); - }, - - 'Array | Matrix': function (n) { - return deepMap(n, erf); - } + }); - // TODO: For complex numbers, use the approximation for the Faddeeva function - // from "More Efficient Computation of the Complex Error Function" (AMS) + diag.toTex = undefined; // use default template - }); + return diag; - /** - * Approximates the error function erf() for x <= 0.46875 using this function: - * n - * erf(x) = x * sum (p_j * x^(2j)) / (q_j * x^(2j)) - * j=0 - */ - function erf1(y) { - var ysq = y * y; - var xnum = P[0][4]*ysq; - var xden = ysq; - var i; + /** + * Creeate diagonal matrix from a vector or vice versa + * @param {Array | Matrix} x + * @param {number} k + * @param {string} format Storage format for matrix. If null, + * an Array is returned + * @returns {Array | Matrix} + * @private + */ + function _diag (x, k, size, format) { + if (!isInteger$23(k)) { + throw new TypeError ('Second parameter in function diag must be an integer'); + } + + var kSuper = k > 0 ? k : 0; + var kSub = k < 0 ? -k : 0; - for (i = 0; i < 3; i += 1) { - xnum = (xnum + P[0][i]) * ysq; - xden = (xden + Q[0][i]) * ysq; + // check dimensions + switch (size.length) { + case 1: + return _createDiagonalMatrix(x, k, format, size[0], kSub, kSuper); + case 2: + return _getDiagonal(x, k, format, size, kSub, kSuper); + } + throw new RangeError('Matrix for function diag must be 2 dimensional'); } - return y * (xnum + P[0][3]) / (xden + Q[0][3]); - } - - /** - * Approximates the complement of the error function erfc() for - * 0.46875 <= x <= 4.0 using this function: - * n - * erfc(x) = e^(-x^2) * sum (p_j * x^j) / (q_j * x^j) - * j=0 - */ - function erfc2(y) { - var xnum = P[1][8] * y; - var xden = y; - var i; - - for (i = 0; i < 7; i += 1) { - xnum = (xnum + P[1][i]) * y; - xden = (xden + Q[1][i]) * y; + + function _createDiagonalMatrix(x, k, format, l, kSub, kSuper) { + // matrix size + var ms = [l + kSub, l + kSuper]; + // get matrix constructor + var F = type.Matrix.storage(format || 'dense'); + // create diagonal matrix + var m = F.diagonal(ms, x, k); + // check we need to return a matrix + return format !== null ? m : m.valueOf(); + } + + function _getDiagonal(x, k, format, s, kSub, kSuper) { + // check x is a Matrix + if (type.isMatrix(x)) { + // get diagonal matrix + var dm = x.diagonal(k); + // check we need to return a matrix + if (format !== null) { + // check we need to change matrix format + if (format !== dm.storage()) + return matrix$$1(dm, format); + return dm; + } + return dm.valueOf(); + } + // vector size + var n = Math.min(s[0] - kSub, s[1] - kSuper); + // diagonal values + var vector = []; + // loop diagonal + for (var i = 0; i < n; i++) { + vector[i] = x[i + kSub][i + kSuper]; + } + // check we need to return a matrix + return format !== null ? matrix$$1(vector) : vector; } - var result = (xnum + P[1][7]) / (xden + Q[1][7]); - var ysq = parseInt(y * 16) / 16; - var del = (y - ysq) * (y + ysq); - return Math.exp(-ysq*ysq) * Math.exp(-del) * result; } - /** - * Approximates the complement of the error function erfc() for x > 4.0 using - * this function: - * - * erfc(x) = (e^(-x^2) / x) * [ 1/sqrt(pi) + - * n - * 1/(x^2) * sum (p_j * x^(-2j)) / (q_j * x^(-2j)) ] - * j=0 - */ - function erfc3(y) { - var ysq = 1 / (y * y); - var xnum = P[2][5] * ysq; - var xden = ysq; - var i; + var name$186 = 'diag'; + var factory_1$197 = factory$198; - for (i = 0; i < 4; i += 1) { - xnum = (xnum + P[2][i]) * ysq; - xden = (xden + Q[2][i]) * ysq; - } - var result = ysq * (xnum + P[2][4]) / (xden + Q[2][4]); - result = (SQRPI - result) / y; - ysq = parseInt(y * 16) / 16; - var del = (y - ysq) * (y + ysq); - return Math.exp(-ysq*ysq) * Math.exp(-del) * result; - } - - erf.toTex = {1: 'erf\\left(${args[0]}\\right)'}; - - return erf; -} - -/** - * Upper bound for the first approximation interval, 0 <= x <= THRESH - * @constant - */ -var THRESH = 0.46875; - -/** - * Constant used by W. J. Cody's Fortran77 implementation to denote sqrt(pi) - * @constant - */ -var SQRPI = 5.6418958354775628695e-1; - -/** - * Coefficients for each term of the numerator sum (p_j) for each approximation - * interval (see W. J. Cody's paper for more details) - * @constant - */ -var P = [[ - 3.16112374387056560e00, 1.13864154151050156e02, - 3.77485237685302021e02, 3.20937758913846947e03, - 1.85777706184603153e-1 -], [ - 5.64188496988670089e-1, 8.88314979438837594e00, - 6.61191906371416295e01, 2.98635138197400131e02, - 8.81952221241769090e02, 1.71204761263407058e03, - 2.05107837782607147e03, 1.23033935479799725e03, - 2.15311535474403846e-8 -], [ - 3.05326634961232344e-1, 3.60344899949804439e-1, - 1.25781726111229246e-1, 1.60837851487422766e-2, - 6.58749161529837803e-4, 1.63153871373020978e-2 -]]; - -/** - * Coefficients for each term of the denominator sum (q_j) for each approximation - * interval (see W. J. Cody's paper for more details) - * @constant - */ -var Q = [[ - 2.36012909523441209e01, 2.44024637934444173e02, - 1.28261652607737228e03, 2.84423683343917062e03 -], [ - 1.57449261107098347e01, 1.17693950891312499e02, - 5.37181101862009858e02, 1.62138957456669019e03, - 3.29079923573345963e03, 4.36261909014324716e03, - 3.43936767414372164e03, 1.23033935480374942e03 -], [ - 2.56852019228982242e00, 1.87295284992346047e00, - 5.27905102951428412e-1, 6.05183413124413191e-2, - 2.33520497626869185e-3 -]]; - -/** - * Maximum/minimum safe numbers to input to erf() (in ES6+, this number is - * Number.[MAX|MIN]_SAFE_INTEGER). erf() for all numbers beyond this limit will - * return 1 - */ -var MAX_NUM = Math.pow(2, 53); - - -var name$226 = 'erf'; -var factory_1$238 = factory$239; - -var erf$1 = { - name: name$226, - factory: factory_1$238 -}; - -var special = [ - erf$1 -]; - -var flatten$14 = array.flatten; - - -function factory$240 (type, config, load, typed) { - var add = load(addScalar); - var divide = load(divideScalar); - var compare = load(compare$1); - var partitionSelect = load(partitionSelect$1); - var improveErrorMessage$$1 = load(improveErrorMessage); + var diag$1 = { + name: name$186, + factory: factory_1$197 + }; - /** - * Compute the median of a matrix or a list with values. The values are - * sorted and the middle value is returned. In case of an even number of - * values, the average of the two middle values is returned. - * Supported types of values are: Number, BigNumber, Unit - * - * In case of a (multi dimensional) array or matrix, the median of all - * elements will be calculated. - * - * Syntax: - * - * math.median(a, b, c, ...) - * math.median(A) - * - * Examples: - * - * math.median(5, 2, 7); // returns 5 - * math.median([3, -1, 5, 7]); // returns 4 - * - * See also: - * - * mean, min, max, sum, prod, std, var, quantileSeq - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The median - */ - var median = typed('median', { - // median([a, b, c, d, ...]) - 'Array | Matrix': _median, - - // median([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': function (array$$1, dim) { - // TODO: implement median(A, dim) - throw new Error('median(A, dim) is not yet supported'); - //return reduce(arguments[0], arguments[1], ...); - }, + var size$3 = array.size; - // median(a, b, c, d, ...) - '...': function (args) { - if (containsCollections(args)) { - throw new TypeError('Scalar values expected in function median'); - } + function factory$199 (type, config, load, typed) { + var add$$1 = load(add); + var multiply = load(multiply$1); - return _median(args); - } - }); + /** + * Calculate the dot product of two vectors. The dot product of + * `A = [a1, a2, a3, ..., an]` and `B = [b1, b2, b3, ..., bn]` is defined as: + * + * dot(A, B) = a1 * b1 + a2 * b2 + a3 * b3 + ... + an * bn + * + * Syntax: + * + * math.dot(x, y) + * + * Examples: + * + * math.dot([2, 4, 1], [2, 2, 3]); // returns number 15 + * math.multiply([2, 4, 1], [2, 2, 3]); // returns number 15 + * + * See also: + * + * multiply, cross + * + * @param {Array | Matrix} x First vector + * @param {Array | Matrix} y Second vector + * @return {number} Returns the dot product of `x` and `y` + */ + var dot = typed('dot', { + 'Matrix, Matrix': function (x, y) { + return _dot(x.toArray(), y.toArray()); + }, + 'Matrix, Array': function (x, y) { + return _dot(x.toArray(), y); + }, - /** - * Recursively calculate the median of an n-dimensional array - * @param {Array} array - * @return {Number} median - * @private - */ - function _median(array$$1) { - try { - array$$1 = flatten$14(array$$1.valueOf()); + 'Array, Matrix': function (x, y) { + return _dot(x, y.toArray()); + }, - var num = array$$1.length; - if (num == 0) { - throw new Error('Cannot calculate median of an empty array'); - } + 'Array, Array': _dot + }); + + dot.toTex = {2: '\\left(${args[0]}\\cdot${args[1]}\\right)'}; - if (num % 2 == 0) { - // even: return the average of the two middle values - var mid = num / 2 - 1; - var right = partitionSelect(array$$1, mid + 1); + return dot; - // array now partitioned at mid + 1, take max of left part - var left = array$$1[mid]; - for (var i = 0; i < mid; ++i) { - if (compare(array$$1[i], left) > 0) { - left = array$$1[i]; - } - } + /** + * Calculate the dot product for two arrays + * @param {Array} x First vector + * @param {Array} y Second vector + * @returns {number} Returns the dot product of x and y + * @private + */ + // TODO: double code with math.multiply + function _dot(x, y) { + var xSize= size$3(x); + var ySize = size$3(y); + var len = xSize[0]; - return middle2(left, right); - } - else { - // odd: return the middle value - var m = partitionSelect(array$$1, (num - 1) / 2); + if (xSize.length !== 1 || ySize.length !== 1) throw new RangeError('Vector expected'); // TODO: better error message + if (xSize[0] != ySize[0]) throw new RangeError('Vectors must have equal length (' + xSize[0] + ' != ' + ySize[0] + ')'); + if (len == 0) throw new RangeError('Cannot calculate the dot product of empty vectors'); - return middle(m); + var prod = 0; + for (var i = 0; i < len; i++) { + prod = add$$1(prod, multiply(x[i], y[i])); } - } - catch (err) { - throw improveErrorMessage$$1(err, 'median'); - } - } - - // helper function to type check the middle value of the array - var middle = typed({ - 'number | BigNumber | Complex | Unit': function (value) { - return value; - } - }); - // helper function to type check the two middle value of the array - var middle2 = typed({ - 'number | BigNumber | Complex | Unit, number | BigNumber | Complex | Unit': function (left, right) { - return divide(add(left, right), 2); + return prod; } - }); - - median.toTex = undefined; // use default template - - return median; -} + } -var name$227 = 'median'; -var factory_1$239 = factory$240; + var name$187 = 'dot'; + var factory_1$198 = factory$199; -var median$1 = { - name: name$227, - factory: factory_1$239 -}; + var dot$1 = { + name: name$187, + factory: factory_1$198 + }; -var flatten$15 = array.flatten; + var format$6 = string.format; -function factory$241 (type, config, load, typed) { - var abs = load(abs$1); - var map = load(map$7); - var median = load(median$1); - var subtract = load(subtract$1); - var improveErrorMessage$$1 = load(improveErrorMessage); + function factory$200 (type, config, load, typed) { - /** - * Compute the median absolute deviation of a matrix or a list with values. - * The median absolute deviation is defined as the median of the absolute - * deviations from the median. - * - * Syntax: - * - * math.mad(a, b, c, ...) - * math.mad(A) - * - * Examples: - * - * math.mad(10, 20, 30); // returns 10 - * math.mad([1, 2, 3]); // returns 1 - * math.mad([[1, 2, 3], [4, 5, 6]]); // returns 1.5 - * - * See also: - * - * median, mean, std, abs - * - * @param {Array | Matrix} array - * A single matrix or multiple scalar values. - * @return {*} The median absolute deviation. - */ - var mad = typed('mad', { - // mad([a, b, c, d, ...]) - 'Array | Matrix': _mad, + var abs = load(abs$1); + var add$$1 = load(add); + var eye = load(eye$1); + var inv = load(inv$1); + var multiply = load(multiply$1); - // mad(a, b, c, d, ...) - '...': function (args) { - return _mad(args); - } - }); + var SparseMatrix = type.SparseMatrix; - mad.toTex = undefined; // use default template + /** + * Compute the matrix exponential, expm(A) = e^A. The matrix must be square. + * Not to be confused with exp(a), which performs element-wise + * exponentiation. + * + * The exponential is calculated using the Padé approximant with scaling and + * squaring; see "Nineteen Dubious Ways to Compute the Exponential of a + * Matrix," by Moler and Van Loan. + * + * Syntax: + * + * math.expm(x) + * + * Examples: + * + * var A = [[0,2],[0,0]] + * math.expm(A); // returns [[1,2],[0,1]] + * + * See also: + * + * exp + * + * @param {Matrix} x A square Matrix + * @return {Matrix} The exponential of x + */ + var expm = typed('expm', { - return mad; + 'Matrix': function (A) { - function _mad(array$$1) { - array$$1 = flatten$15(array$$1.valueOf()); + // Check matrix size + var size = A.size(); + + if(size.length !== 2 || size[0] !== size[1]) { + throw new RangeError('Matrix must be square ' + + '(size: ' + format$6(size) + ')'); + } + + var n = size[0]; - if (array$$1.length === 0) { - throw new Error('Cannot calculate median absolute deviation (mad) of an empty array'); - } + // Desired accuracy of the approximant (The actual accuracy + // will be affected by round-off error) + var eps = 1e-15; + + // The Padé approximant is not so accurate when the values of A + // are "large", so scale A by powers of two. Then compute the + // exponential, and square the result repeatedly according to + // the identity e^A = (e^(A/m))^m + + // Compute infinity-norm of A, ||A||, to see how "big" it is + var infNorm = infinityNorm(A); + + // Find the optimal scaling factor and number of terms in the + // Padé approximant to reach the desired accuracy + var params = findParams(infNorm, eps); + var q = params.q; + var j = params.j; + + // The Pade approximation to e^A is: + // Rqq(A) = Dqq(A) ^ -1 * Nqq(A) + // where + // Nqq(A) = sum(i=0, q, (2q-i)!p! / [ (2q)!i!(q-i)! ] A^i + // Dqq(A) = sum(i=0, q, (2q-i)!q! / [ (2q)!i!(q-i)! ] (-A)^i + + // Scale A by 1 / 2^j + var Apos = multiply(A, Math.pow(2, -j)); + + // The i=0 term is just the identity matrix + var N = eye(n); + var D = eye(n); + + // Initialization (i=0) + var factor = 1; + + // Initialization (i=1) + var Apos_to_i = Apos; // Cloning not necessary + var alternate = -1; + + for(var i=1; i<=q; i++) { + if(i>1) { + Apos_to_i = multiply(Apos_to_i, Apos); + alternate = -alternate; + } + factor = factor*(q-i+1)/((2*q-i+1)*i); + + N = add$$1(N, multiply(factor, Apos_to_i)); + D = add$$1(D, multiply(factor*alternate, Apos_to_i)); + } + + var R = multiply(inv(D), N); + + // Square j times + for(var i=0; i max) { - max = count[values[i]]; - mode = [values[i]]; + var twoqfac = qfac; + for(var i=q+1; i<=2*q; i++) { + twoqfac *= i; } + var twoqp1fac = twoqfac * (2*q+1); + + return 8.0 * + Math.pow(infNorm / Math.pow(2, j), 2*q) * + qfac*qfac / (twoqfac*twoqp1fac); } - return mode; - }} + + expm.toTex = {1: '\\exp\\left(${args[0]}\\right)'}; -var name$229 = 'mode'; -var factory_1$241 = factory$242; + return expm; + } -var mode$1 = { - name: name$229, - factory: factory_1$241 -}; + var name$188 = 'expm'; + var factory_1$199 = factory$200; -function factory$243 (type, config, load, typed) { - var multiply = load(multiplyScalar); - var improveErrorMessage$$1 = load(improveErrorMessage); + var expm$1 = { + name: name$188, + factory: factory_1$199 + }; - /** - * Compute the product of a matrix or a list with values. - * In case of a (multi dimensional) array or matrix, the sum of all - * elements will be calculated. - * - * Syntax: - * - * math.prod(a, b, c, ...) - * math.prod(A) - * - * Examples: - * - * math.multiply(2, 3); // returns 6 - * math.prod(2, 3); // returns 6 - * math.prod(2, 3, 4); // returns 24 - * math.prod([2, 3, 4]); // returns 24 - * math.prod([[2, 5], [4, 3]]); // returns 120 - * - * See also: - * - * mean, median, min, max, sum, std, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The product of all values - */ - var prod = typed('prod', { - // prod([a, b, c, d, ...]) - 'Array | Matrix': _prod, - - // prod([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': function (array, dim) { - // TODO: implement prod(A, dim) - throw new Error('prod(A, dim) is not yet supported'); - //return reduce(arguments[0], arguments[1], math.prod); - }, + var filter$2 = array.filter; + var filterRegExp$1 = array.filterRegExp; + var maxArgumentCount$4 = _function.maxArgumentCount; - // prod(a, b, c, d, ...) - '...': function (args) { - return _prod(args); - } - }); - - prod.toTex = undefined; // use default template + function factory$201 (type, config, load, typed) { + var matrix$$1 = load(matrix); + + /** + * Filter the items in an array or one dimensional matrix. + * + * Syntax: + * + * math.filter(x, test) + * + * Examples: + * + * function isPositive (x) { + * return x > 0; + * } + * math.filter([6, -2, -1, 4, 3], isPositive); // returns [6, 4, 3] + * + * math.filter(["23", "foo", "100", "55", "bar"], /[0-9]+/); // returns ["23", "100", "55"] + * + * See also: + * + * forEach, map, sort + * + * @param {Matrix | Array} x A one dimensional matrix or array to filter + * @param {Function | RegExp} test + * A function or regular expression to test items. + * All entries for which `test` returns true are returned. + * When `test` is a function, it is invoked with three parameters: + * the value of the element, the index of the element, and the + * matrix/array being traversed. The function must return a boolean. + * @return {Matrix | Array} Returns the filtered matrix. + */ + var filter = typed('filter', { + 'Array, function': _filterCallback, - return prod; + 'Matrix, function': function (x, test) { + return matrix$$1(_filterCallback(x.toArray(), test)); + }, - /** - * Recursively calculate the product of an n-dimensional array - * @param {Array} array - * @return {number} prod - * @private - */ - function _prod(array) { - var prod = undefined; + 'Array, RegExp': filterRegExp$1, - deepForEach(array, function (value) { - try { - prod = (prod === undefined) ? value : multiply(prod, value); - } - catch (err) { - throw improveErrorMessage$$1(err, 'prod', value); + 'Matrix, RegExp': function (x, test) { + return matrix$$1(filterRegExp$1(x.toArray(), test)); } }); - if (prod === undefined) { - throw new Error('Cannot calculate prod of an empty array'); - } + filter.toTex = undefined; // use default template - return prod; + return filter; } -} - -var name$230 = 'prod'; -var factory_1$242 = factory$243; - -var prod$1 = { - name: name$230, - factory: factory_1$242 -}; - -var isInteger$29 = number.isInteger; -var isNumber$4 = number.isNumber; -var flatten$17 = array.flatten; - - -function factory$244 (type, config, load, typed) { - var add$$1 = load(add); - var multiply = load(multiply$1); - var partitionSelect = load(partitionSelect$1); - var compare = load(compare$1); /** - * Compute the prob order quantile of a matrix or a list with values. - * The sequence is sorted and the middle value is returned. - * Supported types of sequence values are: Number, BigNumber, Unit - * Supported types of probability are: Number, BigNumber - * - * In case of a (multi dimensional) array or matrix, the prob order quantile - * of all elements will be calculated. - * - * Syntax: - * - * math.quantileSeq(A, prob[, sorted]) - * math.quantileSeq(A, [prob1, prob2, ...][, sorted]) - * math.quantileSeq(A, N[, sorted]) - * - * Examples: - * - * math.quantileSeq([3, -1, 5, 7], 0.5); // returns 4 - * math.quantileSeq([3, -1, 5, 7], [1/3, 2/3]); // returns [3, 5] - * math.quantileSeq([3, -1, 5, 7], 2); // returns [3, 5] - * math.quantileSeq([-1, 3, 5, 7], 0.5, true); // returns 4 - * - * See also: - * - * median, mean, min, max, sum, prod, std, var - * - * @param {Array, Matrix} data A single matrix or Array - * @param {Number, BigNumber, Array} probOrN prob is the order of the quantile, while N is - * the amount of evenly distributed steps of - * probabilities; only one of these options can - * be provided - * @param {Boolean} sorted=false is data sorted in ascending order - * @return {Number, BigNumber, Unit, Array} Quantile(s) + * Filter values in a callback given a callback function + * @param {Array} x + * @param {Function} callback + * @return {Array} Returns the filtered array + * @private */ - function quantileSeq(data, probOrN, sorted) { - var probArr, dataArr, one; + function _filterCallback (x, callback) { + // figure out what number of arguments the callback function expects + var args = maxArgumentCount$4(callback); - if (arguments.length < 2 || arguments.length > 3) { - throw new SyntaxError('Function quantileSeq requires two or three parameters'); - } + return filter$2(x, function (value, index, array$$1) { + // invoke the callback function with the right number of arguments + if (args === 1) { + return callback(value); + } + else if (args === 2) { + return callback(value, [index]); + } + else { // 3 or -1 + return callback(value, [index], array$$1); + } + }); + } - if (isCollection(data)) { - sorted = sorted || false; - if (typeof sorted === 'boolean') { - dataArr = data.valueOf(); - if (isNumber$4(probOrN)) { - if (probOrN < 0) { - throw new Error('N/prob must be non-negative'); - } + var name$189 = 'filter'; + var factory_1$200 = factory$201; - if (probOrN <= 1) { - // quantileSeq([a, b, c, d, ...], prob[,sorted]) - return _quantileSeq(dataArr, probOrN, sorted); - } + var filter_1 = { + name: name$189, + factory: factory_1$200 + }; - if (probOrN > 1) { - // quantileSeq([a, b, c, d, ...], N[,sorted]) - if (!isInteger$29(probOrN)) { - throw new Error('N must be a positive integer'); - } + var clone$9 = object.clone; + var _flatten = array.flatten; - var nPlusOne = probOrN + 1; - probArr = new Array(probOrN); - for (var i = 0; i < probOrN;) { - probArr[i] = _quantileSeq(dataArr, (++i) / nPlusOne, sorted); - } - return probArr; - } - } + function factory$202 (type, config, load, typed) { + var matrix$$1 = load(matrix); - if (type.isBigNumber(probOrN)) { - if (probOrN.isNegative()) { - throw new Error('N/prob must be non-negative'); - } + /** + * Flatten a multi dimensional matrix into a single dimensional matrix. + * + * Syntax: + * + * math.flatten(x) + * + * Examples: + * + * math.flatten([[1,2], [3,4]]); // returns [1, 2, 3, 4] + * + * See also: + * + * concat, resize, size, squeeze + * + * @param {Matrix | Array} x Matrix to be flattened + * @return {Matrix | Array} Returns the flattened matrix + */ + var flatten = typed('flatten', { + 'Array': function (x) { + return _flatten(clone$9(x)); + }, - one = new probOrN.constructor(1); + 'Matrix': function (x) { + var flat = _flatten(clone$9(x.toArray())); + // TODO: return the same matrix type as x + return matrix$$1(flat); + } + }); - if (probOrN.lte(one)) { - // quantileSeq([a, b, c, d, ...], prob[,sorted]) - return _quantileSeq(dataArr, probOrN, sorted); - } + flatten.toTex = undefined; // use default template - if (probOrN.gt(one)) { - // quantileSeq([a, b, c, d, ...], N[,sorted]) - if (!probOrN.isInteger()) { - throw new Error('N must be a positive integer'); - } + return flatten; + } - // largest possible Array length is 2^32-1; - // 2^32 < 10^15, thus safe conversion guaranteed - var intN = probOrN.toNumber(); - if (intN > 4294967295) { - throw new Error('N must be less than or equal to 2^32-1, as that is the maximum length of an Array'); - } + var name$190 = 'flatten'; + var factory_1$201 = factory$202; - var nPlusOne = new type.BigNumber(intN + 1); - probArr = new Array(intN); - for (var i = 0; i < intN;) { - probArr[i] = _quantileSeq(dataArr, new type.BigNumber(++i).div(nPlusOne), sorted); - } - return probArr; - } - } + var flatten$3 = { + name: name$190, + factory: factory_1$201 + }; - if (Array.isArray(probOrN)) { - // quantileSeq([a, b, c, d, ...], [prob1, prob2, ...][,sorted]) - probArr = new Array(probOrN.length); - for (var i = 0; i < probArr.length; ++i) { - var currProb = probOrN[i]; - if (isNumber$4(currProb)) { - if (currProb < 0 || currProb > 1) { - throw new Error('Probability must be between 0 and 1, inclusive'); - } - } else if (type.isBigNumber(currProb)) { - one = new currProb.constructor(1); - if (currProb.isNegative() || currProb.gt(one)) { - throw new Error('Probability must be between 0 and 1, inclusive'); - } - } else { - throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function - } + var maxArgumentCount$5 = _function.maxArgumentCount; + var forEach$4 = array.forEach; - probArr[i] = _quantileSeq(dataArr, currProb, sorted); - } - return probArr; - } + function factory$203 (type, config, load, typed) { + /** + * Iterate over all elements of a matrix/array, and executes the given callback function. + * + * Syntax: + * + * math.forEach(x, callback) + * + * Examples: + * + * math.forEach([1, 2, 3], function(value) { + * console.log(value); + * }); + * // outputs 1, 2, 3 + * + * See also: + * + * filter, map, sort + * + * @param {Matrix | Array} x The matrix to iterate on. + * @param {Function} callback The callback function is invoked with three + * parameters: the value of the element, the index + * of the element, and the Matrix/array being traversed. + */ + var forEach = typed('forEach', { + 'Array, function': _forEach, - throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function + 'Matrix, function': function (x, callback) { + return x.forEach(callback); } + }); - throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function - } + forEach.toTex = undefined; // use default template - throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function + return forEach; } /** - * Calculate the prob order quantile of an n-dimensional array. - * + * forEach for a multi dimensional array * @param {Array} array - * @param {Number, BigNumber} prob - * @param {Boolean} sorted - * @return {Number, BigNumber, Unit} prob order quantile + * @param {Function} callback * @private */ - function _quantileSeq(array$$1, prob, sorted) { - var flat = flatten$17(array$$1); - var len = flat.length; - if (len === 0) { - throw new Error('Cannot calculate quantile of an empty sequence'); - } - - if (isNumber$4(prob)) { - var index = prob * (len-1); - var fracPart = index % 1; - if (fracPart === 0) { - var value = sorted ? flat[index] : partitionSelect(flat, index); + function _forEach (array$$1, callback) { + // figure out what number of arguments the callback function expects + var args = maxArgumentCount$5(callback); - validate(value); - - return value; + var recurse = function (value, index) { + if (Array.isArray(value)) { + forEach$4(value, function (child, i) { + // we create a copy of the index array and append the new index value + recurse(child, index.concat(i)); + }); } - - var integerPart = Math.floor(index); - - var left, right; - if (sorted) { - left = flat[integerPart]; - right = flat[integerPart+1]; - } else { - right = partitionSelect(flat, integerPart+1); - - // max of partition is kth largest - left = flat[integerPart]; - for (var i = 0; i < integerPart; ++i) { - if (compare(flat[i], left) > 0) { - left = flat[i]; - } + else { + // invoke the callback function with the right number of arguments + if (args === 1) { + callback(value); + } + else if (args === 2) { + callback(value, index); + } + else { // 3 or -1 + callback(value, index, array$$1); } } + }; + recurse(array$$1, []); + } - validate(left); - validate(right); - - // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1] - return add$$1(multiply(left, 1 - fracPart), multiply(right, fracPart)); - } + var name$191 = 'forEach'; + var factory_1$202 = factory$203; - // If prob is a BigNumber - var index = prob.times(len-1); - if (index.isInteger()) { - index = index.toNumber(); - var value = sorted ? flat[index] : partitionSelect(flat, index); + var forEach_1 = { + name: name$191, + factory: factory_1$202 + }; - validate(value); + var size$4 = array.size; - return value; - } + function factory$204(type, config, load, typed) { + var matrix$$1 = load(matrix); + var multiplyScalar$$1 = load(multiplyScalar); + /** + * Calculates the kronecker product of 2 matrices or vectors. + * + * NOTE: If a one dimensional vector / matrix is given, it will be + * wrapped so its two dimensions. + * See the examples. + * + * Syntax: + * + * math.kron(x, y) + * + * Examples: + * + * math.kron([[1, 0], [0, 1]], [[1, 2], [3, 4]]); + * // returns [ [ 1, 2, 0, 0 ], [ 3, 4, 0, 0 ], [ 0, 0, 1, 2 ], [ 0, 0, 3, 4 ] ] + * + * math.kron([1,1], [2,3,4]); + * // returns [ [ 2, 3, 4, 2, 3, 4 ] ] + * + * See also: + * + * multiply, dot, cross + * + * @param {Array | Matrix} x First vector + * @param {Array | Matrix} y Second vector + * @return {Array | Matrix} Returns the kronecker product of `x` and `y` + */ + var kron = typed('kron', { + 'Matrix, Matrix': function(x, y) { + return matrix$$1(_kron(x.toArray(), y.toArray())); + }, - var integerPart = index.floor(); - var fracPart = index.minus(integerPart); - var integerPartNumber = integerPart.toNumber(); + 'Matrix, Array': function(x, y) { + return matrix$$1(_kron(x.toArray(), y)); + }, - var left, right; - if (sorted) { - left = flat[integerPartNumber]; - right = flat[integerPartNumber+1]; - } else { - right = partitionSelect(flat, integerPartNumber+1); + 'Array, Matrix': function(x, y) { + return matrix$$1(_kron(x, y.toArray())); + }, - // max of partition is kth largest - left = flat[integerPartNumber]; - for (var i = 0; i < integerPartNumber; ++i) { - if (compare(flat[i], left) > 0) { - left = flat[i]; - } - } - } + 'Array, Array': _kron + }); - validate(left); - validate(right); + return kron; - // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1] - var one = new fracPart.constructor(1); - return add$$1(multiply(left, one.minus(fracPart)), multiply(right, fracPart)); + /** + * Calculate the kronecker product of two matrices / vectors + * @param {Array} a First vector + * @param {Array} b Second vector + * @returns {Array} Returns the kronecker product of x and y + * @private + */ + function _kron(a, b) { + // Deal with the dimensions of the matricies. + if (size$4(a).length === 1) { + // Wrap it in a 2D Matrix + a = [a]; + } + if (size$4(b).length === 1) { + // Wrap it in a 2D Matrix + b = [b]; + } + if (size$4(a).length > 2 || size$4(b).length > 2) { + throw new RangeError('Vectors with dimensions greater then 2 are not supported expected ' + + '(Size x = ' + JSON.stringify(a.length) + ', y = ' + JSON.stringify(b.length) + ')'); + } + var t = []; + var r = []; + + return a.map(function(a) { + return b.map(function(b) { + return a.map(function(y) { + return b.map(function(x) { + return r.push(multiplyScalar$$1(y, x)); + }); + }, t.push(r = [])); + }); + }, t = []) && t; + } } - /** - * Check if array value types are valid, throw error otherwise. - * @param {number | BigNumber | Unit} x - * @param {number | BigNumber | Unit} x - * @private - */ - var validate = typed({ - 'number | BigNumber | Unit': function (x) { - return x; - } - }); - - return quantileSeq; -} - -var name$231 = 'quantileSeq'; -var factory_1$243 = factory$244; + var name$192 = 'kron'; + var factory_1$203 = factory$204; -var quantileSeq$1 = { - name: name$231, - factory: factory_1$243 -}; - -var DEFAULT_NORMALIZATION = 'unbiased'; - - - -function factory$245 (type, config, load, typed) { - var add = load(addScalar); - var subtract = load(subtract$1); - var multiply = load(multiplyScalar); - var divide = load(divideScalar); - var improveErrorMessage$$1 = load(improveErrorMessage); + var kron$1 = { + name: name$192, + factory: factory_1$203 + }; - /** - * Compute the variance of a matrix or a list with values. - * In case of a (multi dimensional) array or matrix, the variance over all - * elements will be calculated. - * - * Optionally, the type of normalization can be specified as second - * parameter. The parameter `normalization` can be one of the following values: - * - * - 'unbiased' (default) The sum of squared errors is divided by (n - 1) - * - 'uncorrected' The sum of squared errors is divided by n - * - 'biased' The sum of squared errors is divided by (n + 1) - * - * Note that older browser may not like the variable name `var`. In that - * case, the function can be called as `math['var'](...)` instead of - * `math.var(...)`. - * - * Syntax: - * - * math.var(a, b, c, ...) - * math.var(A) - * math.var(A, normalization) - * - * Examples: - * - * math.var(2, 4, 6); // returns 4 - * math.var([2, 4, 6, 8]); // returns 6.666666666666667 - * math.var([2, 4, 6, 8], 'uncorrected'); // returns 5 - * math.var([2, 4, 6, 8], 'biased'); // returns 4 - * - * math.var([[1, 2, 3], [4, 5, 6]]); // returns 3.5 - * - * See also: - * - * mean, median, max, min, prod, std, sum - * - * @param {Array | Matrix} array - * A single matrix or or multiple scalar values - * @param {string} [normalization='unbiased'] - * Determines how to normalize the variance. - * Choose 'unbiased' (default), 'uncorrected', or 'biased'. - * @return {*} The variance - */ - var variance = typed('variance', { - // var([a, b, c, d, ...]) - 'Array | Matrix': function (array) { - return _var(array, DEFAULT_NORMALIZATION); - }, + var maxArgumentCount$6 = _function.maxArgumentCount; - // var([a, b, c, d, ...], normalization) - 'Array | Matrix, string': _var, + function factory$205 (type, config, load, typed) { + /** + * Create a new matrix or array with the results of the callback function executed on + * each entry of the matrix/array. + * + * Syntax: + * + * math.map(x, callback) + * + * Examples: + * + * math.map([1, 2, 3], function(value) { + * return value * value; + * }); // returns [1, 4, 9] + * + * See also: + * + * filter, forEach, sort + * + * @param {Matrix | Array} x The matrix to iterate on. + * @param {Function} callback The callback method is invoked with three + * parameters: the value of the element, the index + * of the element, and the matrix being traversed. + * @return {Matrix | array} Transformed map of x + */ + var map = typed('map', { + 'Array, function': _map$1, - // var(a, b, c, d, ...) - '...': function (args) { - return _var(args, DEFAULT_NORMALIZATION); - } - }); + 'Matrix, function': function (x, callback) { + return x.map(callback); + } + }); - variance.toTex = '\\mathrm{Var}\\left(${args}\\right)'; + map.toTex = undefined; // use default template - return variance; + return map; + } /** - * Recursively calculate the variance of an n-dimensional array + * Map for a multi dimensional array * @param {Array} array - * @param {string} normalization - * Determines how to normalize the variance: - * - 'unbiased' The sum of squared errors is divided by (n - 1) - * - 'uncorrected' The sum of squared errors is divided by n - * - 'biased' The sum of squared errors is divided by (n + 1) - * @return {number | BigNumber} variance + * @param {Function} callback + * @return {Array} * @private */ - function _var(array, normalization) { - var sum = 0; - var num = 0; - - if (array.length == 0) { - throw new SyntaxError('Function var requires one or more parameters (0 provided)'); - } + function _map$1 (array, callback) { + // figure out what number of arguments the callback function expects + var args = maxArgumentCount$6(callback); - // calculate the mean and number of elements - deepForEach(array, function (value) { - try { - sum = add(sum, value); - num++; + var recurse = function (value, index) { + if (Array.isArray(value)) { + return value.map(function (child, i) { + // we create a copy of the index array and append the new index value + return recurse(child, index.concat(i)); + }); } - catch (err) { - throw improveErrorMessage$$1(err, 'var', value); + else { + // invoke the callback function with the right number of arguments + if (args === 1) { + return callback(value); + } + else if (args === 2) { + return callback(value, index); + } + else { // 3 or -1 + return callback(value, index, array); + } } - }); - if (num === 0) throw new Error('Cannot calculate var of an empty array'); - - var mean = divide(sum, num); - - // calculate the variance - sum = 0; - deepForEach(array, function (value) { - var diff = subtract(value, mean); - sum = add(sum, multiply(diff, diff)); - }); - - switch (normalization) { - case 'uncorrected': - return divide(sum, num); - - case 'biased': - return divide(sum, num + 1); - - case 'unbiased': - var zero = type.isBigNumber(sum) ? new type.BigNumber(0) : 0; - return (num == 1) ? zero : divide(sum, num - 1); + }; - default: - throw new Error('Unknown normalization "' + normalization + '". ' + - 'Choose "unbiased" (default), "uncorrected", or "biased".'); - } + return recurse(array, []); } -} -var name$232 = 'var'; -var factory_1$244 = factory$245; + var name$193 = 'map'; + var factory_1$204 = factory$205; -var _var$1 = { - name: name$232, - factory: factory_1$244 -}; + var map$7 = { + name: name$193, + factory: factory_1$204 + }; -function factory$246 (type, config, load, typed) { - var sqrt = load(sqrt$1); - var variance = load(_var$1); + var isInteger$24 = number.isInteger; + var resize$2 = array.resize; - /** - * Compute the standard deviation of a matrix or a list with values. - * The standard deviations is defined as the square root of the variance: - * `std(A) = sqrt(var(A))`. - * In case of a (multi dimensional) array or matrix, the standard deviation - * over all elements will be calculated. - * - * Optionally, the type of normalization can be specified as second - * parameter. The parameter `normalization` can be one of the following values: - * - * - 'unbiased' (default) The sum of squared errors is divided by (n - 1) - * - 'uncorrected' The sum of squared errors is divided by n - * - 'biased' The sum of squared errors is divided by (n + 1) - * - * Syntax: - * - * math.std(a, b, c, ...) - * math.std(A) - * math.std(A, normalization) - * - * Examples: - * - * math.std(2, 4, 6); // returns 2 - * math.std([2, 4, 6, 8]); // returns 2.581988897471611 - * math.std([2, 4, 6, 8], 'uncorrected'); // returns 2.23606797749979 - * math.std([2, 4, 6, 8], 'biased'); // returns 2 - * - * math.std([[1, 2, 3], [4, 5, 6]]); // returns 1.8708286933869707 - * - * See also: - * - * mean, median, max, min, prod, sum, var - * - * @param {Array | Matrix} array - * A single matrix or or multiple scalar values - * @param {string} [normalization='unbiased'] - * Determines how to normalize the variance. - * Choose 'unbiased' (default), 'uncorrected', or 'biased'. - * @return {*} The standard deviation - */ - var std = typed('std', { - // std([a, b, c, d, ...]) - 'Array | Matrix': _std, + function factory$206 (type, config, load, typed) { + var matrix$$1 = load(matrix); - // std([a, b, c, d, ...], normalization) - 'Array | Matrix, string': _std, + /** + * Create a matrix filled with ones. The created matrix can have one or + * multiple dimensions. + * + * Syntax: + * + * math.ones(m) + * math.ones(m, format) + * math.ones(m, n) + * math.ones(m, n, format) + * math.ones([m, n]) + * math.ones([m, n], format) + * math.ones([m, n, p, ...]) + * math.ones([m, n, p, ...], format) + * + * Examples: + * + * math.ones(3); // returns [1, 1, 1] + * math.ones(3, 2); // returns [[1, 1], [1, 1], [1, 1]] + * math.ones(3, 2, 'dense'); // returns Dense Matrix [[1, 1], [1, 1], [1, 1]] + * + * var A = [[1, 2, 3], [4, 5, 6]]; + * math.ones(math.size(A)); // returns [[1, 1, 1], [1, 1, 1]] + * + * See also: + * + * zeros, eye, size, range + * + * @param {...number | Array} size The size of each dimension of the matrix + * @param {string} [format] The Matrix storage format + * + * @return {Array | Matrix | number} A matrix filled with ones + */ + var ones = typed('ones', { + '': function () { + return (config.matrix === 'Array') + ? _ones([]) + : _ones([], 'default'); + }, - // std(a, b, c, d, ...) - '...': function (args) { - return _std(args); - } - }); - - std.toTex = undefined; // use default template + // math.ones(m, n, p, ..., format) + // TODO: more accurate signature '...number | BigNumber, string' as soon as typed-function supports this + '...number | BigNumber | string': function (size) { + var last = size[size.length - 1]; + if (typeof last === 'string') { + var format = size.pop(); + return _ones(size, format); + } + else if (config.matrix === 'Array') { + return _ones(size); + } + else { + return _ones(size, 'default'); + } + }, - return std; + 'Array': _ones, - function _std(array, normalization) { - if (array.length == 0) { - throw new SyntaxError('Function std requires one or more parameters (0 provided)'); - } + 'Matrix': function (size) { + var format = size.storage(); + return _ones(size.valueOf(), format); + }, - try { - return sqrt(variance.apply(null, arguments)); - } - catch (err) { - if (err instanceof TypeError && err.message.indexOf(' var') !== -1) { - throw new TypeError(err.message.replace(' var', ' std')); + 'Array | Matrix, string': function (size, format) { + return _ones (size.valueOf(), format); + } + }); + + ones.toTex = undefined; // use default template + + return ones; + + /** + * Create an Array or Matrix with ones + * @param {Array} size + * @param {string} [format='default'] + * @return {Array | Matrix} + * @private + */ + function _ones(size, format) { + var hasBigNumbers = _normalize(size); + var defaultValue = hasBigNumbers ? new type.BigNumber(1) : 1; + _validate(size); + + if (format) { + // return a matrix + var m = matrix$$1(format); + if (size.length > 0) { + return m.resize(size, defaultValue); + } + return m; } else { - throw err; + // return an Array + var arr = []; + if (size.length > 0) { + return resize$2(arr, size, defaultValue); + } + return arr; } } + + // replace BigNumbers with numbers, returns true if size contained BigNumbers + function _normalize(size) { + var hasBigNumbers = false; + size.forEach(function (value, index, arr) { + if (type.isBigNumber(value)) { + hasBigNumbers = true; + arr[index] = value.toNumber(); + } + }); + return hasBigNumbers; + } + + // validate arguments + function _validate (size) { + size.forEach(function (value) { + if (typeof value !== 'number' || !isInteger$24(value) || value < 0) { + throw new Error('Parameters in function ones must be positive integers'); + } + }); + } } -} -var name$233 = 'std'; -var factory_1$245 = factory$246; + var name$194 = 'ones'; + var factory_1$205 = factory$206; -var std$1 = { - name: name$233, - factory: factory_1$245 -}; + var ones$1 = { + name: name$194, + factory: factory_1$205 + }; -var statistics = [ - mad$1, - max$1, - mean$1, - median$1, - min$1, - mode$1, - prod$1, - quantileSeq$1, - std$1, - sum$1, - _var$1 -]; + var nearlyEqual$6 = number.nearlyEqual; -function factory$247 (type, config, load, typed) { - /** - * Format a value of any type into a string. - * - * Syntax: - * - * math.format(value) - * math.format(value, options) - * math.format(value, precision) - * math.format(value, callback) - * - * Where: - * - * - `value: *` - * The value to be formatted - * - `options: Object` - * An object with formatting options. Available options: - * - `notation: string` - * 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 - * `lower` and `upper` bounds, and uses exponential notation elsewhere. - * Lower bound is included, upper bound is excluded. - * For example '123.4' and '1.4e7'. - * - `precision: number` - * A number between 0 and 16 to round the digits of the number. In case - * of notations 'exponential' 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. - * - `lowerExp: number` - * Exponent determining the lower boundary for formatting a value with - * an exponent when `notation='auto`. Default value is `-3`. - * - `upperExp: number` - * Exponent determining the upper boundary for formatting a value with - * an exponent when `notation='auto`. Default value is `5`. - * - `fraction: string`. Available values: 'ratio' (default) or 'decimal'. - * For example `format(fraction(1, 3))` will output '1/3' when 'ratio' is - * configured, and will output `0.(3)` when 'decimal' is configured. - * - `callback: function` - * A custom formatting function, invoked for all numeric elements in `value`, - * for example all elements of a matrix, or the real and imaginary - * parts of a complex number. This callback can be used to override the - * built-in numeric notation with any type of formatting. Function `callback` - * is called with `value` as parameter and must return a string. - * - * When `value` is an Object: - * - * - When the object contains a property `format` being a function, this function - * is invoked as `value.format(options)` and the result is returned. - * - When the object has its own `toString` method, this method is invoked - * and the result is returned. - * - In other cases the function will loop over all object properties and - * return JSON object notation like '{"a": 2, "b": 3}'. - * - * When value is a function: - * - * - When the function has a property `syntax`, it returns this - * syntax description. - * - In other cases, a string `'function'` is returned. - * - * Examples: - * - * math.format(6.4); // returns '6.4' - * math.format(1240000); // returns '1.24e6' - * math.format(1/3); // returns '0.3333333333333333' - * math.format(1/3, 3); // returns '0.333' - * math.format(21385, 2); // returns '21000' - * math.format(12e8, {notation: 'fixed'}); // returns '1200000000' - * math.format(2.3, {notation: 'fixed', precision: 4}); // returns '2.3000' - * math.format(52.8, {notation: 'exponential'}); // returns '5.28e+1' - * math.format(12400,{notation: 'engineering'}); // returns '12.400e+3' - * math.format(2000, {lowerExp: -2, upperExp: 2}); // returns '2e+3' - * - * function formatCurrency(value) { - * // return currency notation with two digits: - * return '$' + value.toFixed(2); - * - * // you could also use math.format inside the callback: - * // return '$' + math.format(value, {notation: 'fixed', precision: 2}); - * } - * math.format([2.1, 3, 0.016], formatCurrency}; // returns '[$2.10, $3.00, $0.02]' - * - * See also: - * - * print - * - * @param {*} value Value to be stringified - * @param {Object | Function | number} [options] Formatting options - * @return {string} The formatted value - */ - var format = typed('format', { - 'any': string.format, - 'any, Object | function | number': string.format - }); - format.toTex = undefined; // use default template + function factory$207 (type, config, load, typed) { - return format; -} + var matrix$$1 = load(matrix); -var name$234 = 'format'; -var factory_1$246 = factory$247; + var algorithm03$$1 = load(algorithm03); + var algorithm05$$1 = load(algorithm05); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + /** + * Compare two values. Returns 1 when x > y, -1 when x < y, and 0 when x == y. + * + * x and y are considered equal when the relative difference between x and y + * is smaller than the configured epsilon. The function cannot be used to + * compare values smaller than approximately 2.22e-16. + * + * For matrices, the function is evaluated element wise. + * Strings are compared by their numerical value. + * + * Syntax: + * + * math.compare(x, y) + * + * Examples: + * + * math.compare(6, 1); // returns 1 + * math.compare(2, 3); // returns -1 + * math.compare(7, 7); // returns 0 + * math.compare('10', '2'); // returns 1 + * math.compare('1000', '1e3'); // returns 0 + * + * var a = math.unit('5 cm'); + * var b = math.unit('40 mm'); + * math.compare(a, b); // returns 1 + * + * math.compare(2, [1, 2, 3]); // returns [1, 0, -1] + * + * See also: + * + * equal, unequal, smaller, smallerEq, larger, largerEq, compareNatural, compareText + * + * @param {number | BigNumber | Fraction | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | Fraction | Unit | string | Array | Matrix} y Second value to compare + * @return {number | BigNumber | Fraction | Array | Matrix} Returns the result of the comparison: + * 1 when x > y, -1 when x < y, and 0 when x == y. + */ + var compare = typed('compare', { -var format$8 = { - name: name$234, - factory: factory_1$246 -}; + 'boolean, boolean': function (x, y) { + return x === y ? 0 : (x > y ? 1 : -1); + }, -var isString$5 = string.isString; -var format$9 = string.format; + 'number, number': function (x, y) { + return (x === y || nearlyEqual$6(x, y, config.epsilon)) + ? 0 + : (x > y ? 1 : -1); + }, -function factory$248 (type, config, load, typed) { - /** - * Interpolate values into a string template. - * - * Syntax: - * - * math.print(template, values) - * math.print(template, values, precision) - * math.print(template, values, options) - * - * Example usage: - * - * // the following outputs: 'Lucy is 5 years old' - * math.print('Lucy is $age years old', {age: 5}); - * - * // the following outputs: 'The value of pi is 3.141592654' - * math.print('The value of pi is $pi', {pi: math.pi}, 10); - * - * // the following outputs: 'hello Mary! The date is 2013-03-23' - * math.print('Hello $user.name! The date is $date', { - * user: { - * name: 'Mary', - * }, - * date: new Date(2013, 2, 23).toISOString().substring(0, 10) - * }); - * - * // the following outputs: 'My favorite fruits are apples and bananas !' - * math.print('My favorite fruits are $0 and $1 !', [ - * 'apples', - * 'bananas' - * ]); - * - * See also: - * - * format - * - * @param {string} template A string containing variable placeholders. - * @param {Object | Array | Matrix} values An object or array containing variables - * which will be filled in in the template. - * @param {number | Object} [options] Formatting options, - * or the number of digits to format numbers. - * See function math.format for a description - * of all options. - * @return {string} Interpolated string - */ - var print = typed ('print', { - // note: Matrix will be converted automatically to an Array - 'string, Object | Array': _print, - 'string, Object | Array, number | Object': _print - }); + 'BigNumber, BigNumber': function (x, y) { + return (x.eq(y) || nearlyEqual(x, y, config.epsilon)) + ? new type.BigNumber(0) + : new type.BigNumber(x.cmp(y)); + }, - print.toTex = undefined; // use default template + 'Fraction, Fraction': function (x, y) { + return new type.Fraction(x.compare(y)); + }, - return print; -} + 'Complex, Complex': function () { + throw new TypeError('No ordering relation is defined for complex numbers'); + }, -/** - * Interpolate values into a string template. - * @param {string} template - * @param {Object} values - * @param {number | Object} [options] - * @returns {string} Interpolated string - * @private - */ -function _print(template, values, options) { - return template.replace(/\$([\w\.]+)/g, function (original, key) { - var keys = key.split('.'); - var value = values[keys.shift()]; - while (keys.length && value !== undefined) { - var k = keys.shift(); - value = k ? value[k] : value + '.'; + 'Unit, Unit': function (x, y) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); } + return compare(x.value, y.value); + }, - if (value !== undefined) { - if (!isString$5(value)) { - return format$9(value, options); - } - else { - return value; - } - } + 'SparseMatrix, SparseMatrix': function(x, y) { + return algorithm05$$1(x, y, compare); + }, - return original; - } - ); -} + 'SparseMatrix, DenseMatrix': function(x, y) { + return algorithm03$$1(y, x, compare, true); + }, -var name$235 = 'print'; -var factory_1$247 = factory$248; + 'DenseMatrix, SparseMatrix': function(x, y) { + return algorithm03$$1(x, y, compare, false); + }, -var print = { - name: name$235, - factory: factory_1$247 -}; + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, compare); + }, -var string$10 = [ - format$8, - print -]; + 'Array, Array': function (x, y) { + // use matrix implementation + return compare(matrix$$1(x), matrix$$1(y)).valueOf(); + }, -function factory$249 (type, config, load, typed) { + 'Array, Matrix': function (x, y) { + // use matrix implementation + return compare(matrix$$1(x), y); + }, - /** - * Calculate the inverse cosine of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acos(x) - * - * Examples: - * - * math.acos(0.5); // returns number 1.0471975511965979 - * math.acos(math.cos(1.5)); // returns number 1.5 - * - * math.acos(2); // returns Complex 0 + 1.3169578969248166 i - * - * See also: - * - * cos, atan, asin - * - * @param {number | BigNumber | Complex | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} The arc cosine of x - */ - var acos = typed('acos', { - 'number': function (x) { - if ((x >= -1 && x <= 1) || config.predictable) { - return Math.acos(x); - } - else { - return new type.Complex(x, 0).acos(); - } - }, + 'Matrix, Array': function (x, y) { + // use matrix implementation + return compare(x, matrix$$1(y)); + }, - 'Complex': function (x) { - return x.acos(); - }, + 'SparseMatrix, any': function (x, y) { + return algorithm12$$1(x, y, compare, false); + }, - 'BigNumber': function (x) { - return x.acos(); - }, + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, compare, false); + }, - 'Array | Matrix': function (x) { - return deepMap(x, acos); - } - }); + 'any, SparseMatrix': function (x, y) { + return algorithm12$$1(y, x, compare, true); + }, - acos.toTex = {1: '\\cos^{-1}\\left(${args[0]}\\right)'}; + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, compare, true); + }, - return acos; -} + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, compare, false).valueOf(); + }, -var name$236 = 'acos'; -var factory_1$248 = factory$249; + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, compare, true).valueOf(); + } + }); -var acos$1 = { - name: name$236, - factory: factory_1$248 -}; + compare.toTex = undefined; // use default template -function factory$250 (type, config, load, typed) { + return compare; + } - /** - * Calculate the hyperbolic arccos of a value, - * defined as `acosh(x) = ln(sqrt(x^2 - 1) + x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acosh(x) - * - * Examples: - * - * math.acosh(1.5); // returns 0.9624236501192069 - * - * See also: - * - * cosh, asinh, atanh - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arccosine of x - */ - var acosh = typed('acosh', { - 'number': function (x) { - if (x >= 1 || config.predictable) { - return _acosh(x); - } - if (x <= -1) { - return new type.Complex(Math.log(Math.sqrt(x*x - 1) - x), Math.PI); - } - return new type.Complex(x, 0).acosh(); - }, + var name$195 = 'compare'; + var factory_1$206 = factory$207; - 'Complex': function (x) { - return x.acosh(); - }, + var compare$1 = { + name: name$195, + factory: factory_1$206 + }; - 'BigNumber': function (x) { - return x.acosh(); - }, + var isInteger$25 = number.isInteger; - 'Array | Matrix': function (x) { - return deepMap(x, acosh); + function factory$208 (type, config, load, typed) { + var asc = load(compare$1); + function desc(a, b) { + return -asc(a, b); } - }); - acosh.toTex = {1: '\\cosh^{-1}\\left(${args[0]}\\right)'}; + /** + * Partition-based selection of an array or 1D matrix. + * Will find the kth smallest value, and mutates the input array. + * Uses Quickselect. + * + * Syntax: + * + * math.partitionSelect(x, k) + * math.partitionSelect(x, k, compare) + * + * Examples: + * + * math.partitionSelect([5, 10, 1], 2); // returns 10 + * math.partitionSelect(['C', 'B', 'A', 'D'], 1); // returns 'B' + * + * function sortByLength (a, b) { + * return a.length - b.length; + * } + * math.partitionSelect(['Langdon', 'Tom', 'Sara'], 2, sortByLength); // returns 'Langdon' + * + * See also: + * + * sort + * + * @param {Matrix | Array} x A one dimensional matrix or array to sort + * @param {Number} k The kth smallest value to be retrieved; zero-based index + * @param {Function | 'asc' | 'desc'} [compare='asc'] + * An optional comparator function. The function is called as + * `compare(a, b)`, and must return 1 when a > b, -1 when a < b, + * and 0 when a == b. + * @return {*} Returns the kth lowest value. + */ + return typed('partitionSelect', { + 'Array | Matrix, number': function (x, k) { + return _partitionSelect(x, k, asc); + }, - return acosh; -} + 'Array | Matrix, number, string': function (x, k, compare) { + if (compare === 'asc') { + return _partitionSelect(x, k, asc); + } + else if (compare === 'desc') { + return _partitionSelect(x, k, desc); + } + else { + throw new Error('Compare string must be "asc" or "desc"'); + } + }, -/** - * Calculate the hyperbolic arccos of a number - * @param {number} x - * @return {number} - * @private - */ -var _acosh = Math.acosh || function (x) { - return Math.log(Math.sqrt(x*x - 1) + x) -}; + 'Array | Matrix, number, function': _partitionSelect + }); -var name$237 = 'acosh'; -var factory_1$249 = factory$250; + function _partitionSelect(x, k, compare) { + if (!isInteger$25(k) || k < 0) { + throw new Error('k must be a non-negative integer'); + } -var acosh$1 = { - name: name$237, - factory: factory_1$249 -}; + if (type.isMatrix(x)) { + var size = x.size(); + if (size.length > 1) { + throw new Error('Only one dimensional matrices supported'); + } + return quickSelect(x.valueOf(), k, compare); + } -function factory$251 (type, config, load, typed) { + if (Array.isArray(x)) { + return quickSelect(x, k, compare); + } + } - /** - * Calculate the inverse cotangent of a value, defined as `acot(x) = atan(1/x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acot(x) - * - * Examples: - * - * math.acot(0.5); // returns number 0.4636476090008061 - * math.acot(math.cot(1.5)); // returns number 1.5 - * - * math.acot(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * cot, atan - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} The arc cotangent of x - */ - var acot = typed('acot', { - 'number': function (x) { - return Math.atan(1 / x); - }, + /** + * Quickselect algorithm. + * Code adapted from: + * http://blog.teamleadnet.com/2012/07/quick-select-algorithm-find-kth-element.html + * + * @param {Array} arr + * @param {Number} k + * @param {Function} compare + * @private + */ + function quickSelect(arr, k, compare) { + if (k >= arr.length) { + throw new Error('k out of bounds'); + } + + var from = 0; + var to = arr.length - 1; + + // if from == to we reached the kth element + while (from < to) { + var r = from; + var w = to; + var pivot = arr[Math.floor(Math.random() * (to - from + 1)) + from]; + + // stop if the reader and writer meets + while (r < w) { + // arr[r] >= pivot + if (compare(arr[r], pivot) >= 0) { // put the large values at the end + var tmp = arr[w]; + arr[w] = arr[r]; + arr[r] = tmp; + --w; + } else { // the value is smaller than the pivot, skip + ++r; + } + } - 'Complex': function (x) { - return x.acot(); - }, + // if we stepped up (r++) we need to step one down (arr[r] > pivot) + if (compare(arr[r], pivot) > 0) { + --r; + } - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).atan(); - }, + // the r pointer is on the end of the first k elements + if (k <= r) { + to = r; + } else { + from = r + 1; + } + } - 'Array | Matrix': function (x) { - return deepMap(x, acot); + return arr[k]; } - }); + } - acot.toTex = {1: '\\cot^{-1}\\left(${args[0]}\\right)'}; + var name$196 = 'partitionSelect'; + var factory_1$207 = factory$208; - return acot; -} + var partitionSelect$1 = { + name: name$196, + factory: factory_1$207 + }; -var name$238 = 'acot'; -var factory_1$250 = factory$251; + var isInteger$26 = number.isInteger; -var acot$1 = { - name: name$238, - factory: factory_1$250 -}; -function factory$252 (type, config, load, typed) { + function factory$209 (type, config, load, typed) { + var matrix$$1 = load(matrix); - /** - * Calculate the hyperbolic arccotangent of a value, - * defined as `acoth(x) = atanh(1/x) = (ln((x+1)/x) + ln(x/(x-1))) / 2`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acoth(x) - * - * Examples: - * - * math.acoth(0.5); // returns 0.8047189562170503 - * - * See also: - * - * acsch, asech - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arccotangent of x - */ - var acoth = typed('acoth', { - 'number': function (x) { - if (x >= 1 || x <= -1 || config.predictable) { - return isFinite(x) ? (Math.log((x+1)/x) + Math.log(x/(x-1))) / 2 : 0; - } - return new type.Complex(x, 0).acoth(); - }, + /** + * Reshape a multi dimensional array to fit the specified dimensions + * + * Syntax: + * + * math.reshape(x, sizes) + * + * Examples: + * + * math.reshape([1, 2, 3, 4, 5, 6], [2, 3]); + * // returns Array [[1, 2, 3], [4, 5, 6]] + * + * math.reshape([[1, 2], [3, 4]], [1, 4]); + * // returns Array [[1, 2, 3, 4]] + * + * math.reshape([[1, 2], [3, 4]], [4]); + * // returns Array [1, 2, 3, 4] + * + * var x = math.matrix([1, 2, 3, 4, 5, 6, 7, 8]); + * math.reshape(x, [2, 2, 2]); + * // returns Matrix [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] + * + * See also: + * + * size, squeeze, resize + * + * @param {Array | Matrix | *} x Matrix to be reshaped + * @param {number[]} sizes One dimensional array with integral sizes for + * each dimension + * + * @return {* | Array | Matrix} A reshaped clone of matrix `x` + * + * @throws {TypeError} If `sizes` does not contain solely integers + * @throws {DimensionError} If the product of the new dimension sizes does + * not equal that of the old ones + */ + var reshape = typed('reshape', { - 'Complex': function (x) { - return x.acoth(); - }, + 'Matrix, Array': function (x, sizes) { + if(x.reshape) { + return x.reshape(sizes); + } else { + return matrix$$1(array.reshape(x.valueOf(), sizes)); + } + }, - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).atanh(); - }, + 'Array, Array': function (x, sizes) { + sizes.forEach(function (size) { + if (!isInteger$26(size)) { + throw new TypeError('Invalid size for dimension: ' + size); + } + }); + return array.reshape(x, sizes); + } - 'Array | Matrix': function (x) { - return deepMap(x, acoth); - } - }); + }); - acoth.toTex = {1: '\\coth^{-1}\\left(${args[0]}\\right)'}; + reshape.toTex = undefined; // use default template - return acoth; -} + return reshape; + } -var name$239 = 'acoth'; -var factory_1$251 = factory$252; + var name$197 = 'reshape'; + var factory_1$208 = factory$209; -var acoth$1 = { - name: name$239, - factory: factory_1$251 -}; + var reshape$1 = { + name: name$197, + factory: factory_1$208 + }; -function factory$253 (type, config, load, typed) { + var isInteger$27 = number.isInteger; + var format$7 = string.format; + var clone$10 = object.clone; - /** - * Calculate the inverse cosecant of a value, defined as `acsc(x) = asin(1/x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acsc(x) - * - * Examples: - * - * math.acsc(0.5); // returns number 0.5235987755982989 - * math.acsc(math.csc(1.5)); // returns number ~1.5 - * - * math.acsc(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * csc, asin, asec - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} The arc cosecant of x - */ - var acsc = typed('acsc', { - 'number': function (x) { - if (x <= -1 || x >= 1 || config.predictable) { - return Math.asin(1 / x); - } - return new type.Complex(x, 0).acsc(); - }, - 'Complex': function (x) { - return x.acsc(); - }, + function factory$210 (type, config, load, typed) { + var matrix$$1 = load(matrix); - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).asin(); - }, + /** + * Resize a matrix + * + * Syntax: + * + * math.resize(x, size) + * math.resize(x, size, defaultValue) + * + * Examples: + * + * math.resize([1, 2, 3, 4, 5], [3]); // returns Array [1, 2, 3] + * math.resize([1, 2, 3], [5], 0); // returns Array [1, 2, 3, 0, 0] + * math.resize(2, [2, 3], 0); // returns Matrix [[2, 0, 0], [0, 0, 0]] + * math.resize("hello", [8], "!"); // returns string 'hello!!!' + * + * See also: + * + * size, squeeze, subset, reshape + * + * @param {Array | Matrix | *} x Matrix to be resized + * @param {Array | Matrix} size One dimensional array with numbers + * @param {number | string} [defaultValue=0] Zero by default, except in + * case of a string, in that case + * defaultValue = ' ' + * @return {* | Array | Matrix} A resized clone of matrix `x` + */ + // TODO: rework resize to a typed-function + var resize = function resize (x, size, defaultValue) { + if (arguments.length != 2 && arguments.length != 3) { + throw new ArgumentsError_1('resize', arguments.length, 2, 3); + } - 'Array | Matrix': function (x) { - return deepMap(x, acsc); - } - }); + if (type.isMatrix(size)) { + size = size.valueOf(); // get Array + } - acsc.toTex = {1: '\\csc^{-1}\\left(${args[0]}\\right)'}; + if (type.isBigNumber(size[0])) { + // convert bignumbers to numbers + size = size.map(function (value) { + return type.isBigNumber(value) ? value.toNumber() : value; + }); + } + + // check x is a Matrix + if (type.isMatrix(x)) { + // use optimized matrix implementation, return copy + return x.resize(size, defaultValue, true); + } + + if (typeof x === 'string') { + // resize string + return _resizeString(x, size, defaultValue); + } + + // check result should be a matrix + var asMatrix = Array.isArray(x) ? false : (config.matrix !== 'Array'); - return acsc; -} + if (size.length == 0) { + // output a scalar + while (Array.isArray(x)) { + x = x[0]; + } -var name$240 = 'acsc'; -var factory_1$252 = factory$253; + return clone$10(x); + } + else { + // output an array/matrix + if (!Array.isArray(x)) { + x = [x]; + } + x = clone$10(x); -var acsc$1 = { - name: name$240, - factory: factory_1$252 -}; + var res = array.resize(x, size, defaultValue); + return asMatrix ? matrix$$1(res) : res; + } + }; -function factory$254 (type, config, load, typed) { + resize.toTex = undefined; // use default template - /** - * Calculate the hyperbolic arccosecant of a value, - * defined as `acsch(x) = asinh(1/x) = ln(1/x + sqrt(1/x^2 + 1))`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acsch(x) - * - * Examples: - * - * math.acsch(0.5); // returns 1.4436354751788103 - * - * See also: - * - * asech, acoth - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arccosecant of x - */ - var acsch = typed('acsch', { - 'number': function (x) { - x = 1 / x; - return Math.log(x + Math.sqrt(x*x + 1)); - }, + return resize; - 'Complex': function (x) { - return x.acsch(); - }, + /** + * Resize a string + * @param {string} str + * @param {number[]} size + * @param {string} [defaultChar=' '] + * @private + */ + function _resizeString(str, size, defaultChar) { + if (defaultChar !== undefined) { + if (typeof defaultChar !== 'string' || defaultChar.length !== 1) { + throw new TypeError('Single character expected as defaultValue'); + } + } + else { + defaultChar = ' '; + } - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).asinh(); - }, + if (size.length !== 1) { + throw new DimensionError_1(size.length, 1); + } + var len = size[0]; + if (typeof len !== 'number' || !isInteger$27(len)) { + throw new TypeError('Invalid size, must contain positive integers ' + + '(size: ' + format$7(size) + ')'); + } - 'Array | Matrix': function (x) { - return deepMap(x, acsch); + if (str.length > len) { + return str.substring(0, len); + } + else if (str.length < len) { + var res = str; + for (var i = 0, ii = len - str.length; i < ii; i++) { + res += defaultChar; + } + return res; + } + else { + return str; + } } - }); + } - acsch.toTex = {1: '\\mathrm{csch}^{-1}\\left(${args[0]}\\right)'}; + var name$198 = 'resize'; + var factory_1$209 = factory$210; - return acsch; -} + var resize$3 = { + name: name$198, + factory: factory_1$209 + }; + + function factory$211 (type, config, load, typed) { + var matrix$$1 = load(matrix); -var name$241 = 'acsch'; -var factory_1$253 = factory$254; + /** + * Calculate the size of a matrix or scalar. + * + * Syntax: + * + * math.size(x) + * + * Examples: + * + * math.size(2.3); // returns [] + * math.size('hello world'); // returns [11] + * + * var A = [[1, 2, 3], [4, 5, 6]]; + * math.size(A); // returns [2, 3] + * math.size(math.range(1,6)); // returns [5] + * + * See also: + * + * resize, squeeze, subset + * + * @param {boolean | number | Complex | Unit | string | Array | Matrix} x A matrix + * @return {Array | Matrix} A vector with size of `x`. + */ + var size = typed('size', { + 'Matrix': function (x) { + // TODO: return the same matrix type as the input + return matrix$$1(x.size()); + }, -var acsch$1 = { - name: name$241, - factory: factory_1$253 -}; + 'Array': array.size, -function factory$255 (type, config, load, typed) { + 'string': function (x) { + return (config.matrix === 'Array') ? [x.length] : matrix$$1([x.length]); + }, - /** - * Calculate the inverse secant of a value. Defined as `asec(x) = acos(1/x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.asec(x) - * - * Examples: - * - * math.asec(0.5); // returns 1.0471975511965979 - * math.asec(math.sec(1.5)); // returns 1.5 - * - * math.asec(2); // returns 0 + 1.3169578969248166 i - * - * See also: - * - * acos, acot, acsc - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} The arc secant of x - */ - var asec = typed('asec', { - 'number': function (x) { - if (x <= -1 || x >= 1 || config.predictable) { - return Math.acos(1 / x); + 'number | Complex | BigNumber | Unit | boolean | null': function (x) { + // scalar + return (config.matrix === 'Array') ? [] : matrix$$1([]); } - return new type.Complex(x, 0).asec(); - }, - - 'Complex': function (x) { - return x.asec(); - }, + }); - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).acos(); - }, + size.toTex = undefined; // use default template - 'Array | Matrix': function (x) { - return deepMap(x, asec); - } - }); + return size; + } - asec.toTex = {1: '\\sec^{-1}\\left(${args[0]}\\right)'}; + var name$199 = 'size'; + var factory_1$210 = factory$211; - return asec; -} + var size$5 = { + name: name$199, + factory: factory_1$210 + }; -var name$242 = 'asec'; -var factory_1$254 = factory$255; + /* + * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license + * Author: Jim Palmer (based on chunking idea from Dave Koelle) + */ + /*jshint unused:false */ + var naturalSort = function naturalSort (a, b) { + var re = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, + sre = /(^[ ]*|[ ]*$)/g, + dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, + hre = /^0x[0-9a-f]+$/i, + ore = /^0/, + i = function(s) { return naturalSort.insensitive && ('' + s).toLowerCase() || '' + s; }, + // convert all to strings strip whitespace + x = i(a).replace(sre, '') || '', + y = i(b).replace(sre, '') || '', + // chunk/tokenize + xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), + yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), + // numeric, hex or date detection + xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && x.match(dre) && Date.parse(x)), + yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null, + oFxNcL, oFyNcL; + // first try and sort Hex codes or Dates + if (yD) { + if ( xD < yD ) { return -1; } + else if ( xD > yD ) { return 1; } + } + // natural sorting through split numeric strings and default strings + for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) { + // find floats not starting with '0', string or 0 if not defined (Clint Priest) + oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0; + oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0; + // handle numeric vs string comparison - number < string - (Kyle Adams) + if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; } + // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' + else if (typeof oFxNcL !== typeof oFyNcL) { + oFxNcL += ''; + oFyNcL += ''; + } + if (oFxNcL < oFyNcL) { return -1; } + if (oFxNcL > oFyNcL) { return 1; } + } + return 0; + }; + + function factory$212 (type, config, load, typed) { + var getTypeOf = load(_typeof$1); + var compare = load(compare$1); + + var compareBooleans = compare.signatures['boolean,boolean']; -var asec$1 = { - name: name$242, - factory: factory_1$254 -}; + /** + * Compare two values of any type in a deterministic, natural way. + * + * For numeric values, the function works the same as `math.compare`. + * For types of values that can't be compared mathematically, + * the function compares in a natural way. + * + * For numeric values, x and y are considered equal when the relative + * difference between x and y is smaller than the configured epsilon. + * The function cannot be used to compare values smaller than + * approximately 2.22e-16. + * + * For Complex numbers, first the real parts are compared. If equal, + * the imaginary parts are compared. + * + * Strings are compared with a natural sorting algorithm, which + * orders strings in a "logic" way following some heuristics. + * This differs from the function `compare`, which converts the string + * into a numeric value and compares that. The function `compareText` + * on the other hand compares text lexically. + * + * Arrays and Matrices are compared value by value until there is an + * unequal pair of values encountered. Objects are compared by sorted + * keys until the keys or their values are unequal. + * + * Syntax: + * + * math.compareNatural(x, y) + * + * Examples: + * + * math.compareNatural(6, 1); // returns 1 + * math.compareNatural(2, 3); // returns -1 + * math.compareNatural(7, 7); // returns 0 + * + * math.compareNatural('10', '2'); // returns 1 + * math.compareText('10', '2'); // returns -1 + * math.compare('10', '2'); // returns 1 + * + * math.compareNatural('Answer: 10', 'Answer: 2'); // returns 1 + * math.compareText('Answer: 10', 'Answer: 2'); // returns -1 + * math.compare('Answer: 10', 'Answer: 2'); + * // Error: Cannot convert "Answer: 10" to a number + * + * var a = math.unit('5 cm'); + * var b = math.unit('40 mm'); + * math.compareNatural(a, b); // returns 1 + * + * var c = math.complex('2 + 3i'); + * var d = math.complex('2 + 4i'); + * math.compareNatural(c, d); // returns -1 + * + * math.compareNatural([1, 2, 4], [1, 2, 3]); // returns 1 + * math.compareNatural([1, 2, 3], [1, 2]); // returns 1 + * math.compareNatural([1, 5], [1, 2, 3]); // returns 1 + * math.compareNatural([1, 2], [1, 2]); // returns 0 + * + * math.compareNatural({a: 2}, {a: 4}); // returns -1 + * + * See also: + * + * compare, compareText + * + * @param {*} x First value to compare + * @param {*} y Second value to compare + * @return {number} Returns the result of the comparison: + * 1 when x > y, -1 when x < y, and 0 when x == y. + */ + var compareNatural = typed('compareNatural', { + 'any, any': function (x, y) { + var typeX = getTypeOf(x); + var typeY = getTypeOf(y); + var c; + + // numeric types + if ((typeX === 'number' || typeX === 'BigNumber' || typeX === 'Fraction') && + (typeY === 'number' || typeY === 'BigNumber' || typeY === 'Fraction')) { + c = compare(x, y); + if (c.toString() !== '0') { + // c can be number, BigNumber, or Fraction + return c > 0 ? 1 : -1; // return a number + } + else { + return naturalSort(typeX, typeY); + } + } -function factory$256 (type, config, load, typed) { - var acosh = typed.find(load(acosh$1), ['Complex']); + // matrix types + if (typeX === 'Array' || typeX === 'Matrix' || + typeY === 'Array' || typeY === 'Matrix') { + c = compareMatricesAndArrays (x, y); + if (c !== 0) { + return c; + } + else { + return naturalSort(typeX, typeY); + } + } - /** - * Calculate the hyperbolic arcsecant of a value, - * defined as `asech(x) = acosh(1/x) = ln(sqrt(1/x^2 - 1) + 1/x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.asech(x) - * - * Examples: - * - * math.asech(0.5); // returns 1.3169578969248166 - * - * See also: - * - * acsch, acoth - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arcsecant of x - */ - var asech = typed('asech', { - 'number': function (x) { - if ((x <= 1 && x >= -1) || config.predictable) { - x = 1 / x; + // in case of different types, order by name of type, i.e. 'BigNumber' < 'Complex' + if (typeX !== typeY) { + return naturalSort(typeX, typeY); + } - var ret = Math.sqrt(x*x - 1); - if (x > 0 || config.predictable) { - return Math.log(ret + x); + if (typeX === 'Complex') { + return compareComplexNumbers(x, y); } - return new type.Complex(Math.log(ret - x), Math.PI); - } + if (typeX === 'Unit') { + if (x.equalBase(y)) { + return compareNatural(x.value, y.value); + } - return new type.Complex(x, 0).asech(); - }, + // compare by units + return compareArrays(x.formatUnits(), y.formatUnits()); + } - 'Complex': function (x) { - return x.asech() - }, + if (typeX === 'boolean') { + return compareBooleans(x, y); + } - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).acosh(); - }, + if (typeX === 'string') { + return naturalSort(x, y); + } - 'Array | Matrix': function (x) { - return deepMap(x, asech); - } - }); + if (typeX === 'Object') { + return compareObjects(x, y); + } - asech.toTex = {1: '\\mathrm{sech}^{-1}\\left(${args[0]}\\right)'}; + if (typeX === 'null') { + return 0; + } - return asech; -} + if (typeX === 'undefined') { + return 0; + } -var name$243 = 'asech'; -var factory_1$255 = factory$256; + // this should not occur... + throw new TypeError('Unsupported type of value "' + typeX + '"'); + } + }); -var asech$1 = { - name: name$243, - factory: factory_1$255 -}; + compareNatural.toTex = undefined; // use default template -function factory$257 (type, config, load, typed) { + /** + * Compare mixed matrix/array types, by converting to same-shaped array. + * This comparator is non-deterministic regarding input types. + * @param {Array | SparseMatrix | DenseMatrix | *} x + * @param {Array | SparseMatrix | DenseMatrix | *} y + * @returns {number} Returns the comparison result: -1, 0, or 1 + */ + function compareMatricesAndArrays (x, y) { + if (type.isSparseMatrix(x) && type.isSparseMatrix(y)) { + return compareArrays(x.toJSON().values, y.toJSON().values); + } + if (type.isSparseMatrix(x)) { + // note: convert to array is expensive + return compareMatricesAndArrays(x.toArray(), y); + } + if (type.isSparseMatrix(y)) { + // note: convert to array is expensive + return compareMatricesAndArrays(x, y.toArray()); + } - /** - * Calculate the inverse sine of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.asin(x) - * - * Examples: - * - * math.asin(0.5); // returns number 0.5235987755982989 - * math.asin(math.sin(1.5)); // returns number ~1.5 - * - * math.asin(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * sin, atan, acos - * - * @param {number | BigNumber | Complex | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} The arc sine of x - */ - var asin = typed('asin', { - 'number': function (x) { - if ((x >= -1 && x <= 1) || config.predictable) { - return Math.asin(x); + // convert DenseArray into Array + if (type.isDenseMatrix(x)) { + return compareMatricesAndArrays(x.toJSON().data, y); } - else { - return new type.Complex(x, 0).asin(); + if (type.isDenseMatrix(y)) { + return compareMatricesAndArrays(x, y.toJSON().data); } - }, - 'Complex': function (x) { - return x.asin(); - }, + // convert scalars to array + if (!Array.isArray(x)) { + return compareMatricesAndArrays([x], y); + } + if (!Array.isArray(y)) { + return compareMatricesAndArrays(x, [y]); + } - 'BigNumber': function (x) { - return x.asin(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since asin(0) = 0 - return deepMap(x, asin, true); + return compareArrays(x, y); } - }); - asin.toTex = {1: '\\sin^{-1}\\left(${args[0]}\\right)'}; + /** + * Compare two Arrays + * + * - First, compares value by value + * - Next, if all corresponding values are equal, + * look at the length: longest array will be considered largest + * + * @param {Array} x + * @param {Array} y + * @returns {number} Returns the comparison result: -1, 0, or 1 + */ + function compareArrays (x, y) { + // compare each value + for (var i = 0, ii = Math.min(x.length, y.length); i < ii; i++) { + var v = compareNatural(x[i], y[i]); + if (v !== 0) { + return v; + } + } + + // compare the size of the arrays + if (x.length > y.length) { return 1; } + if (x.length < y.length) { return -1; } + + // both Arrays have equal size and content + return 0; + } - return asin; -} + /** + * Compare two objects + * + * - First, compare sorted property names + * - Next, compare the property values + * + * @param {Object} x + * @param {Object} y + * @returns {number} Returns the comparison result: -1, 0, or 1 + */ + function compareObjects (x, y) { + var keysX = Object.keys(x); + var keysY = Object.keys(y); + + // compare keys + keysX.sort(naturalSort); + keysY.sort(naturalSort); + var c = compareArrays(keysX, keysY); + if (c !== 0) { + return c; + } -var name$244 = 'asin'; -var factory_1$256 = factory$257; + // compare values + for (var i = 0; i < keysX.length; i++) { + var v = compareNatural(x[keysX[i]], y[keysY[i]]); + if (v !== 0) { + return v; + } + } -var asin$1 = { - name: name$244, - factory: factory_1$256 -}; + return 0; + } -function factory$258 (type, config, load, typed) { + return compareNatural; + } /** - * Calculate the hyperbolic arcsine of a value, - * defined as `asinh(x) = ln(x + sqrt(x^2 + 1))`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.asinh(x) - * - * Examples: - * - * math.asinh(0.5); // returns 0.48121182505960347 + * Compare two complex numbers, `x` and `y`: * - * See also: - * - * acosh, atanh - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arcsine of x + * - First, compare the real values of `x` and `y` + * - If equal, compare the imaginary values of `x` and `y` + * + * @params {Complex} x + * @params {Complex} y + * @returns {number} Returns the comparison result: -1, 0, or 1 */ - var asinh = typed('asinh', { - 'number': Math.asinh || function (x) { - return Math.log(Math.sqrt(x*x + 1) + x); - }, + function compareComplexNumbers (x, y) { + if (x.re > y.re) { return 1; } + if (x.re < y.re) { return -1; } - 'Complex': function (x) { - return x.asinh(); - }, + if (x.im > y.im) { return 1; } + if (x.im < y.im) { return -1; } - 'BigNumber': function (x) { - return x.asinh(); - }, + return 0; + } - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since asinh(0) = 0 - return deepMap(x, asinh, true); - } - }); + var name$200 = 'compareNatural'; + var factory_1$211 = factory$212; - asinh.toTex = {1: '\\sinh^{-1}\\left(${args[0]}\\right)'}; + var compareNatural$1 = { + name: name$200, + factory: factory_1$211 + }; - return asinh; -} + var size$6 = array.size; -var name$245 = 'asinh'; -var factory_1$257 = factory$258; + function factory$213 (type, config, load, typed) { + var matrix$$1 = load(matrix); + var compareAsc = load(compare$1); + var compareDesc = function (a, b) { + return -compareAsc(a, b); + }; + var compareNatural = load(compareNatural$1); -var asinh$1 = { - name: name$245, - factory: factory_1$257 -}; + /** + * Sort the items in a matrix. + * + * Syntax: + * + * math.sort(x) + * math.sort(x, compare) + * + * Examples: + * + * math.sort([5, 10, 1]); // returns [1, 5, 10] + * math.sort(['C', 'B', 'A', 'D'], math.compareNatural); + * // returns ['A', 'B', 'C', 'D'] + * + * function sortByLength (a, b) { + * return a.length - b.length; + * } + * math.sort(['Langdon', 'Tom', 'Sara'], sortByLength); + * // returns ['Tom', 'Sara', 'Langdon'] + * + * See also: + * + * filter, forEach, map, compare, compareNatural + * + * @param {Matrix | Array} x A one dimensional matrix or array to sort + * @param {Function | 'asc' | 'desc' | 'natural'} [compare='asc'] + * An optional _comparator function or name. The function is called as + * `compare(a, b)`, and must return 1 when a > b, -1 when a < b, + * and 0 when a == b. + * @return {Matrix | Array} Returns the sorted matrix. + */ + var sort = typed('sort', { + 'Array': function (x) { + _arrayIsVector(x); + return x.sort(compareAsc); + }, -function factory$259 (type, config, load, typed) { + 'Matrix': function (x) { + _matrixIsVector(x); + return matrix$$1(x.toArray().sort(compareAsc), x.storage()); + }, - /** - * Calculate the inverse tangent of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.atan(x) - * - * Examples: - * - * math.atan(0.5); // returns number 0.4636476090008061 - * math.atan(math.tan(1.5)); // returns number 1.5 - * - * math.atan(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * tan, asin, acos - * - * @param {number | BigNumber | Complex | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} The arc tangent of x - */ - var atan = typed('atan', { - 'number': function (x) { - return Math.atan(x); - }, + 'Array, function': function (x, _comparator) { + _arrayIsVector(x); + return x.sort(_comparator); + }, - 'Complex': function (x) { - return x.atan(); - }, + 'Matrix, function': function (x, _comparator) { + _matrixIsVector(x); + return matrix$$1(x.toArray().sort(_comparator), x.storage()); + }, - 'BigNumber': function (x) { - return x.atan(); - }, + 'Array, string': function (x, order) { + _arrayIsVector(x); + return x.sort(_comparator(order)); + }, - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since atan(0) = 0 - return deepMap(x, atan, true); - } - }); + 'Matrix, string': function (x, order) { + _matrixIsVector(x); + return matrix$$1(x.toArray().sort(_comparator(order)), x.storage()); + } + }); + + sort.toTex = undefined; // use default template - atan.toTex = {1: '\\tan^{-1}\\left(${args[0]}\\right)'}; + /** + * Get the comparator for given order ('asc', 'desc', 'natural') + * @param {'asc' | 'desc' | 'natural'} order + * @return {Function} Returns a _comparator function + */ + function _comparator (order) { + if (order === 'asc') { + return compareAsc; + } + else if (order === 'desc') { + return compareDesc; + } + else if (order === 'natural') { + return compareNatural; + } + else { + throw new Error('String "asc", "desc", or "natural" expected'); + } + } - return atan; -} + /** + * Validate whether an array is one dimensional + * Throws an error when this is not the case + * @param {Array} array + * @private + */ + function _arrayIsVector (array$$1) { + if (size$6(array$$1).length !== 1) { + throw new Error('One dimensional array expected'); + } + } -var name$246 = 'atan'; -var factory_1$258 = factory$259; + /** + * Validate whether a matrix is one dimensional + * Throws an error when this is not the case + * @param {Matrix} matrix + * @private + */ + function _matrixIsVector (matrix$$1) { + if (matrix$$1.size().length !== 1) { + throw new Error('One dimensional matrix expected'); + } + } -var atan$1 = { - name: name$246, - factory: factory_1$258 -}; + return sort; + } -function factory$260 (type, config, load, typed) { + var name$201 = 'sort'; + var factory_1$212 = factory$213; - var matrix$$1 = load(matrix); + var sort$1 = { + name: name$201, + factory: factory_1$212 + }; - var algorithm02$$1 = load(algorithm02); - var algorithm03$$1 = load(algorithm03); - var algorithm09$$1 = load(algorithm09); - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + function factory$214(type, config, load, typed) { + var matrix$$1 = load(matrix); + var abs = load(abs$1); + var add$$1 = load(add); + var divide = load(divide$1); + var multiply = load(multiply$1); + var sqrt = load(sqrt$1); + var subtract = load(subtract$1); + var inv = load(inv$1); + var size = load(size$5); + var max = load(max$1); + var eye = load(eye$1); - /** - * Calculate the inverse tangent function with two arguments, y/x. - * By providing two arguments, the right quadrant of the computed angle can be - * determined. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.atan2(y, x) - * - * Examples: - * - * math.atan2(2, 2) / math.pi; // returns number 0.25 - * - * var angle = math.unit(60, 'deg'); // returns Unit 60 deg - * var x = math.cos(angle); - * var y = math.sin(angle); - * - * math.atan(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * tan, atan, sin, cos - * - * @param {number | Array | Matrix} y Second dimension - * @param {number | Array | Matrix} x First dimension - * @return {number | Array | Matrix} Four-quadrant inverse tangent - */ - var atan2 = typed('atan2', { + /** + * Calculate the principal square root of a square matrix. + * The principal square root matrix `X` of another matrix `A` is such that `X * X = A`. + * + * https://en.wikipedia.org/wiki/Square_root_of_a_matrix + * + * Syntax: + * + * X = math.sqrtm(A) + * + * Examples: + * + * math.sqrtm([[1, 2], [3, 4]]); // returns [[-2, 1], [1.5, -0.5]] + * + * See also: + * + * sqrt, pow + * + * @param {Array | Matrix} A The square matrix `A` + * @return {Array | Matrix} The principal square root of matrix `A` + */ + var sqrtm = typed('sqrtm', { + 'Array | Matrix': function (A) { + var size = type.isMatrix(A) ? A.size() : array.size(A); + switch (size.length) { + case 1: + // Single element Array | Matrix + if (size[0] == 1) { + return sqrt(A); + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); + } - 'number, number': Math.atan2, + case 2: + // Two-dimensional Array | Matrix + var rows = size[0]; + var cols = size[1]; + if (rows == cols) { + return _denmanBeavers(A); + } + else { + throw new RangeError('Matrix must be square ' + + '(size: ' + string.format(size) + ')'); + } + } + } + }); - // Complex numbers doesn't seem to have a reasonable implementation of - // atan2(). Even Matlab removed the support, after they only calculated - // the atan only on base of the real part of the numbers and ignored the imaginary. + var _maxIterations = 1e3; + var _tolerance = 1e-6; - 'BigNumber, BigNumber': function (y, x) { - return type.BigNumber.atan2(y, x); - }, + /** + * Calculate the principal square root matrix using the Denman–Beavers iterative method + * + * https://en.wikipedia.org/wiki/Square_root_of_a_matrix#By_Denman–Beavers_iteration + * + * @param {Array | Matrix} A The square matrix `A` + * @return {Array | Matrix} The principal square root of matrix `A` + * @private + */ + function _denmanBeavers(A) { + var error; + var iterations = 0; - 'SparseMatrix, SparseMatrix': function (x, y) { - return algorithm09$$1(x, y, atan2, false); - }, + var Y = A; + var Z = eye(size(A)); - 'SparseMatrix, DenseMatrix': function (x, y) { - // mind the order of y and x! - return algorithm02$$1(y, x, atan2, true); - }, + do { + var Y_k = Y; + Y = multiply(0.5, add$$1(Y_k, inv(Z))); + Z = multiply(0.5, add$$1(Z, inv(Y_k))); - 'DenseMatrix, SparseMatrix': function (x, y) { - return algorithm03$$1(x, y, atan2, false); - }, + error = max(abs(subtract(Y, Y_k))); - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, atan2); - }, + if (error > _tolerance && ++iterations > _maxIterations) { + throw new Error('computing square root of matrix: iterative method could not converge'); + } + } while (error > _tolerance); - 'Array, Array': function (x, y) { - return atan2(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + return Y; + } - 'Array, Matrix': function (x, y) { - return atan2(matrix$$1(x), y); - }, + sqrtm.toTex = {1: '{${args[0]}}' + latex.operators['pow'] + '{\\frac{1}{2}}'}; - 'Matrix, Array': function (x, y) { - return atan2(x, matrix$$1(y)); - }, + return sqrtm; + } - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm11$$1(x, y, atan2, false); - }, + var name$202 = 'sqrtm'; + var factory_1$213 = factory$214; - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, atan2, false); - }, + var sqrtm$1 = { + name: name$202, + factory: factory_1$213 + }; - 'number | BigNumber, SparseMatrix': function (x, y) { - // mind the order of y and x - return algorithm12$$1(y, x, atan2, true); - }, + function factory$215 (type, config, load, typed) { + var matrix$$1 = load(matrix); - 'number | BigNumber, DenseMatrix': function (x, y) { - // mind the order of y and x - return algorithm14$$1(y, x, atan2, true); - }, + /** + * Squeeze a matrix, remove inner and outer singleton dimensions from a matrix. + * + * Syntax: + * + * math.squeeze(x) + * + * Examples: + * + * math.squeeze([3]); // returns 3 + * math.squeeze([[3]]); // returns 3 + * + * var A = math.zeros(3, 1); // returns [[0], [0], [0]] (size 3x1) + * math.squeeze(A); // returns [0, 0, 0] (size 3) + * + * var B = math.zeros(1, 3); // returns [[0, 0, 0]] (size 1x3) + * math.squeeze(B); // returns [0, 0, 0] (size 3) + * + * // only inner and outer dimensions are removed + * var C = math.zeros(2, 1, 3); // returns [[[0, 0, 0]], [[0, 0, 0]]] (size 2x1x3) + * math.squeeze(C); // returns [[[0, 0, 0]], [[0, 0, 0]]] (size 2x1x3) + * + * See also: + * + * subset + * + * @param {Matrix | Array} x Matrix to be squeezed + * @return {Matrix | Array} Squeezed matrix + */ + var squeeze = typed('squeeze', { + 'Array': function (x) { + return array.squeeze(object.clone(x)); + }, - 'Array, number | BigNumber': function (x, y) { - return algorithm14$$1(matrix$$1(x), y, atan2, false).valueOf(); - }, + 'Matrix': function (x) { + var res = array.squeeze(x.toArray()); + // FIXME: return the same type of matrix as the input + return Array.isArray(res) ? matrix$$1(res) : res; + }, - 'number | BigNumber, Array': function (x, y) { - return algorithm14$$1(matrix$$1(y), x, atan2, true).valueOf(); - } - }); + 'any': function (x) { + // scalar + return object.clone(x); + } + }); - atan2.toTex = {2: '\\mathrm{atan2}\\left(${args}\\right)'}; + squeeze.toTex = undefined; // use default template + + return squeeze; + } + + var name$203 = 'squeeze'; + var factory_1$214 = factory$215; + + var squeeze$1 = { + name: name$203, + factory: factory_1$214 + }; + + var matrix$3 = [ + concat$1, + cross$1, + det$1, + diag$1, + dot$1, + eye$1, + expm$1, + filter_1, + flatten$3, + forEach_1, + inv$1, + kron$1, + map$7, + ones$1, + partitionSelect$1, + range$1, + reshape$1, + resize$3, + size$5, + sort$1, + sqrtm$1, + squeeze$1, + subset$1, + trace$1, + transpose$1, + zeros$1 + ]; - return atan2; -} + function factory$216 (type, config, load, typed) { + var add = load(addScalar); + var improveErrorMessage$$1 = load(improveErrorMessage); -var name$247 = 'atan2'; -var factory_1$259 = factory$260; + /** + * Compute the sum of a matrix or a list with values. + * In case of a (multi dimensional) array or matrix, the sum of all + * elements will be calculated. + * + * Syntax: + * + * math.sum(a, b, c, ...) + * math.sum(A) + * + * Examples: + * + * math.sum(2, 1, 4, 3); // returns 10 + * math.sum([2, 1, 4, 3]); // returns 10 + * math.sum([[2, 5], [4, 3], [1, 7]]); // returns 22 + * + * See also: + * + * mean, median, min, max, prod, std, var + * + * @param {... *} args A single matrix or or multiple scalar values + * @return {*} The sum of all values + */ + var sum = typed('sum', { + 'Array | Matrix': function (args) { + // sum([a, b, c, d, ...]) + return _sum(args); + }, -var atan2$1 = { - name: name$247, - factory: factory_1$259 -}; + 'Array | Matrix, number | BigNumber': function () { + // sum([a, b, c, d, ...], dim) + // TODO: implement sum(A, dim) + throw new Error('sum(A, dim) is not yet supported'); + }, -function factory$261 (type, config, load, typed) { - /** - * Calculate the hyperbolic arctangent of a value, - * defined as `atanh(x) = ln((1 + x)/(1 - x)) / 2`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.atanh(x) - * - * Examples: - * - * math.atanh(0.5); // returns 0.5493061443340549 - * - * See also: - * - * acosh, asinh - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arctangent of x - */ - var atanh = typed('atanh', { - 'number': function (x) { - if ((x <= 1 && x >= -1) || config.predictable) { - return _atanh(x); + '...': function (args) { + // sum(a, b, c, d, ...) + return _sum(args); } - return new type.Complex(x, 0).atanh(); - }, + }); - 'Complex': function (x) { - return x.atanh(); - }, + sum.toTex = undefined; // use default template - 'BigNumber': function (x) { - return x.atanh(); - }, + return sum; + + /** + * Recursively calculate the sum of an n-dimensional array + * @param {Array} array + * @return {number} sum + * @private + */ + function _sum(array) { + var sum = undefined; + + deepForEach(array, function (value) { + try { + sum = (sum === undefined) ? value : add(sum, value); + } + catch (err) { + throw improveErrorMessage$$1(err, 'sum', value); + } + }); - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since atanh(0) = 0 - return deepMap(x, atanh, true); + if (sum === undefined) { + switch (config.number) { + case 'number': + return 0; + case 'BigNumber': + return new type.BigNumber(0); + case 'Fraction': + return new type.Fraction(0); + default: + return 0; + } + } + + return sum; } - }); + } - atanh.toTex = {1: '\\tanh^{-1}\\left(${args[0]}\\right)'}; + var name$204 = 'sum'; + var factory_1$215 = factory$216; - return atanh; -} + var sum$1 = { + name: name$204, + factory: factory_1$215 + }; -/** - * Calculate the hyperbolic arctangent of a number - * @param {number} x - * @return {number} - * @private - */ -var _atanh = Math.atanh || function (x) { - return Math.log((1 + x)/(1 - x)) / 2 -}; + function factory$217(type, config, load, typed) { + var matrix$$1 = load(matrix); + var divide = load(divide$1); + var sum = load(sum$1); + var multiply = load(multiply$1); + var dotDivide = load(dotDivide$1); + var log = load(log$1); + var isNumeric = load(isNumeric$1); -var name$248 = 'atanh'; -var factory_1$260 = factory$261; + /** + * Calculate the Kullback-Leibler (KL) divergence between two distributions + * + * Syntax: + * + * math.kldivergence(x, y) + * + * Examples: + * + * math.kldivergence([0.7,0.5,0.4], [0.2,0.9,0.5]); //returns 0.24376698773121153 + * + * + * @param {Array | Matrix} q First vector + * @param {Array | Matrix} p Second vector + * @return {number} Returns distance between q and p + */ + var kldivergence = typed('kldivergence', { + 'Array, Array': function(q, p) { + return _kldiv(matrix$$1(q), matrix$$1(p)); + }, -var atanh$1 = { - name: name$248, - factory: factory_1$260 -}; + 'Matrix, Array': function(q, p) { + return _kldiv(q, matrix$$1(p)); + }, -function factory$262 (type, config, load, typed) { + 'Array, Matrix': function(q, p){ + return _kldiv(matrix$$1(q), p); + }, - /** - * Calculate the cosine of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cos(x) - * - * Examples: - * - * math.cos(2); // returns number -0.4161468365471422 - * math.cos(math.pi / 4); // returns number 0.7071067811865475 - * math.cos(math.unit(180, 'deg')); // returns number -1 - * math.cos(math.unit(60, 'deg')); // returns number 0.5 - * - * var angle = 0.2; - * math.pow(math.sin(angle), 2) + math.pow(math.cos(angle), 2); // returns number ~1 - * - * See also: - * - * cos, tan - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Cosine of x - */ - var cos = typed('cos', { - 'number': Math.cos, - - 'Complex': function (x) { - return x.cos(); - }, + 'Matrix, Matrix': function(q, p){ + return _kldiv(q, p); + } - 'BigNumber': function (x) { - return x.cos(); - }, + }); - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cos is no angle'); - } - return cos(x.value); - }, + function _kldiv(q, p) { + var plength = p.size().length; + var qlength = q.size().length; + if (plength > 1) { + throw new Error('first object must be one dimensional'); + } + + if (qlength > 1) { + throw new Error('second object must be one dimensional'); + } + + if(plength !== qlength){ + throw new Error("Length of two vectors must be equal"); + } + + //Before calculation, apply normalization + var sumq = sum(q); + if (sumq === 0) { + throw new Error("Sum of elements in first object must be non zero"); + } - 'Array | Matrix': function (x) { - return deepMap(x, cos); - } - }); + var sump = sum(p); + if (sump === 0) { + throw new Error("Sum of elements in second object must be non zero"); + } + var qnorm = divide(q, sum(q)); + var pnorm = divide(p, sum(p)); - cos.toTex = {1: '\\cos\\left(${args[0]}\\right)'}; + var result = sum(multiply(qnorm, log(dotDivide(qnorm, pnorm)))); + if (isNumeric(result)) { + return result; + } + else { + return Number.NaN; + } + } - return cos; -} + return kldivergence; + } -var name$249 = 'cos'; -var factory_1$261 = factory$262; -var cos$1 = { - name: name$249, - factory: factory_1$261 -}; + var name$205 = 'kldivergence'; + var factory_1$216 = factory$217; -function factory$263 (type, config, load, typed) { - /** - * Calculate the hyperbolic cosine of a value, - * defined as `cosh(x) = 1/2 * (exp(x) + exp(-x))`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cosh(x) - * - * Examples: - * - * math.cosh(0.5); // returns number 1.1276259652063807 - * - * See also: - * - * sinh, tanh - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic cosine of x - */ - var cosh = typed('cosh', { - 'number': _cosh, - - 'Complex': function (x) { - return x.cosh(); - }, - - 'BigNumber': function (x) { - return x.cosh(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cosh is no angle'); - } - return cosh(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, cosh); - } - }); - - cosh.toTex = {1: '\\cosh\\left(${args[0]}\\right)'}; - - return cosh; -} - -/** - * Calculate the hyperbolic cosine of a number - * @param {number} x - * @returns {number} - * @private - */ -var _cosh = Math.cosh || function (x) { - return (Math.exp(x) + Math.exp(-x)) / 2; -}; - -var name$250 = 'cosh'; -var factory_1$262 = factory$263; + var kldivergence$1 = { + name: name$205, + factory: factory_1$216 + }; -var cosh$1 = { - name: name$250, - factory: factory_1$262 -}; + function factory$218 (type, config, load, typed) { + var add$$1 = load(add); + var multiply = load(multiply$1); + var divide = load(divide$1); + var factorial = load(factorial$1); + var isInteger = load(isInteger$22); + var isPositive = load(isPositive$1); -function factory$264 (type, config, load, typed) { - /** - * Calculate the cotangent of a value. Defined as `cot(x) = 1 / tan(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cot(x) - * - * Examples: - * - * math.cot(2); // returns number -0.45765755436028577 - * 1 / math.tan(2); // returns number -0.45765755436028577 - * - * See also: - * - * tan, sec, csc - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Cotangent of x - */ - var cot = typed('cot', { - 'number': function (x) { - return 1 / Math.tan(x); - }, + /** + * Multinomial Coefficients compute the number of ways of picking a1, a2, ..., ai unordered outcomes from `n` possibilities. + * + * multinomial takes one array of integers as an argument. + * The following condition must be enforced: every ai <= 0 + * + * Syntax: + * + * math.multinomial(a) // a is an array type + * + * Examples: + * + * math.multinomial([1,2,1]); // returns 12 + * + * See also: + * + * combinations, factorial + * + * @param {number[] | BigNumber[]} a Integer numbers of objects in the subset + * @return {Number | BigNumber} Multinomial coefficient. + */ + return typed('multinomial', { + 'Array | Matrix': function (a) { + var sum = 0; + var denom = 1; + + deepForEach(a, function(ai) { + if(!isInteger(ai) || !isPositive(ai)) { + throw new TypeError('Positive integer value expected in function multinomial'); + } + sum = add$$1(sum, ai); + denom = multiply(denom, factorial(ai)); + }); - 'Complex': function (x) { - return x.cot(); - }, + return divide(factorial(sum), denom); + } + }); + } - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.tan()); - }, + var name$206 = 'multinomial'; + var factory_1$217 = factory$218; - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cot is no angle'); - } - return cot(x.value); - }, + var multinomial$1 = { + name: name$206, + factory: factory_1$217 + }; - 'Array | Matrix': function (x) { - return deepMap(x, cot); - } - }); + var isInteger$28 = number.isInteger; - cot.toTex = {1: '\\cot\\left(${args[0]}\\right)'}; + function factory$219 (type, config, load, typed) { + var factorial = load(factorial$1); - return cot; -} + /** + * Compute the number of ways of obtaining an ordered subset of `k` elements + * from a set of `n` elements. + * + * Permutations only takes integer arguments. + * The following condition must be enforced: k <= n. + * + * Syntax: + * + * math.permutations(n) + * math.permutations(n, k) + * + * Examples: + * + * math.permutations(5); // 120 + * math.permutations(5, 3); // 60 + * + * See also: + * + * combinations, factorial + * + * @param {number | BigNumber} n The number of objects in total + * @param {number | BigNumber} [k] The number of objects in the subset + * @return {number | BigNumber} The number of permutations + */ + var permutations = typed('permutations', { + 'number | BigNumber': factorial, -var name$251 = 'cot'; -var factory_1$263 = factory$264; + 'number, number': function (n, k) { + var result, i; -var cot$1 = { - name: name$251, - factory: factory_1$263 -}; + if (!isInteger$28(n) || n < 0) { + throw new TypeError('Positive integer value expected in function permutations'); + } + if (!isInteger$28(k) || k < 0) { + throw new TypeError('Positive integer value expected in function permutations'); + } + if (k > n) { + throw new TypeError('second argument k must be less than or equal to first argument n'); + } -function factory$265 (type, config, load, typed) { - /** - * Calculate the hyperbolic cotangent of a value, - * defined as `coth(x) = 1 / tanh(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.coth(x) - * - * Examples: - * - * // coth(x) = 1 / tanh(x) - * math.coth(2); // returns 1.0373147207275482 - * 1 / math.tanh(2); // returns 1.0373147207275482 - * - * See also: - * - * sinh, tanh, cosh - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic cotangent of x - */ - var coth = typed('coth', { - 'number': _coth, - - 'Complex': function (x) { - return x.coth(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.tanh()); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function coth is no angle'); - } - return coth(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, coth); - } - }); - - coth.toTex = {1: '\\coth\\left(${args[0]}\\right)'}; - - return coth; -} - -/** - * Calculate the hyperbolic cosine of a number - * @param {number} x - * @returns {number} - * @private - */ -function _coth(x) { - var e = Math.exp(2 * x); - return (e + 1) / (e - 1); -} - -var name$252 = 'coth'; -var factory_1$264 = factory$265; + // Permute n objects, k at a time + result = 1; + for (i = n - k + 1; i <= n; i++) { + result = result * i; + } -var coth$1 = { - name: name$252, - factory: factory_1$264 -}; + return result; + }, -function factory$266 (type, config, load, typed) { - /** - * Calculate the cosecant of a value, defined as `csc(x) = 1/sin(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.csc(x) - * - * Examples: - * - * math.csc(2); // returns number 1.099750170294617 - * 1 / math.sin(2); // returns number 1.099750170294617 - * - * See also: - * - * sin, sec, cot - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Cosecant of x - */ - var csc = typed('csc', { - 'number': function (x) { - return 1 / Math.sin(x); - }, + 'BigNumber, BigNumber': function (n, k) { + var result, i; - 'Complex': function (x) { - return x.csc(); - }, + if (!isPositiveInteger$1(n) || !isPositiveInteger$1(k)) { + throw new TypeError('Positive integer value expected in function permutations'); + } + if (k.gt(n)) { + throw new TypeError('second argument k must be less than or equal to first argument n'); + } - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.sin()); - }, + result = new type.BigNumber(1); + for (i = n.minus(k).plus(1); i.lte(n); i = i.plus(1)) { + result = result.times(i); + } - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function csc is no angle'); + return result; } - return csc(x.value); - }, - 'Array | Matrix': function (x) { - return deepMap(x, csc); - } - }); + // TODO: implement support for collection in permutations + }); + + permutations.toTex = undefined; // use default template - csc.toTex = {1: '\\csc\\left(${args[0]}\\right)'}; + return permutations; + } - return csc; -} + /** + * Test whether BigNumber n is a positive integer + * @param {BigNumber} n + * @returns {boolean} isPositiveInteger + */ + function isPositiveInteger$1(n) { + return n.isInteger() && n.gte(0); + } -var name$253 = 'csc'; -var factory_1$265 = factory$266; + var name$207 = 'permutations'; + var factory_1$218 = factory$219; -var csc$1 = { - name: name$253, - factory: factory_1$265 -}; + var permutations$1 = { + name: name$207, + factory: factory_1$218 + }; -var sign$3 = number.sign; + var seedRandom = createCommonjsModule(function (module) { -function factory$267 (type, config, load, typed) { - /** - * Calculate the hyperbolic cosecant of a value, - * defined as `csch(x) = 1 / sinh(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.csch(x) - * - * Examples: - * - * // csch(x) = 1/ sinh(x) - * math.csch(0.5); // returns 1.9190347513349437 - * 1 / math.sinh(0.5); // returns 1.9190347513349437 - * - * See also: - * - * sinh, sech, coth - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic cosecant of x - */ - var csch = typed('csch', { - 'number': _csch, + var width = 256;// each RC4 output is 0 <= x < 256 + var chunks = 6;// at least six RC4 outputs for each double + var digits = 52;// there are 52 significant digits in a double + var pool = [];// pool: entropy pool starts empty + var GLOBAL = typeof commonjsGlobal === 'undefined' ? window : commonjsGlobal; - 'Complex': function (x) { - return x.csch(); - }, + // + // The following constants are related to IEEE 754 limits. + // + var startdenom = Math.pow(width, chunks), + significance = Math.pow(2, digits), + overflow = significance * 2, + mask = width - 1; - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.sinh()); - }, - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function csch is no angle'); - } - return csch(x.value); - }, + var oldRandom = Math.random; - 'Array | Matrix': function (x) { - return deepMap(x, csch); + // + // seedrandom() + // This is the seedrandom function described above. + // + module.exports = function(seed, options) { + if (options && options.global === true) { + options.global = false; + Math.random = module.exports(seed, options); + options.global = true; + return Math.random; } - }); - - csch.toTex = {1: '\\mathrm{csch}\\left(${args[0]}\\right)'}; - - return csch; -} - -/** - * Calculate the hyperbolic cosecant of a number - * @param {number} x - * @returns {number} - * @private - */ -function _csch(x) { - // consider values close to zero (+/-) - if (x == 0) { - return Number.POSITIVE_INFINITY; - } - else { - return Math.abs(2 / (Math.exp(x) - Math.exp(-x))) * sign$3(x); - } -} + var use_entropy = (options && options.entropy) || false; + var key = []; -var name$254 = 'csch'; -var factory_1$266 = factory$267; - -var csch$1 = { - name: name$254, - factory: factory_1$266 -}; - -function factory$268 (type, config, load, typed) { - /** - * Calculate the secant of a value, defined as `sec(x) = 1/cos(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sec(x) - * - * Examples: - * - * math.sec(2); // returns number -2.4029979617223822 - * 1 / math.cos(2); // returns number -2.4029979617223822 - * - * See also: - * - * cos, csc, cot - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Secant of x - */ - var sec = typed('sec', { - 'number': function (x) { - return 1 / Math.cos(x); - }, - - 'Complex': function (x) { - return x.sec(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.cos()); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sec is no angle'); - } - return sec(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, sec); - } - }); - - sec.toTex = {1: '\\sec\\left(${args[0]}\\right)'}; - - return sec; -} - -var name$255 = 'sec'; -var factory_1$267 = factory$268; - -var sec$1 = { - name: name$255, - factory: factory_1$267 -}; - -function factory$269 (type, config, load, typed) { - /** - * Calculate the hyperbolic secant of a value, - * defined as `sech(x) = 1 / cosh(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sech(x) - * - * Examples: - * - * // sech(x) = 1/ cosh(x) - * math.sech(0.5); // returns 0.886818883970074 - * 1 / math.cosh(0.5); // returns 0.886818883970074 - * - * See also: - * - * cosh, csch, coth - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic secant of x - */ - var sech = typed('sech', { - 'number': _sech, + // Flatten the seed string or build one from local entropy if needed. + var shortseed = mixkey(flatten( + use_entropy ? [seed, tostring(pool)] : + 0 in arguments ? seed : autoseed(), 3), key); + + // Use the seed to initialize an ARC4 generator. + var arc4 = new ARC4(key); + + // Mix the randomness into accumulated entropy. + mixkey(tostring(arc4.S), pool); + + // Override Math.random + + // This function returns a random double in [0, 1) that contains + // randomness in every bit of the mantissa of the IEEE 754 value. + + return function() { // Closure to return a random double: + var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 + d = startdenom, // and denominator d = 2 ^ 48. + x = 0; // and no 'extra last byte'. + while (n < significance) { // Fill up all significant digits by + n = (n + x) * width; // shifting numerator and + d *= width; // denominator and generating a + x = arc4.g(1); // new least-significant-byte. + } + while (n >= overflow) { // To avoid rounding up, before adding + n /= 2; // last byte, shift everything + d /= 2; // right using integer Math until + x >>>= 1; // we have exactly the desired bits. + } + return (n + x) / d; // Form the number within [0, 1). + }; + }; - 'Complex': function (x) { - return x.sech(); - }, + module.exports.resetGlobal = function () { + Math.random = oldRandom; + }; - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.cosh()); - }, + // + // ARC4 + // + // An ARC4 implementation. The constructor takes a key in the form of + // an array of at most (width) integers that should be 0 <= x < (width). + // + // The g(count) method returns a pseudorandom integer that concatenates + // the next (count) outputs from ARC4. Its return value is a number x + // that is in the range 0 <= x < (width ^ count). + // + /** @constructor */ + function ARC4(key) { + var t, keylen = key.length, + me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; + + // The empty key [] is treated as [0]. + if (!keylen) { key = [keylen++]; } + + // Set up S using the standard key scheduling algorithm. + while (i < width) { + s[i] = i++; + } + for (i = 0; i < width; i++) { + s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; + s[j] = t; + } - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sech is no angle'); + // The "g" method returns the next (count) outputs as one number. + (me.g = function(count) { + // Using instance members instead of closure state nearly doubles speed. + var t, r = 0, + i = me.i, j = me.j, s = me.S; + while (count--) { + t = s[i = mask & (i + 1)]; + r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; } - return sech(x.value); - }, + me.i = i; me.j = j; + return r; + // For robust unpredictability discard an initial batch of values. + // See http://www.rsa.com/rsalabs/node.asp?id=2009 + })(width); + } - 'Array | Matrix': function (x) { - return deepMap(x, sech); + // + // flatten() + // Converts an object tree to nested arrays of strings. + // + function flatten(obj, depth) { + var result = [], typ = (typeof obj)[0], prop; + if (depth && typ == 'o') { + for (prop in obj) { + try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} + } } - }); + return (result.length ? result : typ == 's' ? obj : obj + '\0'); + } - sech.toTex = {1: '\\mathrm{sech}\\left(${args[0]}\\right)'}; + // + // mixkey() + // Mixes a string seed into a key that is an array of integers, and + // returns a shortened string seed that is equivalent to the result key. + // + function mixkey(seed, key) { + var stringseed = seed + '', smear, j = 0; + while (j < stringseed.length) { + key[mask & j] = + mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); + } + return tostring(key); + } - return sech; -} + // + // autoseed() + // Returns an object for autoseeding, using window.crypto if available. + // + /** @param {Uint8Array=} seed */ + function autoseed(seed) { + try { + GLOBAL.crypto.getRandomValues(seed = new Uint8Array(width)); + return tostring(seed); + } catch (e) { + return [+new Date, GLOBAL, GLOBAL.navigator && GLOBAL.navigator.plugins, + GLOBAL.screen, tostring(pool)]; + } + } -/** - * Calculate the hyperbolic secant of a number - * @param {number} x - * @returns {number} - * @private - */ -function _sech(x) { - return 2 / (Math.exp(x) + Math.exp(-x)); -} + // + // tostring() + // Converts an array of charcodes to a string + // + function tostring(a) { + return String.fromCharCode.apply(0, a); + } -var name$256 = 'sech'; -var factory_1$268 = factory$269; + // + // When seedrandom.js is loaded, we immediately mix a few bits + // from the built-in RNG into the entropy pool. Because we do + // not want to intefere with determinstic PRNG state later, + // seedrandom will not call Math.random on its own again after + // initialization. + // + mixkey(Math.random(), pool); + }); + var seedRandom_1 = seedRandom.resetGlobal; -var sech$1 = { - name: name$256, - factory: factory_1$268 -}; + // create a random seed here to prevent an infinite loop from seed-random + // inside the factory. Reason is that math.random is defined as a getter/setter + // and seed-random generates a seed from the local entropy by reading every + // defined object including `math` itself. That means that whilst getting + // math.random, it tries to get math.random, etc... an infinite loop. + // See https://github.com/ForbesLindesay/seed-random/issues/6 + var singletonRandom = seedRandom(); -function factory$270 (type, config, load, typed) { + function factory$220 (type, config, load, typed, math) { + var random; - /** - * Calculate the sine of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sin(x) - * - * Examples: - * - * math.sin(2); // returns number 0.9092974268256813 - * math.sin(math.pi / 4); // returns number 0.7071067811865475 - * math.sin(math.unit(90, 'deg')); // returns number 1 - * math.sin(math.unit(30, 'deg')); // returns number 0.5 - * - * var angle = 0.2; - * math.pow(math.sin(angle), 2) + math.pow(math.cos(angle), 2); // returns number ~1 - * - * See also: - * - * cos, tan - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Sine of x - */ - var sin = typed('sin', { - 'number': Math.sin, + // create a new random generator with given seed + function setSeed (seed) { + random = seed === null ? singletonRandom : seedRandom(String(seed)); + } - 'Complex': function (x) { - return x.sin(); - }, + // initialize a seeded pseudo random number generator with config's random seed + setSeed(config.randomSeed); - 'BigNumber': function (x) { - return x.sin(); - }, + // wrapper function so the rng can be updated via generator + function rng() { + return random(); + } - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sin is no angle'); + // updates generator with a new instance of a seeded pseudo random number generator + math.on('config', function (curr, prev, changes) { + // if the user specified a randomSeed + if(changes.randomSeed !== undefined) { + // update generator with a new instance of a seeded pseudo random number generator + setSeed(curr.randomSeed); } - return sin(x.value); - }, + }); - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since sin(0) = 0 - return deepMap(x, sin, true); - } - }); + return rng; + } - sin.toTex = {1: '\\sin\\left(${args[0]}\\right)'}; + var factory_1$219 = factory$220; + var math$17 = true; - return sin; -} + var seededRNG = { + factory: factory_1$219, + math: math$17 + }; -var name$257 = 'sin'; -var factory_1$269 = factory$270; + var isNumber$3 = number.isNumber; -var sin$1 = { - name: name$257, - factory: factory_1$269 -}; + // TODO: rethink math.distribution + // TODO: rework to a typed function + function factory$221 (type, config, load, typed, math) { + var matrix$$1 = load(matrix); + var array$$1 = array; -function factory$271 (type, config, load, typed) { - /** - * Calculate the hyperbolic sine of a value, - * defined as `sinh(x) = 1/2 * (exp(x) - exp(-x))`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sinh(x) - * - * Examples: - * - * math.sinh(0.5); // returns number 0.5210953054937474 - * - * See also: - * - * cosh, tanh - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic sine of x - */ - var sinh = typed('sinh', { - 'number': _sinh, - - 'Complex': function (x) { - return x.sinh(); - }, - - 'BigNumber': function (x) { - return x.sinh(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sinh is no angle'); - } - return sinh(x.value); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since sinh(0) = 0 - return deepMap(x, sinh, true); - } - }); - - sinh.toTex = {1: '\\sinh\\left(${args[0]}\\right)'}; - - return sinh; -} - -/** - * Calculate the hyperbolic sine of a number - * @param {number} x - * @returns {number} - * @private - */ -var _sinh = Math.sinh || function (x) { - return (Math.exp(x) - Math.exp(-x)) / 2; -}; - -var name$258 = 'sinh'; -var factory_1$270 = factory$271; + // seeded pseudo random number generator + var rng = load(seededRNG); -var sinh$1 = { - name: name$258, - factory: factory_1$270 -}; + /** + * Create a distribution object with a set of random functions for given + * random distribution. + * + * Syntax: + * + * math.distribution(name) + * + * Examples: + * + * var normalDist = math.distribution('normal'); // create a normal distribution + * normalDist.random(0, 10); // get a random value between 0 and 10 + * + * See also: + * + * random, randomInt, pickRandom + * + * @param {string} name Name of a distribution. Choose from 'uniform', 'normal'. + * @return {Object} Returns a distribution object containing functions: + * `random([size] [, min] [, max])`, + * `randomInt([min] [, max])`, + * `pickRandom(array)` + */ + function distribution(name) { + if (!distributions.hasOwnProperty(name)) + throw new Error('Unknown distribution ' + name); -function factory$272 (type, config, load, typed) { - /** - * Calculate the tangent of a value. `tan(x)` is equal to `sin(x) / cos(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.tan(x) - * - * Examples: - * - * math.tan(0.5); // returns number 0.5463024898437905 - * math.sin(0.5) / math.cos(0.5); // returns number 0.5463024898437905 - * math.tan(math.pi / 4); // returns number 1 - * math.tan(math.unit(45, 'deg')); // returns number 1 - * - * See also: - * - * atan, sin, cos - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Tangent of x - */ - var tan = typed('tan', { - 'number': Math.tan, + var args = Array.prototype.slice.call(arguments, 1), + distribution = distributions[name].apply(this, args); - 'Complex': function (x) { - return x.tan(); - }, + return (function(distribution) { - 'BigNumber': function (x) { - return x.tan(); - }, + // This is the public API for all distributions + var randFunctions = { - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function tan is no angle'); - } - return tan(x.value); - }, + random: function(arg1, arg2, arg3) { + var size, min, max; - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since tan(0) = 0 - return deepMap(x, tan, true); - } - }); + if (arguments.length > 3) { + throw new ArgumentsError_1('random', arguments.length, 0, 3); + } else if (arguments.length === 1) { + // `random(max)` or `random(size)` + if (isCollection(arg1)) { + size = arg1; + } else { + max = arg1; + } + } else if (arguments.length === 2) { + // `random(min, max)` or `random(size, max)` + if (isCollection(arg1)) { + size = arg1; + max = arg2; + } else { + min = arg1; + max = arg2; + } + } else { + // `random(size, min, max)` + size = arg1; + min = arg2; + max = arg3; + } - tan.toTex = {1: '\\tan\\left(${args[0]}\\right)'}; + // TODO: validate type of size + if ((min !== undefined && !isNumber$3(min)) || (max !== undefined && !isNumber$3(max))) { + throw new TypeError('Invalid argument in function random'); + } - return tan; -} + if (max === undefined) max = 1; + if (min === undefined) min = 0; + if (size !== undefined) { + var res = _randomDataForMatrix(size.valueOf(), min, max, _random); + return type.isMatrix(size) ? matrix$$1(res) : res; + } + return _random(min, max); + }, -var name$259 = 'tan'; -var factory_1$271 = factory$272; + randomInt: typed({ + 'number | Array': function(arg) { + var min = 0; -var tan$1 = { - name: name$259, - factory: factory_1$271 -}; + if (isCollection(arg)) { + var size = arg; + var max = 1; + var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); + return type.isMatrix(size) ? matrix$$1(res) : res; + } else { + var max = arg; + return _randomInt(min, max); + } + }, + 'number | Array, number': function(arg1, arg2) { + if (isCollection(arg1)) { + var size = arg1; + var max = arg2; + var min = 0; + var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); + return type.isMatrix(size) ? matrix$$1(res) : res; + } + else { + var min = arg1; + var max = arg2; + return _randomInt(min, max); + } + }, + 'Array, number, number': function(size, min, max) { + var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); + return (size && size.isMatrix === true) ? matrix$$1(res) : res; + } + }), -function factory$273 (type, config, load, typed) { - /** - * Calculate the hyperbolic tangent of a value, - * defined as `tanh(x) = (exp(2 * x) - 1) / (exp(2 * x) + 1)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.tanh(x) - * - * Examples: - * - * // tanh(x) = sinh(x) / cosh(x) = 1 / coth(x) - * math.tanh(0.5); // returns 0.46211715726000974 - * math.sinh(0.5) / math.cosh(0.5); // returns 0.46211715726000974 - * 1 / math.coth(0.5); // returns 0.46211715726000974 - * - * See also: - * - * sinh, cosh, coth - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic tangent of x - */ - var tanh = typed('tanh', { - 'number': _tanh, - - 'Complex': function (x) { - return x.tanh(); - }, - - 'BigNumber': function (x) { - return x.tanh(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function tanh is no angle'); - } - return tanh(x.value); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since tanh(0) = 0 - return deepMap(x, tanh, true); - } - }); - - tanh.toTex = {1: '\\tanh\\left(${args[0]}\\right)'}; - - return tanh; -} - -/** - * Calculate the hyperbolic tangent of a number - * @param {number} x - * @returns {number} - * @private - */ -var _tanh = Math.tanh || function (x) { - var e = Math.exp(2 * x); - return (e - 1) / (e + 1); -}; - -var name$260 = 'tanh'; -var factory_1$272 = factory$273; - -var tanh$1 = { - name: name$260, - factory: factory_1$272 -}; - -var trigonometry = [ - acos$1, - acosh$1, - acot$1, - acoth$1, - acsc$1, - acsch$1, - asec$1, - asech$1, - asin$1, - asinh$1, - atan$1, - atan2$1, - atanh$1, - cos$1, - cosh$1, - cot$1, - coth$1, - csc$1, - csch$1, - sec$1, - sech$1, - sin$1, - sinh$1, - tan$1, - tanh$1 -]; - -function factory$274 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); + pickRandom: typed({ + 'Array': function(possibles) { + return _pickRandom(possibles); + }, + 'Array, number | Array': function(possibles, arg2) { + var number$$1, weights; - /** - * Change the unit of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.to(x, unit) - * - * Examples: - * - * math.to(math.unit('2 inch'), 'cm'); // returns Unit 5.08 cm - * math.to(math.unit('2 inch'), math.unit(null, 'cm')); // returns Unit 5.08 cm - * math.to(math.unit(16, 'bytes'), 'bits'); // returns Unit 128 bits - * - * See also: - * - * unit - * - * @param {Unit | Array | Matrix} x The unit to be converted. - * @param {Unit | Array | Matrix} unit New unit. Can be a string like "cm" - * or a unit without value. - * @return {Unit | Array | Matrix} value with changed, fixed unit. - */ - var to = typed('to', { + if (Array.isArray(arg2)) { + weights = arg2; + } else if (isNumber$3(arg2)) { + number$$1 = arg2; + } else { + throw new TypeError('Invalid argument in function pickRandom') + } - 'Unit, Unit | string': function (x, unit) { - return x.to(unit); - }, + return _pickRandom(possibles, number$$1, weights); + }, + 'Array, number | Array, Array | number': function(possibles, arg2, arg3) { + var number$$1, weights; - 'Matrix, Matrix': function (x, y) { - // SparseMatrix does not support Units - return algorithm13$$1(x, y, to); - }, + if (Array.isArray(arg2)) { + weights = arg2; + number$$1 = arg3; + } else { + weights = arg3; + number$$1 = arg2; + } - 'Array, Array': function (x, y) { - // use matrix implementation - return to(matrix$$1(x), matrix$$1(y)).valueOf(); - }, + if (!Array.isArray(weights) || !isNumber$3(number$$1)) { + throw new TypeError('Invalid argument in function pickRandom'); + } - 'Array, Matrix': function (x, y) { - // use matrix implementation - return to(matrix$$1(x), y); - }, + return _pickRandom(possibles, number$$1, weights); + } + }) + }; - 'Matrix, Array': function (x, y) { - // use matrix implementation - return to(x, matrix$$1(y)); - }, + var _pickRandom = function(possibles, number$$1, weights) { + var single = (typeof number$$1 === 'undefined'); - 'Matrix, any': function (x, y) { - // SparseMatrix does not support Units - return algorithm14$$1(x, y, to, false); - }, + if (single) { + number$$1 = 1; + } - 'any, Matrix': function (x, y) { - // SparseMatrix does not support Units - return algorithm14$$1(y, x, to, true); - }, + if (type.isMatrix(possibles)) { + possibles = possibles.valueOf(); // get Array + } else if (!Array.isArray(possibles)) { + throw new TypeError('Unsupported type of value in function pickRandom'); + } - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, to, false).valueOf(); - }, + if (array$$1.size(possibles).length > 1) { + throw new Error('Only one dimensional vectors supported'); + } - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, to, true).valueOf(); - } - }); + if (typeof weights !== 'undefined') { + if (weights.length != possibles.length) { + throw new Error('Weights must have the same length as possibles'); + } - to.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['to'] + '${args[1]}\\right)' - }; + var totalWeights = 0; - return to; -} + for (var i = 0, len = weights.length; i < len; i++) { + if (!isNumber$3(weights[i]) || weights[i] < 0) { + throw new Error('Weights must be an array of positive numbers'); + } -var name$261 = 'to'; -var factory_1$273 = factory$274; + totalWeights += weights[i]; + } + } -var to$1 = { - name: name$261, - factory: factory_1$273 -}; + var length = possibles.length; -var unit$1 = [ - to$1 -]; + if (length == 0) { + return []; + } else if (number$$1 >= length) { + return number$$1 > 1 ? possibles : possibles[0]; + } -function factory$275 (type, config, load, typed) { - /** - * Test whether a value is prime: has no divisors other than itself and one. - * The function supports type `number`, `bignumber`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isPrime(x) - * - * Examples: - * - * math.isPrime(3); // returns true - * math.isPrime(-2); // returns false - * math.isPrime(0); // returns false - * math.isPrime(-0); // returns false - * math.isPrime(0.5); // returns false - * math.isPrime('2'); // returns true - * math.isPrime([2, 17, 100]); // returns [true, true, false] - * - * See also: - * - * isNumeric, isZero, isNegative, isInteger - * - * @param {number | BigNumber | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is larger than zero. - * Throws an error in case of an unknown data type. - */ - var isPrime = typed('isPrime', { - 'number': function (x) { - if (x < 2){ - return false; - } - if (x == 2){ - return true; - } - if (x % 2 == 0){ - return false; - } - for (var i = 3; i * i <= x; i += 2){ - if (x % i == 0){ - return false; - } - } - return true; - }, + var result = []; + var pick; - 'BigNumber': function (x) { - if (x.lt(2)){ - return false; - } - if (x.equals(2)){ - return true; - } - if (x.mod(2).isZero()){ - return false; - } - for(var i = type.BigNumber(3); i.times(i).lte(x); i = i.plus(1)){ - if (x.mod(i).isZero()){ - return false; - } - } - return true; - }, + while (result.length < number$$1) { + if (typeof weights === 'undefined') { + pick = possibles[Math.floor(rng() * length)]; + } else { + var randKey = rng() * totalWeights; - 'Array | Matrix': function (x) { - return deepMap(x, isPrime); - } - }); + for (var i = 0, len = possibles.length; i < len; i++) { + randKey -= weights[i]; + + if (randKey < 0) { + pick = possibles[i]; + break; + } + } + } - return isPrime; -} + if (result.indexOf(pick) == -1) { + result.push(pick); + } + } -var name$262 = 'isPrime'; -var factory_1$274 = factory$275; + return single ? result[0] : result; -var isPrime$1 = { - name: name$262, - factory: factory_1$274 -}; + // TODO: add support for multi dimensional matrices + }; -function factory$276 (type, config, load, typed) { - /** - * Test whether a value is NaN (not a number). - * The function supports types `number`, `BigNumber`, `Fraction`, `Unit` and `Complex`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isNaN(x) - * - * Examples: - * - * math.isNaN(3); // returns false - * math.isNaN(NaN); // returns true - * math.isNaN(0); // returns false - * math.isNaN(math.bignumber(NaN)); // returns true - * math.isNaN(math.bignumber(0)); // returns false - * math.isNaN(math.fraction(-2, 5)); // returns false - * math.isNaN('-2'); // returns false - * math.isNaN([2, 0, -3, NaN]'); // returns [false, false, false, true] - * - * See also: - * - * isNumeric, isNegative, isPositive, isZero, isInteger - * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is NaN. - * Throws an error in case of an unknown data type. - */ - var isNaN = typed('isNaN', { - 'number': function (x) { - return Number.isNaN(x); - }, + var _random = function(min, max) { + return min + distribution() * (max - min); + }; - 'BigNumber': function (x) { - return x.isNaN(); - }, + var _randomInt = function(min, max) { + return Math.floor(min + distribution() * (max - min)); + }; - 'Fraction': function (x) { - return false; - }, + // This is a function for generating a random matrix recursively. + var _randomDataForMatrix = function(size, min, max, randFunc) { + var data = [], length, i; + size = size.slice(0); - 'Complex': function (x) { - return x.isNaN(); - }, + if (size.length > 1) { + for (var i = 0, length = size.shift(); i < length; i++) { + data.push(_randomDataForMatrix(size, min, max, randFunc)); + } + } else { + for (var i = 0, length = size.shift(); i < length; i++) { + data.push(randFunc(min, max)); + } + } - 'Unit': function (x) { - return Number.isNaN(x.value); - }, + return data; + }; + + return randFunctions; - 'Array | Matrix': function (x) { - return deepMap(x, Number.isNaN); + })(distribution); } - }); - return isNaN; -} - -var name$263 = 'isNaN'; -var factory_1$275 = factory$276; - -var _isNaN$1 = { - name: name$263, - factory: factory_1$275 -}; - -var utils$1 = [ - clone$5, - isInteger$22, - isNegative$1, - isNumeric$1, - isPositive$1, - isPrime$1, - isZero$1, - _isNaN$1, - _typeof$1 -]; - -var _function$3 = [ - algebra, - arithmetic, - bitwise$1, - combinatorics, - complex$5, - geometry, - logical, - matrix$3, - probability, - relational, - set, - special, - statistics, - string$10, - trigonometry, - unit$1, - utils$1 -]; - -function factory$277 (type, config, load, typed, math) { - /** - * Instantiate mathjs data types from their JSON representation - * @param {string} key - * @param {*} value - * @returns {*} Returns the revived object - */ - return function reviver(key, value) { - var constructor = type[value && value.mathjs] || - (math.expression && math.expression.node[value && value.mathjs]); - // TODO: instead of checking math.expression.node, expose all Node classes on math.type too + // Each distribution is a function that takes no argument and when called returns + // a number between 0 and 1. + var distributions = { - if (constructor && typeof constructor.fromJSON === 'function') { - return constructor.fromJSON(value); - } + uniform: function() { + return rng; + }, - return value; + // Implementation of normal distribution using Box-Muller transform + // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform + // We take : mean = 0.5, standard deviation = 1/6 + // so that 99.7% values are in [0, 1]. + normal: function() { + return function() { + var u1, u2, + picked = -1; + // We reject values outside of the interval [0, 1] + // TODO: check if it is ok to do that? + while (picked < 0 || picked > 1) { + u1 = rng(); + u2 = rng(); + picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; + } + return picked; + } + } + }; + + distribution.toTex = undefined; // use default template + + return distribution; } -} -var name$264 = 'reviver'; -var path$64 = 'json'; -var factory_1$276 = factory$277; -var math$18 = true; // request the math namespace as fifth argument + var name$208 = 'distribution'; + var factory_1$220 = factory$221; -var reviver = { - name: name$264, - path: path$64, - factory: factory_1$276, - math: math$18 -}; + var distribution = { + name: name$208, + factory: factory_1$220 + }; -var json = [ - reviver -]; + function factory$222 (type, config, load, typed) { + var distribution$$1 = load(distribution); -var error = [ - { - name: 'ArgumentsError', path: 'error', - factory: function () { - return ArgumentsError_1; - } - }, - { - name: 'DimensionError', - path: 'error', - factory: function () { - return DimensionError_1; - } - }, - { - name: 'IndexError', - path: 'error', - factory: function () { - return IndexError_1; - } - } -]; - -// import customized constants file - -var lib = [ - type, // data types (Matrix, Complex, Unit, ...) - constants$1, // constants - expression, // expression parsing - _function$3, // functions - json, // serialization utility (math.json.reviver) - error // errors -]; - -var numeric1_2_6 = createCommonjsModule(function (module, exports) { - -var numeric = exports; -if(typeof commonjsGlobal !== "undefined") { commonjsGlobal.numeric = numeric; } - -numeric.version = "1.2.6"; - -// 1. Utility functions -numeric.bench = function bench (f,interval) { - var t1,t2,n,i; - if(typeof interval === "undefined") { interval = 15; } - n = 0.5; - t1 = new Date(); - while(1) { - n*=2; - for(i=n;i>3;i-=4) { f(); f(); f(); f(); } - while(i>0) { f(); i--; } - t2 = new Date(); - if(t2-t1 > interval) break; - } - for(i=n;i>3;i-=4) { f(); f(); f(); f(); } - while(i>0) { f(); i--; } - t2 = new Date(); - return 1000*(3*n-1)/(t2-t1); -}; - -numeric._myIndexOf = (function _myIndexOf(w) { - var n = this.length,k; - for(k=0;k numeric.largeArray) { ret.push('...Large Array...'); return true; } - var flag = false; - ret.push('['); - for(k=0;k0) { ret.push(','); if(flag) ret.push('\n '); } flag = foo(x[k]); } - ret.push(']'); - return true; - } - ret.push('{'); - var flag = false; - for(k in x) { if(x.hasOwnProperty(k)) { if(flag) ret.push(',\n'); flag = true; ret.push(k); ret.push(': \n'); foo(x[k]); } } - ret.push('}'); - return true; - } - foo(x); - return ret.join(''); -}; + /** + * Random pick one or more values from a one dimensional array. + * Array elements are picked using a random function with uniform or weighted distribution. + * + * Syntax: + * + * math.pickRandom(array) + * math.pickRandom(array, number) + * math.pickRandom(array, weights) + * math.pickRandom(array, number, weights) + * math.pickRandom(array, weights, number) + * + * Examples: + * + * math.pickRandom([3, 6, 12, 2]); // returns one of the values in the array + * math.pickRandom([3, 6, 12, 2], 2); // returns an array of two of the values in the array + * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1]); // returns one of the values in the array with weighted distribution + * math.pickRandom([3, 6, 12, 2], 2, [1, 3, 2, 1]); // returns an array of two of the values in the array with weighted distribution + * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1], 2); // returns an array of two of the values in the array with weighted distribution + * + * See also: + * + * random, randomInt + * + * @param {Array} array A one dimensional array + * @param {Int} number An int or float + * @param {Array} weights An array of ints or floats + * @return {number | Array} Returns a single random value from array when number is 1 or undefined. + * Returns an array with the configured number of elements when number is > 1. + */ + // TODO: rework pickRandom to a typed-function + var pickRandom = distribution$$1('uniform').pickRandom; -numeric.parseDate = function parseDate(d) { - function foo(d) { - if(typeof d === 'string') { return Date.parse(d.replace(/-/g,'/')); } - if(!(d instanceof Array)) { throw new Error("parseDate: parameter must be arrays of strings"); } - var ret = [],k; - for(k=0;k0) { - ret[count] = []; - for(j=0;j> 2; - q = ((x & 3) << 4) + (y >> 4); - r = ((y & 15) << 2) + (z >> 6); - s = z & 63; - if(i+1>=n) { r = s = 64; } - else if(i+2>=n) { s = 64; } - ret += key.charAt(p) + key.charAt(q) + key.charAt(r) + key.charAt(s); - } - return ret; - } - function crc32Array (a,from,to) { - if(typeof from === "undefined") { from = 0; } - if(typeof to === "undefined") { to = a.length; } - var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]; - - var crc = -1, y = 0, n = a.length,i; + var name$209 = 'pickRandom'; + var factory_1$221 = factory$222; - for (i = from; i < to; i++) { - y = (crc ^ a[i]) & 0xFF; - crc = (crc >>> 8) ^ table[y]; - } - - return crc ^ (-1); - } - - var h = img[0].length, w = img[0][0].length, s1, s2, k,length,a,b,i,j,adler32,crc32; - var stream = [ - 137, 80, 78, 71, 13, 10, 26, 10, // 0: PNG signature - 0,0,0,13, // 8: IHDR Chunk length - 73, 72, 68, 82, // 12: "IHDR" - (w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w&255, // 16: Width - (h >> 24) & 255, (h >> 16) & 255, (h >> 8) & 255, h&255, // 20: Height - 8, // 24: bit depth - 2, // 25: RGB - 0, // 26: deflate - 0, // 27: no filter - 0, // 28: no interlace - -1,-2,-3,-4, // 29: CRC - -5,-6,-7,-8, // 33: IDAT Chunk length - 73, 68, 65, 84, // 37: "IDAT" - // RFC 1950 header starts here - 8, // 41: RFC1950 CMF - 29 // 42: RFC1950 FLG - ]; - crc32 = crc32Array(stream,12,29); - stream[29] = (crc32>>24)&255; - stream[30] = (crc32>>16)&255; - stream[31] = (crc32>>8)&255; - stream[32] = (crc32)&255; - s1 = 1; - s2 = 0; - for(i=0;i>8)&255; - stream.push(a); stream.push(b); - stream.push((~a)&255); stream.push((~b)&255); - if(i===0) stream.push(0); - for(j=0;j255) a = 255; - else if(a<0) a=0; - else a = Math.round(a); - s1 = (s1 + a )%65521; - s2 = (s2 + s1)%65521; - stream.push(a); - } - } - stream.push(0); - } - adler32 = (s2<<16)+s1; - stream.push((adler32>>24)&255); - stream.push((adler32>>16)&255); - stream.push((adler32>>8)&255); - stream.push((adler32)&255); - length = stream.length - 41; - stream[33] = (length>>24)&255; - stream[34] = (length>>16)&255; - stream[35] = (length>>8)&255; - stream[36] = (length)&255; - crc32 = crc32Array(stream,37); - stream.push((crc32>>24)&255); - stream.push((crc32>>16)&255); - stream.push((crc32>>8)&255); - stream.push((crc32)&255); - stream.push(0); - stream.push(0); - stream.push(0); - stream.push(0); -// a = stream.length; - stream.push(73); // I - stream.push(69); // E - stream.push(78); // N - stream.push(68); // D - stream.push(174); // CRC1 - stream.push(66); // CRC2 - stream.push(96); // CRC3 - stream.push(130); // CRC4 - return 'data:image/png;base64,'+base64(stream); -}; - -// 2. Linear algebra with Arrays. -numeric._dim = function _dim(x) { - var ret = []; - while(typeof x === "object") { ret.push(x.length); x = x[0]; } - return ret; -}; - -numeric.dim = function dim(x) { - var y,z; - if(typeof x === "object") { - y = x[0]; - if(typeof y === "object") { - z = y[0]; - if(typeof z === "object") { - return numeric._dim(x); - } - return [x.length,y.length]; - } - return [x.length]; - } - return []; -}; - -numeric.mapreduce = function mapreduce(body,init) { - return Function('x','accum','_s','_k', - 'if(typeof accum === "undefined") accum = '+init+';\n'+ - 'if(typeof x === "number") { var xi = x; '+body+'; return accum; }\n'+ - 'if(typeof _s === "undefined") _s = numeric.dim(x);\n'+ - 'if(typeof _k === "undefined") _k = 0;\n'+ - 'var _n = _s[_k];\n'+ - 'var i,xi;\n'+ - 'if(_k < _s.length-1) {\n'+ - ' for(i=_n-1;i>=0;i--) {\n'+ - ' accum = arguments.callee(x[i],accum,_s,_k+1);\n'+ - ' }'+ - ' return accum;\n'+ - '}\n'+ - 'for(i=_n-1;i>=1;i-=2) { \n'+ - ' xi = x[i];\n'+ - ' '+body+';\n'+ - ' xi = x[i-1];\n'+ - ' '+body+';\n'+ - '}\n'+ - 'if(i === 0) {\n'+ - ' xi = x[i];\n'+ - ' '+body+'\n'+ - '}\n'+ - 'return accum;' - ); -}; -numeric.mapreduce2 = function mapreduce2(body,setup) { - return Function('x', - 'var n = x.length;\n'+ - 'var i,xi;\n'+setup+';\n'+ - 'for(i=n-1;i!==-1;--i) { \n'+ - ' xi = x[i];\n'+ - ' '+body+';\n'+ - '}\n'+ - 'return accum;' - ); -}; + var pickRandom$1 = { + name: name$209, + factory: factory_1$221 + }; + function factory$223 (type, config, load, typed) { + var distribution$$1 = load(distribution); -numeric.same = function same(x,y) { - var i,n; - if(!(x instanceof Array) || !(y instanceof Array)) { return false; } - n = x.length; - if(n !== y.length) { return false; } - for(i=0;i=0;i-=2) { ret[i+1] = v; ret[i] = v; } - if(i===-1) { ret[0] = v; } - return ret; - } - for(i=n-1;i>=0;i--) { ret[i] = numeric.rep(s,v,k+1); } - return ret; -}; - - -numeric.dotMMsmall = function dotMMsmall(x,y) { - var i,j,k,p,q,r,ret,foo,bar,woo,i0; - p = x.length; q = y.length; r = y[0].length; - ret = Array(p); - for(i=p-1;i>=0;i--) { - foo = Array(r); - bar = x[i]; - for(k=r-1;k>=0;k--) { - woo = bar[q-1]*y[q-1][k]; - for(j=q-2;j>=1;j-=2) { - i0 = j-1; - woo += bar[j]*y[j][k] + bar[i0]*y[i0][k]; - } - if(j===0) { woo += bar[0]*y[0][k]; } - foo[k] = woo; - } - ret[i] = foo; - } - return ret; -}; -numeric._getCol = function _getCol(A,j,x) { - var n = A.length, i; - for(i=n-1;i>0;--i) { - x[i] = A[i][j]; - --i; - x[i] = A[i][j]; - } - if(i===0) x[0] = A[0][j]; -}; -numeric.dotMMbig = function dotMMbig(x,y){ - var gc = numeric._getCol, p = y.length, v = Array(p); - var m = x.length, n = y[0].length, A = new Array(m), xj; - var VV = numeric.dotVV; - var i,j; - --p; - --m; - for(i=m;i!==-1;--i) A[i] = Array(n); - --n; - for(i=n;i!==-1;--i) { - gc(y,i,v); - for(j=m;j!==-1;--j) { - xj = x[j]; - A[j][i] = VV(xj,v); - } - } - return A; -}; - -numeric.dotMV = function dotMV(x,y) { - var p = x.length, q = y.length,i; - var ret = Array(p), dotVV = numeric.dotVV; - for(i=p-1;i>=0;i--) { ret[i] = dotVV(x[i],y); } - return ret; -}; + /** + * Return a random number larger or equal to `min` and smaller than `max` + * using a uniform distribution. + * + * Syntax: + * + * math.random() // generate a random number between 0 and 1 + * math.random(max) // generate a random number between 0 and max + * math.random(min, max) // generate a random number between min and max + * math.random(size) // generate a matrix with random numbers between 0 and 1 + * math.random(size, max) // generate a matrix with random numbers between 0 and max + * math.random(size, min, max) // generate a matrix with random numbers between min and max + * + * Examples: + * + * math.random(); // returns a random number between 0 and 1 + * math.random(100); // returns a random number between 0 and 100 + * math.random(30, 40); // returns a random number between 30 and 40 + * math.random([2, 3]); // returns a 2x3 matrix with random numbers between 0 and 1 + * + * See also: + * + * randomInt, pickRandom + * + * @param {Array | Matrix} [size] If provided, an array or matrix with given + * size and filled with random values is returned + * @param {number} [min] Minimum boundary for the random value, included + * @param {number} [max] Maximum boundary for the random value, excluded + * @return {number | Array | Matrix} A random number + */ + // TODO: rework random to a typed-function + var random = distribution$$1('uniform').random; -numeric.dotVM = function dotVM(x,y) { - var j,k,p,q,ret,woo,i0; - p = x.length; q = y[0].length; - ret = Array(q); - for(k=q-1;k>=0;k--) { - woo = x[p-1]*y[p-1][k]; - for(j=p-2;j>=1;j-=2) { - i0 = j-1; - woo += x[j]*y[j][k] + x[i0]*y[i0][k]; - } - if(j===0) { woo += x[0]*y[0][k]; } - ret[k] = woo; - } - return ret; -}; + random.toTex = undefined; // use default template -numeric.dotVV = function dotVV(x,y) { - var i,n=x.length,i1,ret = x[n-1]*y[n-1]; - for(i=n-2;i>=1;i-=2) { - i1 = i-1; - ret += x[i]*y[i] + x[i1]*y[i1]; - } - if(i===0) { ret += x[0]*y[0]; } - return ret; -}; - -numeric.dot = function dot(x,y) { - var d = numeric.dim; - switch(d(x).length*1000+d(y).length) { - case 2002: - if(y.length < 10) return numeric.dotMMsmall(x,y); - else return numeric.dotMMbig(x,y); - case 2001: return numeric.dotMV(x,y); - case 1002: return numeric.dotVM(x,y); - case 1001: return numeric.dotVV(x,y); - case 1000: return numeric.mulVS(x,y); - case 1: return numeric.mulSV(x,y); - case 0: return x*y; - default: throw new Error('numeric.dot only works on vectors and matrices'); - } -}; - -numeric.diag = function diag(d) { - var i,i1,j,n = d.length, A = Array(n), Ai; - for(i=n-1;i>=0;i--) { - Ai = Array(n); - i1 = i+2; - for(j=n-1;j>=i1;j-=2) { - Ai[j] = 0; - Ai[j-1] = 0; - } - if(j>i) { Ai[j] = 0; } - Ai[i] = d[i]; - for(j=i-1;j>=1;j-=2) { - Ai[j] = 0; - Ai[j-1] = 0; - } - if(j===0) { Ai[0] = 0; } - A[i] = Ai; - } - return A; -}; -numeric.getDiag = function(A) { - var n = Math.min(A.length,A[0].length),i,ret = Array(n); - for(i=n-1;i>=1;--i) { - ret[i] = A[i][i]; - --i; - ret[i] = A[i][i]; - } - if(i===0) { - ret[0] = A[0][0]; - } - return ret; -}; - -numeric.identity = function identity(n) { return numeric.diag(numeric.rep([n],1)); }; -numeric.pointwise = function pointwise(params,body,setup) { - if(typeof setup === "undefined") { setup = ""; } - var fun = []; - var k; - var avec = /\[i\]$/,p,thevec = ''; - var haveret = false; - for(k=0;k=0;i--) ret[i] = arguments.callee('+params.join(',')+',_s,_k+1);\n'+ - ' return ret;\n'+ - '}\n'+ - setup+'\n'+ - 'for(i=_n-1;i!==-1;--i) {\n'+ - ' '+body+'\n'+ - '}\n'+ - 'return ret;' - ); - return Function.apply(null,fun); -}; -numeric.pointwise2 = function pointwise2(params,body,setup) { - if(typeof setup === "undefined") { setup = ""; } - var fun = []; - var k; - var avec = /\[i\]$/,p,thevec = ''; - var haveret = false; - for(k=0;k=0;i--) { _biforeach(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } -}); -numeric._biforeach2 = (function _biforeach2(x,y,s,k,f) { - if(k === s.length-1) { return f(x,y); } - var i,n=s[k],ret = Array(n); - for(i=n-1;i>=0;--i) { ret[i] = _biforeach2(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } - return ret; -}); -numeric._foreach = (function _foreach(x,s,k,f) { - if(k === s.length-1) { f(x); return; } - var i,n=s[k]; - for(i=n-1;i>=0;i--) { _foreach(x[i],s,k+1,f); } -}); -numeric._foreach2 = (function _foreach2(x,s,k,f) { - if(k === s.length-1) { return f(x); } - var i,n=s[k], ret = Array(n); - for(i=n-1;i>=0;i--) { ret[i] = _foreach2(x[i],s,k+1,f); } - return ret; -}); - -/*numeric.anyV = numeric.mapreduce('if(xi) return true;','false'); -numeric.allV = numeric.mapreduce('if(!xi) return false;','true'); -numeric.any = function(x) { if(typeof x.length === "undefined") return x; return numeric.anyV(x); } -numeric.all = function(x) { if(typeof x.length === "undefined") return x; return numeric.allV(x); }*/ - -numeric.ops2 = { - add: '+', - sub: '-', - mul: '*', - div: '/', - mod: '%', - and: '&&', - or: '||', - eq: '===', - neq: '!==', - lt: '<', - gt: '>', - leq: '<=', - geq: '>=', - band: '&', - bor: '|', - bxor: '^', - lshift: '<<', - rshift: '>>', - rrshift: '>>>' -}; -numeric.opseq = { - addeq: '+=', - subeq: '-=', - muleq: '*=', - diveq: '/=', - modeq: '%=', - lshifteq: '<<=', - rshifteq: '>>=', - rrshifteq: '>>>=', - bandeq: '&=', - boreq: '|=', - bxoreq: '^=' -}; -numeric.mathfuns = ['abs','acos','asin','atan','ceil','cos', - 'exp','floor','log','round','sin','sqrt','tan', - 'isNaN','isFinite']; -numeric.mathfuns2 = ['atan2','pow','max','min']; -numeric.ops1 = { - neg: '-', - not: '!', - bnot: '~', - clone: '' -}; -numeric.mapreducers = { - any: ['if(xi) return true;','var accum = false;'], - all: ['if(!xi) return false;','var accum = true;'], - sum: ['accum += xi;','var accum = 0;'], - prod: ['accum *= xi;','var accum = 1;'], - norm2Squared: ['accum += xi*xi;','var accum = 0;'], - norminf: ['accum = max(accum,abs(xi));','var accum = 0, max = Math.max, abs = Math.abs;'], - norm1: ['accum += abs(xi)','var accum = 0, abs = Math.abs;'], - sup: ['accum = max(accum,xi);','var accum = -Infinity, max = Math.max;'], - inf: ['accum = min(accum,xi);','var accum = Infinity, min = Math.min;'] -}; - -(function () { - var i,o; - for(i=0;iv0) { i0 = i; v0 = k; } } - Aj = A[i0]; A[i0] = A[j]; A[j] = Aj; - Ij = I[i0]; I[i0] = I[j]; I[j] = Ij; - x = Aj[j]; - for(k=j;k!==n;++k) Aj[k] /= x; - for(k=n-1;k!==-1;--k) Ij[k] /= x; - for(i=m-1;i!==-1;--i) { - if(i!==j) { - Ai = A[i]; - Ii = I[i]; - x = Ai[j]; - for(k=j+1;k!==n;++k) Ai[k] -= Aj[k]*x; - for(k=n-1;k>0;--k) { Ii[k] -= Ij[k]*x; --k; Ii[k] -= Ij[k]*x; } - if(k===0) Ii[0] -= Ij[0]*x; - } - } + return random; + } + + var name$210 = 'random'; + var factory_1$222 = factory$223; + + var random$1 = { + name: name$210, + factory: factory_1$222 + }; + + function factory$224 (type, config, load, typed) { + var distribution$$1 = load(distribution); + + /** + * Return a random integer number larger or equal to `min` and smaller than `max` + * using a uniform distribution. + * + * Syntax: + * + * math.randomInt(max) // generate a random integer between 0 and max + * math.randomInt(min, max) // generate a random integer between min and max + * math.randomInt(size) // generate a matrix with random integer between 0 and 1 + * math.randomInt(size, max) // generate a matrix with random integer between 0 and max + * math.randomInt(size, min, max) // generate a matrix with random integer between min and max + * + * Examples: + * + * math.randomInt(100); // returns a random integer between 0 and 100 + * math.randomInt(30, 40); // returns a random integer between 30 and 40 + * math.randomInt([2, 3]); // returns a 2x3 matrix with random integers between 0 and 1 + * + * See also: + * + * random, pickRandom + * + * @param {Array | Matrix} [size] If provided, an array or matrix with given + * size and filled with random values is returned + * @param {number} [min] Minimum boundary for the random value, included + * @param {number} [max] Maximum boundary for the random value, excluded + * @return {number | Array | Matrix} A random integer value + */ + // TODO: rework randomInt to a typed-function + var randomInt = distribution$$1('uniform').randomInt; + + randomInt.toTex = undefined; // use default template + + return randomInt; + } + + var name$211 = 'randomInt'; + var factory_1$223 = factory$224; + + var randomInt$1 = { + name: name$211, + factory: factory_1$223 + }; + + var probability = [ + //require('./distribution'), // TODO: rethink math.distribution + combinations$1, + factorial$1, + gamma$1, + kldivergence$1, + multinomial$1, + permutations$1, + pickRandom$1, + random$1, + randomInt$1 + ]; + + function factory$225 (type, config, load, typed) { + + var matrix$$1 = load(matrix); + var _typeof = load(_typeof$1); + + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + /** + * Compare two strings lexically. Comparison is case sensitive. + * Returns 1 when x > y, -1 when x < y, and 0 when x == y. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.compareText(x, y) + * + * Examples: + * + * math.compareText('B', 'A'); // returns 1 + * math.compareText('2', '10'); // returns 1 + * math.compare('2', '10'); // returns -1 + * math.compareNatural('2', '10'); // returns -1 + * + * math.compareText('B', ['A', 'B', 'C']); // returns [1, 0, -1] + * + * See also: + * + * equal, equalText, compare, compareNatural + * + * @param {string | Array | DenseMatrix} x First string to compare + * @param {string | Array | DenseMatrix} y Second string to compare + * @return {number | Array | DenseMatrix} Returns the result of the comparison: + * 1 when x > y, -1 when x < y, and 0 when x == y. + */ + var compareText = typed('compareText', { + + 'any, any': _compareText, + + 'DenseMatrix, DenseMatrix': function(x, y) { + return algorithm13$$1(x, y, _compareText); + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return compareText(matrix$$1(x), matrix$$1(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return compareText(matrix$$1(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return compareText(x, matrix$$1(y)); + }, + + 'DenseMatrix, any': function (x, y) { + return algorithm14$$1(x, y, _compareText, false); + }, + + 'any, DenseMatrix': function (x, y) { + return algorithm14$$1(y, x, _compareText, true); + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, _compareText, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, _compareText, true).valueOf(); + } + }); + + /** + * Compare two strings + * @param {string} x + * @param {string} y + * @returns {number} + * @private + */ + function _compareText(x, y) { + // we don't want to convert numbers to string, only accept string input + if (!type.isString(x)) { + throw new TypeError('Unexpected type of argument in function compareText ' + + '(expected: string or Array or Matrix, actual: ' + _typeof(x) + ', index: 0)'); + } + if (!type.isString(y)) { + throw new TypeError('Unexpected type of argument in function compareText ' + + '(expected: string or Array or Matrix, actual: ' + _typeof(y) + ', index: 1)'); + } + + return (x === y) + ? 0 + : (x > y ? 1 : -1); } - return I; -}; - -numeric.det = function det(x) { - var s = numeric.dim(x); - if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: det() only works on square matrices'); } - var n = s[0], ret = 1,i,j,k,A = numeric.clone(x),Aj,Ai,alpha,temp,k1; - for(j=0;j Math.abs(A[k][j])) { k = i; } } - if(k !== j) { - temp = A[k]; A[k] = A[j]; A[j] = temp; - ret *= -1; - } - Aj = A[j]; - for(i=j+1;i=1;i-=2) { - A1 = x[i]; - A0 = x[i-1]; - for(j=n-1;j>=1;--j) { - Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; - --j; - Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; + return true; } - if(j===0) { - Bj = ret[0]; Bj[i] = A1[0]; Bj[i-1] = A0[0]; + else { + return false; } - } - if(i===0) { - A0 = x[0]; - for(j=n-1;j>=1;--j) { - ret[j][0] = A0[j]; - --j; - ret[j][0] = A0[j]; + } + else { + if (Array.isArray(y)) { + return false; } - if(j===0) { ret[0][0] = A0[0]; } - } - return ret; -}; -numeric.negtranspose = function negtranspose(x) { - var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj; - for(j=0;j=1;i-=2) { - A1 = x[i]; - A0 = x[i-1]; - for(j=n-1;j>=1;--j) { - Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; - --j; - Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; - } - if(j===0) { - Bj = ret[0]; Bj[i] = -A1[0]; Bj[i-1] = -A0[0]; - } - } - if(i===0) { - A0 = x[0]; - for(j=n-1;j>=1;--j) { - ret[j][0] = -A0[j]; - --j; - ret[j][0] = -A0[j]; - } - if(j===0) { ret[0][0] = -A0[0]; } - } - return ret; -}; - -numeric._random = function _random(s,k) { - var i,n=s[k],ret=Array(n), rnd; - if(k === s.length-1) { - rnd = Math.random; - for(i=n-1;i>=1;i-=2) { - ret[i] = rnd(); - ret[i-1] = rnd(); + else { + return equal(x, y); } - if(i===0) { ret[0] = rnd(); } - return ret; + } } - for(i=n-1;i>=0;i--) ret[i] = _random(s,k+1); - return ret; -}; -numeric.random = function random(s) { return numeric._random(s,0); }; + } -numeric.norm2 = function norm2(x) { return Math.sqrt(numeric.norm2Squared(x)); }; + var name$213 = 'deepEqual'; + var factory_1$225 = factory$226; -numeric.linspace = function linspace(a,b,n) { - if(typeof n === "undefined") n = Math.max(Math.round(b-a)+1,1); - if(n<2) { return n===1?[a]:[]; } - var i,ret = Array(n); - n--; - for(i=n;i>=0;i--) { ret[i] = (i*b+(n-i)*a)/n; } - return ret; -}; + var deepEqual$2 = { + name: name$213, + factory: factory_1$225 + }; + + function factory$227 (type, config, load, typed) { + var compareText = load(compareText$1); + var isZero = load(isZero$1); + + /** + * Check equality of two strings. Comparison is case sensitive. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.equalText(x, y) + * + * Examples: + * + * math.equalText('Hello', 'Hello'); // returns true + * math.equalText('a', 'A'); // returns false + * math.equal('2e3', '2000'); // returns true + * math.equalText('2e3', '2000'); // returns false + * + * math.equalText('B', ['A', 'B', 'C']); // returns [false, true, false] + * + * See also: + * + * equal, compareText, compare, compareNatural + * + * @param {string | Array | DenseMatrix} x First string to compare + * @param {string | Array | DenseMatrix} y Second string to compare + * @return {number | Array | DenseMatrix} Returns true if the values are equal, and false if not. + */ + var equalText = typed('equalText', { + + 'any, any': function (x, y) { + return isZero(compareText(x, y)); + } + + }); + + equalText.toTex = undefined; // use default template + + return equalText; + } + + var name$214 = 'equalText'; + var factory_1$226 = factory$227; + + var equalText$1 = { + name: name$214, + factory: factory_1$226 + }; + + var nearlyEqual$7 = number.nearlyEqual; + + + function factory$228 (type, config, load, typed) { + + var matrix$$1 = load(matrix); + + var algorithm03$$1 = load(algorithm03); + var algorithm07$$1 = load(algorithm07); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + var latex$$1 = latex; + + /** + * Test whether value x is smaller or equal to y. + * + * The function returns true when x is smaller than y or the relative + * difference between x and y is smaller than the configured epsilon. The + * function cannot be used to compare values smaller than approximately 2.22e-16. + * + * For matrices, the function is evaluated element wise. + * Strings are compared by their numerical value. + * + * Syntax: + * + * math.smallerEq(x, y) + * + * Examples: + * + * math.smaller(1 + 2, 3); // returns false + * math.smallerEq(1 + 2, 3); // returns true + * + * See also: + * + * equal, unequal, smaller, larger, largerEq, compare + * + * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare + * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare + * @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false + */ + var smallerEq = typed('smallerEq', { + + 'boolean, boolean': function (x, y) { + return x <= y; + }, + + 'number, number': function (x, y) { + return x <= y || nearlyEqual$7(x, y, config.epsilon); + }, -numeric.getBlock = function getBlock(x,from,to) { - var s = numeric.dim(x); - function foo(x,k) { - var i,a = from[k], n = to[k]-a, ret = Array(n); - if(k === s.length-1) { - for(i=n;i>=0;i--) { ret[i] = x[i+a]; } - return ret; + 'BigNumber, BigNumber': function (x, y) { + return x.lte(y) || nearlyEqual(x, y, config.epsilon); + }, + + 'Fraction, Fraction': function (x, y) { + return x.compare(y) !== 1; + }, + + 'Complex, Complex': function () { + throw new TypeError('No ordering relation is defined for complex numbers'); + }, + + 'Unit, Unit': function (x, y) { + if (!x.equalBase(y)) { + throw new Error('Cannot compare units with different base'); } - for(i=n;i>=0;i--) { ret[i] = foo(x[i+a],k+1); } - return ret; - } - return foo(x,0); -}; + return smallerEq(x.value, y.value); + }, -numeric.setBlock = function setBlock(x,from,to,B) { - var s = numeric.dim(x); - function foo(x,y,k) { - var i,a = from[k], n = to[k]-a; - if(k === s.length-1) { for(i=n;i>=0;i--) { x[i+a] = y[i]; } } - for(i=n;i>=0;i--) { foo(x[i+a],y[i],k+1); } - } - foo(x,B,0); - return x; -}; - -numeric.getRange = function getRange(A,I,J) { - var m = I.length, n = J.length; - var i,j; - var B = Array(m), Bi, AI; - for(i=m-1;i!==-1;--i) { - B[i] = Array(n); - Bi = B[i]; - AI = A[I[i]]; - for(j=n-1;j!==-1;--j) Bi[j] = AI[J[j]]; - } - return B; -}; - -numeric.blockMatrix = function blockMatrix(X) { - var s = numeric.dim(X); - if(s.length<4) return numeric.blockMatrix([X]); - var m=s[0],n=s[1],M,N,i,j,Xij; - M = 0; N = 0; - for(i=0;i=0;i--) { - Ai = Array(n); - xi = x[i]; - for(j=n-1;j>=3;--j) { - Ai[j] = xi * y[j]; - --j; - Ai[j] = xi * y[j]; - --j; - Ai[j] = xi * y[j]; - --j; - Ai[j] = xi * y[j]; - } - while(j>=0) { Ai[j] = xi * y[j]; --j; } - A[i] = Ai; - } - return A; -}; - -// 3. The Tensor type T -numeric.T = function T(x,y) { this.x = x; this.y = y; }; -numeric.t = function t(x,y) { return new numeric.T(x,y); }; - -numeric.Tbinop = function Tbinop(rr,rc,cr,cc,setup) { - var io = numeric.indexOf; - if(typeof setup !== "string") { - var k; - setup = ''; - for(k in numeric) { - if(numeric.hasOwnProperty(k) && (rr.indexOf(k)>=0 || rc.indexOf(k)>=0 || cr.indexOf(k)>=0 || cc.indexOf(k)>=0) && k.length>1) { - setup += 'var '+k+' = numeric.'+k+';\n'; + else { + var b1 = flatten$4(Array.isArray(a1) ? a1 : a1.toArray()).sort(compareNatural); + var b2 = flatten$4(Array.isArray(a2) ? a2 : a2.toArray()).sort(compareNatural); + var result = []; + for (var i=0; i d) { k=j; d = d1; } - } - if(k!==i) { - temp = Ax[i]; Ax[i] = Ax[k]; Ax[k] = temp; - temp = Ay[i]; Ay[i] = Ay[k]; Ay[k] = temp; - temp = Rx[i]; Rx[i] = Rx[k]; Rx[k] = temp; - temp = Ry[i]; Ry[i] = Ry[k]; Ry[k] = temp; - } - Aix = Ax[i]; Aiy = Ay[i]; - Rix = Rx[i]; Riy = Ry[i]; - ax = Aix[i]; ay = Aiy[i]; - for(j=i+1;j0;i--) { - Rix = Rx[i]; Riy = Ry[i]; - for(j=i-1;j>=0;j--) { - Rjx = Rx[j]; Rjy = Ry[j]; - ax = Ax[j][i]; ay = Ay[j][i]; - for(k=n-1;k>=0;k--) { - bx = Rix[k]; by = Riy[k]; - Rjx[k] -= ax*bx - ay*by; - Rjy[k] -= ax*by + ay*bx; - } + // return a matrix otherwise + return new matrix(result); + } + }); + + return setCartesian; + } + + var name$216 = 'setCartesian'; + var factory_1$228 = factory$229; + + var setCartesian$1 = { + name: name$216, + factory: factory_1$228 + }; + + var flatten$5 = array.flatten; + var identify = array.identify; + var generalize = array.generalize; + + function factory$230 (type, config, load, typed) { + var index = load(MatrixIndex); + var matrix = load(DenseMatrix); + var size = load(size$5); + var subset = load(subset$1); + var compareNatural = load(compareNatural$1); + + /** + * Create the difference of two (multi)sets: every element of set1, that is not the element of set2. + * Multi-dimension arrays will be converted to single-dimension arrays before the operation. + * + * Syntax: + * + * math.setDifference(set1, set2) + * + * Examples: + * + * math.setDifference([1, 2, 3, 4], [3, 4, 5, 6]); // returns [1, 2] + * math.setDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]]); // returns [1, 2] + * + * See also: + * + * setUnion, setIntersect, setSymDifference + * + * @param {Array | Matrix} a1 A (multi)set + * @param {Array | Matrix} a2 A (multi)set + * @return {Array | Matrix} The difference of two (multi)sets + */ + var setDifference = typed('setDifference', { + 'Array | Matrix, Array | Matrix': function (a1, a2) { + if (subset(size(a1), new index(0)) === 0) { // empty-anything=empty + var result = []; } - } - return new numeric.T(Rx,Ry); -}; -numeric.T.prototype.get = function get(i) { - var x = this.x, y = this.y, k = 0, ik, n = i.length; - if(y) { - while(k= 0 ? 1 : -1; - var alpha = s*numeric.norm2(x); - v[0] += alpha; - var foo = numeric.norm2(v); - if(foo === 0) { /* this should not happen */ throw new Error('eig: internal error'); } - return numeric.div(v,foo); -}; - -numeric.toUpperHessenberg = function toUpperHessenberg(me) { - var s = numeric.dim(me); - if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: toUpperHessenberg() only works on square matrices'); } - var m = s[0], i,j,k,x,v,A = numeric.clone(me),B,C,Ai,Ci,Q = numeric.identity(m),Qi; - for(j=0;j0) { - v = numeric.house(x); - B = numeric.getBlock(A,[j+1,j],[m-1,m-1]); - C = numeric.tensor(v,numeric.dot(v,B)); - for(i=j+1;i=4*det) { - var s1,s2; - s1 = 0.5*(tr+Math.sqrt(tr*tr-4*det)); - s2 = 0.5*(tr-Math.sqrt(tr*tr-4*det)); - Hloc = numeric.add(numeric.sub(numeric.dot(Hloc,Hloc), - numeric.mul(Hloc,s1+s2)), - numeric.diag(numeric.rep([3],s1*s2))); - } else { - Hloc = numeric.add(numeric.sub(numeric.dot(Hloc,Hloc), - numeric.mul(Hloc,tr)), - numeric.diag(numeric.rep([3],det))); - } - x = [Hloc[0][0],Hloc[1][0],Hloc[2][0]]; - v = numeric.house(x); - B = [H[0],H[1],H[2]]; - C = numeric.tensor(v,numeric.dot(v,B)); - for(i=0;i<3;i++) { Hi = H[i]; Ci = C[i]; for(k=0;k=0) { - if(p1<0) x = -0.5*(p1-sqrt(disc)); - else x = -0.5*(p1+sqrt(disc)); - n1 = (a-x)*(a-x)+b*b; - n2 = c*c+(d-x)*(d-x); - if(n1>n2) { - n1 = sqrt(n1); - p = (a-x)/n1; - q = b/n1; - } else { - n2 = sqrt(n2); - p = c/n2; - q = (d-x)/n2; - } - Q0 = new T([[q,-p],[p,q]]); - Q.setRows(i,j,Q0.dot(Q.getRows(i,j))); - } else { - x = -0.5*p1; - y = 0.5*sqrt(-disc); - n1 = (a-x)*(a-x)+b*b; - n2 = c*c+(d-x)*(d-x); - if(n1>n2) { - n1 = sqrt(n1+y*y); - p = (a-x)/n1; - q = b/n1; - x = 0; - y /= n1; - } else { - n2 = sqrt(n2+y*y); - p = c/n2; - q = (d-x)/n2; - x = y/n2; - y = 0; - } - Q0 = new T([[q,-p],[p,q]],[[x,y],[y,-x]]); - Q.setRows(i,j,Q0.dot(Q.getRows(i,j))); - } + // return an array, if the input was an array + if (Array.isArray(a)) { + return result; } - } - var R = Q.dot(A).dot(Q.transjugate()), n = A.length, E = numeric.T.identity(n); - for(j=0;j0) { - for(k=j-1;k>=0;k--) { - var Rk = R.get([k,k]), Rj = R.get([j,j]); - if(numeric.neq(Rk.x,Rj.x) || numeric.neq(Rk.y,Rj.y)) { - x = R.getRow(k).getBlock([k],[j-1]); - y = E.getRow(j).getBlock([k],[j-1]); - E.set([j,k],(R.get([k,j]).neg().sub(x.dot(y))).div(Rk.sub(Rj))); - } else { - E.setRow(j,E.getRow(k)); - continue; + // return a matrix otherwise + return new matrix(result); + } + }); + + return setDistinct; + } + + var name$218 = 'setDistinct'; + var factory_1$230 = factory$231; + + var setDistinct$1 = { + name: name$218, + factory: factory_1$230 + }; + + var flatten$7 = array.flatten; + var identify$1 = array.identify; + var generalize$1 = array.generalize; + + function factory$232 (type, config, load, typed) { + var index = load(MatrixIndex); + var matrix = load(DenseMatrix); + var size = load(size$5); + var subset = load(subset$1); + var compareNatural = load(compareNatural$1); + + /** + * Create the intersection of two (multi)sets. + * Multi-dimension arrays will be converted to single-dimension arrays before the operation. + * + * Syntax: + * + * math.setIntersect(set1, set2) + * + * Examples: + * + * math.setIntersect([1, 2, 3, 4], [3, 4, 5, 6]); // returns [3, 4] + * math.setIntersect([[1, 2], [3, 4]], [[3, 4], [5, 6]]); // returns [3, 4] + * + * See also: + * + * setUnion, setDifference + * + * @param {Array | Matrix} a1 A (multi)set + * @param {Array | Matrix} a2 A (multi)set + * @return {Array | Matrix} The intersection of two (multi)sets + */ + var setIntersect = typed('setIntersect', { + 'Array | Matrix, Array | Matrix': function (a1, a2) { + if (subset(size(a1), new index(0)) === 0 || subset(size(a2), new index(0)) === 0) { // of any of them is empty, return empty + var result = []; + } + else { + var b1 = identify$1(flatten$7(Array.isArray(a1) ? a1 : a1.toArray()).sort(compareNatural)); + var b2 = identify$1(flatten$7(Array.isArray(a2) ? a2 : a2.toArray()).sort(compareNatural)); + var result = []; + for (var i=0; i=counts.length) counts[counts.length] = 0; - if(foo[j]!==0) counts[j]++; - } - } - var n = counts.length; - var Ai = Array(n+1); - Ai[0] = 0; - for(i=0;i= k11) { - xj[n] = j[m]; - if(m===0) return; - ++n; - --m; - km = k[m]; - k11 = k1[m]; - } else { - foo = Pinv[Aj[km]]; - if(x[foo] === 0) { - x[foo] = 1; - k[m] = km; - ++m; - j[m] = foo; - km = Ai[foo]; - k1[m] = k11 = Ai[foo+1]; - } else ++km; - } - } -}; -numeric.ccsLPSolve = function ccsLPSolve(A,B,x,xj,I,Pinv,dfs) { - var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1; - var Bi = B[0], Bj = B[1], Bv = B[2]; - var i,i0,i1,j,j0,j1,k,l,a; - i0 = Bi[I]; - i1 = Bi[I+1]; - xj.length = 0; - for(i=i0;i0; i--) { + for (var j=0; j array$$1[j+1].length) { + temp = array$$1[j]; + array$$1[j] = array$$1[j+1]; + array$$1[j+1] = temp; + } } + } + return array$$1; } - return x; -}; -numeric.ccsLUP1 = function ccsLUP1(A,threshold) { - var m = A[0].length-1; - var L = [numeric.rep([m+1],0),[],[]], U = [numeric.rep([m+1], 0),[],[]]; - var Li = L[0], Lj = L[1], Lv = L[2], Ui = U[0], Uj = U[1], Uv = U[2]; - var x = numeric.rep([m],0), xj = numeric.rep([m],0); - var i,j,k,a,e,c,d; - var sol = numeric.ccsLPSolve, abs = Math.abs; - var P = numeric.linspace(0,m-1),Pinv = numeric.linspace(0,m-1); - var dfs = new numeric.ccsDFS(m); - if(typeof threshold === "undefined") { threshold = 1; } - for(i=0;i a) { e = k; a = c; } - } - if(abs(x[i])= k11) { - xj[n] = Pinv[j[m]]; - if(m===0) return; - ++n; - --m; - km = k[m]; - k11 = k1[m]; - } else { - foo = Aj[km]; - if(x[foo] === 0) { - x[foo] = 1; - k[m] = km; - ++m; - j[m] = foo; - foo = Pinv[foo]; - km = Ai[foo]; - k1[m] = k11 = Ai[foo+1]; - } else ++km; - } - } -}; -numeric.ccsLPSolve0 = function ccsLPSolve0(A,B,y,xj,I,Pinv,P,dfs) { - var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1; - var Bi = B[0], Bj = B[1], Bv = B[2]; + } + + var name$222 = 'setPowerset'; + var factory_1$234 = factory$235; + + var setPowerset$1 = { + name: name$222, + factory: factory_1$234 + }; + + var flatten$11 = array.flatten; + + function factory$236 (type, config, load, typed) { + var compareNatural = load(compareNatural$1); - var i,i0,i1,j,j0,j1,k,l,a; - i0 = Bi[I]; - i1 = Bi[I+1]; - xj.length = 0; - for(i=i0;i a) { e = k; a = c; } - } - if(abs(y[P[i]]) ret[k]) ret[k] = A.length; - var i; - for(i in A) { - if(A.hasOwnProperty(i)) dim(A[i],ret,k+1); - } - return ret; -}; - -numeric.sclone = function clone(A,k,n) { - if(typeof k === "undefined") { k=0; } - if(typeof n === "undefined") { n = numeric.sdim(A).length; } - var i,ret = Array(A.length); - if(k === n-1) { - for(i in A) { if(A.hasOwnProperty(i)) ret[i] = A[i]; } - return ret; - } - for(i in A) { - if(A.hasOwnProperty(i)) ret[i] = clone(A[i],k+1,n); - } - return ret; -}; + } + }); -numeric.sdiag = function diag(d) { - var n = d.length,i,ret = Array(n),i1; - for(i=n-1;i>=1;i-=2) { - i1 = i-1; - ret[i] = []; ret[i][i] = d[i]; - ret[i1] = []; ret[i1][i1] = d[i1]; + return setSize; + } + + var name$223 = 'setSize'; + var factory_1$235 = factory$236; + + var setSize$1 = { + name: name$223, + factory: factory_1$235 + }; + + var flatten$12 = array.flatten; + + function factory$237 (type, config, load, typed) { + var index = load(MatrixIndex); + var concat = load(concat$1); + var size = load(size$5); + var subset = load(subset$1); + var setDifference = load(setDifference$1); + + /** + * Create the symmetric difference of two (multi)sets. + * Multi-dimension arrays will be converted to single-dimension arrays before the operation. + * + * Syntax: + * + * math.setSymDifference(set1, set2) + * + * Examples: + * + * math.setSymDifference([1, 2, 3, 4], [3, 4, 5, 6]); // returns [1, 2, 5, 6] + * math.setSymDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]]); // returns [1, 2, 5, 6] + * + * See also: + * + * setUnion, setIntersect, setDifference + * + * @param {Array | Matrix} a1 A (multi)set + * @param {Array | Matrix} a2 A (multi)set + * @return {Array | Matrix} The symmetric difference of two (multi)sets + */ + var setSymDifference = typed('setSymDifference', { + 'Array | Matrix, Array | Matrix': function (a1, a2) { + if (subset(size(a1), new index(0)) === 0) { // if any of them is empty, return the other one + return flatten$12(a2); + } + else if (subset(size(a2), new index(0)) === 0) { + return flatten$12(a1); + } + var b1 = flatten$12(a1); + var b2 = flatten$12(a2); + return concat(setDifference(b1, b2), setDifference(b2, b1)); + } + }); + + return setSymDifference; + } + + var name$224 = 'setSymDifference'; + var factory_1$236 = factory$237; + + var setSymDifference$1 = { + name: name$224, + factory: factory_1$236 + }; + + var flatten$13 = array.flatten; + + function factory$238 (type, config, load, typed) { + var index = load(MatrixIndex); + var concat = load(concat$1); + var size = load(size$5); + var subset = load(subset$1); + var setIntersect = load(setIntersect$1); + var setSymDifference = load(setSymDifference$1); + + /** + * Create the union of two (multi)sets. + * Multi-dimension arrays will be converted to single-dimension arrays before the operation. + * + * Syntax: + * + * math.setUnion(set1, set2) + * + * Examples: + * + * math.setUnion([1, 2, 3, 4], [3, 4, 5, 6]); // returns [1, 2, 3, 4, 5, 6] + * math.setUnion([[1, 2], [3, 4]], [[3, 4], [5, 6]]); // returns [1, 2, 3, 4, 5, 6] + * + * See also: + * + * setIntersect, setDifference + * + * @param {Array | Matrix} a1 A (multi)set + * @param {Array | Matrix} a2 A (multi)set + * @return {Array | Matrix} The union of two (multi)sets + */ + var setUnion = typed('setUnion', { + 'Array | Matrix, Array | Matrix': function (a1, a2) { + if (subset(size(a1), new index(0)) === 0) { // if any of them is empty, return the other one + return flatten$13(a2); + } + else if (subset(size(a2), new index(0)) === 0) { + return flatten$13(a1); + } + var b1 = flatten$13(a1); + var b2 = flatten$13(a2); + return concat(setSymDifference(b1, b2), setIntersect(b1, b2)); + } + }); + + return setUnion; + } + + var name$225 = 'setUnion'; + var factory_1$237 = factory$238; + + var setUnion$1 = { + name: name$225, + factory: factory_1$237 + }; + + var set = [ + setCartesian$1, + setDifference$1, + setDistinct$1, + setIntersect$1, + setIsSubset$1, + setMultiplicity$1, + setPowerset$1, + setSize$1, + setSymDifference$1, + setUnion$1 + ]; + + var sign$2 = number.sign; + + + function factory$239 (type, config, load, typed) { + /** + * Compute the erf function of a value using a rational Chebyshev + * approximations for different intervals of x. + * + * This is a translation of W. J. Cody's Fortran implementation from 1987 + * ( http://www.netlib.org/specfun/erf ). See the AMS publication + * "Rational Chebyshev Approximations for the Error Function" by W. J. Cody + * for an explanation of this process. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.erf(x) + * + * Examples: + * + * math.erf(0.2); // returns 0.22270258921047847 + * math.erf(-0.5); // returns -0.5204998778130465 + * math.erf(4); // returns 0.9999999845827421 + * + * @param {number | Array | Matrix} x A real number + * @return {number | Array | Matrix} The erf of `x` + */ + var erf = typed('erf', { + 'number': function (x) { + var y = Math.abs(x); + + if (y >= MAX_NUM) { + return sign$2(x); + } + if (y <= THRESH) { + return sign$2(x) * erf1(y); + } + if (y <= 4.0) { + return sign$2(x) * (1 - erfc2(y)); + } + return sign$2(x) * (1 - erfc3(y)); + }, + + // TODO: Not sure if there's a way to guarantee some degree of accuracy here. + // Perhaps it would be best to set the precision of the number to that which + // is guaranteed by erf() + 'BigNumber': function (n) { + return new type.BigNumber(erf(n.toNumber())); + }, + + 'Array | Matrix': function (n) { + return deepMap(n, erf); + } + + // TODO: For complex numbers, use the approximation for the Faddeeva function + // from "More Efficient Computation of the Complex Error Function" (AMS) + + }); + + /** + * Approximates the error function erf() for x <= 0.46875 using this function: + * n + * erf(x) = x * sum (p_j * x^(2j)) / (q_j * x^(2j)) + * j=0 + */ + function erf1(y) { + var ysq = y * y; + var xnum = P[0][4]*ysq; + var xden = ysq; + var i; + + for (i = 0; i < 3; i += 1) { + xnum = (xnum + P[0][i]) * ysq; + xden = (xden + Q[0][i]) * ysq; + } + return y * (xnum + P[0][3]) / (xden + Q[0][3]); + } + + /** + * Approximates the complement of the error function erfc() for + * 0.46875 <= x <= 4.0 using this function: + * n + * erfc(x) = e^(-x^2) * sum (p_j * x^j) / (q_j * x^j) + * j=0 + */ + function erfc2(y) { + var xnum = P[1][8] * y; + var xden = y; + var i; + + for (i = 0; i < 7; i += 1) { + xnum = (xnum + P[1][i]) * y; + xden = (xden + Q[1][i]) * y; + } + var result = (xnum + P[1][7]) / (xden + Q[1][7]); + var ysq = parseInt(y * 16) / 16; + var del = (y - ysq) * (y + ysq); + return Math.exp(-ysq*ysq) * Math.exp(-del) * result; + } + + /** + * Approximates the complement of the error function erfc() for x > 4.0 using + * this function: + * + * erfc(x) = (e^(-x^2) / x) * [ 1/sqrt(pi) + + * n + * 1/(x^2) * sum (p_j * x^(-2j)) / (q_j * x^(-2j)) ] + * j=0 + */ + function erfc3(y) { + var ysq = 1 / (y * y); + var xnum = P[2][5] * ysq; + var xden = ysq; + var i; + + for (i = 0; i < 4; i += 1) { + xnum = (xnum + P[2][i]) * ysq; + xden = (xden + Q[2][i]) * ysq; + } + var result = ysq * (xnum + P[2][4]) / (xden + Q[2][4]); + result = (SQRPI - result) / y; + ysq = parseInt(y * 16) / 16; + var del = (y - ysq) * (y + ysq); + return Math.exp(-ysq*ysq) * Math.exp(-del) * result; + } + + erf.toTex = {1: 'erf\\left(${args[0]}\\right)'}; + + return erf; + } + + /** + * Upper bound for the first approximation interval, 0 <= x <= THRESH + * @constant + */ + var THRESH = 0.46875; + + /** + * Constant used by W. J. Cody's Fortran77 implementation to denote sqrt(pi) + * @constant + */ + var SQRPI = 5.6418958354775628695e-1; + + /** + * Coefficients for each term of the numerator sum (p_j) for each approximation + * interval (see W. J. Cody's paper for more details) + * @constant + */ + var P = [[ + 3.16112374387056560e00, 1.13864154151050156e02, + 3.77485237685302021e02, 3.20937758913846947e03, + 1.85777706184603153e-1 + ], [ + 5.64188496988670089e-1, 8.88314979438837594e00, + 6.61191906371416295e01, 2.98635138197400131e02, + 8.81952221241769090e02, 1.71204761263407058e03, + 2.05107837782607147e03, 1.23033935479799725e03, + 2.15311535474403846e-8 + ], [ + 3.05326634961232344e-1, 3.60344899949804439e-1, + 1.25781726111229246e-1, 1.60837851487422766e-2, + 6.58749161529837803e-4, 1.63153871373020978e-2 + ]]; + + /** + * Coefficients for each term of the denominator sum (q_j) for each approximation + * interval (see W. J. Cody's paper for more details) + * @constant + */ + var Q = [[ + 2.36012909523441209e01, 2.44024637934444173e02, + 1.28261652607737228e03, 2.84423683343917062e03 + ], [ + 1.57449261107098347e01, 1.17693950891312499e02, + 5.37181101862009858e02, 1.62138957456669019e03, + 3.29079923573345963e03, 4.36261909014324716e03, + 3.43936767414372164e03, 1.23033935480374942e03 + ], [ + 2.56852019228982242e00, 1.87295284992346047e00, + 5.27905102951428412e-1, 6.05183413124413191e-2, + 2.33520497626869185e-3 + ]]; + + /** + * Maximum/minimum safe numbers to input to erf() (in ES6+, this number is + * Number.[MAX|MIN]_SAFE_INTEGER). erf() for all numbers beyond this limit will + * return 1 + */ + var MAX_NUM = Math.pow(2, 53); + + + var name$226 = 'erf'; + var factory_1$238 = factory$239; + + var erf$1 = { + name: name$226, + factory: factory_1$238 + }; + + var special = [ + erf$1 + ]; + + var flatten$14 = array.flatten; + + + function factory$240 (type, config, load, typed) { + var add = load(addScalar); + var divide = load(divideScalar); + var compare = load(compare$1); + var partitionSelect = load(partitionSelect$1); + var improveErrorMessage$$1 = load(improveErrorMessage); + + /** + * Compute the median of a matrix or a list with values. The values are + * sorted and the middle value is returned. In case of an even number of + * values, the average of the two middle values is returned. + * Supported types of values are: Number, BigNumber, Unit + * + * In case of a (multi dimensional) array or matrix, the median of all + * elements will be calculated. + * + * Syntax: + * + * math.median(a, b, c, ...) + * math.median(A) + * + * Examples: + * + * math.median(5, 2, 7); // returns 5 + * math.median([3, -1, 5, 7]); // returns 4 + * + * See also: + * + * mean, min, max, sum, prod, std, var, quantileSeq + * + * @param {... *} args A single matrix or or multiple scalar values + * @return {*} The median + */ + var median = typed('median', { + // median([a, b, c, d, ...]) + 'Array | Matrix': _median, + + // median([a, b, c, d, ...], dim) + 'Array | Matrix, number | BigNumber': function (array$$1, dim) { + // TODO: implement median(A, dim) + throw new Error('median(A, dim) is not yet supported'); + //return reduce(arguments[0], arguments[1], ...); + }, + + // median(a, b, c, d, ...) + '...': function (args) { + if (containsCollections(args)) { + throw new TypeError('Scalar values expected in function median'); + } + + return _median(args); + } + }); + + + /** + * Recursively calculate the median of an n-dimensional array + * @param {Array} array + * @return {Number} median + * @private + */ + function _median(array$$1) { + try { + array$$1 = flatten$14(array$$1.valueOf()); + + var num = array$$1.length; + if (num == 0) { + throw new Error('Cannot calculate median of an empty array'); + } + + if (num % 2 == 0) { + // even: return the average of the two middle values + var mid = num / 2 - 1; + var right = partitionSelect(array$$1, mid + 1); + + // array now partitioned at mid + 1, take max of left part + var left = array$$1[mid]; + for (var i = 0; i < mid; ++i) { + if (compare(array$$1[i], left) > 0) { + left = array$$1[i]; + } + } + + return middle2(left, right); + } + else { + // odd: return the middle value + var m = partitionSelect(array$$1, (num - 1) / 2); + + return middle(m); + } + } + catch (err) { + throw improveErrorMessage$$1(err, 'median'); + } + } + + // helper function to type check the middle value of the array + var middle = typed({ + 'number | BigNumber | Complex | Unit': function (value) { + return value; + } + }); + + // helper function to type check the two middle value of the array + var middle2 = typed({ + 'number | BigNumber | Complex | Unit, number | BigNumber | Complex | Unit': function (left, right) { + return divide(add(left, right), 2); + } + }); + + median.toTex = undefined; // use default template + + return median; + } + + var name$227 = 'median'; + var factory_1$239 = factory$240; + + var median$1 = { + name: name$227, + factory: factory_1$239 + }; + + var flatten$15 = array.flatten; + + function factory$241 (type, config, load, typed) { + var abs = load(abs$1); + var map = load(map$7); + var median = load(median$1); + var subtract = load(subtract$1); + var improveErrorMessage$$1 = load(improveErrorMessage); + + /** + * Compute the median absolute deviation of a matrix or a list with values. + * The median absolute deviation is defined as the median of the absolute + * deviations from the median. + * + * Syntax: + * + * math.mad(a, b, c, ...) + * math.mad(A) + * + * Examples: + * + * math.mad(10, 20, 30); // returns 10 + * math.mad([1, 2, 3]); // returns 1 + * math.mad([[1, 2, 3], [4, 5, 6]]); // returns 1.5 + * + * See also: + * + * median, mean, std, abs + * + * @param {Array | Matrix} array + * A single matrix or multiple scalar values. + * @return {*} The median absolute deviation. + */ + var mad = typed('mad', { + // mad([a, b, c, d, ...]) + 'Array | Matrix': _mad, + + // mad(a, b, c, d, ...) + '...': function (args) { + return _mad(args); + } + }); + + mad.toTex = undefined; // use default template + + return mad; + + function _mad(array$$1) { + array$$1 = flatten$15(array$$1.valueOf()); + + if (array$$1.length === 0) { + throw new Error('Cannot calculate median absolute deviation (mad) of an empty array'); + } + + try { + var med = median(array$$1); + return median(map(array$$1, function (value) { + return abs(subtract(value, med)); + })); + } + catch (err) { + if (err instanceof TypeError && err.message.indexOf('median') !== -1) { + throw new TypeError(err.message.replace('median', 'mad')); + } + else { + throw improveErrorMessage$$1(err, 'mad'); + } + } + } + } + + var name$228 = 'mad'; + var factory_1$240 = factory$241; + + var mad$1 = { + name: name$228, + factory: factory_1$240 + }; + + var flatten$16 = array.flatten; + + function factory$242 (type, config, load, typed) { + + /** + * Computes the mode of a set of numbers or a list with values(numbers or characters). + * If there are more than one modes, it returns a list of those values. + * + * Syntax: + * + * math.mode(a, b, c, ...) + * math.mode(A) + * + * Examples: + * + * math.mode(2, 1, 4, 3, 1); // returns [1] + * math.mode([1, 2.7, 3.2, 4, 2.7]); // returns [2.7] + * math.mode(1, 4, 6, 1, 6) // returns [1, 6] + * math.mode('a','a','b','c') // returns ["a"] + * math.mode(1, 1.5, 'abc') // returns [1, 1.5, "abc"] + * + * See also: + * + * median, + * mean + * + * @param {... *} args A single matrix + * @return {*} The mode of all values + */ + + var mode = typed('mode', { + 'Array | Matrix' : _mode, + + '...': function (args) { + return _mode(args); + } + }); + + return mode; + + /** + * Calculates the mode in an 1-dimensional array + * @param {Array} values + * @return {number} mode + * @private + */ + function _mode(values) { + values = flatten$16(values.valueOf()); + var num = values.length; + if (num == 0) { + throw new Error('Cannot calculate mode of an empty array'); + } + + var count = {}, + mode = [], + max = 0; + for (var i in values) { + if (!(values[i] in count)){ + count[values[i]] = 0; + } + count[values[i]]++; + if (count[values[i]] == max){ + mode.push(values[i]); + } + else if (count[values[i]] > max) { + max = count[values[i]]; + mode = [values[i]]; + } + } + return mode; + }} + + var name$229 = 'mode'; + var factory_1$241 = factory$242; + + var mode$1 = { + name: name$229, + factory: factory_1$241 + }; + + function factory$243 (type, config, load, typed) { + var multiply = load(multiplyScalar); + var improveErrorMessage$$1 = load(improveErrorMessage); + + /** + * Compute the product of a matrix or a list with values. + * In case of a (multi dimensional) array or matrix, the sum of all + * elements will be calculated. + * + * Syntax: + * + * math.prod(a, b, c, ...) + * math.prod(A) + * + * Examples: + * + * math.multiply(2, 3); // returns 6 + * math.prod(2, 3); // returns 6 + * math.prod(2, 3, 4); // returns 24 + * math.prod([2, 3, 4]); // returns 24 + * math.prod([[2, 5], [4, 3]]); // returns 120 + * + * See also: + * + * mean, median, min, max, sum, std, var + * + * @param {... *} args A single matrix or or multiple scalar values + * @return {*} The product of all values + */ + var prod = typed('prod', { + // prod([a, b, c, d, ...]) + 'Array | Matrix': _prod, + + // prod([a, b, c, d, ...], dim) + 'Array | Matrix, number | BigNumber': function (array, dim) { + // TODO: implement prod(A, dim) + throw new Error('prod(A, dim) is not yet supported'); + //return reduce(arguments[0], arguments[1], math.prod); + }, + + // prod(a, b, c, d, ...) + '...': function (args) { + return _prod(args); + } + }); + + prod.toTex = undefined; // use default template + + return prod; + + /** + * Recursively calculate the product of an n-dimensional array + * @param {Array} array + * @return {number} prod + * @private + */ + function _prod(array) { + var prod = undefined; + + deepForEach(array, function (value) { + try { + prod = (prod === undefined) ? value : multiply(prod, value); + } + catch (err) { + throw improveErrorMessage$$1(err, 'prod', value); + } + }); + + if (prod === undefined) { + throw new Error('Cannot calculate prod of an empty array'); + } + + return prod; + } + } + + var name$230 = 'prod'; + var factory_1$242 = factory$243; + + var prod$1 = { + name: name$230, + factory: factory_1$242 + }; + + var isInteger$29 = number.isInteger; + var isNumber$4 = number.isNumber; + var flatten$17 = array.flatten; + + + function factory$244 (type, config, load, typed) { + var add$$1 = load(add); + var multiply = load(multiply$1); + var partitionSelect = load(partitionSelect$1); + var compare = load(compare$1); + + /** + * Compute the prob order quantile of a matrix or a list with values. + * The sequence is sorted and the middle value is returned. + * Supported types of sequence values are: Number, BigNumber, Unit + * Supported types of probability are: Number, BigNumber + * + * In case of a (multi dimensional) array or matrix, the prob order quantile + * of all elements will be calculated. + * + * Syntax: + * + * math.quantileSeq(A, prob[, sorted]) + * math.quantileSeq(A, [prob1, prob2, ...][, sorted]) + * math.quantileSeq(A, N[, sorted]) + * + * Examples: + * + * math.quantileSeq([3, -1, 5, 7], 0.5); // returns 4 + * math.quantileSeq([3, -1, 5, 7], [1/3, 2/3]); // returns [3, 5] + * math.quantileSeq([3, -1, 5, 7], 2); // returns [3, 5] + * math.quantileSeq([-1, 3, 5, 7], 0.5, true); // returns 4 + * + * See also: + * + * median, mean, min, max, sum, prod, std, var + * + * @param {Array, Matrix} data A single matrix or Array + * @param {Number, BigNumber, Array} probOrN prob is the order of the quantile, while N is + * the amount of evenly distributed steps of + * probabilities; only one of these options can + * be provided + * @param {Boolean} sorted=false is data sorted in ascending order + * @return {Number, BigNumber, Unit, Array} Quantile(s) + */ + function quantileSeq(data, probOrN, sorted) { + var probArr, dataArr, one; + + if (arguments.length < 2 || arguments.length > 3) { + throw new SyntaxError('Function quantileSeq requires two or three parameters'); + } + + if (isCollection(data)) { + sorted = sorted || false; + if (typeof sorted === 'boolean') { + dataArr = data.valueOf(); + if (isNumber$4(probOrN)) { + if (probOrN < 0) { + throw new Error('N/prob must be non-negative'); + } + + if (probOrN <= 1) { + // quantileSeq([a, b, c, d, ...], prob[,sorted]) + return _quantileSeq(dataArr, probOrN, sorted); + } + + if (probOrN > 1) { + // quantileSeq([a, b, c, d, ...], N[,sorted]) + if (!isInteger$29(probOrN)) { + throw new Error('N must be a positive integer'); + } + + var nPlusOne = probOrN + 1; + probArr = new Array(probOrN); + for (var i = 0; i < probOrN;) { + probArr[i] = _quantileSeq(dataArr, (++i) / nPlusOne, sorted); + } + return probArr; + } + } + + if (type.isBigNumber(probOrN)) { + if (probOrN.isNegative()) { + throw new Error('N/prob must be non-negative'); + } + + one = new probOrN.constructor(1); + + if (probOrN.lte(one)) { + // quantileSeq([a, b, c, d, ...], prob[,sorted]) + return _quantileSeq(dataArr, probOrN, sorted); + } + + if (probOrN.gt(one)) { + // quantileSeq([a, b, c, d, ...], N[,sorted]) + if (!probOrN.isInteger()) { + throw new Error('N must be a positive integer'); + } + + // largest possible Array length is 2^32-1; + // 2^32 < 10^15, thus safe conversion guaranteed + var intN = probOrN.toNumber(); + if (intN > 4294967295) { + throw new Error('N must be less than or equal to 2^32-1, as that is the maximum length of an Array'); + } + + var nPlusOne = new type.BigNumber(intN + 1); + probArr = new Array(intN); + for (var i = 0; i < intN;) { + probArr[i] = _quantileSeq(dataArr, new type.BigNumber(++i).div(nPlusOne), sorted); + } + return probArr; + } + } + + if (Array.isArray(probOrN)) { + // quantileSeq([a, b, c, d, ...], [prob1, prob2, ...][,sorted]) + probArr = new Array(probOrN.length); + for (var i = 0; i < probArr.length; ++i) { + var currProb = probOrN[i]; + if (isNumber$4(currProb)) { + if (currProb < 0 || currProb > 1) { + throw new Error('Probability must be between 0 and 1, inclusive'); + } + } else if (type.isBigNumber(currProb)) { + one = new currProb.constructor(1); + if (currProb.isNegative() || currProb.gt(one)) { + throw new Error('Probability must be between 0 and 1, inclusive'); + } + } else { + throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function + } + + probArr[i] = _quantileSeq(dataArr, currProb, sorted); + } + return probArr; + } + + throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function + } + + throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function + } + + throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function + } + + /** + * Calculate the prob order quantile of an n-dimensional array. + * + * @param {Array} array + * @param {Number, BigNumber} prob + * @param {Boolean} sorted + * @return {Number, BigNumber, Unit} prob order quantile + * @private + */ + function _quantileSeq(array$$1, prob, sorted) { + var flat = flatten$17(array$$1); + var len = flat.length; + if (len === 0) { + throw new Error('Cannot calculate quantile of an empty sequence'); + } + + if (isNumber$4(prob)) { + var index = prob * (len-1); + var fracPart = index % 1; + if (fracPart === 0) { + var value = sorted ? flat[index] : partitionSelect(flat, index); + + validate(value); + + return value; + } + + var integerPart = Math.floor(index); + + var left, right; + if (sorted) { + left = flat[integerPart]; + right = flat[integerPart+1]; + } else { + right = partitionSelect(flat, integerPart+1); + + // max of partition is kth largest + left = flat[integerPart]; + for (var i = 0; i < integerPart; ++i) { + if (compare(flat[i], left) > 0) { + left = flat[i]; + } + } + } + + validate(left); + validate(right); + + // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1] + return add$$1(multiply(left, 1 - fracPart), multiply(right, fracPart)); + } + + // If prob is a BigNumber + var index = prob.times(len-1); + if (index.isInteger()) { + index = index.toNumber(); + var value = sorted ? flat[index] : partitionSelect(flat, index); + + validate(value); + + return value; + } + + var integerPart = index.floor(); + var fracPart = index.minus(integerPart); + var integerPartNumber = integerPart.toNumber(); + + var left, right; + if (sorted) { + left = flat[integerPartNumber]; + right = flat[integerPartNumber+1]; + } else { + right = partitionSelect(flat, integerPartNumber+1); + + // max of partition is kth largest + left = flat[integerPartNumber]; + for (var i = 0; i < integerPartNumber; ++i) { + if (compare(flat[i], left) > 0) { + left = flat[i]; + } + } + } + + validate(left); + validate(right); + + // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1] + var one = new fracPart.constructor(1); + return add$$1(multiply(left, one.minus(fracPart)), multiply(right, fracPart)); + } + + /** + * Check if array value types are valid, throw error otherwise. + * @param {number | BigNumber | Unit} x + * @param {number | BigNumber | Unit} x + * @private + */ + var validate = typed({ + 'number | BigNumber | Unit': function (x) { + return x; + } + }); + + return quantileSeq; + } + + var name$231 = 'quantileSeq'; + var factory_1$243 = factory$244; + + var quantileSeq$1 = { + name: name$231, + factory: factory_1$243 + }; + + var DEFAULT_NORMALIZATION = 'unbiased'; + + + + function factory$245 (type, config, load, typed) { + var add = load(addScalar); + var subtract = load(subtract$1); + var multiply = load(multiplyScalar); + var divide = load(divideScalar); + var improveErrorMessage$$1 = load(improveErrorMessage); + + /** + * Compute the variance of a matrix or a list with values. + * In case of a (multi dimensional) array or matrix, the variance over all + * elements will be calculated. + * + * Optionally, the type of normalization can be specified as second + * parameter. The parameter `normalization` can be one of the following values: + * + * - 'unbiased' (default) The sum of squared errors is divided by (n - 1) + * - 'uncorrected' The sum of squared errors is divided by n + * - 'biased' The sum of squared errors is divided by (n + 1) + * + * Note that older browser may not like the variable name `var`. In that + * case, the function can be called as `math['var'](...)` instead of + * `math.var(...)`. + * + * Syntax: + * + * math.var(a, b, c, ...) + * math.var(A) + * math.var(A, normalization) + * + * Examples: + * + * math.var(2, 4, 6); // returns 4 + * math.var([2, 4, 6, 8]); // returns 6.666666666666667 + * math.var([2, 4, 6, 8], 'uncorrected'); // returns 5 + * math.var([2, 4, 6, 8], 'biased'); // returns 4 + * + * math.var([[1, 2, 3], [4, 5, 6]]); // returns 3.5 + * + * See also: + * + * mean, median, max, min, prod, std, sum + * + * @param {Array | Matrix} array + * A single matrix or or multiple scalar values + * @param {string} [normalization='unbiased'] + * Determines how to normalize the variance. + * Choose 'unbiased' (default), 'uncorrected', or 'biased'. + * @return {*} The variance + */ + var variance = typed('variance', { + // var([a, b, c, d, ...]) + 'Array | Matrix': function (array) { + return _var(array, DEFAULT_NORMALIZATION); + }, + + // var([a, b, c, d, ...], normalization) + 'Array | Matrix, string': _var, + + // var(a, b, c, d, ...) + '...': function (args) { + return _var(args, DEFAULT_NORMALIZATION); + } + }); + + variance.toTex = '\\mathrm{Var}\\left(${args}\\right)'; + + return variance; + + /** + * Recursively calculate the variance of an n-dimensional array + * @param {Array} array + * @param {string} normalization + * Determines how to normalize the variance: + * - 'unbiased' The sum of squared errors is divided by (n - 1) + * - 'uncorrected' The sum of squared errors is divided by n + * - 'biased' The sum of squared errors is divided by (n + 1) + * @return {number | BigNumber} variance + * @private + */ + function _var(array, normalization) { + var sum = 0; + var num = 0; + + if (array.length == 0) { + throw new SyntaxError('Function var requires one or more parameters (0 provided)'); + } + + // calculate the mean and number of elements + deepForEach(array, function (value) { + try { + sum = add(sum, value); + num++; + } + catch (err) { + throw improveErrorMessage$$1(err, 'var', value); + } + }); + if (num === 0) throw new Error('Cannot calculate var of an empty array'); + + var mean = divide(sum, num); + + // calculate the variance + sum = 0; + deepForEach(array, function (value) { + var diff = subtract(value, mean); + sum = add(sum, multiply(diff, diff)); + }); + + switch (normalization) { + case 'uncorrected': + return divide(sum, num); + + case 'biased': + return divide(sum, num + 1); + + case 'unbiased': + var zero = type.isBigNumber(sum) ? new type.BigNumber(0) : 0; + return (num == 1) ? zero : divide(sum, num - 1); + + default: + throw new Error('Unknown normalization "' + normalization + '". ' + + 'Choose "unbiased" (default), "uncorrected", or "biased".'); + } + } + } + + var name$232 = 'var'; + var factory_1$244 = factory$245; + + var _var$1 = { + name: name$232, + factory: factory_1$244 + }; + + function factory$246 (type, config, load, typed) { + var sqrt = load(sqrt$1); + var variance = load(_var$1); + + /** + * Compute the standard deviation of a matrix or a list with values. + * The standard deviations is defined as the square root of the variance: + * `std(A) = sqrt(var(A))`. + * In case of a (multi dimensional) array or matrix, the standard deviation + * over all elements will be calculated. + * + * Optionally, the type of normalization can be specified as second + * parameter. The parameter `normalization` can be one of the following values: + * + * - 'unbiased' (default) The sum of squared errors is divided by (n - 1) + * - 'uncorrected' The sum of squared errors is divided by n + * - 'biased' The sum of squared errors is divided by (n + 1) + * + * Syntax: + * + * math.std(a, b, c, ...) + * math.std(A) + * math.std(A, normalization) + * + * Examples: + * + * math.std(2, 4, 6); // returns 2 + * math.std([2, 4, 6, 8]); // returns 2.581988897471611 + * math.std([2, 4, 6, 8], 'uncorrected'); // returns 2.23606797749979 + * math.std([2, 4, 6, 8], 'biased'); // returns 2 + * + * math.std([[1, 2, 3], [4, 5, 6]]); // returns 1.8708286933869707 + * + * See also: + * + * mean, median, max, min, prod, sum, var + * + * @param {Array | Matrix} array + * A single matrix or or multiple scalar values + * @param {string} [normalization='unbiased'] + * Determines how to normalize the variance. + * Choose 'unbiased' (default), 'uncorrected', or 'biased'. + * @return {*} The standard deviation + */ + var std = typed('std', { + // std([a, b, c, d, ...]) + 'Array | Matrix': _std, + + // std([a, b, c, d, ...], normalization) + 'Array | Matrix, string': _std, + + // std(a, b, c, d, ...) + '...': function (args) { + return _std(args); + } + }); + + std.toTex = undefined; // use default template + + return std; + + function _std(array, normalization) { + if (array.length == 0) { + throw new SyntaxError('Function std requires one or more parameters (0 provided)'); + } + + try { + return sqrt(variance.apply(null, arguments)); + } + catch (err) { + if (err instanceof TypeError && err.message.indexOf(' var') !== -1) { + throw new TypeError(err.message.replace(' var', ' std')); + } + else { + throw err; + } + } + } + } + + var name$233 = 'std'; + var factory_1$245 = factory$246; + + var std$1 = { + name: name$233, + factory: factory_1$245 + }; + + var statistics = [ + mad$1, + max$1, + mean$1, + median$1, + min$1, + mode$1, + prod$1, + quantileSeq$1, + std$1, + sum$1, + _var$1 + ]; + + function factory$247 (type, config, load, typed) { + /** + * Format a value of any type into a string. + * + * Syntax: + * + * math.format(value) + * math.format(value, options) + * math.format(value, precision) + * math.format(value, callback) + * + * Where: + * + * - `value: *` + * The value to be formatted + * - `options: Object` + * An object with formatting options. Available options: + * - `notation: string` + * 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 + * `lower` and `upper` bounds, and uses exponential notation elsewhere. + * Lower bound is included, upper bound is excluded. + * For example '123.4' and '1.4e7'. + * - `precision: number` + * A number between 0 and 16 to round the digits of the number. In case + * of notations 'exponential' 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. + * - `lowerExp: number` + * Exponent determining the lower boundary for formatting a value with + * an exponent when `notation='auto`. Default value is `-3`. + * - `upperExp: number` + * Exponent determining the upper boundary for formatting a value with + * an exponent when `notation='auto`. Default value is `5`. + * - `fraction: string`. Available values: 'ratio' (default) or 'decimal'. + * For example `format(fraction(1, 3))` will output '1/3' when 'ratio' is + * configured, and will output `0.(3)` when 'decimal' is configured. + * - `callback: function` + * A custom formatting function, invoked for all numeric elements in `value`, + * for example all elements of a matrix, or the real and imaginary + * parts of a complex number. This callback can be used to override the + * built-in numeric notation with any type of formatting. Function `callback` + * is called with `value` as parameter and must return a string. + * + * When `value` is an Object: + * + * - When the object contains a property `format` being a function, this function + * is invoked as `value.format(options)` and the result is returned. + * - When the object has its own `toString` method, this method is invoked + * and the result is returned. + * - In other cases the function will loop over all object properties and + * return JSON object notation like '{"a": 2, "b": 3}'. + * + * When value is a function: + * + * - When the function has a property `syntax`, it returns this + * syntax description. + * - In other cases, a string `'function'` is returned. + * + * Examples: + * + * math.format(6.4); // returns '6.4' + * math.format(1240000); // returns '1.24e6' + * math.format(1/3); // returns '0.3333333333333333' + * math.format(1/3, 3); // returns '0.333' + * math.format(21385, 2); // returns '21000' + * math.format(12e8, {notation: 'fixed'}); // returns '1200000000' + * math.format(2.3, {notation: 'fixed', precision: 4}); // returns '2.3000' + * math.format(52.8, {notation: 'exponential'}); // returns '5.28e+1' + * math.format(12400,{notation: 'engineering'}); // returns '12.400e+3' + * math.format(2000, {lowerExp: -2, upperExp: 2}); // returns '2e+3' + * + * function formatCurrency(value) { + * // return currency notation with two digits: + * return '$' + value.toFixed(2); + * + * // you could also use math.format inside the callback: + * // return '$' + math.format(value, {notation: 'fixed', precision: 2}); + * } + * math.format([2.1, 3, 0.016], formatCurrency}; // returns '[$2.10, $3.00, $0.02]' + * + * See also: + * + * print + * + * @param {*} value Value to be stringified + * @param {Object | Function | number} [options] Formatting options + * @return {string} The formatted value + */ + var format = typed('format', { + 'any': string.format, + 'any, Object | function | number': string.format + }); + + format.toTex = undefined; // use default template + + return format; + } + + var name$234 = 'format'; + var factory_1$246 = factory$247; + + var format$8 = { + name: name$234, + factory: factory_1$246 + }; + + var isString$5 = string.isString; + var format$9 = string.format; + + function factory$248 (type, config, load, typed) { + /** + * Interpolate values into a string template. + * + * Syntax: + * + * math.print(template, values) + * math.print(template, values, precision) + * math.print(template, values, options) + * + * Example usage: + * + * // the following outputs: 'Lucy is 5 years old' + * math.print('Lucy is $age years old', {age: 5}); + * + * // the following outputs: 'The value of pi is 3.141592654' + * math.print('The value of pi is $pi', {pi: math.pi}, 10); + * + * // the following outputs: 'hello Mary! The date is 2013-03-23' + * math.print('Hello $user.name! The date is $date', { + * user: { + * name: 'Mary', + * }, + * date: new Date(2013, 2, 23).toISOString().substring(0, 10) + * }); + * + * // the following outputs: 'My favorite fruits are apples and bananas !' + * math.print('My favorite fruits are $0 and $1 !', [ + * 'apples', + * 'bananas' + * ]); + * + * See also: + * + * format + * + * @param {string} template A string containing variable placeholders. + * @param {Object | Array | Matrix} values An object or array containing variables + * which will be filled in in the template. + * @param {number | Object} [options] Formatting options, + * or the number of digits to format numbers. + * See function math.format for a description + * of all options. + * @return {string} Interpolated string + */ + var print = typed ('print', { + // note: Matrix will be converted automatically to an Array + 'string, Object | Array': _print, + 'string, Object | Array, number | Object': _print + }); + + print.toTex = undefined; // use default template + + return print; + } + + /** + * Interpolate values into a string template. + * @param {string} template + * @param {Object} values + * @param {number | Object} [options] + * @returns {string} Interpolated string + * @private + */ + function _print(template, values, options) { + return template.replace(/\$([\w\.]+)/g, function (original, key) { + var keys = key.split('.'); + var value = values[keys.shift()]; + while (keys.length && value !== undefined) { + var k = keys.shift(); + value = k ? value[k] : value + '.'; + } + + if (value !== undefined) { + if (!isString$5(value)) { + return format$9(value, options); + } + else { + return value; + } + } + + return original; + } + ); + } + + var name$235 = 'print'; + var factory_1$247 = factory$248; + + var print = { + name: name$235, + factory: factory_1$247 + }; + + var string$10 = [ + format$8, + print + ]; + + function factory$249 (type, config, load, typed) { + + /** + * Calculate the inverse cosine of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.acos(x) + * + * Examples: + * + * math.acos(0.5); // returns number 1.0471975511965979 + * math.acos(math.cos(1.5)); // returns number 1.5 + * + * math.acos(2); // returns Complex 0 + 1.3169578969248166 i + * + * See also: + * + * cos, atan, asin + * + * @param {number | BigNumber | Complex | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} The arc cosine of x + */ + var acos = typed('acos', { + 'number': function (x) { + if ((x >= -1 && x <= 1) || config.predictable) { + return Math.acos(x); + } + else { + return new type.Complex(x, 0).acos(); + } + }, + + 'Complex': function (x) { + return x.acos(); + }, + + 'BigNumber': function (x) { + return x.acos(); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, acos); + } + }); + + acos.toTex = {1: '\\cos^{-1}\\left(${args[0]}\\right)'}; + + return acos; + } + + var name$236 = 'acos'; + var factory_1$248 = factory$249; + + var acos$1 = { + name: name$236, + factory: factory_1$248 + }; + + function factory$250 (type, config, load, typed) { + + /** + * Calculate the hyperbolic arccos of a value, + * defined as `acosh(x) = ln(sqrt(x^2 - 1) + x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.acosh(x) + * + * Examples: + * + * math.acosh(1.5); // returns 0.9624236501192069 + * + * See also: + * + * cosh, asinh, atanh + * + * @param {number | Complex | Unit | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic arccosine of x + */ + var acosh = typed('acosh', { + 'number': function (x) { + if (x >= 1 || config.predictable) { + return _acosh(x); + } + if (x <= -1) { + return new type.Complex(Math.log(Math.sqrt(x*x - 1) - x), Math.PI); + } + return new type.Complex(x, 0).acosh(); + }, + + 'Complex': function (x) { + return x.acosh(); + }, + + 'BigNumber': function (x) { + return x.acosh(); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, acosh); + } + }); + + acosh.toTex = {1: '\\cosh^{-1}\\left(${args[0]}\\right)'}; + + return acosh; + } + + /** + * Calculate the hyperbolic arccos of a number + * @param {number} x + * @return {number} + * @private + */ + var _acosh = Math.acosh || function (x) { + return Math.log(Math.sqrt(x*x - 1) + x) + }; + + var name$237 = 'acosh'; + var factory_1$249 = factory$250; + + var acosh$1 = { + name: name$237, + factory: factory_1$249 + }; + + function factory$251 (type, config, load, typed) { + + /** + * Calculate the inverse cotangent of a value, defined as `acot(x) = atan(1/x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.acot(x) + * + * Examples: + * + * math.acot(0.5); // returns number 0.4636476090008061 + * math.acot(math.cot(1.5)); // returns number 1.5 + * + * math.acot(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i + * + * See also: + * + * cot, atan + * + * @param {number | Complex | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} The arc cotangent of x + */ + var acot = typed('acot', { + 'number': function (x) { + return Math.atan(1 / x); + }, + + 'Complex': function (x) { + return x.acot(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x).atan(); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, acot); + } + }); + + acot.toTex = {1: '\\cot^{-1}\\left(${args[0]}\\right)'}; + + return acot; + } + + var name$238 = 'acot'; + var factory_1$250 = factory$251; + + var acot$1 = { + name: name$238, + factory: factory_1$250 + }; + + function factory$252 (type, config, load, typed) { + + /** + * Calculate the hyperbolic arccotangent of a value, + * defined as `acoth(x) = atanh(1/x) = (ln((x+1)/x) + ln(x/(x-1))) / 2`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.acoth(x) + * + * Examples: + * + * math.acoth(0.5); // returns 0.8047189562170503 + * + * See also: + * + * acsch, asech + * + * @param {number | Complex | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic arccotangent of x + */ + var acoth = typed('acoth', { + 'number': function (x) { + if (x >= 1 || x <= -1 || config.predictable) { + return isFinite(x) ? (Math.log((x+1)/x) + Math.log(x/(x-1))) / 2 : 0; + } + return new type.Complex(x, 0).acoth(); + }, + + 'Complex': function (x) { + return x.acoth(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x).atanh(); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, acoth); + } + }); + + acoth.toTex = {1: '\\coth^{-1}\\left(${args[0]}\\right)'}; + + return acoth; + } + + var name$239 = 'acoth'; + var factory_1$251 = factory$252; + + var acoth$1 = { + name: name$239, + factory: factory_1$251 + }; + + function factory$253 (type, config, load, typed) { + + /** + * Calculate the inverse cosecant of a value, defined as `acsc(x) = asin(1/x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.acsc(x) + * + * Examples: + * + * math.acsc(0.5); // returns number 0.5235987755982989 + * math.acsc(math.csc(1.5)); // returns number ~1.5 + * + * math.acsc(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i + * + * See also: + * + * csc, asin, asec + * + * @param {number | Complex | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} The arc cosecant of x + */ + var acsc = typed('acsc', { + 'number': function (x) { + if (x <= -1 || x >= 1 || config.predictable) { + return Math.asin(1 / x); + } + return new type.Complex(x, 0).acsc(); + }, + + 'Complex': function (x) { + return x.acsc(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x).asin(); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, acsc); + } + }); + + acsc.toTex = {1: '\\csc^{-1}\\left(${args[0]}\\right)'}; + + return acsc; + } + + var name$240 = 'acsc'; + var factory_1$252 = factory$253; + + var acsc$1 = { + name: name$240, + factory: factory_1$252 + }; + + function factory$254 (type, config, load, typed) { + + /** + * Calculate the hyperbolic arccosecant of a value, + * defined as `acsch(x) = asinh(1/x) = ln(1/x + sqrt(1/x^2 + 1))`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.acsch(x) + * + * Examples: + * + * math.acsch(0.5); // returns 1.4436354751788103 + * + * See also: + * + * asech, acoth + * + * @param {number | Complex | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic arccosecant of x + */ + var acsch = typed('acsch', { + 'number': function (x) { + x = 1 / x; + return Math.log(x + Math.sqrt(x*x + 1)); + }, + + 'Complex': function (x) { + return x.acsch(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x).asinh(); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, acsch); + } + }); + + acsch.toTex = {1: '\\mathrm{csch}^{-1}\\left(${args[0]}\\right)'}; + + return acsch; + } + + var name$241 = 'acsch'; + var factory_1$253 = factory$254; + + var acsch$1 = { + name: name$241, + factory: factory_1$253 + }; + + function factory$255 (type, config, load, typed) { + + /** + * Calculate the inverse secant of a value. Defined as `asec(x) = acos(1/x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.asec(x) + * + * Examples: + * + * math.asec(0.5); // returns 1.0471975511965979 + * math.asec(math.sec(1.5)); // returns 1.5 + * + * math.asec(2); // returns 0 + 1.3169578969248166 i + * + * See also: + * + * acos, acot, acsc + * + * @param {number | Complex | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} The arc secant of x + */ + var asec = typed('asec', { + 'number': function (x) { + if (x <= -1 || x >= 1 || config.predictable) { + return Math.acos(1 / x); + } + return new type.Complex(x, 0).asec(); + }, + + 'Complex': function (x) { + return x.asec(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x).acos(); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, asec); + } + }); + + asec.toTex = {1: '\\sec^{-1}\\left(${args[0]}\\right)'}; + + return asec; + } + + var name$242 = 'asec'; + var factory_1$254 = factory$255; + + var asec$1 = { + name: name$242, + factory: factory_1$254 + }; + + function factory$256 (type, config, load, typed) { + var acosh = typed.find(load(acosh$1), ['Complex']); + + /** + * Calculate the hyperbolic arcsecant of a value, + * defined as `asech(x) = acosh(1/x) = ln(sqrt(1/x^2 - 1) + 1/x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.asech(x) + * + * Examples: + * + * math.asech(0.5); // returns 1.3169578969248166 + * + * See also: + * + * acsch, acoth + * + * @param {number | Complex | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic arcsecant of x + */ + var asech = typed('asech', { + 'number': function (x) { + if ((x <= 1 && x >= -1) || config.predictable) { + x = 1 / x; + + var ret = Math.sqrt(x*x - 1); + if (x > 0 || config.predictable) { + return Math.log(ret + x); + } + + return new type.Complex(Math.log(ret - x), Math.PI); + } + + return new type.Complex(x, 0).asech(); + }, + + 'Complex': function (x) { + return x.asech() + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x).acosh(); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, asech); + } + }); + + asech.toTex = {1: '\\mathrm{sech}^{-1}\\left(${args[0]}\\right)'}; + + return asech; + } + + var name$243 = 'asech'; + var factory_1$255 = factory$256; + + var asech$1 = { + name: name$243, + factory: factory_1$255 + }; + + function factory$257 (type, config, load, typed) { + + /** + * Calculate the inverse sine of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.asin(x) + * + * Examples: + * + * math.asin(0.5); // returns number 0.5235987755982989 + * math.asin(math.sin(1.5)); // returns number ~1.5 + * + * math.asin(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i + * + * See also: + * + * sin, atan, acos + * + * @param {number | BigNumber | Complex | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} The arc sine of x + */ + var asin = typed('asin', { + 'number': function (x) { + if ((x >= -1 && x <= 1) || config.predictable) { + return Math.asin(x); + } + else { + return new type.Complex(x, 0).asin(); + } + }, + + 'Complex': function (x) { + return x.asin(); + }, + + 'BigNumber': function (x) { + return x.asin(); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since asin(0) = 0 + return deepMap(x, asin, true); + } + }); + + asin.toTex = {1: '\\sin^{-1}\\left(${args[0]}\\right)'}; + + return asin; + } + + var name$244 = 'asin'; + var factory_1$256 = factory$257; + + var asin$1 = { + name: name$244, + factory: factory_1$256 + }; + + function factory$258 (type, config, load, typed) { + + /** + * Calculate the hyperbolic arcsine of a value, + * defined as `asinh(x) = ln(x + sqrt(x^2 + 1))`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.asinh(x) + * + * Examples: + * + * math.asinh(0.5); // returns 0.48121182505960347 + * + * See also: + * + * acosh, atanh + * + * @param {number | Complex | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic arcsine of x + */ + var asinh = typed('asinh', { + 'number': Math.asinh || function (x) { + return Math.log(Math.sqrt(x*x + 1) + x); + }, + + 'Complex': function (x) { + return x.asinh(); + }, + + 'BigNumber': function (x) { + return x.asinh(); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since asinh(0) = 0 + return deepMap(x, asinh, true); + } + }); + + asinh.toTex = {1: '\\sinh^{-1}\\left(${args[0]}\\right)'}; + + return asinh; + } + + var name$245 = 'asinh'; + var factory_1$257 = factory$258; + + var asinh$1 = { + name: name$245, + factory: factory_1$257 + }; + + function factory$259 (type, config, load, typed) { + + /** + * Calculate the inverse tangent of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.atan(x) + * + * Examples: + * + * math.atan(0.5); // returns number 0.4636476090008061 + * math.atan(math.tan(1.5)); // returns number 1.5 + * + * math.atan(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i + * + * See also: + * + * tan, asin, acos + * + * @param {number | BigNumber | Complex | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} The arc tangent of x + */ + var atan = typed('atan', { + 'number': function (x) { + return Math.atan(x); + }, + + 'Complex': function (x) { + return x.atan(); + }, + + 'BigNumber': function (x) { + return x.atan(); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since atan(0) = 0 + return deepMap(x, atan, true); + } + }); + + atan.toTex = {1: '\\tan^{-1}\\left(${args[0]}\\right)'}; + + return atan; + } + + var name$246 = 'atan'; + var factory_1$258 = factory$259; + + var atan$1 = { + name: name$246, + factory: factory_1$258 + }; + + function factory$260 (type, config, load, typed) { + + var matrix$$1 = load(matrix); + + var algorithm02$$1 = load(algorithm02); + var algorithm03$$1 = load(algorithm03); + var algorithm09$$1 = load(algorithm09); + var algorithm11$$1 = load(algorithm11); + var algorithm12$$1 = load(algorithm12); + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + /** + * Calculate the inverse tangent function with two arguments, y/x. + * By providing two arguments, the right quadrant of the computed angle can be + * determined. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.atan2(y, x) + * + * Examples: + * + * math.atan2(2, 2) / math.pi; // returns number 0.25 + * + * var angle = math.unit(60, 'deg'); // returns Unit 60 deg + * var x = math.cos(angle); + * var y = math.sin(angle); + * + * math.atan(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i + * + * See also: + * + * tan, atan, sin, cos + * + * @param {number | Array | Matrix} y Second dimension + * @param {number | Array | Matrix} x First dimension + * @return {number | Array | Matrix} Four-quadrant inverse tangent + */ + var atan2 = typed('atan2', { + + 'number, number': Math.atan2, + + // Complex numbers doesn't seem to have a reasonable implementation of + // atan2(). Even Matlab removed the support, after they only calculated + // the atan only on base of the real part of the numbers and ignored the imaginary. + + 'BigNumber, BigNumber': function (y, x) { + return type.BigNumber.atan2(y, x); + }, + + 'SparseMatrix, SparseMatrix': function (x, y) { + return algorithm09$$1(x, y, atan2, false); + }, + + 'SparseMatrix, DenseMatrix': function (x, y) { + // mind the order of y and x! + return algorithm02$$1(y, x, atan2, true); + }, + + 'DenseMatrix, SparseMatrix': function (x, y) { + return algorithm03$$1(x, y, atan2, false); + }, + + 'DenseMatrix, DenseMatrix': function (x, y) { + return algorithm13$$1(x, y, atan2); + }, + + 'Array, Array': function (x, y) { + return atan2(matrix$$1(x), matrix$$1(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + return atan2(matrix$$1(x), y); + }, + + 'Matrix, Array': function (x, y) { + return atan2(x, matrix$$1(y)); + }, + + 'SparseMatrix, number | BigNumber': function (x, y) { + return algorithm11$$1(x, y, atan2, false); + }, + + 'DenseMatrix, number | BigNumber': function (x, y) { + return algorithm14$$1(x, y, atan2, false); + }, + + 'number | BigNumber, SparseMatrix': function (x, y) { + // mind the order of y and x + return algorithm12$$1(y, x, atan2, true); + }, + + 'number | BigNumber, DenseMatrix': function (x, y) { + // mind the order of y and x + return algorithm14$$1(y, x, atan2, true); + }, + + 'Array, number | BigNumber': function (x, y) { + return algorithm14$$1(matrix$$1(x), y, atan2, false).valueOf(); + }, + + 'number | BigNumber, Array': function (x, y) { + return algorithm14$$1(matrix$$1(y), x, atan2, true).valueOf(); + } + }); + + atan2.toTex = {2: '\\mathrm{atan2}\\left(${args}\\right)'}; + + return atan2; + } + + var name$247 = 'atan2'; + var factory_1$259 = factory$260; + + var atan2$1 = { + name: name$247, + factory: factory_1$259 + }; + + function factory$261 (type, config, load, typed) { + /** + * Calculate the hyperbolic arctangent of a value, + * defined as `atanh(x) = ln((1 + x)/(1 - x)) / 2`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.atanh(x) + * + * Examples: + * + * math.atanh(0.5); // returns 0.5493061443340549 + * + * See also: + * + * acosh, asinh + * + * @param {number | Complex | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic arctangent of x + */ + var atanh = typed('atanh', { + 'number': function (x) { + if ((x <= 1 && x >= -1) || config.predictable) { + return _atanh(x); + } + return new type.Complex(x, 0).atanh(); + }, + + 'Complex': function (x) { + return x.atanh(); + }, + + 'BigNumber': function (x) { + return x.atanh(); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since atanh(0) = 0 + return deepMap(x, atanh, true); + } + }); + + atanh.toTex = {1: '\\tanh^{-1}\\left(${args[0]}\\right)'}; + + return atanh; + } + + /** + * Calculate the hyperbolic arctangent of a number + * @param {number} x + * @return {number} + * @private + */ + var _atanh = Math.atanh || function (x) { + return Math.log((1 + x)/(1 - x)) / 2 + }; + + var name$248 = 'atanh'; + var factory_1$260 = factory$261; + + var atanh$1 = { + name: name$248, + factory: factory_1$260 + }; + + function factory$262 (type, config, load, typed) { + + /** + * Calculate the cosine of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.cos(x) + * + * Examples: + * + * math.cos(2); // returns number -0.4161468365471422 + * math.cos(math.pi / 4); // returns number 0.7071067811865475 + * math.cos(math.unit(180, 'deg')); // returns number -1 + * math.cos(math.unit(60, 'deg')); // returns number 0.5 + * + * var angle = 0.2; + * math.pow(math.sin(angle), 2) + math.pow(math.cos(angle), 2); // returns number ~1 + * + * See also: + * + * cos, tan + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} Cosine of x + */ + var cos = typed('cos', { + 'number': Math.cos, + + 'Complex': function (x) { + return x.cos(); + }, + + 'BigNumber': function (x) { + return x.cos(); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cos is no angle'); + } + return cos(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, cos); + } + }); + + cos.toTex = {1: '\\cos\\left(${args[0]}\\right)'}; + + return cos; + } + + var name$249 = 'cos'; + var factory_1$261 = factory$262; + + var cos$1 = { + name: name$249, + factory: factory_1$261 + }; + + function factory$263 (type, config, load, typed) { + /** + * Calculate the hyperbolic cosine of a value, + * defined as `cosh(x) = 1/2 * (exp(x) + exp(-x))`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.cosh(x) + * + * Examples: + * + * math.cosh(0.5); // returns number 1.1276259652063807 + * + * See also: + * + * sinh, tanh + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic cosine of x + */ + var cosh = typed('cosh', { + 'number': _cosh, + + 'Complex': function (x) { + return x.cosh(); + }, + + 'BigNumber': function (x) { + return x.cosh(); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cosh is no angle'); + } + return cosh(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, cosh); + } + }); + + cosh.toTex = {1: '\\cosh\\left(${args[0]}\\right)'}; + + return cosh; + } + + /** + * Calculate the hyperbolic cosine of a number + * @param {number} x + * @returns {number} + * @private + */ + var _cosh = Math.cosh || function (x) { + return (Math.exp(x) + Math.exp(-x)) / 2; + }; + + var name$250 = 'cosh'; + var factory_1$262 = factory$263; + + var cosh$1 = { + name: name$250, + factory: factory_1$262 + }; + + function factory$264 (type, config, load, typed) { + /** + * Calculate the cotangent of a value. Defined as `cot(x) = 1 / tan(x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.cot(x) + * + * Examples: + * + * math.cot(2); // returns number -0.45765755436028577 + * 1 / math.tan(2); // returns number -0.45765755436028577 + * + * See also: + * + * tan, sec, csc + * + * @param {number | Complex | Unit | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Cotangent of x + */ + var cot = typed('cot', { + 'number': function (x) { + return 1 / Math.tan(x); + }, + + 'Complex': function (x) { + return x.cot(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x.tan()); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function cot is no angle'); + } + return cot(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, cot); + } + }); + + cot.toTex = {1: '\\cot\\left(${args[0]}\\right)'}; + + return cot; + } + + var name$251 = 'cot'; + var factory_1$263 = factory$264; + + var cot$1 = { + name: name$251, + factory: factory_1$263 + }; + + function factory$265 (type, config, load, typed) { + /** + * Calculate the hyperbolic cotangent of a value, + * defined as `coth(x) = 1 / tanh(x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.coth(x) + * + * Examples: + * + * // coth(x) = 1 / tanh(x) + * math.coth(2); // returns 1.0373147207275482 + * 1 / math.tanh(2); // returns 1.0373147207275482 + * + * See also: + * + * sinh, tanh, cosh + * + * @param {number | Complex | Unit | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic cotangent of x + */ + var coth = typed('coth', { + 'number': _coth, + + 'Complex': function (x) { + return x.coth(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x.tanh()); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function coth is no angle'); + } + return coth(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, coth); + } + }); + + coth.toTex = {1: '\\coth\\left(${args[0]}\\right)'}; + + return coth; + } + + /** + * Calculate the hyperbolic cosine of a number + * @param {number} x + * @returns {number} + * @private + */ + function _coth(x) { + var e = Math.exp(2 * x); + return (e + 1) / (e - 1); + } + + var name$252 = 'coth'; + var factory_1$264 = factory$265; + + var coth$1 = { + name: name$252, + factory: factory_1$264 + }; + + function factory$266 (type, config, load, typed) { + /** + * Calculate the cosecant of a value, defined as `csc(x) = 1/sin(x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.csc(x) + * + * Examples: + * + * math.csc(2); // returns number 1.099750170294617 + * 1 / math.sin(2); // returns number 1.099750170294617 + * + * See also: + * + * sin, sec, cot + * + * @param {number | Complex | Unit | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Cosecant of x + */ + var csc = typed('csc', { + 'number': function (x) { + return 1 / Math.sin(x); + }, + + 'Complex': function (x) { + return x.csc(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x.sin()); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function csc is no angle'); + } + return csc(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, csc); + } + }); + + csc.toTex = {1: '\\csc\\left(${args[0]}\\right)'}; + + return csc; + } + + var name$253 = 'csc'; + var factory_1$265 = factory$266; + + var csc$1 = { + name: name$253, + factory: factory_1$265 + }; + + var sign$3 = number.sign; + + function factory$267 (type, config, load, typed) { + /** + * Calculate the hyperbolic cosecant of a value, + * defined as `csch(x) = 1 / sinh(x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.csch(x) + * + * Examples: + * + * // csch(x) = 1/ sinh(x) + * math.csch(0.5); // returns 1.9190347513349437 + * 1 / math.sinh(0.5); // returns 1.9190347513349437 + * + * See also: + * + * sinh, sech, coth + * + * @param {number | Complex | Unit | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic cosecant of x + */ + var csch = typed('csch', { + 'number': _csch, + + 'Complex': function (x) { + return x.csch(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x.sinh()); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function csch is no angle'); + } + return csch(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, csch); + } + }); + + csch.toTex = {1: '\\mathrm{csch}\\left(${args[0]}\\right)'}; + + return csch; + } + + /** + * Calculate the hyperbolic cosecant of a number + * @param {number} x + * @returns {number} + * @private + */ + function _csch(x) { + // consider values close to zero (+/-) + if (x == 0) { + return Number.POSITIVE_INFINITY; + } + else { + return Math.abs(2 / (Math.exp(x) - Math.exp(-x))) * sign$3(x); + } + } + + var name$254 = 'csch'; + var factory_1$266 = factory$267; + + var csch$1 = { + name: name$254, + factory: factory_1$266 + }; + + function factory$268 (type, config, load, typed) { + /** + * Calculate the secant of a value, defined as `sec(x) = 1/cos(x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.sec(x) + * + * Examples: + * + * math.sec(2); // returns number -2.4029979617223822 + * 1 / math.cos(2); // returns number -2.4029979617223822 + * + * See also: + * + * cos, csc, cot + * + * @param {number | Complex | Unit | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Secant of x + */ + var sec = typed('sec', { + 'number': function (x) { + return 1 / Math.cos(x); + }, + + 'Complex': function (x) { + return x.sec(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x.cos()); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function sec is no angle'); + } + return sec(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, sec); + } + }); + + sec.toTex = {1: '\\sec\\left(${args[0]}\\right)'}; + + return sec; + } + + var name$255 = 'sec'; + var factory_1$267 = factory$268; + + var sec$1 = { + name: name$255, + factory: factory_1$267 + }; + + function factory$269 (type, config, load, typed) { + /** + * Calculate the hyperbolic secant of a value, + * defined as `sech(x) = 1 / cosh(x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.sech(x) + * + * Examples: + * + * // sech(x) = 1/ cosh(x) + * math.sech(0.5); // returns 0.886818883970074 + * 1 / math.cosh(0.5); // returns 0.886818883970074 + * + * See also: + * + * cosh, csch, coth + * + * @param {number | Complex | Unit | Array | Matrix} x Function input + * @return {number | Complex | Array | Matrix} Hyperbolic secant of x + */ + var sech = typed('sech', { + 'number': _sech, + + 'Complex': function (x) { + return x.sech(); + }, + + 'BigNumber': function (x) { + return new type.BigNumber(1).div(x.cosh()); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function sech is no angle'); + } + return sech(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, sech); + } + }); + + sech.toTex = {1: '\\mathrm{sech}\\left(${args[0]}\\right)'}; + + return sech; + } + + /** + * Calculate the hyperbolic secant of a number + * @param {number} x + * @returns {number} + * @private + */ + function _sech(x) { + return 2 / (Math.exp(x) + Math.exp(-x)); + } + + var name$256 = 'sech'; + var factory_1$268 = factory$269; + + var sech$1 = { + name: name$256, + factory: factory_1$268 + }; + + function factory$270 (type, config, load, typed) { + + /** + * Calculate the sine of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.sin(x) + * + * Examples: + * + * math.sin(2); // returns number 0.9092974268256813 + * math.sin(math.pi / 4); // returns number 0.7071067811865475 + * math.sin(math.unit(90, 'deg')); // returns number 1 + * math.sin(math.unit(30, 'deg')); // returns number 0.5 + * + * var angle = 0.2; + * math.pow(math.sin(angle), 2) + math.pow(math.cos(angle), 2); // returns number ~1 + * + * See also: + * + * cos, tan + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} Sine of x + */ + var sin = typed('sin', { + 'number': Math.sin, + + 'Complex': function (x) { + return x.sin(); + }, + + 'BigNumber': function (x) { + return x.sin(); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function sin is no angle'); + } + return sin(x.value); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since sin(0) = 0 + return deepMap(x, sin, true); + } + }); + + sin.toTex = {1: '\\sin\\left(${args[0]}\\right)'}; + + return sin; + } + + var name$257 = 'sin'; + var factory_1$269 = factory$270; + + var sin$1 = { + name: name$257, + factory: factory_1$269 + }; + + function factory$271 (type, config, load, typed) { + /** + * Calculate the hyperbolic sine of a value, + * defined as `sinh(x) = 1/2 * (exp(x) - exp(-x))`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.sinh(x) + * + * Examples: + * + * math.sinh(0.5); // returns number 0.5210953054937474 + * + * See also: + * + * cosh, tanh + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic sine of x + */ + var sinh = typed('sinh', { + 'number': _sinh, + + 'Complex': function (x) { + return x.sinh(); + }, + + 'BigNumber': function (x) { + return x.sinh(); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function sinh is no angle'); + } + return sinh(x.value); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since sinh(0) = 0 + return deepMap(x, sinh, true); + } + }); + + sinh.toTex = {1: '\\sinh\\left(${args[0]}\\right)'}; + + return sinh; + } + + /** + * Calculate the hyperbolic sine of a number + * @param {number} x + * @returns {number} + * @private + */ + var _sinh = Math.sinh || function (x) { + return (Math.exp(x) - Math.exp(-x)) / 2; + }; + + var name$258 = 'sinh'; + var factory_1$270 = factory$271; + + var sinh$1 = { + name: name$258, + factory: factory_1$270 + }; + + function factory$272 (type, config, load, typed) { + /** + * Calculate the tangent of a value. `tan(x)` is equal to `sin(x) / cos(x)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.tan(x) + * + * Examples: + * + * math.tan(0.5); // returns number 0.5463024898437905 + * math.sin(0.5) / math.cos(0.5); // returns number 0.5463024898437905 + * math.tan(math.pi / 4); // returns number 1 + * math.tan(math.unit(45, 'deg')); // returns number 1 + * + * See also: + * + * atan, sin, cos + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} Tangent of x + */ + var tan = typed('tan', { + 'number': Math.tan, + + 'Complex': function (x) { + return x.tan(); + }, + + 'BigNumber': function (x) { + return x.tan(); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function tan is no angle'); + } + return tan(x.value); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since tan(0) = 0 + return deepMap(x, tan, true); + } + }); + + tan.toTex = {1: '\\tan\\left(${args[0]}\\right)'}; + + return tan; + } + + var name$259 = 'tan'; + var factory_1$271 = factory$272; + + var tan$1 = { + name: name$259, + factory: factory_1$271 + }; + + function factory$273 (type, config, load, typed) { + /** + * Calculate the hyperbolic tangent of a value, + * defined as `tanh(x) = (exp(2 * x) - 1) / (exp(2 * x) + 1)`. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.tanh(x) + * + * Examples: + * + * // tanh(x) = sinh(x) / cosh(x) = 1 / coth(x) + * math.tanh(0.5); // returns 0.46211715726000974 + * math.sinh(0.5) / math.cosh(0.5); // returns 0.46211715726000974 + * 1 / math.coth(0.5); // returns 0.46211715726000974 + * + * See also: + * + * sinh, cosh, coth + * + * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input + * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic tangent of x + */ + var tanh = typed('tanh', { + 'number': _tanh, + + 'Complex': function (x) { + return x.tanh(); + }, + + 'BigNumber': function (x) { + return x.tanh(); + }, + + 'Unit': function (x) { + if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { + throw new TypeError ('Unit in function tanh is no angle'); + } + return tanh(x.value); + }, + + 'Array | Matrix': function (x) { + // deep map collection, skip zeros since tanh(0) = 0 + return deepMap(x, tanh, true); + } + }); + + tanh.toTex = {1: '\\tanh\\left(${args[0]}\\right)'}; + + return tanh; + } + + /** + * Calculate the hyperbolic tangent of a number + * @param {number} x + * @returns {number} + * @private + */ + var _tanh = Math.tanh || function (x) { + var e = Math.exp(2 * x); + return (e - 1) / (e + 1); + }; + + var name$260 = 'tanh'; + var factory_1$272 = factory$273; + + var tanh$1 = { + name: name$260, + factory: factory_1$272 + }; + + var trigonometry = [ + acos$1, + acosh$1, + acot$1, + acoth$1, + acsc$1, + acsch$1, + asec$1, + asech$1, + asin$1, + asinh$1, + atan$1, + atan2$1, + atanh$1, + cos$1, + cosh$1, + cot$1, + coth$1, + csc$1, + csch$1, + sec$1, + sech$1, + sin$1, + sinh$1, + tan$1, + tanh$1 + ]; + + function factory$274 (type, config, load, typed) { + var latex$$1 = latex; + + var matrix$$1 = load(matrix); + + var algorithm13$$1 = load(algorithm13); + var algorithm14$$1 = load(algorithm14); + + /** + * Change the unit of a value. + * + * For matrices, the function is evaluated element wise. + * + * Syntax: + * + * math.to(x, unit) + * + * Examples: + * + * math.to(math.unit('2 inch'), 'cm'); // returns Unit 5.08 cm + * math.to(math.unit('2 inch'), math.unit(null, 'cm')); // returns Unit 5.08 cm + * math.to(math.unit(16, 'bytes'), 'bits'); // returns Unit 128 bits + * + * See also: + * + * unit + * + * @param {Unit | Array | Matrix} x The unit to be converted. + * @param {Unit | Array | Matrix} unit New unit. Can be a string like "cm" + * or a unit without value. + * @return {Unit | Array | Matrix} value with changed, fixed unit. + */ + var to = typed('to', { + + 'Unit, Unit | string': function (x, unit) { + return x.to(unit); + }, + + 'Matrix, Matrix': function (x, y) { + // SparseMatrix does not support Units + return algorithm13$$1(x, y, to); + }, + + 'Array, Array': function (x, y) { + // use matrix implementation + return to(matrix$$1(x), matrix$$1(y)).valueOf(); + }, + + 'Array, Matrix': function (x, y) { + // use matrix implementation + return to(matrix$$1(x), y); + }, + + 'Matrix, Array': function (x, y) { + // use matrix implementation + return to(x, matrix$$1(y)); + }, + + 'Matrix, any': function (x, y) { + // SparseMatrix does not support Units + return algorithm14$$1(x, y, to, false); + }, + + 'any, Matrix': function (x, y) { + // SparseMatrix does not support Units + return algorithm14$$1(y, x, to, true); + }, + + 'Array, any': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(x), y, to, false).valueOf(); + }, + + 'any, Array': function (x, y) { + // use matrix implementation + return algorithm14$$1(matrix$$1(y), x, to, true).valueOf(); + } + }); + + to.toTex = { + 2: '\\left(${args[0]}' + latex$$1.operators['to'] + '${args[1]}\\right)' + }; + + return to; + } + + var name$261 = 'to'; + var factory_1$273 = factory$274; + + var to$1 = { + name: name$261, + factory: factory_1$273 + }; + + var unit$1 = [ + to$1 + ]; + + function factory$275 (type, config, load, typed) { + /** + * Test whether a value is prime: has no divisors other than itself and one. + * The function supports type `number`, `bignumber`. + * + * The function is evaluated element-wise in case of Array or Matrix input. + * + * Syntax: + * + * math.isPrime(x) + * + * Examples: + * + * math.isPrime(3); // returns true + * math.isPrime(-2); // returns false + * math.isPrime(0); // returns false + * math.isPrime(-0); // returns false + * math.isPrime(0.5); // returns false + * math.isPrime('2'); // returns true + * math.isPrime([2, 17, 100]); // returns [true, true, false] + * + * See also: + * + * isNumeric, isZero, isNegative, isInteger + * + * @param {number | BigNumber | Array | Matrix} x Value to be tested + * @return {boolean} Returns true when `x` is larger than zero. + * Throws an error in case of an unknown data type. + */ + var isPrime = typed('isPrime', { + 'number': function (x) { + if (x < 2){ + return false; + } + if (x == 2){ + return true; + } + if (x % 2 == 0){ + return false; + } + for (var i = 3; i * i <= x; i += 2){ + if (x % i == 0){ + return false; + } + } + return true; + }, + + 'BigNumber': function (x) { + if (x.lt(2)){ + return false; + } + if (x.equals(2)){ + return true; + } + if (x.mod(2).isZero()){ + return false; + } + for(var i = type.BigNumber(3); i.times(i).lte(x); i = i.plus(1)){ + if (x.mod(i).isZero()){ + return false; + } + } + return true; + }, + + 'Array | Matrix': function (x) { + return deepMap(x, isPrime); + } + }); + + return isPrime; + } + + var name$262 = 'isPrime'; + var factory_1$274 = factory$275; + + var isPrime$1 = { + name: name$262, + factory: factory_1$274 + }; + + function factory$276 (type, config, load, typed) { + /** + * Test whether a value is NaN (not a number). + * The function supports types `number`, `BigNumber`, `Fraction`, `Unit` and `Complex`. + * + * The function is evaluated element-wise in case of Array or Matrix input. + * + * Syntax: + * + * math.isNaN(x) + * + * Examples: + * + * math.isNaN(3); // returns false + * math.isNaN(NaN); // returns true + * math.isNaN(0); // returns false + * math.isNaN(math.bignumber(NaN)); // returns true + * math.isNaN(math.bignumber(0)); // returns false + * math.isNaN(math.fraction(-2, 5)); // returns false + * math.isNaN('-2'); // returns false + * math.isNaN([2, 0, -3, NaN]'); // returns [false, false, false, true] + * + * See also: + * + * isNumeric, isNegative, isPositive, isZero, isInteger + * + * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested + * @return {boolean} Returns true when `x` is NaN. + * Throws an error in case of an unknown data type. + */ + var isNaN = typed('isNaN', { + 'number': function (x) { + return Number.isNaN(x); + }, + + 'BigNumber': function (x) { + return x.isNaN(); + }, + + 'Fraction': function (x) { + return false; + }, + + 'Complex': function (x) { + return x.isNaN(); + }, + + 'Unit': function (x) { + return Number.isNaN(x.value); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, Number.isNaN); + } + }); + + return isNaN; + } + + var name$263 = 'isNaN'; + var factory_1$275 = factory$276; + + var _isNaN$1 = { + name: name$263, + factory: factory_1$275 + }; + + var utils$1 = [ + clone$5, + isInteger$22, + isNegative$1, + isNumeric$1, + isPositive$1, + isPrime$1, + isZero$1, + _isNaN$1, + _typeof$1 + ]; + + var _function$3 = [ + algebra, + arithmetic, + bitwise$1, + combinatorics, + complex$5, + geometry, + logical, + matrix$3, + probability, + relational, + set, + special, + statistics, + string$10, + trigonometry, + unit$1, + utils$1 + ]; + + function factory$277 (type, config, load, typed, math) { + /** + * Instantiate mathjs data types from their JSON representation + * @param {string} key + * @param {*} value + * @returns {*} Returns the revived object + */ + return function reviver(key, value) { + var constructor = type[value && value.mathjs] || + (math.expression && math.expression.node[value && value.mathjs]); + // TODO: instead of checking math.expression.node, expose all Node classes on math.type too + + if (constructor && typeof constructor.fromJSON === 'function') { + return constructor.fromJSON(value); + } + + return value; + } + } + + var name$264 = 'reviver'; + var path$64 = 'json'; + var factory_1$276 = factory$277; + var math$18 = true; // request the math namespace as fifth argument + + var reviver = { + name: name$264, + path: path$64, + factory: factory_1$276, + math: math$18 + }; + + var json = [ + reviver + ]; + + var error = [ + { + name: 'ArgumentsError', path: 'error', + factory: function () { + return ArgumentsError_1; + } + }, + { + name: 'DimensionError', + path: 'error', + factory: function () { + return DimensionError_1; + } + }, + { + name: 'IndexError', + path: 'error', + factory: function () { + return IndexError_1; + } + } + ]; + + // import customized constants file + + var lib = [ + type, // data types (Matrix, Complex, Unit, ...) + constants$1, // constants + expression, // expression parsing + _function$3, // functions + json, // serialization utility (math.json.reviver) + error // errors + ]; + + var numeric1_2_6 = createCommonjsModule(function (module, exports) { + + var numeric = exports; + if(typeof commonjsGlobal !== "undefined") { commonjsGlobal.numeric = numeric; } + + numeric.version = "1.2.6"; + + // 1. Utility functions + numeric.bench = function bench (f,interval) { + var t1,t2,n,i; + if(typeof interval === "undefined") { interval = 15; } + n = 0.5; + t1 = new Date(); + while(1) { + n*=2; + for(i=n;i>3;i-=4) { f(); f(); f(); f(); } + while(i>0) { f(); i--; } + t2 = new Date(); + if(t2-t1 > interval) break; + } + for(i=n;i>3;i-=4) { f(); f(); f(); f(); } + while(i>0) { f(); i--; } + t2 = new Date(); + return 1000*(3*n-1)/(t2-t1); + }; + + numeric._myIndexOf = (function _myIndexOf(w) { + var n = this.length,k; + for(k=0;k numeric.largeArray) { ret.push('...Large Array...'); return true; } + var flag = false; + ret.push('['); + for(k=0;k0) { ret.push(','); if(flag) ret.push('\n '); } flag = foo(x[k]); } + ret.push(']'); + return true; + } + ret.push('{'); + var flag = false; + for(k in x) { if(x.hasOwnProperty(k)) { if(flag) ret.push(',\n'); flag = true; ret.push(k); ret.push(': \n'); foo(x[k]); } } + ret.push('}'); + return true; + } + foo(x); + return ret.join(''); + }; + + numeric.parseDate = function parseDate(d) { + function foo(d) { + if(typeof d === 'string') { return Date.parse(d.replace(/-/g,'/')); } + if(!(d instanceof Array)) { throw new Error("parseDate: parameter must be arrays of strings"); } + var ret = [],k; + for(k=0;k0) { + ret[count] = []; + for(j=0;j> 2; + q = ((x & 3) << 4) + (y >> 4); + r = ((y & 15) << 2) + (z >> 6); + s = z & 63; + if(i+1>=n) { r = s = 64; } + else if(i+2>=n) { s = 64; } + ret += key.charAt(p) + key.charAt(q) + key.charAt(r) + key.charAt(s); + } + return ret; + } + function crc32Array (a,from,to) { + if(typeof from === "undefined") { from = 0; } + if(typeof to === "undefined") { to = a.length; } + var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]; + + var crc = -1, y = 0, n = a.length,i; + + for (i = from; i < to; i++) { + y = (crc ^ a[i]) & 0xFF; + crc = (crc >>> 8) ^ table[y]; + } + + return crc ^ (-1); + } + + var h = img[0].length, w = img[0][0].length, s1, s2, k,length,a,b,i,j,adler32,crc32; + var stream = [ + 137, 80, 78, 71, 13, 10, 26, 10, // 0: PNG signature + 0,0,0,13, // 8: IHDR Chunk length + 73, 72, 68, 82, // 12: "IHDR" + (w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w&255, // 16: Width + (h >> 24) & 255, (h >> 16) & 255, (h >> 8) & 255, h&255, // 20: Height + 8, // 24: bit depth + 2, // 25: RGB + 0, // 26: deflate + 0, // 27: no filter + 0, // 28: no interlace + -1,-2,-3,-4, // 29: CRC + -5,-6,-7,-8, // 33: IDAT Chunk length + 73, 68, 65, 84, // 37: "IDAT" + // RFC 1950 header starts here + 8, // 41: RFC1950 CMF + 29 // 42: RFC1950 FLG + ]; + crc32 = crc32Array(stream,12,29); + stream[29] = (crc32>>24)&255; + stream[30] = (crc32>>16)&255; + stream[31] = (crc32>>8)&255; + stream[32] = (crc32)&255; + s1 = 1; + s2 = 0; + for(i=0;i>8)&255; + stream.push(a); stream.push(b); + stream.push((~a)&255); stream.push((~b)&255); + if(i===0) stream.push(0); + for(j=0;j255) a = 255; + else if(a<0) a=0; + else a = Math.round(a); + s1 = (s1 + a )%65521; + s2 = (s2 + s1)%65521; + stream.push(a); + } + } + stream.push(0); + } + adler32 = (s2<<16)+s1; + stream.push((adler32>>24)&255); + stream.push((adler32>>16)&255); + stream.push((adler32>>8)&255); + stream.push((adler32)&255); + length = stream.length - 41; + stream[33] = (length>>24)&255; + stream[34] = (length>>16)&255; + stream[35] = (length>>8)&255; + stream[36] = (length)&255; + crc32 = crc32Array(stream,37); + stream.push((crc32>>24)&255); + stream.push((crc32>>16)&255); + stream.push((crc32>>8)&255); + stream.push((crc32)&255); + stream.push(0); + stream.push(0); + stream.push(0); + stream.push(0); + // a = stream.length; + stream.push(73); // I + stream.push(69); // E + stream.push(78); // N + stream.push(68); // D + stream.push(174); // CRC1 + stream.push(66); // CRC2 + stream.push(96); // CRC3 + stream.push(130); // CRC4 + return 'data:image/png;base64,'+base64(stream); + }; + + // 2. Linear algebra with Arrays. + numeric._dim = function _dim(x) { + var ret = []; + while(typeof x === "object") { ret.push(x.length); x = x[0]; } + return ret; + }; + + numeric.dim = function dim(x) { + var y,z; + if(typeof x === "object") { + y = x[0]; + if(typeof y === "object") { + z = y[0]; + if(typeof z === "object") { + return numeric._dim(x); + } + return [x.length,y.length]; + } + return [x.length]; + } + return []; + }; + + numeric.mapreduce = function mapreduce(body,init) { + return Function('x','accum','_s','_k', + 'if(typeof accum === "undefined") accum = '+init+';\n'+ + 'if(typeof x === "number") { var xi = x; '+body+'; return accum; }\n'+ + 'if(typeof _s === "undefined") _s = numeric.dim(x);\n'+ + 'if(typeof _k === "undefined") _k = 0;\n'+ + 'var _n = _s[_k];\n'+ + 'var i,xi;\n'+ + 'if(_k < _s.length-1) {\n'+ + ' for(i=_n-1;i>=0;i--) {\n'+ + ' accum = arguments.callee(x[i],accum,_s,_k+1);\n'+ + ' }'+ + ' return accum;\n'+ + '}\n'+ + 'for(i=_n-1;i>=1;i-=2) { \n'+ + ' xi = x[i];\n'+ + ' '+body+';\n'+ + ' xi = x[i-1];\n'+ + ' '+body+';\n'+ + '}\n'+ + 'if(i === 0) {\n'+ + ' xi = x[i];\n'+ + ' '+body+'\n'+ + '}\n'+ + 'return accum;' + ); + }; + numeric.mapreduce2 = function mapreduce2(body,setup) { + return Function('x', + 'var n = x.length;\n'+ + 'var i,xi;\n'+setup+';\n'+ + 'for(i=n-1;i!==-1;--i) { \n'+ + ' xi = x[i];\n'+ + ' '+body+';\n'+ + '}\n'+ + 'return accum;' + ); + }; + + + numeric.same = function same(x,y) { + var i,n; + if(!(x instanceof Array) || !(y instanceof Array)) { return false; } + n = x.length; + if(n !== y.length) { return false; } + for(i=0;i=0;i-=2) { ret[i+1] = v; ret[i] = v; } + if(i===-1) { ret[0] = v; } + return ret; + } + for(i=n-1;i>=0;i--) { ret[i] = numeric.rep(s,v,k+1); } + return ret; + }; + + + numeric.dotMMsmall = function dotMMsmall(x,y) { + var i,j,k,p,q,r,ret,foo,bar,woo,i0; + p = x.length; q = y.length; r = y[0].length; + ret = Array(p); + for(i=p-1;i>=0;i--) { + foo = Array(r); + bar = x[i]; + for(k=r-1;k>=0;k--) { + woo = bar[q-1]*y[q-1][k]; + for(j=q-2;j>=1;j-=2) { + i0 = j-1; + woo += bar[j]*y[j][k] + bar[i0]*y[i0][k]; + } + if(j===0) { woo += bar[0]*y[0][k]; } + foo[k] = woo; + } + ret[i] = foo; + } + return ret; + }; + numeric._getCol = function _getCol(A,j,x) { + var n = A.length, i; + for(i=n-1;i>0;--i) { + x[i] = A[i][j]; + --i; + x[i] = A[i][j]; + } + if(i===0) x[0] = A[0][j]; + }; + numeric.dotMMbig = function dotMMbig(x,y){ + var gc = numeric._getCol, p = y.length, v = Array(p); + var m = x.length, n = y[0].length, A = new Array(m), xj; + var VV = numeric.dotVV; + var i,j; + --p; + --m; + for(i=m;i!==-1;--i) A[i] = Array(n); + --n; + for(i=n;i!==-1;--i) { + gc(y,i,v); + for(j=m;j!==-1;--j) { + xj = x[j]; + A[j][i] = VV(xj,v); + } + } + return A; + }; + + numeric.dotMV = function dotMV(x,y) { + var p = x.length, q = y.length,i; + var ret = Array(p), dotVV = numeric.dotVV; + for(i=p-1;i>=0;i--) { ret[i] = dotVV(x[i],y); } + return ret; + }; + + numeric.dotVM = function dotVM(x,y) { + var j,k,p,q,ret,woo,i0; + p = x.length; q = y[0].length; + ret = Array(q); + for(k=q-1;k>=0;k--) { + woo = x[p-1]*y[p-1][k]; + for(j=p-2;j>=1;j-=2) { + i0 = j-1; + woo += x[j]*y[j][k] + x[i0]*y[i0][k]; + } + if(j===0) { woo += x[0]*y[0][k]; } + ret[k] = woo; + } + return ret; + }; + + numeric.dotVV = function dotVV(x,y) { + var i,n=x.length,i1,ret = x[n-1]*y[n-1]; + for(i=n-2;i>=1;i-=2) { + i1 = i-1; + ret += x[i]*y[i] + x[i1]*y[i1]; + } + if(i===0) { ret += x[0]*y[0]; } + return ret; + }; + + numeric.dot = function dot(x,y) { + var d = numeric.dim; + switch(d(x).length*1000+d(y).length) { + case 2002: + if(y.length < 10) return numeric.dotMMsmall(x,y); + else return numeric.dotMMbig(x,y); + case 2001: return numeric.dotMV(x,y); + case 1002: return numeric.dotVM(x,y); + case 1001: return numeric.dotVV(x,y); + case 1000: return numeric.mulVS(x,y); + case 1: return numeric.mulSV(x,y); + case 0: return x*y; + default: throw new Error('numeric.dot only works on vectors and matrices'); + } + }; + + numeric.diag = function diag(d) { + var i,i1,j,n = d.length, A = Array(n), Ai; + for(i=n-1;i>=0;i--) { + Ai = Array(n); + i1 = i+2; + for(j=n-1;j>=i1;j-=2) { + Ai[j] = 0; + Ai[j-1] = 0; + } + if(j>i) { Ai[j] = 0; } + Ai[i] = d[i]; + for(j=i-1;j>=1;j-=2) { + Ai[j] = 0; + Ai[j-1] = 0; + } + if(j===0) { Ai[0] = 0; } + A[i] = Ai; + } + return A; + }; + numeric.getDiag = function(A) { + var n = Math.min(A.length,A[0].length),i,ret = Array(n); + for(i=n-1;i>=1;--i) { + ret[i] = A[i][i]; + --i; + ret[i] = A[i][i]; + } + if(i===0) { + ret[0] = A[0][0]; + } + return ret; + }; + + numeric.identity = function identity(n) { return numeric.diag(numeric.rep([n],1)); }; + numeric.pointwise = function pointwise(params,body,setup) { + if(typeof setup === "undefined") { setup = ""; } + var fun = []; + var k; + var avec = /\[i\]$/,p,thevec = ''; + var haveret = false; + for(k=0;k=0;i--) ret[i] = arguments.callee('+params.join(',')+',_s,_k+1);\n'+ + ' return ret;\n'+ + '}\n'+ + setup+'\n'+ + 'for(i=_n-1;i!==-1;--i) {\n'+ + ' '+body+'\n'+ + '}\n'+ + 'return ret;' + ); + return Function.apply(null,fun); + }; + numeric.pointwise2 = function pointwise2(params,body,setup) { + if(typeof setup === "undefined") { setup = ""; } + var fun = []; + var k; + var avec = /\[i\]$/,p,thevec = ''; + var haveret = false; + for(k=0;k=0;i--) { _biforeach(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } + }); + numeric._biforeach2 = (function _biforeach2(x,y,s,k,f) { + if(k === s.length-1) { return f(x,y); } + var i,n=s[k],ret = Array(n); + for(i=n-1;i>=0;--i) { ret[i] = _biforeach2(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } + return ret; + }); + numeric._foreach = (function _foreach(x,s,k,f) { + if(k === s.length-1) { f(x); return; } + var i,n=s[k]; + for(i=n-1;i>=0;i--) { _foreach(x[i],s,k+1,f); } + }); + numeric._foreach2 = (function _foreach2(x,s,k,f) { + if(k === s.length-1) { return f(x); } + var i,n=s[k], ret = Array(n); + for(i=n-1;i>=0;i--) { ret[i] = _foreach2(x[i],s,k+1,f); } + return ret; + }); + + /*numeric.anyV = numeric.mapreduce('if(xi) return true;','false'); + numeric.allV = numeric.mapreduce('if(!xi) return false;','true'); + numeric.any = function(x) { if(typeof x.length === "undefined") return x; return numeric.anyV(x); } + numeric.all = function(x) { if(typeof x.length === "undefined") return x; return numeric.allV(x); }*/ + + numeric.ops2 = { + add: '+', + sub: '-', + mul: '*', + div: '/', + mod: '%', + and: '&&', + or: '||', + eq: '===', + neq: '!==', + lt: '<', + gt: '>', + leq: '<=', + geq: '>=', + band: '&', + bor: '|', + bxor: '^', + lshift: '<<', + rshift: '>>', + rrshift: '>>>' + }; + numeric.opseq = { + addeq: '+=', + subeq: '-=', + muleq: '*=', + diveq: '/=', + modeq: '%=', + lshifteq: '<<=', + rshifteq: '>>=', + rrshifteq: '>>>=', + bandeq: '&=', + boreq: '|=', + bxoreq: '^=' + }; + numeric.mathfuns = ['abs','acos','asin','atan','ceil','cos', + 'exp','floor','log','round','sin','sqrt','tan', + 'isNaN','isFinite']; + numeric.mathfuns2 = ['atan2','pow','max','min']; + numeric.ops1 = { + neg: '-', + not: '!', + bnot: '~', + clone: '' + }; + numeric.mapreducers = { + any: ['if(xi) return true;','var accum = false;'], + all: ['if(!xi) return false;','var accum = true;'], + sum: ['accum += xi;','var accum = 0;'], + prod: ['accum *= xi;','var accum = 1;'], + norm2Squared: ['accum += xi*xi;','var accum = 0;'], + norminf: ['accum = max(accum,abs(xi));','var accum = 0, max = Math.max, abs = Math.abs;'], + norm1: ['accum += abs(xi)','var accum = 0, abs = Math.abs;'], + sup: ['accum = max(accum,xi);','var accum = -Infinity, max = Math.max;'], + inf: ['accum = min(accum,xi);','var accum = Infinity, min = Math.min;'] + }; + + (function () { + var i,o; + for(i=0;iv0) { i0 = i; v0 = k; } } + Aj = A[i0]; A[i0] = A[j]; A[j] = Aj; + Ij = I[i0]; I[i0] = I[j]; I[j] = Ij; + x = Aj[j]; + for(k=j;k!==n;++k) Aj[k] /= x; + for(k=n-1;k!==-1;--k) Ij[k] /= x; + for(i=m-1;i!==-1;--i) { + if(i!==j) { + Ai = A[i]; + Ii = I[i]; + x = Ai[j]; + for(k=j+1;k!==n;++k) Ai[k] -= Aj[k]*x; + for(k=n-1;k>0;--k) { Ii[k] -= Ij[k]*x; --k; Ii[k] -= Ij[k]*x; } + if(k===0) Ii[0] -= Ij[0]*x; + } + } + } + return I; + }; + + numeric.det = function det(x) { + var s = numeric.dim(x); + if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: det() only works on square matrices'); } + var n = s[0], ret = 1,i,j,k,A = numeric.clone(x),Aj,Ai,alpha,temp,k1; + for(j=0;j Math.abs(A[k][j])) { k = i; } } + if(k !== j) { + temp = A[k]; A[k] = A[j]; A[j] = temp; + ret *= -1; + } + Aj = A[j]; + for(i=j+1;i=1;i-=2) { + A1 = x[i]; + A0 = x[i-1]; + for(j=n-1;j>=1;--j) { + Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; + --j; + Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; + } + if(j===0) { + Bj = ret[0]; Bj[i] = A1[0]; Bj[i-1] = A0[0]; + } + } + if(i===0) { + A0 = x[0]; + for(j=n-1;j>=1;--j) { + ret[j][0] = A0[j]; + --j; + ret[j][0] = A0[j]; + } + if(j===0) { ret[0][0] = A0[0]; } + } + return ret; + }; + numeric.negtranspose = function negtranspose(x) { + var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj; + for(j=0;j=1;i-=2) { + A1 = x[i]; + A0 = x[i-1]; + for(j=n-1;j>=1;--j) { + Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; + --j; + Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; + } + if(j===0) { + Bj = ret[0]; Bj[i] = -A1[0]; Bj[i-1] = -A0[0]; + } + } + if(i===0) { + A0 = x[0]; + for(j=n-1;j>=1;--j) { + ret[j][0] = -A0[j]; + --j; + ret[j][0] = -A0[j]; + } + if(j===0) { ret[0][0] = -A0[0]; } + } + return ret; + }; + + numeric._random = function _random(s,k) { + var i,n=s[k],ret=Array(n), rnd; + if(k === s.length-1) { + rnd = Math.random; + for(i=n-1;i>=1;i-=2) { + ret[i] = rnd(); + ret[i-1] = rnd(); + } + if(i===0) { ret[0] = rnd(); } + return ret; + } + for(i=n-1;i>=0;i--) ret[i] = _random(s,k+1); + return ret; + }; + numeric.random = function random(s) { return numeric._random(s,0); }; + + numeric.norm2 = function norm2(x) { return Math.sqrt(numeric.norm2Squared(x)); }; + + numeric.linspace = function linspace(a,b,n) { + if(typeof n === "undefined") n = Math.max(Math.round(b-a)+1,1); + if(n<2) { return n===1?[a]:[]; } + var i,ret = Array(n); + n--; + for(i=n;i>=0;i--) { ret[i] = (i*b+(n-i)*a)/n; } + return ret; + }; + + numeric.getBlock = function getBlock(x,from,to) { + var s = numeric.dim(x); + function foo(x,k) { + var i,a = from[k], n = to[k]-a, ret = Array(n); + if(k === s.length-1) { + for(i=n;i>=0;i--) { ret[i] = x[i+a]; } + return ret; + } + for(i=n;i>=0;i--) { ret[i] = foo(x[i+a],k+1); } + return ret; + } + return foo(x,0); + }; + + numeric.setBlock = function setBlock(x,from,to,B) { + var s = numeric.dim(x); + function foo(x,y,k) { + var i,a = from[k], n = to[k]-a; + if(k === s.length-1) { for(i=n;i>=0;i--) { x[i+a] = y[i]; } } + for(i=n;i>=0;i--) { foo(x[i+a],y[i],k+1); } + } + foo(x,B,0); + return x; + }; + + numeric.getRange = function getRange(A,I,J) { + var m = I.length, n = J.length; + var i,j; + var B = Array(m), Bi, AI; + for(i=m-1;i!==-1;--i) { + B[i] = Array(n); + Bi = B[i]; + AI = A[I[i]]; + for(j=n-1;j!==-1;--j) Bi[j] = AI[J[j]]; + } + return B; + }; + + numeric.blockMatrix = function blockMatrix(X) { + var s = numeric.dim(X); + if(s.length<4) return numeric.blockMatrix([X]); + var m=s[0],n=s[1],M,N,i,j,Xij; + M = 0; N = 0; + for(i=0;i=0;i--) { + Ai = Array(n); + xi = x[i]; + for(j=n-1;j>=3;--j) { + Ai[j] = xi * y[j]; + --j; + Ai[j] = xi * y[j]; + --j; + Ai[j] = xi * y[j]; + --j; + Ai[j] = xi * y[j]; + } + while(j>=0) { Ai[j] = xi * y[j]; --j; } + A[i] = Ai; + } + return A; + }; + + // 3. The Tensor type T + numeric.T = function T(x,y) { this.x = x; this.y = y; }; + numeric.t = function t(x,y) { return new numeric.T(x,y); }; + + numeric.Tbinop = function Tbinop(rr,rc,cr,cc,setup) { + var io = numeric.indexOf; + if(typeof setup !== "string") { + var k; + setup = ''; + for(k in numeric) { + if(numeric.hasOwnProperty(k) && (rr.indexOf(k)>=0 || rc.indexOf(k)>=0 || cr.indexOf(k)>=0 || cc.indexOf(k)>=0) && k.length>1) { + setup += 'var '+k+' = numeric.'+k+';\n'; + } + } + } + return Function(['y'], + 'var x = this;\n'+ + 'if(!(y instanceof numeric.T)) { y = new numeric.T(y); }\n'+ + setup+'\n'+ + 'if(x.y) {'+ + ' if(y.y) {'+ + ' return new numeric.T('+cc+');\n'+ + ' }\n'+ + ' return new numeric.T('+cr+');\n'+ + '}\n'+ + 'if(y.y) {\n'+ + ' return new numeric.T('+rc+');\n'+ + '}\n'+ + 'return new numeric.T('+rr+');\n' + ); + }; + + numeric.T.prototype.add = numeric.Tbinop( + 'add(x.x,y.x)', + 'add(x.x,y.x),y.y', + 'add(x.x,y.x),x.y', + 'add(x.x,y.x),add(x.y,y.y)'); + numeric.T.prototype.sub = numeric.Tbinop( + 'sub(x.x,y.x)', + 'sub(x.x,y.x),neg(y.y)', + 'sub(x.x,y.x),x.y', + 'sub(x.x,y.x),sub(x.y,y.y)'); + numeric.T.prototype.mul = numeric.Tbinop( + 'mul(x.x,y.x)', + 'mul(x.x,y.x),mul(x.x,y.y)', + 'mul(x.x,y.x),mul(x.y,y.x)', + 'sub(mul(x.x,y.x),mul(x.y,y.y)),add(mul(x.x,y.y),mul(x.y,y.x))'); + + numeric.T.prototype.reciprocal = function reciprocal() { + var mul = numeric.mul, div = numeric.div; + if(this.y) { + var d = numeric.add(mul(this.x,this.x),mul(this.y,this.y)); + return new numeric.T(div(this.x,d),div(numeric.neg(this.y),d)); + } + return new T(div(1,this.x)); + }; + numeric.T.prototype.div = function div(y) { + if(!(y instanceof numeric.T)) y = new numeric.T(y); + if(y.y) { return this.mul(y.reciprocal()); } + var div = numeric.div; + if(this.y) { return new numeric.T(div(this.x,y.x),div(this.y,y.x)); } + return new numeric.T(div(this.x,y.x)); + }; + numeric.T.prototype.dot = numeric.Tbinop( + 'dot(x.x,y.x)', + 'dot(x.x,y.x),dot(x.x,y.y)', + 'dot(x.x,y.x),dot(x.y,y.x)', + 'sub(dot(x.x,y.x),dot(x.y,y.y)),add(dot(x.x,y.y),dot(x.y,y.x))' + ); + numeric.T.prototype.transpose = function transpose() { + var t = numeric.transpose, x = this.x, y = this.y; + if(y) { return new numeric.T(t(x),t(y)); } + return new numeric.T(t(x)); + }; + numeric.T.prototype.transjugate = function transjugate() { + var t = numeric.transpose, x = this.x, y = this.y; + if(y) { return new numeric.T(t(x),numeric.negtranspose(y)); } + return new numeric.T(t(x)); + }; + numeric.Tunop = function Tunop(r,c,s) { + if(typeof s !== "string") { s = ''; } + return Function( + 'var x = this;\n'+ + s+'\n'+ + 'if(x.y) {'+ + ' '+c+';\n'+ + '}\n'+ + r+';\n' + ); + }; + + numeric.T.prototype.exp = numeric.Tunop( + 'return new numeric.T(ex)', + 'return new numeric.T(mul(cos(x.y),ex),mul(sin(x.y),ex))', + 'var ex = numeric.exp(x.x), cos = numeric.cos, sin = numeric.sin, mul = numeric.mul;'); + numeric.T.prototype.conj = numeric.Tunop( + 'return new numeric.T(x.x);', + 'return new numeric.T(x.x,numeric.neg(x.y));'); + numeric.T.prototype.neg = numeric.Tunop( + 'return new numeric.T(neg(x.x));', + 'return new numeric.T(neg(x.x),neg(x.y));', + 'var neg = numeric.neg;'); + numeric.T.prototype.sin = numeric.Tunop( + 'return new numeric.T(numeric.sin(x.x))', + 'return x.exp().sub(x.neg().exp()).div(new numeric.T(0,2));'); + numeric.T.prototype.cos = numeric.Tunop( + 'return new numeric.T(numeric.cos(x.x))', + 'return x.exp().add(x.neg().exp()).div(2);'); + numeric.T.prototype.abs = numeric.Tunop( + 'return new numeric.T(numeric.abs(x.x));', + 'return new numeric.T(numeric.sqrt(numeric.add(mul(x.x,x.x),mul(x.y,x.y))));', + 'var mul = numeric.mul;'); + numeric.T.prototype.log = numeric.Tunop( + 'return new numeric.T(numeric.log(x.x));', + 'var theta = new numeric.T(numeric.atan2(x.y,x.x)), r = x.abs();\n'+ + 'return new numeric.T(numeric.log(r.x),theta.x);'); + numeric.T.prototype.norm2 = numeric.Tunop( + 'return numeric.norm2(x.x);', + 'var f = numeric.norm2Squared;\n'+ + 'return Math.sqrt(f(x.x)+f(x.y));'); + numeric.T.prototype.inv = function inv() { + var A = this; + if(typeof A.y === "undefined") { return new numeric.T(numeric.inv(A.x)); } + var n = A.x.length, i, j, k; + var Rx = numeric.identity(n),Ry = numeric.rep([n,n],0); + var Ax = numeric.clone(A.x), Ay = numeric.clone(A.y); + var Aix, Aiy, Ajx, Ajy, Rix, Riy, Rjx, Rjy; + var i,j,k,d,d1,ax,ay,bx,by,temp; + for(i=0;i d) { k=j; d = d1; } + } + if(k!==i) { + temp = Ax[i]; Ax[i] = Ax[k]; Ax[k] = temp; + temp = Ay[i]; Ay[i] = Ay[k]; Ay[k] = temp; + temp = Rx[i]; Rx[i] = Rx[k]; Rx[k] = temp; + temp = Ry[i]; Ry[i] = Ry[k]; Ry[k] = temp; + } + Aix = Ax[i]; Aiy = Ay[i]; + Rix = Rx[i]; Riy = Ry[i]; + ax = Aix[i]; ay = Aiy[i]; + for(j=i+1;j0;i--) { + Rix = Rx[i]; Riy = Ry[i]; + for(j=i-1;j>=0;j--) { + Rjx = Rx[j]; Rjy = Ry[j]; + ax = Ax[j][i]; ay = Ay[j][i]; + for(k=n-1;k>=0;k--) { + bx = Rix[k]; by = Riy[k]; + Rjx[k] -= ax*bx - ay*by; + Rjy[k] -= ax*by + ay*bx; + } + } + } + return new numeric.T(Rx,Ry); + }; + numeric.T.prototype.get = function get(i) { + var x = this.x, y = this.y, k = 0, ik, n = i.length; + if(y) { + while(k= 0 ? 1 : -1; + var alpha = s*numeric.norm2(x); + v[0] += alpha; + var foo = numeric.norm2(v); + if(foo === 0) { /* this should not happen */ throw new Error('eig: internal error'); } + return numeric.div(v,foo); + }; + + numeric.toUpperHessenberg = function toUpperHessenberg(me) { + var s = numeric.dim(me); + if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: toUpperHessenberg() only works on square matrices'); } + var m = s[0], i,j,k,x,v,A = numeric.clone(me),B,C,Ai,Ci,Q = numeric.identity(m),Qi; + for(j=0;j0) { + v = numeric.house(x); + B = numeric.getBlock(A,[j+1,j],[m-1,m-1]); + C = numeric.tensor(v,numeric.dot(v,B)); + for(i=j+1;i=4*det) { + var s1,s2; + s1 = 0.5*(tr+Math.sqrt(tr*tr-4*det)); + s2 = 0.5*(tr-Math.sqrt(tr*tr-4*det)); + Hloc = numeric.add(numeric.sub(numeric.dot(Hloc,Hloc), + numeric.mul(Hloc,s1+s2)), + numeric.diag(numeric.rep([3],s1*s2))); + } else { + Hloc = numeric.add(numeric.sub(numeric.dot(Hloc,Hloc), + numeric.mul(Hloc,tr)), + numeric.diag(numeric.rep([3],det))); + } + x = [Hloc[0][0],Hloc[1][0],Hloc[2][0]]; + v = numeric.house(x); + B = [H[0],H[1],H[2]]; + C = numeric.tensor(v,numeric.dot(v,B)); + for(i=0;i<3;i++) { Hi = H[i]; Ci = C[i]; for(k=0;k=0) { + if(p1<0) x = -0.5*(p1-sqrt(disc)); + else x = -0.5*(p1+sqrt(disc)); + n1 = (a-x)*(a-x)+b*b; + n2 = c*c+(d-x)*(d-x); + if(n1>n2) { + n1 = sqrt(n1); + p = (a-x)/n1; + q = b/n1; + } else { + n2 = sqrt(n2); + p = c/n2; + q = (d-x)/n2; + } + Q0 = new T([[q,-p],[p,q]]); + Q.setRows(i,j,Q0.dot(Q.getRows(i,j))); + } else { + x = -0.5*p1; + y = 0.5*sqrt(-disc); + n1 = (a-x)*(a-x)+b*b; + n2 = c*c+(d-x)*(d-x); + if(n1>n2) { + n1 = sqrt(n1+y*y); + p = (a-x)/n1; + q = b/n1; + x = 0; + y /= n1; + } else { + n2 = sqrt(n2+y*y); + p = c/n2; + q = (d-x)/n2; + x = y/n2; + y = 0; + } + Q0 = new T([[q,-p],[p,q]],[[x,y],[y,-x]]); + Q.setRows(i,j,Q0.dot(Q.getRows(i,j))); + } + } + } + var R = Q.dot(A).dot(Q.transjugate()), n = A.length, E = numeric.T.identity(n); + for(j=0;j0) { + for(k=j-1;k>=0;k--) { + var Rk = R.get([k,k]), Rj = R.get([j,j]); + if(numeric.neq(Rk.x,Rj.x) || numeric.neq(Rk.y,Rj.y)) { + x = R.getRow(k).getBlock([k],[j-1]); + y = E.getRow(j).getBlock([k],[j-1]); + E.set([j,k],(R.get([k,j]).neg().sub(x.dot(y))).div(Rk.sub(Rj))); + } else { + E.setRow(j,E.getRow(k)); + continue; + } + } + } + } + for(j=0;j=counts.length) counts[counts.length] = 0; + if(foo[j]!==0) counts[j]++; + } + } + var n = counts.length; + var Ai = Array(n+1); + Ai[0] = 0; + for(i=0;i= k11) { + xj[n] = j[m]; + if(m===0) return; + ++n; + --m; + km = k[m]; + k11 = k1[m]; + } else { + foo = Pinv[Aj[km]]; + if(x[foo] === 0) { + x[foo] = 1; + k[m] = km; + ++m; + j[m] = foo; + km = Ai[foo]; + k1[m] = k11 = Ai[foo+1]; + } else ++km; + } + } + }; + numeric.ccsLPSolve = function ccsLPSolve(A,B,x,xj,I,Pinv,dfs) { + var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1; + var Bi = B[0], Bj = B[1], Bv = B[2]; + + var i,i0,i1,j,j0,j1,k,l,a; + i0 = Bi[I]; + i1 = Bi[I+1]; + xj.length = 0; + for(i=i0;i a) { e = k; a = c; } + } + if(abs(x[i])= k11) { + xj[n] = Pinv[j[m]]; + if(m===0) return; + ++n; + --m; + km = k[m]; + k11 = k1[m]; + } else { + foo = Aj[km]; + if(x[foo] === 0) { + x[foo] = 1; + k[m] = km; + ++m; + j[m] = foo; + foo = Pinv[foo]; + km = Ai[foo]; + k1[m] = k11 = Ai[foo+1]; + } else ++km; + } + } + }; + numeric.ccsLPSolve0 = function ccsLPSolve0(A,B,y,xj,I,Pinv,P,dfs) { + var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1; + var Bi = B[0], Bj = B[1], Bv = B[2]; + + var i,i0,i1,j,j0,j1,k,l,a; + i0 = Bi[I]; + i1 = Bi[I+1]; + xj.length = 0; + for(i=i0;i a) { e = k; a = c; } + } + if(abs(y[P[i]]) ret[k]) ret[k] = A.length; + var i; + for(i in A) { + if(A.hasOwnProperty(i)) dim(A[i],ret,k+1); + } + return ret; + }; + + numeric.sclone = function clone(A,k,n) { + if(typeof k === "undefined") { k=0; } + if(typeof n === "undefined") { n = numeric.sdim(A).length; } + var i,ret = Array(A.length); + if(k === n-1) { + for(i in A) { if(A.hasOwnProperty(i)) ret[i] = A[i]; } + return ret; + } + for(i in A) { + if(A.hasOwnProperty(i)) ret[i] = clone(A[i],k+1,n); + } + return ret; + }; + + numeric.sdiag = function diag(d) { + var n = d.length,i,ret = Array(n),i1; + for(i=n-1;i>=1;i-=2) { + i1 = i-1; + ret[i] = []; ret[i][i] = d[i]; + ret[i1] = []; ret[i1][i1] = d[i1]; + } + if(i===0) { ret[0] = []; ret[0][0] = d[i]; } + return ret; + }; + + numeric.sidentity = function identity(n) { return numeric.sdiag(numeric.rep([n],1)); }; + + numeric.stranspose = function transpose(A) { + var ret = [], n = A.length, i,j,Ai; + for(i in A) { + if(!(A.hasOwnProperty(i))) continue; + Ai = A[i]; + for(j in Ai) { + if(!(Ai.hasOwnProperty(j))) continue; + if(typeof ret[j] !== "object") { ret[j] = []; } + ret[j][i] = Ai[j]; + } + } + return ret; + }; + + numeric.sLUP = function LUP(A,tol) { + throw new Error("The function numeric.sLUP had a bug in it and has been removed. Please use the new numeric.ccsLUP function instead."); + }; + + numeric.sdotMM = function dotMM(A,B) { + var p = A.length, q = B.length, BT = numeric.stranspose(B), r = BT.length, Ai, BTk; + var i,j,k,accum; + var ret = Array(p),reti; + for(i=p-1;i>=0;i--) { + reti = []; + Ai = A[i]; + for(k=r-1;k>=0;k--) { + accum = 0; + BTk = BT[k]; + for(j in Ai) { + if(!(Ai.hasOwnProperty(j))) continue; + if(j in BTk) { accum += Ai[j]*BTk[j]; } + } + if(accum) reti[k] = accum; + } + ret[i] = reti; + } + return ret; + }; + + numeric.sdotMV = function dotMV(A,x) { + var p = A.length, Ai, i,j; + var ret = Array(p), accum; + for(i=p-1;i>=0;i--) { + Ai = A[i]; + accum = 0; + for(j in Ai) { + if(!(Ai.hasOwnProperty(j))) continue; + if(x[j]) accum += Ai[j]*x[j]; + } + if(accum) ret[i] = accum; + } + return ret; + }; + + numeric.sdotVM = function dotMV(x,A) { + var i,j,Ai,alpha; + var ret = []; + for(i in x) { + if(!x.hasOwnProperty(i)) continue; + Ai = A[i]; + alpha = x[i]; + for(j in Ai) { + if(!Ai.hasOwnProperty(j)) continue; + if(!ret[j]) { ret[j] = 0; } + ret[j] += alpha*Ai[j]; + } + } + return ret; + }; + + numeric.sdotVV = function dotVV(x,y) { + var i,ret=0; + for(i in x) { if(x[i] && y[i]) ret+= x[i]*y[i]; } + return ret; + }; + + numeric.sdot = function dot(A,B) { + var m = numeric.sdim(A).length, n = numeric.sdim(B).length; + var k = m*1000+n; + switch(k) { + case 0: return A*B; + case 1001: return numeric.sdotVV(A,B); + case 2001: return numeric.sdotMV(A,B); + case 1002: return numeric.sdotVM(A,B); + case 2002: return numeric.sdotMM(A,B); + default: throw new Error('numeric.sdot not implemented for tensors of order '+m+' and '+n); + } + }; + + numeric.sscatter = function scatter(V) { + var n = V[0].length, Vij, i, j, m = V.length, A = [], Aj; + for(i=n-1;i>=0;--i) { + if(!V[m-1][i]) continue; + Aj = A; + for(j=0;j=0;--i) ret[i] = []; + } + for(i=n;i>=0;--i) ret[i].push(k[i]); + ret[n+1].push(Ai); + } + } else gather(Ai,ret,k); + } + } + if(k.length>n) k.pop(); + return ret; + }; + + // 6. Coordinate matrices + numeric.cLU = function LU(A) { + var I = A[0], J = A[1], V = A[2]; + var p = I.length, m=0, i,j,k,a,b,c; + for(i=0;im) m=I[i]; + m++; + var L = Array(m), U = Array(m), left = numeric.rep([m],Infinity), right = numeric.rep([m],-Infinity); + var Ui, Uj,alpha; + for(k=0;kright[i]) right[i] = j; + } + for(i=0;i right[i+1]) right[i+1] = right[i]; } + for(i=m-1;i>=1;i--) { if(left[i]=0;i--) { + while(Uj[k] > i) { + ret[i] -= Uv[k]*ret[Uj[k]]; + k--; + } + ret[i] /= Uv[k]; + k--; + } + return ret; + }; + + numeric.cgrid = function grid(n,shape) { + if(typeof n === "number") n = [n,n]; + var ret = numeric.rep(n,-1); + var i,j,count; + if(typeof shape !== "function") { + switch(shape) { + case 'L': + shape = function(i,j) { return (i>=n[0]/2 || jN) N = Ai[k]; } + N++; + ret = numeric.rep([N],0); + for(k=0;k1) { + mid = floor((p+q)/2); + if(x[mid] <= x0) p = mid; + else q = mid; + } + return this._at(x0,p); + } + var n = x0.length, i, ret = Array(n); + for(i=n-1;i!==-1;--i) ret[i] = this.at(x0[i]); + return ret; + }; + numeric.Spline.prototype.diff = function diff() { + var x = this.x; + var yl = this.yl; + var yr = this.yr; + var kl = this.kl; + var kr = this.kr; + var n = yl.length; + var i,dx,dy; + var zl = kl, zr = kr, pl = Array(n), pr = Array(n); + var add = numeric.add, mul = numeric.mul, div = numeric.div, sub = numeric.sub; + for(i=n-1;i!==-1;--i) { + dx = x[i+1]-x[i]; + dy = sub(yr[i+1],yl[i]); + pl[i] = div(add(mul(dy, 6),mul(kl[i],-4*dx),mul(kr[i+1],-2*dx)),dx*dx); + pr[i+1] = div(add(mul(dy,-6),mul(kl[i], 2*dx),mul(kr[i+1], 4*dx)),dx*dx); + } + return new numeric.Spline(x,zl,zr,pl,pr); + }; + numeric.Spline.prototype.roots = function roots() { + function sqr(x) { return x*x; } + var ret = []; + var x = this.x, yl = this.yl, yr = this.yr, kl = this.kl, kr = this.kr; + if(typeof yl[0] === "number") { + yl = [yl]; + yr = [yr]; + kl = [kl]; + kr = [kr]; + } + var m = yl.length,n=x.length-1,i,j,k; + var ai,bi,ci,di, ret = Array(m),ri,k0,k1,y0,y1,A,B,D,dx,cx,stops,z0,z1,zm,t0,t1,tm; + var sqrt = Math.sqrt; + for(i=0;i!==m;++i) { + ai = yl[i]; + bi = yr[i]; + ci = kl[i]; + di = kr[i]; + ri = []; + for(j=0;j!==n;j++) { + if(j>0 && bi[j]*ai[j]<0) ri.push(x[j]); + dx = (x[j+1]-x[j]); + cx = x[j]; + y0 = ai[j]; + y1 = bi[j+1]; + k0 = ci[j]/dx; + k1 = di[j+1]/dx; + D = sqr(k0-k1+3*(y0-y1)) + 12*k1*y0; + A = k1+3*y0+2*k0-3*y1; + B = 3*(k1+k0+2*(y0-y1)); + if(D<=0) { + z0 = A/B; + if(z0>x[j] && z0x[j] && z0x[j] && z10) { + t0 = t1; + z0 = z1; + continue; + } + var side = 0; + while(1) { + tm = (z0*t1-z1*t0)/(z0-z1); + if(tm <= t0 || tm >= t1) { break; } + zm = this._at(tm,j); + if(zm*z1>0) { + t1 = tm; + z1 = zm; + if(side === -1) z0*=0.5; + side = -1; + } else if(zm*z0>0) { + t0 = tm; + z0 = zm; + if(side === 1) z1*=0.5; + side = 1; + } else break; + } + ri.push(tm); + t0 = stops[k+1]; + z0 = this._at(t0, j); + } + if(z1 === 0) ri.push(t1); + } + ret[i] = ri; + } + if(typeof this.yl[0] === "number") return ret[0]; + return ret; + }; + numeric.spline = function spline(x,y,k1,kn) { + var n = x.length, b = [], dx = [], dy = []; + var i; + var sub = numeric.sub,mul = numeric.mul,add = numeric.add; + for(i=n-2;i>=0;i--) { dx[i] = x[i+1]-x[i]; dy[i] = sub(y[i+1],y[i]); } + if(typeof k1 === "string" || typeof kn === "string") { + k1 = kn = "periodic"; + } + // Build sparse tridiagonal system + var T = [[],[],[]]; + switch(typeof k1) { + case "undefined": + b[0] = mul(3/(dx[0]*dx[0]),dy[0]); + T[0].push(0,0); + T[1].push(0,1); + T[2].push(2/dx[0],1/dx[0]); + break; + case "string": + b[0] = add(mul(3/(dx[n-2]*dx[n-2]),dy[n-2]),mul(3/(dx[0]*dx[0]),dy[0])); + T[0].push(0,0,0); + T[1].push(n-2,0,1); + T[2].push(1/dx[n-2],2/dx[n-2]+2/dx[0],1/dx[0]); + break; + default: + b[0] = k1; + T[0].push(0); + T[1].push(0); + T[2].push(1); + break; + } + for(i=1;i20) { throw new Error("Numerical gradient fails"); } + x0[i] = x[i]+h; + f1 = f(x0); + x0[i] = x[i]-h; + f2 = f(x0); + x0[i] = x[i]; + if(isNaN(f1) || isNaN(f2)) { h/=16; continue; } + J[i] = (f1-f2)/(2*h); + t0 = x[i]-h; + t1 = x[i]; + t2 = x[i]+h; + d1 = (f1-f0)/h; + d2 = (f0-f2)/h; + N = max(abs(J[i]),abs(f0),abs(f1),abs(f2),abs(t0),abs(t1),abs(t2),1e-8); + errest = min(max(abs(d1-J[i]),abs(d2-J[i]),abs(d1-d2))/N,h/N); + if(errest>eps) { h/=16; } + else break; + } + } + return J; + }; + + numeric.uncmin = function uncmin(f,x0,tol,gradient,maxit,callback,options) { + var grad = numeric.gradient; + if(typeof options === "undefined") { options = {}; } + if(typeof tol === "undefined") { tol = 1e-8; } + if(typeof gradient === "undefined") { gradient = function(x) { return grad(f,x); }; } + if(typeof maxit === "undefined") maxit = 1000; + x0 = numeric.clone(x0); + var n = x0.length; + var f0 = f(x0),f1,df0; + if(isNaN(f0)) throw new Error('uncmin: f(x0) is a NaN!'); + var max = Math.max, norm2 = numeric.norm2; + tol = max(tol,numeric.epsilon); + var step,g0,g1,H1 = options.Hinv || numeric.identity(n); + var dot = numeric.dot, inv = numeric.inv, sub = numeric.sub, add = numeric.add, ten = numeric.tensor, div = numeric.div, mul = numeric.mul; + var all = numeric.all, isfinite = numeric.isFinite, neg = numeric.neg; + var it=0,s,x1,y,Hy,ys,t,nstep; + var msg = ""; + g0 = gradient(x0); + while(it= 0.1*t*df0 || isNaN(f1)) { + t *= 0.5; + ++it; + continue; + } + break; + } + if(t*nstep < tol) { msg = "Line search step size smaller than tol"; break; } + if(it === maxit) { msg = "maxit reached during line search"; break; } + g1 = gradient(x1); + y = sub(g1,g0); + ys = dot(y,s); + Hy = dot(H1,y); + H1 = sub(add(H1, + mul( + (ys+dot(y,Hy))/(ys*ys), + ten(s,s) )), + div(add(ten(Hy,s),ten(s,Hy)),ys)); + x0 = x1; + f0 = f1; + g0 = g1; + ++it; + } + return {solution: x0, f: f0, gradient: g0, invHessian: H1, iterations:it, message: msg}; + }; + + // 10. Ode solver (Dormand-Prince) + numeric.Dopri = function Dopri(x,y,f,ymid,iterations,msg,events) { + this.x = x; + this.y = y; + this.f = f; + this.ymid = ymid; + this.iterations = iterations; + this.events = events; + this.message = msg; + }; + numeric.Dopri.prototype._at = function _at(xi,j) { + function sqr(x) { return x*x; } + var sol = this; + var xs = sol.x; + var ys = sol.y; + var k1 = sol.f; + var ymid = sol.ymid; + var n = xs.length; + var x0,x1,xh,y0,y1,yh,xi; + var h; + var c = 0.5; + var add = numeric.add, mul = numeric.mul,sub = numeric.sub, p,q,w; + x0 = xs[j]; + x1 = xs[j+1]; + y0 = ys[j]; + y1 = ys[j+1]; + h = x1-x0; + xh = x0+c*h; + yh = ymid[j]; + p = sub(k1[j ],mul(y0,1/(x0-xh)+2/(x0-x1))); + q = sub(k1[j+1],mul(y1,1/(x1-xh)+2/(x1-x0))); + w = [sqr(xi - x1) * (xi - xh) / sqr(x0 - x1) / (x0 - xh), + sqr(xi - x0) * sqr(xi - x1) / sqr(x0 - xh) / sqr(x1 - xh), + sqr(xi - x0) * (xi - xh) / sqr(x1 - x0) / (x1 - xh), + (xi - x0) * sqr(xi - x1) * (xi - xh) / sqr(x0-x1) / (x0 - xh), + (xi - x1) * sqr(xi - x0) * (xi - xh) / sqr(x0-x1) / (x1 - xh)]; + return add(add(add(add(mul(y0,w[0]), + mul(yh,w[1])), + mul(y1,w[2])), + mul( p,w[3])), + mul( q,w[4])); + }; + numeric.Dopri.prototype.at = function at(x) { + var i,j,k,floor = Math.floor; + if(typeof x !== "number") { + var n = x.length, ret = Array(n); + for(i=n-1;i!==-1;--i) { + ret[i] = this.at(x[i]); + } + return ret; + } + var x0 = this.x; + i = 0; j = x0.length-1; + while(j-i>1) { + k = floor(0.5*(i+j)); + if(x0[k] <= x) i = k; + else j = k; + } + return this._at(x,i); + }; + + numeric.dopri = function dopri(x0,x1,y0,f,tol,maxit,event) { + if(typeof tol === "undefined") { tol = 1e-6; } + if(typeof maxit === "undefined") { maxit = 1000; } + var xs = [x0], ys = [y0], k1 = [f(x0,y0)], k2,k3,k4,k5,k6,k7, ymid = []; + var A2 = 1/5; + var A3 = [3/40,9/40]; + var A4 = [44/45,-56/15,32/9]; + var A5 = [19372/6561,-25360/2187,64448/6561,-212/729]; + var A6 = [9017/3168,-355/33,46732/5247,49/176,-5103/18656]; + var b = [35/384,0,500/1113,125/192,-2187/6784,11/84]; + var bm = [0.5*6025192743/30085553152, + 0, + 0.5*51252292925/65400821598, + 0.5*-2691868925/45128329728, + 0.5*187940372067/1594534317056, + 0.5*-1776094331/19743644256, + 0.5*11237099/235043384]; + var c = [1/5,3/10,4/5,8/9,1,1]; + var e = [-71/57600,0,71/16695,-71/1920,17253/339200,-22/525,1/40]; + var i = 0,er,j; + var h = (x1-x0)/10; + var it = 0; + var add = numeric.add, mul = numeric.mul, y1,erinf; + var min = Math.min, abs = Math.abs, norminf = numeric.norminf,pow = Math.pow; + var any = numeric.any, lt = numeric.lt, and = numeric.and, sub = numeric.sub; + var e0, e1, ev; + var ret = new numeric.Dopri(xs,ys,k1,ymid,-1,""); + if(typeof event === "function") e0 = event(x0,y0); + while(x0x1) h = x1-x0; + k2 = f(x0+c[0]*h, add(y0,mul( A2*h,k1[i]))); + k3 = f(x0+c[1]*h, add(add(y0,mul(A3[0]*h,k1[i])),mul(A3[1]*h,k2))); + k4 = f(x0+c[2]*h, add(add(add(y0,mul(A4[0]*h,k1[i])),mul(A4[1]*h,k2)),mul(A4[2]*h,k3))); + k5 = f(x0+c[3]*h, add(add(add(add(y0,mul(A5[0]*h,k1[i])),mul(A5[1]*h,k2)),mul(A5[2]*h,k3)),mul(A5[3]*h,k4))); + k6 = f(x0+c[4]*h,add(add(add(add(add(y0,mul(A6[0]*h,k1[i])),mul(A6[1]*h,k2)),mul(A6[2]*h,k3)),mul(A6[3]*h,k4)),mul(A6[4]*h,k5))); + y1 = add(add(add(add(add(y0,mul(k1[i],h*b[0])),mul(k3,h*b[2])),mul(k4,h*b[3])),mul(k5,h*b[4])),mul(k6,h*b[5])); + k7 = f(x0+h,y1); + er = add(add(add(add(add(mul(k1[i],h*e[0]),mul(k3,h*e[2])),mul(k4,h*e[3])),mul(k5,h*e[4])),mul(k6,h*e[5])),mul(k7,h*e[6])); + if(typeof er === "number") erinf = abs(er); + else erinf = norminf(er); + if(erinf > tol) { // reject + h = 0.2*h*pow(tol/erinf,0.25); + if(x0+h === x0) { + ret.msg = "Step size became too small"; + break; + } + continue; + } + ymid[i] = add(add(add(add(add(add(y0, + mul(k1[i],h*bm[0])), + mul(k3 ,h*bm[2])), + mul(k4 ,h*bm[3])), + mul(k5 ,h*bm[4])), + mul(k6 ,h*bm[5])), + mul(k7 ,h*bm[6])); + ++i; + xs[i] = x0+h; + ys[i] = y1; + k1[i] = k7; + if(typeof event === "function") { + var yi,xl = x0,xr = x0+0.5*h,xi; + e1 = event(xr,ymid[i-1]); + ev = and(lt(e0,0),lt(0,e1)); + if(!any(ev)) { xl = xr; xr = x0+h; e0 = e1; e1 = event(xr,y1); ev = and(lt(e0,0),lt(0,e1)); } + if(any(ev)) { + var en,ei; + var side=0, sl = 1.0, sr = 1.0; + while(1) { + if(typeof e0 === "number") xi = (sr*e1*xl-sl*e0*xr)/(sr*e1-sl*e0); + else { + xi = xr; + for(j=e0.length-1;j!==-1;--j) { + if(e0[j]<0 && e1[j]>0) xi = min(xi,(sr*e1[j]*xl-sl*e0[j]*xr)/(sr*e1[j]-sl*e0[j])); + } + } + if(xi <= xl || xi >= xr) break; + yi = ret._at(xi, i-1); + ei = event(xi,yi); + en = and(lt(e0,0),lt(0,ei)); + if(any(en)) { + xr = xi; + e1 = ei; + ev = en; + sr = 1.0; + if(side === -1) sl *= 0.5; + else sl = 1.0; + side = -1; + } else { + xl = xi; + e0 = ei; + sl = 1.0; + if(side === 1) sr *= 0.5; + else sr = 1.0; + side = 1; + } + } + y1 = ret._at(0.5*(x0+xi),i-1); + ret.f[i] = f(xi,yi); + ret.x[i] = xi; + ret.y[i] = yi; + ret.ymid[i-1] = y1; + ret.events = ev; + ret.iterations = it; + return ret; + } + } + x0 += h; + y0 = y1; + e0 = e1; + h = min(0.8*h*pow(tol/erinf,0.25),4*h); + } + ret.iterations = it; + return ret; + }; + + // 11. Ax = b + numeric.LU = function(A, fast) { + fast = fast || false; + + var abs = Math.abs; + var i, j, k, absAjk, Akk, Ak, Pk, Ai; + var max; + var n = A.length, n1 = n-1; + var P = new Array(n); + if(!fast) A = numeric.clone(A); + + for (k = 0; k < n; ++k) { + Pk = k; + Ak = A[k]; + max = abs(Ak[k]); + for (j = k + 1; j < n; ++j) { + absAjk = abs(A[j][k]); + if (max < absAjk) { + max = absAjk; + Pk = j; + } + } + P[k] = Pk; + + if (Pk != k) { + A[k] = A[Pk]; + A[Pk] = Ak; + Ak = A[k]; + } + + Akk = Ak[k]; + + for (i = k + 1; i < n; ++i) { + A[i][k] /= Akk; + } + + for (i = k + 1; i < n; ++i) { + Ai = A[i]; + for (j = k + 1; j < n1; ++j) { + Ai[j] -= Ai[k] * Ak[j]; + ++j; + Ai[j] -= Ai[k] * Ak[j]; + } + if(j===n1) Ai[j] -= Ai[k] * Ak[j]; + } + } + + return { + LU: A, + P: P + }; + }; + + numeric.LUsolve = function LUsolve(LUP, b) { + var i, j; + var LU = LUP.LU; + var n = LU.length; + var x = numeric.clone(b); + var P = LUP.P; + var Pi, LUi, tmp; + + for (i=n-1;i!==-1;--i) x[i] = b[i]; + for (i = 0; i < n; ++i) { + Pi = P[i]; + if (P[i] !== i) { + tmp = x[i]; + x[i] = x[Pi]; + x[Pi] = tmp; + } + + LUi = LU[i]; + for (j = 0; j < i; ++j) { + x[i] -= x[j] * LUi[j]; + } + } + + for (i = n - 1; i >= 0; --i) { + LUi = LU[i]; + for (j = i + 1; j < n; ++j) { + x[i] -= x[j] * LUi[j]; + } + + x[i] /= LUi[i]; + } + + return x; + }; + + numeric.solve = function solve(A,b,fast) { return numeric.LUsolve(numeric.LU(A,fast), b); }; + + // 12. Linear programming + numeric.echelonize = function echelonize(A) { + var s = numeric.dim(A), m = s[0], n = s[1]; + var I = numeric.identity(m); + var P = Array(m); + var i,j,k,l,Ai,Ii,Z,a; + var abs = Math.abs; + var diveq = numeric.diveq; + A = numeric.clone(A); + for(i=0;ia1) alpha = a1; + g = add(c,mul(alpha,p)); + H = dot(A1,A0); + for(i=m-1;i!==-1;--i) H[i][i] += 1; + d = solve(H,div(g,alpha),true); + var t0 = div(z,dot(A,d)); + var t = 1.0; + for(i=n-1;i!==-1;--i) if(t0[i]<0) t = min(t,-0.999*t0[i]); + y = sub(x,mul(d,t)); + z = sub(b,dot(A,y)); + if(!all(gt(z,0))) return { solution: x, message: "", iterations: count }; + x = y; + if(alpha=0) unbounded = false; + else unbounded = true; + } + if(unbounded) return { solution: y, message: "Unbounded", iterations: count }; + } + return { solution: x, message: "maximum iteration count exceeded", iterations:count }; + }; + + numeric._solveLP = function _solveLP(c,A,b,tol,maxit) { + var m = c.length, n = b.length,y; + var sum = numeric.sum, log = numeric.log, mul = numeric.mul, sub = numeric.sub, dot = numeric.dot, div = numeric.div, add = numeric.add; + var c0 = numeric.rep([m],0).concat([1]); + var J = numeric.rep([n,1],-1); + var A0 = numeric.blockMatrix([[A , J ]]); + var b0 = b; + var y = numeric.rep([m],0).concat(Math.max(0,numeric.sup(numeric.neg(b)))+1); + var x0 = numeric.__solveLP(c0,A0,b0,tol,maxit,y,false); + var x = numeric.clone(x0.solution); + x.length = m; + var foo = numeric.inf(sub(b,dot(A,x))); + if(foo<0) { return { solution: NaN, message: "Infeasible", iterations: x0.iterations }; } + var ret = numeric.__solveLP(c, A, b, tol, maxit-x0.iterations, x, true); + ret.iterations += x0.iterations; + return ret; + }; + + numeric.solveLP = function solveLP(c,A,b,Aeq,beq,tol,maxit) { + if(typeof maxit === "undefined") maxit = 1000; + if(typeof tol === "undefined") tol = numeric.epsilon; + if(typeof Aeq === "undefined") return numeric._solveLP(c,A,b,tol,maxit); + var m = Aeq.length, n = Aeq[0].length, o = A.length; + var B = numeric.echelonize(Aeq); + var flags = numeric.rep([n],0); + var P = B.P; + var Q = []; + var i; + for(i=P.length-1;i!==-1;--i) flags[P[i]] = 1; + for(i=n-1;i!==-1;--i) if(flags[i]===0) Q.push(i); + var g = numeric.getRange; + var I = numeric.linspace(0,m-1), J = numeric.linspace(0,o-1); + var Aeq2 = g(Aeq,I,Q), A1 = g(A,J,P), A2 = g(A,J,Q), dot = numeric.dot, sub = numeric.sub; + var A3 = dot(A1,B.I); + var A4 = sub(A2,dot(A3,Aeq2)), b4 = sub(b,dot(A3,beq)); + var c1 = Array(P.length), c2 = Array(Q.length); + for(i=P.length-1;i!==-1;--i) c1[i] = c[P[i]]; + for(i=Q.length-1;i!==-1;--i) c2[i] = c[Q[i]]; + var c4 = sub(c2,dot(c1,dot(B.I,Aeq2))); + var S = numeric._solveLP(c4,A4,b4,tol,maxit); + var x2 = S.solution; + if(x2!==x2) return S; + var x1 = dot(B.I,sub(beq,dot(Aeq2,x2))); + var x = Array(c.length); + for(i=P.length-1;i!==-1;--i) x[P[i]] = x1[i]; + for(i=Q.length-1;i!==-1;--i) x[Q[i]] = x2[i]; + return { solution: x, message:S.message, iterations: S.iterations }; + }; + + numeric.MPStoLP = function MPStoLP(MPS) { + if(MPS instanceof String) { MPS.split('\n'); } + var state = 0; + var states = ['Initial state','NAME','ROWS','COLUMNS','RHS','BOUNDS','ENDATA']; + var n = MPS.length; + var i,j,z,N=0,rows = {}, sign = [], rl = 0, vars = {}, nv = 0; + var name; + var c = [], A = [], b = []; + function err(e) { throw new Error('MPStoLP: '+e+'\nLine '+i+': '+MPS[i]+'\nCurrent state: '+states[state]+'\n'); } + for(i=0;i + // + // Math.seedrandom('yipee'); Sets Math.random to a function that is + // initialized using the given explicit seed. + // + // Math.seedrandom(); Sets Math.random to a function that is + // seeded using the current time, dom state, + // and other accumulated local entropy. + // The generated seed string is returned. + // + // Math.seedrandom('yowza', true); + // Seeds using the given explicit seed mixed + // together with accumulated entropy. + // + // + // Seeds using physical random bits downloaded + // from random.org. + // + // Seeds using urandom bits from call.jsonlib.com, + // which is faster than random.org. + // + // Examples: + // + // Math.seedrandom("hello"); // Use "hello" as the seed. + // document.write(Math.random()); // Always 0.5463663768140734 + // document.write(Math.random()); // Always 0.43973793770592234 + // var rng1 = Math.random; // Remember the current prng. + // + // var autoseed = Math.seedrandom(); // New prng with an automatic seed. + // document.write(Math.random()); // Pretty much unpredictable. + // + // Math.random = rng1; // Continue "hello" prng sequence. + // document.write(Math.random()); // Always 0.554769432473455 + // + // Math.seedrandom(autoseed); // Restart at the previous seed. + // document.write(Math.random()); // Repeat the 'unpredictable' value. + // + // Notes: + // + // Each time seedrandom('arg') is called, entropy from the passed seed + // is accumulated in a pool to help generate future seeds for the + // zero-argument form of Math.seedrandom, so entropy can be injected over + // time by calling seedrandom with explicit data repeatedly. + // + // On speed - This javascript implementation of Math.random() is about + // 3-10x slower than the built-in Math.random() because it is not native + // code, but this is typically fast enough anyway. Seeding is more expensive, + // especially if you use auto-seeding. Some details (timings on Chrome 4): + // + // Our Math.random() - avg less than 0.002 milliseconds per call + // seedrandom('explicit') - avg less than 0.5 milliseconds per call + // seedrandom('explicit', true) - avg less than 2 milliseconds per call + // seedrandom() - avg about 38 milliseconds per call + // + // LICENSE (BSD): + // + // Copyright 2010 David Bau, all rights reserved. + // + // Redistribution and use in source and binary forms, with or without + // modification, are permitted provided that the following conditions are met: + // + // 1. Redistributions of source code must retain the above copyright + // notice, this list of conditions and the following disclaimer. + // + // 2. Redistributions in binary form must reproduce the above copyright + // notice, this list of conditions and the following disclaimer in the + // documentation and/or other materials provided with the distribution. + // + // 3. Neither the name of this module nor the names of its contributors may + // be used to endorse or promote products derived from this software + // without specific prior written permission. + // + // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + // + /** + * All code is in an anonymous closure to keep the global namespace clean. + * + * @param {number=} overflow + * @param {number=} startdenom + */ + + // Patched by Seb so that seedrandom.js does not pollute the Math object. + // My tests suggest that doing Math.trouble = 1 makes Math lookups about 5% + // slower. + numeric.seedrandom = { pow:Math.pow, random:Math.random }; + + (function (pool, math, width, chunks, significance, overflow, startdenom) { + + + // + // seedrandom() + // This is the seedrandom function described above. + // + math['seedrandom'] = function seedrandom(seed, use_entropy) { + var key = []; + var arc4; + + // Flatten the seed string or build one from local entropy if needed. + seed = mixkey(flatten( + use_entropy ? [seed, pool] : + arguments.length ? seed : + [new Date().getTime(), pool, window], 3), key); + + // Use the seed to initialize an ARC4 generator. + arc4 = new ARC4(key); + + // Mix the randomness into accumulated entropy. + mixkey(arc4.S, pool); + + // Override Math.random + + // This function returns a random double in [0, 1) that contains + // randomness in every bit of the mantissa of the IEEE 754 value. + + math['random'] = function random() { // Closure to return a random double: + var n = arc4.g(chunks); // Start with a numerator n < 2 ^ 48 + var d = startdenom; // and denominator d = 2 ^ 48. + var x = 0; // and no 'extra last byte'. + while (n < significance) { // Fill up all significant digits by + n = (n + x) * width; // shifting numerator and + d *= width; // denominator and generating a + x = arc4.g(1); // new least-significant-byte. + } + while (n >= overflow) { // To avoid rounding up, before adding + n /= 2; // last byte, shift everything + d /= 2; // right using integer math until + x >>>= 1; // we have exactly the desired bits. + } + return (n + x) / d; // Form the number within [0, 1). + }; + + // Return the seed that was used + return seed; + }; + + // + // ARC4 + // + // An ARC4 implementation. The constructor takes a key in the form of + // an array of at most (width) integers that should be 0 <= x < (width). + // + // The g(count) method returns a pseudorandom integer that concatenates + // the next (count) outputs from ARC4. Its return value is a number x + // that is in the range 0 <= x < (width ^ count). + // + /** @constructor */ + function ARC4(key) { + var t, u, me = this, keylen = key.length; + var i = 0, j = me.i = me.j = me.m = 0; + me.S = []; + me.c = []; + + // The empty key [] is treated as [0]. + if (!keylen) { key = [keylen++]; } + + // Set up S using the standard key scheduling algorithm. + while (i < width) { me.S[i] = i++; } + for (i = 0; i < width; i++) { + t = me.S[i]; + j = lowbits(j + t + key[i % keylen]); + u = me.S[j]; + me.S[i] = u; + me.S[j] = t; + } + + // The "g" method returns the next (count) outputs as one number. + me.g = function getnext(count) { + var s = me.S; + var i = lowbits(me.i + 1); var t = s[i]; + var j = lowbits(me.j + t); var u = s[j]; + s[i] = u; + s[j] = t; + var r = s[lowbits(t + u)]; + while (--count) { + i = lowbits(i + 1); t = s[i]; + j = lowbits(j + t); u = s[j]; + s[i] = u; + s[j] = t; + r = r * width + s[lowbits(t + u)]; + } + me.i = i; + me.j = j; + return r; + }; + // For robust unpredictability discard an initial batch of values. + // See http://www.rsa.com/rsalabs/node.asp?id=2009 + me.g(width); + } + + // + // flatten() + // Converts an object tree to nested arrays of strings. + // + /** @param {Object=} result + * @param {string=} prop + * @param {string=} typ */ + function flatten(obj, depth, result, prop, typ) { + result = []; + typ = typeof(obj); + if (depth && typ == 'object') { + for (prop in obj) { + if (prop.indexOf('S') < 5) { // Avoid FF3 bug (local/sessionStorage) + try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} + } + } + } + return (result.length ? result : obj + (typ != 'string' ? '\0' : '')); + } + + // + // mixkey() + // Mixes a string seed into a key that is an array of integers, and + // returns a shortened string seed that is equivalent to the result key. + // + /** @param {number=} smear + * @param {number=} j */ + function mixkey(seed, key, smear, j) { + seed += ''; // Ensure the seed is a string + smear = 0; + for (j = 0; j < seed.length; j++) { + key[lowbits(j)] = + lowbits((smear ^= key[lowbits(j)] * 19) + seed.charCodeAt(j)); + } + seed = ''; + for (j in key) { seed += String.fromCharCode(key[j]); } + return seed; + } + + // + // lowbits() + // A quick "n mod width" for width a power of 2. + // + function lowbits(n) { return n & (width - 1); } + + // + // The following constants are related to IEEE 754 limits. + // + startdenom = math.pow(width, chunks); + significance = math.pow(2, significance); + overflow = significance * 2; + + // + // When seedrandom.js is loaded, we immediately mix a few bits + // from the built-in RNG into the entropy pool. Because we do + // not want to intefere with determinstic PRNG state later, + // seedrandom will not call math.random on its own again after + // initialization. + // + mixkey(math.random(), pool); + + // End anonymous scope, and pass initial values. + }( + [], // pool: entropy pool starts empty + numeric.seedrandom, // math: package containing random, pow, and seedrandom + 256, // width: each RC4 output is 0 <= x < 256 + 6, // chunks: at least six RC4 outputs for each double + 52 // significance: there are 52 significant digits in a double + )); + /* This file is a slightly modified version of quadprog.js from Alberto Santini. + * It has been slightly modified by Sébastien Loisel to make sure that it handles + * 0-based Arrays instead of 1-based Arrays. + * License is in resources/LICENSE.quadprog */ + (function(exports) { + + function base0to1(A) { + if(typeof A !== "object") { return A; } + var ret = [], i,n=A.length; + for(i=0;i meq) { + work[l] = sum; + } else { + work[l] = -Math.abs(sum); + if (sum > 0) { + for (j = 1; j <= n; j = j + 1) { + amat[j][i] = -amat[j][i]; + } + bvec[i] = -bvec[i]; + } + } + } + + for (i = 1; i <= nact; i = i + 1) { + work[iwsv + iact[i]] = 0; + } + + nvl = 0; + temp = 0; + for (i = 1; i <= q; i = i + 1) { + if (work[iwsv + i] < temp * work[iwnbv + i]) { + nvl = i; + temp = work[iwsv + i] / work[iwnbv + i]; + } + } + if (nvl === 0) { + return 999; + } + + return 0; + } + + function fn_goto_55() { + for (i = 1; i <= n; i = i + 1) { + sum = 0; + for (j = 1; j <= n; j = j + 1) { + sum = sum + dmat[j][i] * amat[j][nvl]; + } + work[i] = sum; + } + + l1 = iwzv; + for (i = 1; i <= n; i = i + 1) { + work[l1 + i] = 0; + } + for (j = nact + 1; j <= n; j = j + 1) { + for (i = 1; i <= n; i = i + 1) { + work[l1 + i] = work[l1 + i] + dmat[i][j] * work[j]; + } + } + + t1inf = true; + for (i = nact; i >= 1; i = i - 1) { + sum = work[i]; + l = iwrm + (i * (i + 3)) / 2; + l1 = l - i; + for (j = i + 1; j <= nact; j = j + 1) { + sum = sum - work[l] * work[iwrv + j]; + l = l + j; + } + sum = sum / work[l1]; + work[iwrv + i] = sum; + if (iact[i] < meq) { + // continue; + break; + } + if (sum < 0) { + // continue; + break; + } + t1inf = false; + it1 = i; + } + + if (!t1inf) { + t1 = work[iwuv + it1] / work[iwrv + it1]; + for (i = 1; i <= nact; i = i + 1) { + if (iact[i] < meq) { + // continue; + break; + } + if (work[iwrv + i] < 0) { + // continue; + break; + } + temp = work[iwuv + i] / work[iwrv + i]; + if (temp < t1) { + t1 = temp; + it1 = i; + } + } + } + + sum = 0; + for (i = iwzv + 1; i <= iwzv + n; i = i + 1) { + sum = sum + work[i] * work[i]; + } + if (Math.abs(sum) <= vsmall) { + if (t1inf) { + ierr[1] = 1; + // GOTO 999 + return 999; + } else { + for (i = 1; i <= nact; i = i + 1) { + work[iwuv + i] = work[iwuv + i] - t1 * work[iwrv + i]; + } + work[iwuv + nact + 1] = work[iwuv + nact + 1] + t1; + // GOTO 700 + return 700; + } + } else { + sum = 0; + for (i = 1; i <= n; i = i + 1) { + sum = sum + work[iwzv + i] * amat[i][nvl]; + } + tt = -work[iwsv + nvl] / sum; + t2min = true; + if (!t1inf) { + if (t1 < tt) { + tt = t1; + t2min = false; + } + } + + for (i = 1; i <= n; i = i + 1) { + sol[i] = sol[i] + tt * work[iwzv + i]; + if (Math.abs(sol[i]) < vsmall) { + sol[i] = 0; + } + } + + crval[1] = crval[1] + tt * sum * (tt / 2 + work[iwuv + nact + 1]); + for (i = 1; i <= nact; i = i + 1) { + work[iwuv + i] = work[iwuv + i] - tt * work[iwrv + i]; + } + work[iwuv + nact + 1] = work[iwuv + nact + 1] + tt; + + if (t2min) { + nact = nact + 1; + iact[nact] = nvl; + + l = iwrm + ((nact - 1) * nact) / 2 + 1; + for (i = 1; i <= nact - 1; i = i + 1) { + work[l] = work[i]; + l = l + 1; + } + + if (nact === n) { + work[l] = work[n]; + } else { + for (i = n; i >= nact + 1; i = i - 1) { + if (work[i] === 0) { + // continue; + break; + } + gc = Math.max(Math.abs(work[i - 1]), Math.abs(work[i])); + gs = Math.min(Math.abs(work[i - 1]), Math.abs(work[i])); + if (work[i - 1] >= 0) { + temp = Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); + } else { + temp = -Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); + } + gc = work[i - 1] / temp; + gs = work[i] / temp; + + if (gc === 1) { + // continue; + break; + } + if (gc === 0) { + work[i - 1] = gs * temp; + for (j = 1; j <= n; j = j + 1) { + temp = dmat[j][i - 1]; + dmat[j][i - 1] = dmat[j][i]; + dmat[j][i] = temp; + } + } else { + work[i - 1] = temp; + nu = gs / (1 + gc); + for (j = 1; j <= n; j = j + 1) { + temp = gc * dmat[j][i - 1] + gs * dmat[j][i]; + dmat[j][i] = nu * (dmat[j][i - 1] + temp) - dmat[j][i]; + dmat[j][i - 1] = temp; + + } + } + } + work[l] = work[nact]; + } + } else { + sum = -bvec[nvl]; + for (j = 1; j <= n; j = j + 1) { + sum = sum + sol[j] * amat[j][nvl]; + } + if (nvl > meq) { + work[iwsv + nvl] = sum; + } else { + work[iwsv + nvl] = -Math.abs(sum); + if (sum > 0) { + for (j = 1; j <= n; j = j + 1) { + amat[j][nvl] = -amat[j][nvl]; + } + bvec[nvl] = -bvec[nvl]; + } + } + // GOTO 700 + return 700; + } + } + + return 0; + } + + function fn_goto_797() { + l = iwrm + (it1 * (it1 + 1)) / 2 + 1; + l1 = l + it1; + if (work[l1] === 0) { + // GOTO 798 + return 798; + } + gc = Math.max(Math.abs(work[l1 - 1]), Math.abs(work[l1])); + gs = Math.min(Math.abs(work[l1 - 1]), Math.abs(work[l1])); + if (work[l1 - 1] >= 0) { + temp = Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); + } else { + temp = -Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); + } + gc = work[l1 - 1] / temp; + gs = work[l1] / temp; + + if (gc === 1) { + // GOTO 798 + return 798; + } + if (gc === 0) { + for (i = it1 + 1; i <= nact; i = i + 1) { + temp = work[l1 - 1]; + work[l1 - 1] = work[l1]; + work[l1] = temp; + l1 = l1 + i; + } + for (i = 1; i <= n; i = i + 1) { + temp = dmat[i][it1]; + dmat[i][it1] = dmat[i][it1 + 1]; + dmat[i][it1 + 1] = temp; + } + } else { + nu = gs / (1 + gc); + for (i = it1 + 1; i <= nact; i = i + 1) { + temp = gc * work[l1 - 1] + gs * work[l1]; + work[l1] = nu * (work[l1 - 1] + temp) - work[l1]; + work[l1 - 1] = temp; + l1 = l1 + i; + } + for (i = 1; i <= n; i = i + 1) { + temp = gc * dmat[i][it1] + gs * dmat[i][it1 + 1]; + dmat[i][it1 + 1] = nu * (dmat[i][it1] + temp) - dmat[i][it1 + 1]; + dmat[i][it1] = temp; + } + } + + return 0; + } + + function fn_goto_798() { + l1 = l - it1; + for (i = 1; i <= it1; i = i + 1) { + work[l1] = work[l]; + l = l + 1; + l1 = l1 + 1; + } + + work[iwuv + it1] = work[iwuv + it1 + 1]; + iact[it1] = iact[it1 + 1]; + it1 = it1 + 1; + if (it1 < nact) { + // GOTO 797 + return 797; + } + + return 0; + } + + function fn_goto_799() { + work[iwuv + nact] = work[iwuv + nact + 1]; + work[iwuv + nact + 1] = 0; + iact[nact] = 0; + nact = nact - 1; + iter[2] = iter[2] + 1; + + return 0; + } + + go = 0; + while (true) { + go = fn_goto_50(); + if (go === 999) { + return; + } + while (true) { + go = fn_goto_55(); + if (go === 0) { + break; + } + if (go === 999) { + return; + } + if (go === 700) { + if (it1 === nact) { + fn_goto_799(); + } else { + while (true) { + fn_goto_797(); + go = fn_goto_798(); + if (go !== 797) { + break; + } + } + fn_goto_799(); + } + } + } + } + + } + + function solveQP(Dmat, dvec, Amat, bvec, meq, factorized) { + Dmat = base0to1(Dmat); + dvec = base0to1(dvec); + Amat = base0to1(Amat); + var i, n, q, + nact, r, + crval = [], iact = [], sol = [], work = [], iter = [], + message; + + meq = meq || 0; + factorized = factorized ? base0to1(factorized) : [undefined, 0]; + bvec = bvec ? base0to1(bvec) : []; + + // In Fortran the array index starts from 1 + n = Dmat.length - 1; + q = Amat[1].length - 1; + + if (!bvec) { + for (i = 1; i <= q; i = i + 1) { + bvec[i] = 0; + } + } + for (i = 1; i <= q; i = i + 1) { + iact[i] = 0; + } + nact = 0; + r = Math.min(n, q); + for (i = 1; i <= n; i = i + 1) { + sol[i] = 0; + } + crval[1] = 0; + for (i = 1; i <= (2 * n + (r * (r + 5)) / 2 + 2 * q + 1); i = i + 1) { + work[i] = 0; + } + for (i = 1; i <= 2; i = i + 1) { + iter[i] = 0; + } + + qpgen2(Dmat, dvec, n, n, sol, crval, Amat, + bvec, n, q, meq, iact, nact, iter, work, factorized); + + message = ""; + if (factorized[1] === 1) { + message = "constraints are inconsistent, no solution!"; + } + if (factorized[1] === 2) { + message = "matrix D in quadratic function is not positive definite!"; + } + + return { + solution: base1to0(sol), + value: base1to0(crval), + unconstrained_solution: base1to0(dvec), + iterations: base1to0(iter), + iact: base1to0(iact), + message: message + }; + } + exports.solveQP = solveQP; + }(numeric)); + /* + Shanti Rao sent me this routine by private email. I had to modify it + slightly to work on Arrays instead of using a Matrix object. + It is apparently translated from http://stitchpanorama.sourceforge.net/Python/svd.py + */ + + numeric.svd= function svd(A) { + var temp; + //Compute the thin SVD from G. H. Golub and C. Reinsch, Numer. Math. 14, 403-420 (1970) + var prec= numeric.epsilon; //Math.pow(2,-52) // assumes double prec + var tolerance= 1.e-64/prec; + var itmax= 50; + var c=0; + var i=0; + var j=0; + var k=0; + var l=0; + + var u= numeric.clone(A); + var m= u.length; + + var n= u[0].length; + + if (m < n) throw "Need more rows than columns" + + var e = new Array(n); + var q = new Array(n); + for (i=0; i b) + return a*Math.sqrt(1.0+(b*b/a/a)) + else if (b == 0.0) + return a + return b*Math.sqrt(1.0+(a*a/b/b)) + } + + //Householder's reduction to bidiagonal form + + var f= 0.0; + var g= 0.0; + var h= 0.0; + var x= 0.0; + var y= 0.0; + var z= 0.0; + var s= 0.0; + + for (i=0; i < n; i++) + { + e[i]= g; + s= 0.0; + l= i+1; + for (j=i; j < m; j++) + s += (u[j][i]*u[j][i]); + if (s <= tolerance) + g= 0.0; + else + { + f= u[i][i]; + g= Math.sqrt(s); + if (f >= 0.0) g= -g; + h= f*g-s; + u[i][i]=f-g; + for (j=l; j < n; j++) + { + s= 0.0; + for (k=i; k < m; k++) + s += u[k][i]*u[k][j]; + f= s/h; + for (k=i; k < m; k++) + u[k][j]+=f*u[k][i]; + } + } + q[i]= g; + s= 0.0; + for (j=l; j < n; j++) + s= s + u[i][j]*u[i][j]; + if (s <= tolerance) + g= 0.0; + else + { + f= u[i][i+1]; + g= Math.sqrt(s); + if (f >= 0.0) g= -g; + h= f*g - s; + u[i][i+1] = f-g; + for (j=l; j < n; j++) e[j]= u[i][j]/h; + for (j=l; j < m; j++) + { + s=0.0; + for (k=l; k < n; k++) + s += (u[j][k]*u[i][k]); + for (k=l; k < n; k++) + u[j][k]+=s*e[k]; + } + } + y= Math.abs(q[i])+Math.abs(e[i]); + if (y>x) + x=y; + } + + // accumulation of right hand gtransformations + for (i=n-1; i != -1; i+= -1) + { + if (g != 0.0) + { + h= g*u[i][i+1]; + for (j=l; j < n; j++) + v[j][i]=u[i][j]/h; + for (j=l; j < n; j++) + { + s=0.0; + for (k=l; k < n; k++) + s += u[i][k]*v[k][j]; + for (k=l; k < n; k++) + v[k][j]+=(s*v[k][i]); + } + } + for (j=l; j < n; j++) + { + v[i][j] = 0; + v[j][i] = 0; + } + v[i][i] = 1; + g= e[i]; + l= i; + } + + // accumulation of left hand transformations + for (i=n-1; i != -1; i+= -1) + { + l= i+1; + g= q[i]; + for (j=l; j < n; j++) + u[i][j] = 0; + if (g != 0.0) + { + h= u[i][i]*g; + for (j=l; j < n; j++) + { + s=0.0; + for (k=l; k < m; k++) s += u[k][i]*u[k][j]; + f= s/h; + for (k=i; k < m; k++) u[k][j]+=f*u[k][i]; + } + for (j=i; j < m; j++) u[j][i] = u[j][i]/g; + } + else + for (j=i; j < m; j++) u[j][i] = 0; + u[i][i] += 1; + } + + // diagonalization of the bidiagonal form + prec= prec*x; + for (k=n-1; k != -1; k+= -1) + { + for (var iteration=0; iteration < itmax; iteration++) + { // test f splitting + var test_convergence = false; + for (l=k; l != -1; l+= -1) + { + if (Math.abs(e[l]) <= prec) + { test_convergence= true; + break + } + if (Math.abs(q[l-1]) <= prec) + break + } + if (!test_convergence) + { // cancellation of e[l] if l>0 + c= 0.0; + s= 1.0; + var l1= l-1; + for (i =l; i= itmax-1) + throw 'Error: no convergence.' + // shift from bottom 2x2 minor + x= q[l]; + y= q[k-1]; + g= e[k-1]; + h= e[k]; + f= ((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); + g= pythag(f,1.0); + if (f < 0.0) + f= ((x-z)*(x+z)+h*(y/(f-g)-h))/x; + else + f= ((x-z)*(x+z)+h*(y/(f+g)-h))/x; + // next QR transformation + c= 1.0; + s= 1.0; + for (i=l+1; i< k+1; i++) + { + g= e[i]; + y= q[i]; + h= s*g; + g= c*g; + z= pythag(f,h); + e[i-1]= z; + c= f/z; + s= h/z; + f= x*c+g*s; + g= -x*s+g*c; + h= y*s; + y= y*c; + for (j=0; j < n; j++) + { + x= v[j][i-1]; + z= v[j][i]; + v[j][i-1] = x*c+z*s; + v[j][i] = -x*s+z*c; + } + z= pythag(f,h); + q[i-1]= z; + c= f/z; + s= h/z; + f= c*g+s*y; + x= -s*g+c*y; + for (j=0; j < m; j++) + { + y= u[j][i-1]; + z= u[j][i]; + u[j][i-1] = y*c+z*s; + u[j][i] = -y*s+z*c; + } + } + e[l]= 0.0; + e[k]= f; + q[k]= x; + } + } + + //vt= transpose(v) + //return (u,q,vt) + for (i=0;i= 0; j--) + { + if (q[j] < q[i]) + { + // writeln(i,'-',j) + c = q[j]; + q[j] = q[i]; + q[i] = c; + for(k=0;k math.pow === pow_strict_f; + + Object.defineProperty(math, 'pow_strict', { + get: is_pow_strict, + set: set_pow_strict, + }); + + math.pow_strict = true; + + + function set_define_e(bool) { + if(bool) + math.config({define_e: true}); + else + math.config({define_e: false}); + } + var get_define_e = () => math.config().define_e!==false; + function set_define_i(bool) { + if(bool) + math.config({define_i: true}); + else + math.config({define_i: false}); + } + var get_define_i = () => math.config().define_i!==false; + function set_define_pi(bool) { + if(bool) + math.config({define_pi: true}); + else + math.config({define_pi: false}); + } + var get_define_pi = () => math.config().define_pi!==false; + + Object.defineProperty(math, 'define_e', { + get: get_define_e, + set: set_define_e, + }); + Object.defineProperty(math, 'define_i', { + get: get_define_i, + set: set_define_i, + }); + Object.defineProperty(math, 'define_pi', { + get: get_define_pi, + set: set_define_pi, + }); + + return math; + } + + // return a new instance of math.js + var math$19 = create$2(); + + function leaves( tree, include_subscripts ) { + if(!Array.isArray(tree)) + return [tree]; + + var operator = tree[0]; + var operands = tree.slice(1); + + if(include_subscripts && operator === '_') { + if(typeof operands[0] === "string" && + ((typeof operands[1] === "string") || (typeof operands[1] === "number"))) + return [operands[0] + "_"+ operands[1]]; + } + + if(operator === "apply") { + operands = tree.slice(2); + } + if(operands.length === 0) + return []; + + return operands.map( function(v,i) { return leaves(v, include_subscripts); } ) + .reduce( function(a,b) { return a.concat(b); } ); + + } + + function variables( expr_or_tree, include_subscripts = false ) { + + var tree = get_tree(expr_or_tree); + + var result = leaves( tree, include_subscripts ); + + result = result.filter( function(v,i) { + return (typeof v === 'string') && + (math$19.define_e || (v !== "e")) && + (math$19.define_pi || (v !== "pi")) && + (math$19.define_i || (v !== "i")); + }); + + result = result.filter(function(itm,i,a){ + return i === result.indexOf(itm); + }); + + return result; + } + + function operators_list( tree ) { + if (!Array.isArray(tree)) + return []; + + var operator = tree[0]; + var operands = tree.slice(1); + + if(operator === "apply") { + operands = tree.slice(2); + } + if(operands.length === 0) + return [operator]; + + return [operator].concat( + operands.map( function(v,i) { return operators_list(v); } ) + .reduce( function(a,b) { return a.concat(b); } )); + + } + + function operators$1( expr_or_tree ) { + + var tree = get_tree(expr_or_tree); + + var result = operators_list( tree ); + + result = result.filter( function(v,i) { + return (v !== 'apply'); + }); + + result = result.filter(function(itm,i,a){ + return i === result.indexOf(itm); + }); + + return result; + } + + function functions_list( tree ) { + if (typeof tree === 'number') { + return []; + } + + if (typeof tree === 'string') { + return []; + } + + if (typeof tree === 'boolean') { + return []; + } + + var operator = tree[0]; + var operands = tree.slice(1); + + var functions = []; + if(operator === "apply") { + functions = [operands[0]]; + operands = tree.slice(2); + } + + return functions.concat( + operands.map( function(v,i) { return functions_list(v); } ) + .reduce( function(a,b) { return a.concat(b); } )); + + } + + function functions( expr_or_tree ) { + + var tree = get_tree(expr_or_tree); + + var result = functions_list( tree ); + + result = result.filter(function(itm,i,a){ + return i === result.indexOf(itm); + }); + + return result; + } + + var variables$1 = /*#__PURE__*/Object.freeze({ + variables: variables, + operators: operators$1, + functions: functions + }); + + var underscore = createCommonjsModule(function (module, exports) { + // Underscore.js 1.8.3 + // http://underscorejs.org + // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors + // Underscore may be freely distributed under the MIT license. + + (function() { + + // Baseline setup + // -------------- + + // Establish the root object, `window` in the browser, or `exports` on the server. + var root = this; + + // Save the previous value of the `_` variable. + var previousUnderscore = root._; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; + + // Create quick reference variables for speed access to core prototypes. + var + push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + hasOwnProperty = ObjProto.hasOwnProperty; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var + nativeIsArray = Array.isArray, + nativeKeys = Object.keys, + nativeBind = FuncProto.bind, + nativeCreate = Object.create; + + // Naked function reference for surrogate-prototype-swapping. + var Ctor = function(){}; + + // Create a safe reference to the Underscore object for use below. + var _ = function(obj) { + if (obj instanceof _) return obj; + if (!(this instanceof _)) return new _(obj); + this._wrapped = obj; + }; + + // Export the Underscore object for **Node.js**, with + // backwards-compatibility for the old `require()` API. If we're in + // the browser, add `_` as a global object. + { + if ('object' !== 'undefined' && module.exports) { + exports = module.exports = _; + } + exports._ = _; + } + + // Current version. + _.VERSION = '1.8.3'; + + // Internal function that returns an efficient (for current engines) version + // of the passed-in callback, to be repeatedly applied in other Underscore + // functions. + var optimizeCb = function(func, context, argCount) { + if (context === void 0) return func; + switch (argCount == null ? 3 : argCount) { + case 1: return function(value) { + return func.call(context, value); + }; + case 2: return function(value, other) { + return func.call(context, value, other); + }; + case 3: return function(value, index, collection) { + return func.call(context, value, index, collection); + }; + case 4: return function(accumulator, value, index, collection) { + return func.call(context, accumulator, value, index, collection); + }; + } + return function() { + return func.apply(context, arguments); + }; + }; + + // A mostly-internal function to generate callbacks that can be applied + // to each element in a collection, returning the desired result — either + // identity, an arbitrary callback, a property matcher, or a property accessor. + var cb = function(value, context, argCount) { + if (value == null) return _.identity; + if (_.isFunction(value)) return optimizeCb(value, context, argCount); + if (_.isObject(value)) return _.matcher(value); + return _.property(value); + }; + _.iteratee = function(value, context) { + return cb(value, context, Infinity); + }; + + // An internal function for creating assigner functions. + var createAssigner = function(keysFunc, undefinedOnly) { + return function(obj) { + var length = arguments.length; + if (length < 2 || obj == null) return obj; + for (var index = 1; index < length; index++) { + var source = arguments[index], + keys = keysFunc(source), + l = keys.length; + for (var i = 0; i < l; i++) { + var key = keys[i]; + if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; + } + } + return obj; + }; + }; + + // An internal function for creating a new object that inherits from another. + var baseCreate = function(prototype) { + if (!_.isObject(prototype)) return {}; + if (nativeCreate) return nativeCreate(prototype); + Ctor.prototype = prototype; + var result = new Ctor; + Ctor.prototype = null; + return result; + }; + + var property = function(key) { + return function(obj) { + return obj == null ? void 0 : obj[key]; + }; + }; + + // Helper for collection methods to determine whether a collection + // should be iterated as an array or as an object + // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength + // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 + var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; + var getLength = property('length'); + var isArrayLike = function(collection) { + var length = getLength(collection); + return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; + }; + + // Collection Functions + // -------------------- + + // The cornerstone, an `each` implementation, aka `forEach`. + // Handles raw objects in addition to array-likes. Treats all + // sparse array-likes as if they were dense. + _.each = _.forEach = function(obj, iteratee, context) { + iteratee = optimizeCb(iteratee, context); + var i, length; + if (isArrayLike(obj)) { + for (i = 0, length = obj.length; i < length; i++) { + iteratee(obj[i], i, obj); + } + } else { + var keys = _.keys(obj); + for (i = 0, length = keys.length; i < length; i++) { + iteratee(obj[keys[i]], keys[i], obj); + } + } + return obj; + }; + + // Return the results of applying the iteratee to each element. + _.map = _.collect = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + results = Array(length); + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + results[index] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Create a reducing function iterating left or right. + function createReduce(dir) { + // Optimized iterator function as using arguments.length + // in the main function will deoptimize the, see #1991. + function iterator(obj, iteratee, memo, keys, index, length) { + for (; index >= 0 && index < length; index += dir) { + var currentKey = keys ? keys[index] : index; + memo = iteratee(memo, obj[currentKey], currentKey, obj); + } + return memo; + } + + return function(obj, iteratee, memo, context) { + iteratee = optimizeCb(iteratee, context, 4); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length, + index = dir > 0 ? 0 : length - 1; + // Determine the initial value if none is provided. + if (arguments.length < 3) { + memo = obj[keys ? keys[index] : index]; + index += dir; + } + return iterator(obj, iteratee, memo, keys, index, length); + }; + } + + // **Reduce** builds up a single result from a list of values, aka `inject`, + // or `foldl`. + _.reduce = _.foldl = _.inject = createReduce(1); + + // The right-associative version of reduce, also known as `foldr`. + _.reduceRight = _.foldr = createReduce(-1); + + // Return the first value which passes a truth test. Aliased as `detect`. + _.find = _.detect = function(obj, predicate, context) { + var key; + if (isArrayLike(obj)) { + key = _.findIndex(obj, predicate, context); + } else { + key = _.findKey(obj, predicate, context); + } + if (key !== void 0 && key !== -1) return obj[key]; + }; + + // Return all the elements that pass a truth test. + // Aliased as `select`. + _.filter = _.select = function(obj, predicate, context) { + var results = []; + predicate = cb(predicate, context); + _.each(obj, function(value, index, list) { + if (predicate(value, index, list)) results.push(value); + }); + return results; + }; + + // Return all the elements for which a truth test fails. + _.reject = function(obj, predicate, context) { + return _.filter(obj, _.negate(cb(predicate)), context); + }; + + // Determine whether all of the elements match a truth test. + // Aliased as `all`. + _.every = _.all = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (!predicate(obj[currentKey], currentKey, obj)) return false; + } + return true; + }; + + // Determine if at least one element in the object matches a truth test. + // Aliased as `any`. + _.some = _.any = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = !isArrayLike(obj) && _.keys(obj), + length = (keys || obj).length; + for (var index = 0; index < length; index++) { + var currentKey = keys ? keys[index] : index; + if (predicate(obj[currentKey], currentKey, obj)) return true; + } + return false; + }; + + // Determine if the array or object contains a given item (using `===`). + // Aliased as `includes` and `include`. + _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + if (typeof fromIndex != 'number' || guard) fromIndex = 0; + return _.indexOf(obj, item, fromIndex) >= 0; + }; + + // Invoke a method (with arguments) on every item in a collection. + _.invoke = function(obj, method) { + var args = slice.call(arguments, 2); + var isFunc = _.isFunction(method); + return _.map(obj, function(value) { + var func = isFunc ? method : value[method]; + return func == null ? func : func.apply(value, args); + }); + }; + + // Convenience version of a common use case of `map`: fetching a property. + _.pluck = function(obj, key) { + return _.map(obj, _.property(key)); + }; + + // Convenience version of a common use case of `filter`: selecting only objects + // containing specific `key:value` pairs. + _.where = function(obj, attrs) { + return _.filter(obj, _.matcher(attrs)); + }; + + // Convenience version of a common use case of `find`: getting the first object + // containing specific `key:value` pairs. + _.findWhere = function(obj, attrs) { + return _.find(obj, _.matcher(attrs)); + }; + + // Return the maximum element (or element-based computation). + _.max = function(obj, iteratee, context) { + var result = -Infinity, lastComputed = -Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value > result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed > lastComputed || computed === -Infinity && result === -Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Return the minimum element (or element-based computation). + _.min = function(obj, iteratee, context) { + var result = Infinity, lastComputed = Infinity, + value, computed; + if (iteratee == null && obj != null) { + obj = isArrayLike(obj) ? obj : _.values(obj); + for (var i = 0, length = obj.length; i < length; i++) { + value = obj[i]; + if (value < result) { + result = value; + } + } + } else { + iteratee = cb(iteratee, context); + _.each(obj, function(value, index, list) { + computed = iteratee(value, index, list); + if (computed < lastComputed || computed === Infinity && result === Infinity) { + result = value; + lastComputed = computed; + } + }); + } + return result; + }; + + // Shuffle a collection, using the modern version of the + // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). + _.shuffle = function(obj) { + var set = isArrayLike(obj) ? obj : _.values(obj); + var length = set.length; + var shuffled = Array(length); + for (var index = 0, rand; index < length; index++) { + rand = _.random(0, index); + if (rand !== index) shuffled[index] = shuffled[rand]; + shuffled[rand] = set[index]; + } + return shuffled; + }; + + // Sample **n** random values from a collection. + // If **n** is not specified, returns a single random element. + // The internal `guard` argument allows it to work with `map`. + _.sample = function(obj, n, guard) { + if (n == null || guard) { + if (!isArrayLike(obj)) obj = _.values(obj); + return obj[_.random(obj.length - 1)]; + } + return _.shuffle(obj).slice(0, Math.max(0, n)); + }; + + // Sort the object's values by a criterion produced by an iteratee. + _.sortBy = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + return _.pluck(_.map(obj, function(value, index, list) { + return { + value: value, + index: index, + criteria: iteratee(value, index, list) + }; + }).sort(function(left, right) { + var a = left.criteria; + var b = right.criteria; + if (a !== b) { + if (a > b || a === void 0) return 1; + if (a < b || b === void 0) return -1; + } + return left.index - right.index; + }), 'value'); + }; + + // An internal function used for aggregate "group by" operations. + var group = function(behavior) { + return function(obj, iteratee, context) { + var result = {}; + iteratee = cb(iteratee, context); + _.each(obj, function(value, index) { + var key = iteratee(value, index, obj); + behavior(result, value, key); + }); + return result; + }; + }; + + // Groups the object's values by a criterion. Pass either a string attribute + // to group by, or a function that returns the criterion. + _.groupBy = group(function(result, value, key) { + if (_.has(result, key)) result[key].push(value); else result[key] = [value]; + }); + + // Indexes the object's values by a criterion, similar to `groupBy`, but for + // when you know that your index values will be unique. + _.indexBy = group(function(result, value, key) { + result[key] = value; + }); + + // Counts instances of an object that group by a certain criterion. Pass + // either a string attribute to count by, or a function that returns the + // criterion. + _.countBy = group(function(result, value, key) { + if (_.has(result, key)) result[key]++; else result[key] = 1; + }); + + // Safely create a real, live array from anything iterable. + _.toArray = function(obj) { + if (!obj) return []; + if (_.isArray(obj)) return slice.call(obj); + if (isArrayLike(obj)) return _.map(obj, _.identity); + return _.values(obj); + }; + + // Return the number of elements in an object. + _.size = function(obj) { + if (obj == null) return 0; + return isArrayLike(obj) ? obj.length : _.keys(obj).length; + }; + + // Split a collection into two arrays: one whose elements all satisfy the given + // predicate, and one whose elements all do not satisfy the predicate. + _.partition = function(obj, predicate, context) { + predicate = cb(predicate, context); + var pass = [], fail = []; + _.each(obj, function(value, key, obj) { + (predicate(value, key, obj) ? pass : fail).push(value); + }); + return [pass, fail]; + }; + + // Array Functions + // --------------- + + // Get the first element of an array. Passing **n** will return the first N + // values in the array. Aliased as `head` and `take`. The **guard** check + // allows it to work with `_.map`. + _.first = _.head = _.take = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[0]; + return _.initial(array, array.length - n); + }; + + // Returns everything but the last entry of the array. Especially useful on + // the arguments object. Passing **n** will return all the values in + // the array, excluding the last N. + _.initial = function(array, n, guard) { + return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); + }; + + // Get the last element of an array. Passing **n** will return the last N + // values in the array. + _.last = function(array, n, guard) { + if (array == null) return void 0; + if (n == null || guard) return array[array.length - 1]; + return _.rest(array, Math.max(0, array.length - n)); + }; + + // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. + // Especially useful on the arguments object. Passing an **n** will return + // the rest N values in the array. + _.rest = _.tail = _.drop = function(array, n, guard) { + return slice.call(array, n == null || guard ? 1 : n); + }; + + // Trim out all falsy values from an array. + _.compact = function(array) { + return _.filter(array, _.identity); + }; + + // Internal implementation of a recursive `flatten` function. + var flatten = function(input, shallow, strict, startIndex) { + var output = [], idx = 0; + for (var i = startIndex || 0, length = getLength(input); i < length; i++) { + var value = input[i]; + if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { + //flatten current level of array or arguments object + if (!shallow) value = flatten(value, shallow, strict); + var j = 0, len = value.length; + output.length += len; + while (j < len) { + output[idx++] = value[j++]; + } + } else if (!strict) { + output[idx++] = value; + } + } + return output; + }; + + // Flatten out an array, either recursively (by default), or just one level. + _.flatten = function(array, shallow) { + return flatten(array, shallow, false); + }; + + // Return a version of the array that does not contain the specified value(s). + _.without = function(array) { + return _.difference(array, slice.call(arguments, 1)); + }; + + // Produce a duplicate-free version of the array. If the array has already + // been sorted, you have the option of using a faster algorithm. + // Aliased as `unique`. + _.uniq = _.unique = function(array, isSorted, iteratee, context) { + if (!_.isBoolean(isSorted)) { + context = iteratee; + iteratee = isSorted; + isSorted = false; + } + if (iteratee != null) iteratee = cb(iteratee, context); + var result = []; + var seen = []; + for (var i = 0, length = getLength(array); i < length; i++) { + var value = array[i], + computed = iteratee ? iteratee(value, i, array) : value; + if (isSorted) { + if (!i || seen !== computed) result.push(value); + seen = computed; + } else if (iteratee) { + if (!_.contains(seen, computed)) { + seen.push(computed); + result.push(value); + } + } else if (!_.contains(result, value)) { + result.push(value); + } + } + return result; + }; + + // Produce an array that contains the union: each distinct element from all of + // the passed-in arrays. + _.union = function() { + return _.uniq(flatten(arguments, true, true)); + }; + + // Produce an array that contains every item shared between all the + // passed-in arrays. + _.intersection = function(array) { + var result = []; + var argsLength = arguments.length; + for (var i = 0, length = getLength(array); i < length; i++) { + var item = array[i]; + if (_.contains(result, item)) continue; + for (var j = 1; j < argsLength; j++) { + if (!_.contains(arguments[j], item)) break; + } + if (j === argsLength) result.push(item); + } + return result; + }; + + // Take the difference between one array and a number of other arrays. + // Only the elements present in just the first array will remain. + _.difference = function(array) { + var rest = flatten(arguments, true, true, 1); + return _.filter(array, function(value){ + return !_.contains(rest, value); + }); + }; + + // Zip together multiple lists into a single array -- elements that share + // an index go together. + _.zip = function() { + return _.unzip(arguments); + }; + + // Complement of _.zip. Unzip accepts an array of arrays and groups + // each array's elements on shared indices + _.unzip = function(array) { + var length = array && _.max(array, getLength).length || 0; + var result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = _.pluck(array, index); + } + return result; + }; + + // Converts lists into objects. Pass either a single array of `[key, value]` + // pairs, or two parallel arrays of the same length -- one of keys, and one of + // the corresponding values. + _.object = function(list, values) { + var result = {}; + for (var i = 0, length = getLength(list); i < length; i++) { + if (values) { + result[list[i]] = values[i]; + } else { + result[list[i][0]] = list[i][1]; + } + } + return result; + }; + + // Generator function to create the findIndex and findLastIndex functions + function createPredicateIndexFinder(dir) { + return function(array, predicate, context) { + predicate = cb(predicate, context); + var length = getLength(array); + var index = dir > 0 ? 0 : length - 1; + for (; index >= 0 && index < length; index += dir) { + if (predicate(array[index], index, array)) return index; + } + return -1; + }; + } + + // Returns the first index on an array-like that passes a predicate test + _.findIndex = createPredicateIndexFinder(1); + _.findLastIndex = createPredicateIndexFinder(-1); + + // Use a comparator function to figure out the smallest index at which + // an object should be inserted so as to maintain order. Uses binary search. + _.sortedIndex = function(array, obj, iteratee, context) { + iteratee = cb(iteratee, context, 1); + var value = iteratee(obj); + var low = 0, high = getLength(array); + while (low < high) { + var mid = Math.floor((low + high) / 2); + if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; + } + return low; + }; + + // Generator function to create the indexOf and lastIndexOf functions + function createIndexFinder(dir, predicateFind, sortedIndex) { + return function(array, item, idx) { + var i = 0, length = getLength(array); + if (typeof idx == 'number') { + if (dir > 0) { + i = idx >= 0 ? idx : Math.max(idx + length, i); + } else { + length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; + } + } else if (sortedIndex && idx && length) { + idx = sortedIndex(array, item); + return array[idx] === item ? idx : -1; + } + if (item !== item) { + idx = predicateFind(slice.call(array, i, length), _.isNaN); + return idx >= 0 ? idx + i : -1; + } + for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { + if (array[idx] === item) return idx; + } + return -1; + }; + } + + // Return the position of the first occurrence of an item in an array, + // or -1 if the item is not included in the array. + // If the array is large and already in sort order, pass `true` + // for **isSorted** to use binary search. + _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); + _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); + + // Generate an integer Array containing an arithmetic progression. A port of + // the native Python `range()` function. See + // [the Python documentation](http://docs.python.org/library/functions.html#range). + _.range = function(start, stop, step) { + if (stop == null) { + stop = start || 0; + start = 0; + } + step = step || 1; + + var length = Math.max(Math.ceil((stop - start) / step), 0); + var range = Array(length); + + for (var idx = 0; idx < length; idx++, start += step) { + range[idx] = start; + } + + return range; + }; + + // Function (ahem) Functions + // ------------------ + + // Determines whether to execute a function as a constructor + // or a normal function with the provided arguments + var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { + if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); + var self = baseCreate(sourceFunc.prototype); + var result = sourceFunc.apply(self, args); + if (_.isObject(result)) return result; + return self; + }; + + // Create a function bound to a given object (assigning `this`, and arguments, + // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if + // available. + _.bind = function(func, context) { + if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); + if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); + var args = slice.call(arguments, 2); + var bound = function() { + return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); + }; + return bound; + }; + + // Partially apply a function by creating a version that has had some of its + // arguments pre-filled, without changing its dynamic `this` context. _ acts + // as a placeholder, allowing any combination of arguments to be pre-filled. + _.partial = function(func) { + var boundArgs = slice.call(arguments, 1); + var bound = function() { + var position = 0, length = boundArgs.length; + var args = Array(length); + for (var i = 0; i < length; i++) { + args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; + } + while (position < arguments.length) args.push(arguments[position++]); + return executeBound(func, bound, this, this, args); + }; + return bound; + }; + + // Bind a number of an object's methods to that object. Remaining arguments + // are the method names to be bound. Useful for ensuring that all callbacks + // defined on an object belong to it. + _.bindAll = function(obj) { + var i, length = arguments.length, key; + if (length <= 1) throw new Error('bindAll must be passed function names'); + for (i = 1; i < length; i++) { + key = arguments[i]; + obj[key] = _.bind(obj[key], obj); + } + return obj; + }; + + // Memoize an expensive function by storing its results. + _.memoize = function(func, hasher) { + var memoize = function(key) { + var cache = memoize.cache; + var address = '' + (hasher ? hasher.apply(this, arguments) : key); + if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); + return cache[address]; + }; + memoize.cache = {}; + return memoize; + }; + + // Delays a function for the given number of milliseconds, and then calls + // it with the arguments supplied. + _.delay = function(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ + return func.apply(null, args); + }, wait); + }; + + // Defers a function, scheduling it to run after the current call stack has + // cleared. + _.defer = _.partial(_.delay, _, 1); + + // Returns a function, that, when invoked, will only be triggered at most once + // during a given window of time. Normally, the throttled function will run + // as much as it can, without ever going more than once per `wait` duration; + // but if you'd like to disable the execution on the leading edge, pass + // `{leading: false}`. To disable execution on the trailing edge, ditto. + _.throttle = function(func, wait, options) { + var context, args, result; + var timeout = null; + var previous = 0; + if (!options) options = {}; + var later = function() { + previous = options.leading === false ? 0 : _.now(); + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + }; + return function() { + var now = _.now(); + if (!previous && options.leading === false) previous = now; + var remaining = wait - (now - previous); + context = this; + args = arguments; + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout); + timeout = null; + } + previous = now; + result = func.apply(context, args); + if (!timeout) context = args = null; + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining); + } + return result; + }; + }; + + // Returns a function, that, as long as it continues to be invoked, will not + // be triggered. The function will be called after it stops being called for + // N milliseconds. If `immediate` is passed, trigger the function on the + // leading edge, instead of the trailing. + _.debounce = function(func, wait, immediate) { + var timeout, args, context, timestamp, result; + + var later = function() { + var last = _.now() - timestamp; + + if (last < wait && last >= 0) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + if (!immediate) { + result = func.apply(context, args); + if (!timeout) context = args = null; + } + } + }; + + return function() { + context = this; + args = arguments; + timestamp = _.now(); + var callNow = immediate && !timeout; + if (!timeout) timeout = setTimeout(later, wait); + if (callNow) { + result = func.apply(context, args); + context = args = null; + } + + return result; + }; + }; + + // Returns the first function passed as an argument to the second, + // allowing you to adjust arguments, run code before and after, and + // conditionally execute the original function. + _.wrap = function(func, wrapper) { + return _.partial(wrapper, func); + }; + + // Returns a negated version of the passed-in predicate. + _.negate = function(predicate) { + return function() { + return !predicate.apply(this, arguments); + }; + }; + + // Returns a function that is the composition of a list of functions, each + // consuming the return value of the function that follows. + _.compose = function() { + var args = arguments; + var start = args.length - 1; + return function() { + var i = start; + var result = args[start].apply(this, arguments); + while (i--) result = args[i].call(this, result); + return result; + }; + }; + + // Returns a function that will only be executed on and after the Nth call. + _.after = function(times, func) { + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + }; + + // Returns a function that will only be executed up to (but not including) the Nth call. + _.before = function(times, func) { + var memo; + return function() { + if (--times > 0) { + memo = func.apply(this, arguments); + } + if (times <= 1) func = null; + return memo; + }; + }; + + // Returns a function that will be executed at most one time, no matter how + // often you call it. Useful for lazy initialization. + _.once = _.partial(_.before, 2); + + // Object Functions + // ---------------- + + // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. + var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); + var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', + 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + + function collectNonEnumProps(obj, keys) { + var nonEnumIdx = nonEnumerableProps.length; + var constructor = obj.constructor; + var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; + + // Constructor is a special case. + var prop = 'constructor'; + if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); + + while (nonEnumIdx--) { + prop = nonEnumerableProps[nonEnumIdx]; + if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { + keys.push(prop); + } + } + } + + // Retrieve the names of an object's own properties. + // Delegates to **ECMAScript 5**'s native `Object.keys` + _.keys = function(obj) { + if (!_.isObject(obj)) return []; + if (nativeKeys) return nativeKeys(obj); + var keys = []; + for (var key in obj) if (_.has(obj, key)) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve all the property names of an object. + _.allKeys = function(obj) { + if (!_.isObject(obj)) return []; + var keys = []; + for (var key in obj) keys.push(key); + // Ahem, IE < 9. + if (hasEnumBug) collectNonEnumProps(obj, keys); + return keys; + }; + + // Retrieve the values of an object's properties. + _.values = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var values = Array(length); + for (var i = 0; i < length; i++) { + values[i] = obj[keys[i]]; + } + return values; + }; + + // Returns the results of applying the iteratee to each element of the object + // In contrast to _.map it returns an object + _.mapObject = function(obj, iteratee, context) { + iteratee = cb(iteratee, context); + var keys = _.keys(obj), + length = keys.length, + results = {}, + currentKey; + for (var index = 0; index < length; index++) { + currentKey = keys[index]; + results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + } + return results; + }; + + // Convert an object into a list of `[key, value]` pairs. + _.pairs = function(obj) { + var keys = _.keys(obj); + var length = keys.length; + var pairs = Array(length); + for (var i = 0; i < length; i++) { + pairs[i] = [keys[i], obj[keys[i]]]; + } + return pairs; + }; + + // Invert the keys and values of an object. The values must be serializable. + _.invert = function(obj) { + var result = {}; + var keys = _.keys(obj); + for (var i = 0, length = keys.length; i < length; i++) { + result[obj[keys[i]]] = keys[i]; + } + return result; + }; + + // Return a sorted list of the function names available on the object. + // Aliased as `methods` + _.functions = _.methods = function(obj) { + var names = []; + for (var key in obj) { + if (_.isFunction(obj[key])) names.push(key); + } + return names.sort(); + }; + + // Extend a given object with all the properties in passed-in object(s). + _.extend = createAssigner(_.allKeys); + + // Assigns a given object with all the own properties in the passed-in object(s) + // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) + _.extendOwn = _.assign = createAssigner(_.keys); + + // Returns the first key on an object that passes a predicate test + _.findKey = function(obj, predicate, context) { + predicate = cb(predicate, context); + var keys = _.keys(obj), key; + for (var i = 0, length = keys.length; i < length; i++) { + key = keys[i]; + if (predicate(obj[key], key, obj)) return key; + } + }; + + // Return a copy of the object only containing the whitelisted properties. + _.pick = function(object, oiteratee, context) { + var result = {}, obj = object, iteratee, keys; + if (obj == null) return result; + if (_.isFunction(oiteratee)) { + keys = _.allKeys(obj); + iteratee = optimizeCb(oiteratee, context); + } else { + keys = flatten(arguments, false, false, 1); + iteratee = function(value, key, obj) { return key in obj; }; + obj = Object(obj); + } + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i]; + var value = obj[key]; + if (iteratee(value, key, obj)) result[key] = value; + } + return result; + }; + + // Return a copy of the object without the blacklisted properties. + _.omit = function(obj, iteratee, context) { + if (_.isFunction(iteratee)) { + iteratee = _.negate(iteratee); + } else { + var keys = _.map(flatten(arguments, false, false, 1), String); + iteratee = function(value, key) { + return !_.contains(keys, key); + }; + } + return _.pick(obj, iteratee, context); + }; + + // Fill in a given object with default properties. + _.defaults = createAssigner(_.allKeys, true); + + // Creates an object that inherits from the given prototype object. + // If additional properties are provided then they will be added to the + // created object. + _.create = function(prototype, props) { + var result = baseCreate(prototype); + if (props) _.extendOwn(result, props); + return result; + }; + + // Create a (shallow-cloned) duplicate of an object. + _.clone = function(obj) { + if (!_.isObject(obj)) return obj; + return _.isArray(obj) ? obj.slice() : _.extend({}, obj); + }; + + // Invokes interceptor with the obj, and then returns obj. + // The primary purpose of this method is to "tap into" a method chain, in + // order to perform operations on intermediate results within the chain. + _.tap = function(obj, interceptor) { + interceptor(obj); + return obj; + }; + + // Returns whether an object has a given set of `key:value` pairs. + _.isMatch = function(object, attrs) { + var keys = _.keys(attrs), length = keys.length; + if (object == null) return !length; + var obj = Object(object); + for (var i = 0; i < length; i++) { + var key = keys[i]; + if (attrs[key] !== obj[key] || !(key in obj)) return false; + } + return true; + }; + + + // Internal recursive comparison function for `isEqual`. + var eq = function(a, b, aStack, bStack) { + // Identical objects are equal. `0 === -0`, but they aren't identical. + // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). + if (a === b) return a !== 0 || 1 / a === 1 / b; + // A strict comparison is necessary because `null == undefined`. + if (a == null || b == null) return a === b; + // Unwrap any wrapped objects. + if (a instanceof _) a = a._wrapped; + if (b instanceof _) b = b._wrapped; + // Compare `[[Class]]` names. + var className = toString.call(a); + if (className !== toString.call(b)) return false; + switch (className) { + // Strings, numbers, regular expressions, dates, and booleans are compared by value. + case '[object RegExp]': + // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') + case '[object String]': + // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")`. + return '' + a === '' + b; + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive. + // Object(NaN) is equivalent to NaN + if (+a !== +a) return +b !== +b; + // An `egal` comparison is performed for other numeric values. + return +a === 0 ? 1 / +a === 1 / b : +a === +b; + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. Dates are compared by their + // millisecond representations. Note that invalid dates with millisecond representations + // of `NaN` are not equivalent. + return +a === +b; + } + + var areArrays = className === '[object Array]'; + if (!areArrays) { + if (typeof a != 'object' || typeof b != 'object') return false; + + // Objects with different constructors are not equivalent, but `Object`s or `Array`s + // from different frames are. + var aCtor = a.constructor, bCtor = b.constructor; + if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && + _.isFunction(bCtor) && bCtor instanceof bCtor) + && ('constructor' in a && 'constructor' in b)) { + return false; + } + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + + // Initializing stack of traversed objects. + // It's done here since we only need them for objects and arrays comparison. + aStack = aStack || []; + bStack = bStack || []; + var length = aStack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (aStack[length] === a) return bStack[length] === b; + } + + // Add the first object to the stack of traversed objects. + aStack.push(a); + bStack.push(b); + + // Recursively compare objects and arrays. + if (areArrays) { + // Compare array lengths to determine if a deep comparison is necessary. + length = a.length; + if (length !== b.length) return false; + // Deep compare the contents, ignoring non-numeric properties. + while (length--) { + if (!eq(a[length], b[length], aStack, bStack)) return false; + } + } else { + // Deep compare objects. + var keys = _.keys(a), key; + length = keys.length; + // Ensure that both objects contain the same number of properties before comparing deep equality. + if (_.keys(b).length !== length) return false; + while (length--) { + // Deep compare each member + key = keys[length]; + if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; + } + } + // Remove the first object from the stack of traversed objects. + aStack.pop(); + bStack.pop(); + return true; + }; + + // Perform a deep comparison to check if two objects are equal. + _.isEqual = function(a, b) { + return eq(a, b); + }; + + // Is a given array, string, or object empty? + // An "empty" object has no enumerable own-properties. + _.isEmpty = function(obj) { + if (obj == null) return true; + if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; + return _.keys(obj).length === 0; + }; + + // Is a given value a DOM element? + _.isElement = function(obj) { + return !!(obj && obj.nodeType === 1); + }; + + // Is a given value an array? + // Delegates to ECMA5's native Array.isArray + _.isArray = nativeIsArray || function(obj) { + return toString.call(obj) === '[object Array]'; + }; + + // Is a given variable an object? + _.isObject = function(obj) { + var type = typeof obj; + return type === 'function' || type === 'object' && !!obj; + }; + + // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. + _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { + _['is' + name] = function(obj) { + return toString.call(obj) === '[object ' + name + ']'; + }; + }); + + // Define a fallback version of the method in browsers (ahem, IE < 9), where + // there isn't any inspectable "Arguments" type. + if (!_.isArguments(arguments)) { + _.isArguments = function(obj) { + return _.has(obj, 'callee'); + }; + } + + // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, + // IE 11 (#1621), and in Safari 8 (#1929). + if (typeof /./ != 'function' && typeof Int8Array != 'object') { + _.isFunction = function(obj) { + return typeof obj == 'function' || false; + }; + } + + // Is a given object a finite number? + _.isFinite = function(obj) { + return isFinite(obj) && !isNaN(parseFloat(obj)); + }; + + // Is the given value `NaN`? (NaN is the only number which does not equal itself). + _.isNaN = function(obj) { + return _.isNumber(obj) && obj !== +obj; + }; + + // Is a given value a boolean? + _.isBoolean = function(obj) { + return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; + }; + + // Is a given value equal to null? + _.isNull = function(obj) { + return obj === null; + }; + + // Is a given variable undefined? + _.isUndefined = function(obj) { + return obj === void 0; + }; + + // Shortcut function for checking if an object has a given property directly + // on itself (in other words, not on a prototype). + _.has = function(obj, key) { + return obj != null && hasOwnProperty.call(obj, key); + }; + + // Utility Functions + // ----------------- + + // Run Underscore.js in *noConflict* mode, returning the `_` variable to its + // previous owner. Returns a reference to the Underscore object. + _.noConflict = function() { + root._ = previousUnderscore; + return this; + }; + + // Keep the identity function around for default iteratees. + _.identity = function(value) { + return value; + }; + + // Predicate-generating functions. Often useful outside of Underscore. + _.constant = function(value) { + return function() { + return value; + }; + }; + + _.noop = function(){}; + + _.property = property; + + // Generates a function for a given object that returns a given property. + _.propertyOf = function(obj) { + return obj == null ? function(){} : function(key) { + return obj[key]; + }; + }; + + // Returns a predicate for checking whether an object has a given set of + // `key:value` pairs. + _.matcher = _.matches = function(attrs) { + attrs = _.extendOwn({}, attrs); + return function(obj) { + return _.isMatch(obj, attrs); + }; + }; + + // Run a function **n** times. + _.times = function(n, iteratee, context) { + var accum = Array(Math.max(0, n)); + iteratee = optimizeCb(iteratee, context, 1); + for (var i = 0; i < n; i++) accum[i] = iteratee(i); + return accum; + }; + + // Return a random integer between min and max (inclusive). + _.random = function(min, max) { + if (max == null) { + max = min; + min = 0; + } + return min + Math.floor(Math.random() * (max - min + 1)); + }; + + // A (possibly faster) way to get the current timestamp as an integer. + _.now = Date.now || function() { + return new Date().getTime(); + }; + + // List of HTML entities for escaping. + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + var unescapeMap = _.invert(escapeMap); + + // Functions for escaping and unescaping strings to/from HTML interpolation. + var createEscaper = function(map) { + var escaper = function(match) { + return map[match]; + }; + // Regexes for identifying a key that needs to be escaped + var source = '(?:' + _.keys(map).join('|') + ')'; + var testRegexp = RegExp(source); + var replaceRegexp = RegExp(source, 'g'); + return function(string) { + string = string == null ? '' : '' + string; + return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; + }; + }; + _.escape = createEscaper(escapeMap); + _.unescape = createEscaper(unescapeMap); + + // If the value of the named `property` is a function then invoke it with the + // `object` as context; otherwise, return it. + _.result = function(object, property, fallback) { + var value = object == null ? void 0 : object[property]; + if (value === void 0) { + value = fallback; + } + return _.isFunction(value) ? value.call(object) : value; + }; + + // Generate a unique integer id (unique within the entire client session). + // Useful for temporary DOM ids. + var idCounter = 0; + _.uniqueId = function(prefix) { + var id = ++idCounter + ''; + return prefix ? prefix + id : id; + }; + + // By default, Underscore uses ERB-style template delimiters, change the + // following template settings to use alternative delimiters. + _.templateSettings = { + evaluate : /<%([\s\S]+?)%>/g, + interpolate : /<%=([\s\S]+?)%>/g, + escape : /<%-([\s\S]+?)%>/g + }; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /(.)^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + "'": "'", + '\\': '\\', + '\r': 'r', + '\n': 'n', + '\u2028': 'u2028', + '\u2029': 'u2029' + }; + + var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + + var escapeChar = function(match) { + return '\\' + escapes[match]; + }; + + // JavaScript micro-templating, similar to John Resig's implementation. + // Underscore templating handles arbitrary delimiters, preserves whitespace, + // and correctly escapes quotes within interpolated code. + // NB: `oldSettings` only exists for backwards compatibility. + _.template = function(text, settings, oldSettings) { + if (!settings && oldSettings) settings = oldSettings; + settings = _.defaults({}, settings, _.templateSettings); + + // Combine delimiters into one regular expression via alternation. + var matcher = RegExp([ + (settings.escape || noMatch).source, + (settings.interpolate || noMatch).source, + (settings.evaluate || noMatch).source + ].join('|') + '|$', 'g'); + + // Compile the template source, escaping string literals appropriately. + var index = 0; + var source = "__p+='"; + text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { + source += text.slice(index, offset).replace(escaper, escapeChar); + index = offset + match.length; + + if (escape) { + source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; + } else if (interpolate) { + source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; + } else if (evaluate) { + source += "';\n" + evaluate + "\n__p+='"; + } + + // Adobe VMs need the match returned to produce the correct offest. + return match; + }); + source += "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; + + source = "var __t,__p='',__j=Array.prototype.join," + + "print=function(){__p+=__j.call(arguments,'');};\n" + + source + 'return __p;\n'; + + try { + var render = new Function(settings.variable || 'obj', '_', source); + } catch (e) { + e.source = source; + throw e; + } + + var template = function(data) { + return render.call(this, data, _); + }; + + // Provide the compiled source as a convenience for precompilation. + var argument = settings.variable || 'obj'; + template.source = 'function(' + argument + '){\n' + source + '}'; + + return template; + }; + + // Add a "chain" function. Start chaining a wrapped Underscore object. + _.chain = function(obj) { + var instance = _(obj); + instance._chain = true; + return instance; + }; + + // OOP + // --------------- + // If Underscore is called as a function, it returns a wrapped object that + // can be used OO-style. This wrapper holds altered versions of all the + // underscore functions. Wrapped objects may be chained. + + // Helper function to continue chaining intermediate results. + var result = function(instance, obj) { + return instance._chain ? _(obj).chain() : obj; + }; + + // Add your own custom functions to the Underscore object. + _.mixin = function(obj) { + _.each(_.functions(obj), function(name) { + var func = _[name] = obj[name]; + _.prototype[name] = function() { + var args = [this._wrapped]; + push.apply(args, arguments); + return result(this, func.apply(_, args)); + }; + }); + }; + + // Add all of the Underscore functions to the wrapper object. + _.mixin(_); + + // Add all mutator Array functions to the wrapper. + _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + var obj = this._wrapped; + method.apply(obj, arguments); + if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; + return result(this, obj); + }; + }); + + // Add all accessor Array functions to the wrapper. + _.each(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + _.prototype[name] = function() { + return result(this, method.apply(this._wrapped, arguments)); + }; + }); + + // Extracts the result from a wrapped and chained object. + _.prototype.value = function() { + return this._wrapped; + }; + + // Provide unwrapping proxy for some methods used in engine operations + // such as arithmetic and JSON stringification. + _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; + + _.prototype.toString = function() { + return '' + this._wrapped; + }; + + // AMD registration happens at the end for compatibility with AMD loaders + // that may not enforce next-turn semantics on modules. Even though general + // practice for AMD registration is to be anonymous, underscore registers + // as a named module because, like jQuery, it is a base library that is + // popular enough to be bundled in a third party lib, but not be part of + // an AMD load request. Those cases could generate an error when an + // anonymous define() is called outside of a loader request. + if (typeof undefined === 'function' && undefined.amd) { + undefined('underscore', [], function() { + return _; + }); + } + }.call(commonjsGlobal)); + }); + var underscore_1 = underscore._; + + function handleNaNInfinityStringify(key, value) { + if (value !== value) { + return '0/0'; + } + + if (value === 1/0) { + return '1/0'; + } + + if (value === -1/0) { + return '-1/0'; + } + + return value; + } + + function handleNaNInfinityParse(key, value) { + if (value === '0/0') { + return 0/0; + } + + if (value === '1/0') { + return Infinity; + } + + if (value === '-1/0') { + return -1/0; + } + + return value; + } + + function deepClone(s) { + return JSON.parse( + JSON.stringify(s, handleNaNInfinityStringify), + handleNaNInfinityParse); + } + + const equal$2 = function(left, right, { + allowed_error_in_numbers = 0, + include_error_in_number_exponents = false, + allowed_error_is_absolute = false, + }={}) { + /* + * Return true if left and right are syntactically equal. + * + */ + + if(!(Array.isArray(left) && Array.isArray(right))) { + if((typeof left) !== (typeof right)) + return false; + + if(typeof left === "number" && Number.isFinite(left)) { + let tol = 1E-14; + let minAbs = Math.min(Math.abs(left),Math.abs(right)); + if(allowed_error_is_absolute) { + tol *= minAbs; + if(allowed_error_in_numbers > tol) { + tol = allowed_error_in_numbers; + } + }else { + if(allowed_error_in_numbers > tol) { + tol = allowed_error_in_numbers; + } + tol *= minAbs; + } + return Math.abs(left-right) <= tol; + } + + return (left===right); + } + + var leftOperator = left[0]; + var leftOperands = left.slice(1); + + var rightOperator = right[0]; + var rightOperands = right.slice(1); + + if (leftOperator !== rightOperator) + return false; + + if (leftOperands.length !== rightOperands.length) + return false; + + if(allowed_error_in_numbers > 0 && !include_error_in_number_exponents && leftOperator === "^") { + let baseEqual = equal$2(leftOperands[0], rightOperands[0], { + allowed_error_in_numbers: allowed_error_in_numbers, + include_error_in_number_exponents: include_error_in_number_exponents, + allowed_error_is_absolute: allowed_error_is_absolute, + }); + + if(!baseEqual) { + return false; + } + let exponentEqual = equal$2(leftOperands[1], rightOperands[1]); + return exponentEqual; + } + + return underscore.every( underscore.zip( leftOperands, rightOperands ), + function(pair) { + return equal$2(pair[0], pair[1], { + allowed_error_in_numbers: allowed_error_in_numbers, + include_error_in_number_exponents: include_error_in_number_exponents, + allowed_error_is_absolute: allowed_error_is_absolute, + }); + }); + }; + + const match = function( tree, pattern, params) { + + /* + * Attempt to match the entire tree to given pattern + * + * Returns + * - object describing the bindings of pattern if the entire tree + * was matched with those bindings + * - false if a match was not found + * + * + * In a pattern: + * - operators much match exactly + * - strings that are designed as variables + * must be bound to a subtree + * - numbers and other strings much exactly match + * + * variables, if defined, specifies which strings in pattern are + * wildcards that can be matched to any subtree + * If defined, variables must be an object with + * key: string from pattern which is a wildcard + * values: must be one of the following + * - true: any subtree matches the wildcard + * - a regular expression: subtree must match regular expression + * (a non-string subtree is first passed to JSON.stringify) + * - a function: takes a tree as an argument and + * returns whether or not that tree is a valid match + * + * If variables is not defined, then all variables from pattern + * will be wildcards that match any subtree + * + * If defined, params is an object with keys + * - allow_permutations: if true, check all permutations of operators + * - allow_implicit_identities: an array of variables from pattern + * that can implicitly match the identity of their enclosing + * operator + * - allow_extended_match: if true, then some tree operands can be skipped + * otherwise, all tree operands must be matched + + */ + + var allow_extended_match=false; + + if(params === undefined) + params = {}; + else { + // don't let extended match parameter propagate + if(params.allow_extended_match) { + allow_extended_match=true; + // copy params to new object + params = Object.assign({}, params); + delete params["allow_extended_match"]; + } + + } + + var variables$$1 = params["variables"]; + if(variables$$1 === undefined) { + variables$$1 = {}; + let vip = variables(pattern); + for(let i=0; i < vip.length;i++ ) { + variables$$1[vip[i]] = true; + } + + // add to params, after copying to new object + params = Object.assign({}, params); + params["variables"] = variables$$1; + } + + if(pattern in variables$$1) { + // check if tree satisfies any conditions for pattern + let condition = variables$$1[pattern]; + if(condition !== true) { + if(condition instanceof RegExp) { + if(typeof tree === 'string') { + if(!tree.match(condition)) + return false; + } + else { + if(!JSON.stringify(tree).match(condition)) + return false; + } + } + else if(typeof variables$$1[pattern] === 'function') { + if(!variables$$1[pattern](tree)) + return false; + } + else { + return false; + } + } + + // record the whole tree as the match to pattern + let result = {}; + result[pattern] = tree; + return result; + } + + if(params.allow_permutations) { + // even though order doesn't matter with permutations + // normalize to default order as it orients operators + // such as inequalities and containments to a direction + // that won't be affected by permutations + tree = default_order(tree); + pattern = default_order(pattern); + } + + // if pattern isn't an array, the tree must be the pattern to match + // (As there are no variables, there is no binding) + if(!Array.isArray(pattern)) { + if (tree === pattern) + return {}; + else + return false; + } + + var treeOperands = allChildren(tree); + var operator=pattern[0]; + var patternOperands = pattern.slice(1); + + // Since pattern is an array, there is no match if tree isn't an array + // of the same or larger length with the same operator + // (unless some pattern variables can be implicitly set to identities) + if (!Array.isArray(tree) || (tree[0] !== operator) + || (treeOperands.length < patternOperands.length)) { + + if(Array.isArray(params.allow_implicit_identities)) { + + let result = matchImplicitIdentity(tree, pattern, params); + if(result) + return result; + } + + // if pattern is a multiplication and + // tree is a unary minus of a multiplication + // convert tree to a muliplication with unary minus on first factor + if(operator === '*' && Array.isArray(tree) && tree[0] === '-' + && Array.isArray(tree[1]) && tree[1][0] === '*') { + treeOperands = allChildren(tree[1]); + treeOperands[0] = ['-', treeOperands[0]]; + } + else + return false; + } + + let result = matchOperands(operator, treeOperands, patternOperands, + params, allow_extended_match); + + if(result) + return result; + + + if(Array.isArray(params.allow_implicit_identities)) + return matchImplicitIdentity([operator].concat(treeOperands), + pattern, params); + else + return false; + }; + + + + function matchOperands(operator, treeOperands, patternOperands, params, + allow_extended_match) { + + // treeOperands will match patternOperands only if + // - each pattern operand can be matched by a tree operand + // (or a group of tree operands) + // - if allow_extended_match, then some tree operands can be skipped + // otherwise, all tree operands must be matched + // - if permutations are allowed (calculated from params and operator) + // patterns can be matched in any order + // otherwise, patterns must be matched in order, possibly skipping + // beginning or ending tree operands (if allow_extended_match) + // - all the resulting bindings are consistent, + // meaning they assigned the same match to any + // repeated placeholder in pattern + + var previous_matches = patternOperands.map(v => Object()); + var nPars = patternOperands.length; + + // TODO: check if commutative + var allow_permutations = false; + if(params.allow_permutations && + (operator === "*" || operator === "+" || operator === "=" + || operator === "and" || operator === "or" || operator === "ne" + || operator === "union" || operator === "intersect")) + allow_permutations=true; + + + function matchOps(treeOpIndicesLeft, patternInd, matches) { + + // max group is the maximum number of tree operands that can be matched by a variable + let max_group = 1; + let max_last_group = 1; + + // only allow multiple matches by variables for associative operators + if(is_associative[operator]) { + max_group = treeOpIndicesLeft.length - (nPars-patternInd-1); + max_last_group = treeOpIndicesLeft.length; } + + if(params.max_group !== undefined) + max_group = (params.max_group < max_group) ? params.max_group + : max_group; + if(params.max_last_group !== undefined) + max_last_group = (params.max_last_group < max_last_group) ? params.max_last_group + : max_last_group; + + + let inds_set; + + if(!allow_extended_match && patternInd === nPars-1) { + // if no extended match, then the last pattern operand + // must match the remaining tree operands + if(treeOpIndicesLeft.length <= max_last_group) { + inds_set = [treeOpIndicesLeft]; + } + else { + return false; + } + } + else if(allow_permutations) { + inds_set = subsets(treeOpIndicesLeft, max_group); + } + else { + inds_set = []; + for(let i=1; i <= max_group; i++) + inds_set.push(treeOpIndicesLeft.slice(0, i)); + + } + + for(let inds of inds_set) { + + let m = previous_matches[patternInd][inds]; + + if(m === undefined) { + + let treeChunk = inds.reduce(function(a,b) { + return a.concat([treeOperands[b]]);}, []); + + if(treeChunk.length > 1) + treeChunk= [operator].concat(treeChunk); + else + treeChunk = treeChunk[0]; + + m = match(treeChunk, patternOperands[patternInd], params); + + previous_matches[patternInd][inds] = m; + + } + + if(!m) + continue; + + // Check consistency of bindings + if (!underscore.every( underscore.intersection( + Object.keys( matches ), + Object.keys( m ) ), + function(k) { + return equal$2(matches[k], m[k]); + })) { + continue; + } + + // combine matches + let combined_matches = Object.assign({}, m); + Object.assign( combined_matches, matches ); + + let treeOpIndices = treeOpIndicesLeft.filter( + v => !inds.includes(v)); + + // if last pattern operand, we're done + if(patternInd === nPars-1) { + let skipped = treeOpIndices.reduce(function(a,b) { + return a.concat([treeOperands[b]]);}, []); + + return {matches: combined_matches, skipped: skipped}; + } + + // attempt to match remaining treeOps + // with remaining pattern operands + let results = matchOps(treeOpIndices, patternInd+1, + combined_matches); + + if(results) { + return results; + } + } + + return false; + } + + var matches = {}; + + // create array of 0, 1, ...., treeOperands.length-1 + var treeIndices = [...Array(treeOperands.length).keys()]; + + if(allow_permutations) { + + let m = matchOps(treeIndices, 0, {}); + + if(!m) + return false; + + matches = m.matches; + if(m.skipped.length > 0) + matches['_skipped'] = m.skipped; + + return matches; + } + else { + let maxSkip = allow_extended_match ? treeOperands.length - nPars : 0; + let skipped_before = []; + let m; + + // without permutations, operands can only be skipped + // at beggining or end + // (matchOps will skip at end but not at beginning + // when permutations are not allowed) + for(let initialSkip=0; initialSkip <= maxSkip; initialSkip++ ) { + + m = matchOps(treeIndices, 0, {}); + + if(m) + break; + + treeIndices = treeIndices.slice(1); + skipped_before.push(treeOperands[initialSkip]); + } + + if(!m) + return false; + + matches = m.matches; + if(m.skipped.length > 0) + matches['_skipped'] = m.skipped; + if(skipped_before.length > 0) + matches['_skipped_before'] = skipped_before; + return matches; + + } + } + + function matchImplicitIdentity(tree, pattern, params) { + + var operator = pattern[0]; + var patternOperands = pattern.slice(1); + + // for now, implement implicit identities just + // for addition, multiplication, and exponents + if(!(operator === '+' || operator === '*' || operator === '^')) + return false; + + // find any pattern operand that is allowed to be an implicit identity + var implicit_identity = null; + for(let i=0; i < patternOperands.length; i++) { + let po = patternOperands[i]; + if(typeof po === 'string' && + params.allow_implicit_identities.includes(po)) { + implicit_identity = po; + break; + } + } + + if(implicit_identity === null) + return false; + + var matches = {}; + + // match implicit_identity to the identity of the operator + if(operator === '+') + matches[implicit_identity] = 0; + else + matches[implicit_identity] = 1; + + // special case where tree beings with unary - + // and pattern is a multiplication where implicit identity is a factor + if(operator === '*' && patternOperands.includes(implicit_identity) + && Array.isArray(tree) && tree[0] === '-') { + matches[implicit_identity] = -1; + tree = tree[1]; + } + + // remove matched variable from pattern + var matched_ind = patternOperands.indexOf(implicit_identity); + patternOperands.splice(matched_ind,1); + + // for exponentiation, only allow for identity in exponent + if(operator === '^' && matched_ind === 0) + return false; + + if(patternOperands.length === 1) { + pattern = patternOperands[0]; + } + else { + pattern = [operator].concat(patternOperands); + } + + var m = match(tree, pattern, params); + + if (m) { + // Check consistency of bindings + if(implicit_identity in m) { + if(!equal$2(m[implicit_identity], matches[implicit_identity])) + return false; + } + Object.assign( matches, m); + } else + return false; + + return matches; + } + + + const substitute = function( pattern, bindings ) { + if (typeof pattern === 'number' || typeof pattern === "boolean") { + return pattern; + } + + if (typeof pattern === 'string') { + if (bindings[pattern] !== undefined) + return deepClone(bindings[pattern]); + + return pattern; + } + + if (Array.isArray(pattern)) { + return [pattern[0]].concat( pattern.slice(1).map( function(p) { + return substitute(p, bindings); + }) ); + } + + return []; + }; + + const transform$2 = function( tree, F ) { + /* + * Transform the tree function F in a bottom-up fashion + * (calling F at children before parents) + * + * F must be be a function that returns a tree + */ + + if (Array.isArray(tree)) { + let new_tree = [tree[0]]; + for( let i=1; i 0; depth-- ) { + old_tree = new_tree; + for(let i=0; i 0 || add_right.length > 0) { + if(Array.isArray(result)) { + if(result[0]===pattern[0]) { + result = result.slice(1); + } + else { + result = [result]; + } + } + result=[pattern[0]].concat( + add_left, result, add_right); + } + + if(params.evaluate_numbers) + result = evaluate_numbers( + result, {max_digits: params.max_digits}); + + return result; + } + else { + return subtree; + } + }); + + } + + if(equal$2(old_tree, new_tree)) { + return new_tree; + } + } + + return new_tree; + }; + + var endsWith = string.endsWith; + var clone$11 = object.clone; + + + function factory$278 (type, config, load, typed, math) { + var add = load(addScalar); + var subtract = load(subtract$1); + var multiply = load(multiplyScalar); + var divide = load(divideScalar); + var pow = load(pow$1); + var abs = load(abs$1); + var fix = load(fix$1); + var round = load(round$1); + var equal = load(equal$1); + var isNumeric = load(isNumeric$1); + var format = load(format$8); + var getTypeOf = load(_typeof$1); + var toNumber = load(number$3); + var Complex = load(Complex_1); + + /** + * A unit can be constructed in the following ways: + * var a = new Unit(value, name); + * var b = new Unit(null, name); + * var c = Unit.parse(str); + * + * Example usage: + * var a = new Unit(5, 'cm'); // 50 mm + * var b = Unit.parse('23 kg'); // 23 kg + * var c = math.in(a, new Unit(null, 'm'); // 0.05 m + * var d = new Unit(9.81, "m/s^2"); // 9.81 m/s^2 + * + * @class Unit + * @constructor Unit + * @param {number | BigNumber | Fraction | Complex | boolean} [value] A value like 5.2 + * @param {string} [name] A unit name like "cm" or "inch", or a derived unit of the form: "u1[^ex1] [u2[^ex2] ...] [/ u3[^ex3] [u4[^ex4]]]", such as "kg m^2/s^2", where each unit appearing after the forward slash is taken to be in the denominator. "kg m^2 s^-2" is a synonym and is also acceptable. Any of the units can include a prefix. + */ + function Unit(value, name) { + if (!(this instanceof Unit)) { + throw new Error('Constructor must be called with the new operator'); + } + + if (!(value == undefined || isNumeric(value) || type.isComplex(value))) { + throw new TypeError('First parameter in Unit constructor must be number, BigNumber, Fraction, Complex, or undefined'); + } + if (name != undefined && (typeof name !== 'string' || name === '')) { + throw new TypeError('Second parameter in Unit constructor must be a string'); + } + + if (name != undefined) { + var u = Unit.parse(name); + this.units = u.units; + this.dimensions = u.dimensions; + } + else { + this.units = [ + { + unit: UNIT_NONE, + prefix: PREFIXES.NONE, // link to a list with supported prefixes + power: 0 + } + ]; + this.dimensions = []; + for(var i=0; i= '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') { + // The grammar branches here. This could either be part of an exponent or the start of a unit that begins with the letter e, such as "4exabytes" + + var tentativeNumber = ''; + var tentativeIndex = index; + + tentativeNumber += c; + next(); + + if (c == '+' || c == '-') { + tentativeNumber += c; + next(); + } + + // Scientific notation MUST be followed by an exponent (otherwise we assume it is not scientific notation) + if (!isDigit(c)) { + // The e or E must belong to something else, so return the number without the e or E. + revert(tentativeIndex); + return number; + } + + // We can now safely say that this is scientific notation. + number = number + tentativeNumber; + while (isDigit(c)) { + number += c; + next(); + } + } + + return number; + } + + function parseUnit() { + var unitName = ''; + + // Alphanumeric characters only; matches [a-zA-Z0-9] + var code = text.charCodeAt(index); + while ( (code >= 48 && code <= 57) || + (code >= 65 && code <= 90) || + (code >= 97 && code <= 122)) { + unitName += c; + next(); + code = text.charCodeAt(index); + } + + // Must begin with [a-zA-Z] + code = unitName.charCodeAt(0); + if ((code >= 65 && code <= 90) || + (code >= 97 && code <= 122)) { + return unitName || null; + } + else { + return null; + } + } + + function parseCharacter(toFind) { + if (c === toFind) { + next(); + return toFind; + } + else { + return null; + } + } + + /** + * Parse a string into a unit. The value of the unit is parsed as number, + * BigNumber, or Fraction depending on the math.js config setting `number`. + * + * Throws an exception if the provided string does not contain a valid unit or + * cannot be parsed. + * @memberof Unit + * @param {string} str A string like "5.2 inch", "4e2 cm/s^2" + * @return {Unit} unit + */ + Unit.parse = function (str, options) { + options = options || {}; + text = str; + index = -1; + c = ''; + + if (typeof text !== 'string') { + throw new TypeError('Invalid argument in Unit.parse, string expected'); + } + + var unit = new Unit(); + unit.units = []; + + var powerMultiplierCurrent = 1; + var expectingUnit = false; + + // A unit should follow this pattern: + // [number] ...[ [*/] unit[^number] ] + // unit[^number] ... [ [*/] unit[^number] ] + + // Rules: + // number is any floating point number. + // unit is any alphanumeric string beginning with an alpha. Units with names like e3 should be avoided because they look like the exponent of a floating point number! + // The string may optionally begin with a number. + // Each unit may optionally be followed by ^number. + // Whitespace or a forward slash is recommended between consecutive units, although the following technically is parseable: + // 2m^2kg/s^2 + // it is not good form. If a unit starts with e, then it could be confused as a floating point number: + // 4erg + + next(); + skipWhitespace(); + + // Optional number at the start of the string + var valueStr = parseNumber(); + var value = null; + if(valueStr) { + if (config.number === 'BigNumber') { + value = new type.BigNumber(valueStr); + } + else if (config.number === 'Fraction') { + value = new type.Fraction(valueStr); + } + else { // number + value = parseFloat(valueStr); + } + + skipWhitespace(); // Whitespace is not required here + + // handle multiplication or division right after the value, like '1/s' + if (parseCharacter('*')) { + powerMultiplierCurrent = 1; + expectingUnit = true; + } + else if (parseCharacter('/')) { + powerMultiplierCurrent = -1; + expectingUnit = true; + } + } + + // Stack to keep track of powerMultipliers applied to each parentheses group + var powerMultiplierStack = []; + + // Running product of all elements in powerMultiplierStack + var powerMultiplierStackProduct = 1; + + while (true) { + skipWhitespace(); + + // Check for and consume opening parentheses, pushing powerMultiplierCurrent to the stack + // A '(' will always appear directly before a unit. + while (c === '(') { + powerMultiplierStack.push(powerMultiplierCurrent); + powerMultiplierStackProduct *= powerMultiplierCurrent; + powerMultiplierCurrent = 1; + next(); + skipWhitespace(); + } + + // Is there something here? + if(c) { + var oldC = c; + var uStr = parseUnit(); + if(uStr == null) { + throw new SyntaxError('Unexpected "' + oldC + '" in "' + text + '" at index ' + index.toString()); + } + } + else { + // End of input. + break; + } + + // Verify the unit exists and get the prefix (if any) + var res = _findUnit(uStr); + if(res == null) { + // Unit not found. + throw new SyntaxError('Unit "' + uStr + '" not found.'); + } + + var power = powerMultiplierCurrent * powerMultiplierStackProduct; + // Is there a "^ number"? + skipWhitespace(); + if (parseCharacter('^')) { + skipWhitespace(); + var p = parseNumber(); + if(p == null) { + // No valid number found for the power! + throw new SyntaxError('In "' + str + '", "^" must be followed by a floating-point number'); + } + power *= p; + } + + // Add the unit to the list + unit.units.push( { + unit: res.unit, + prefix: res.prefix, + power: power + }); + for(var i=0; i 1 || Math.abs(this.units[0].power - 1.0) > 1e-15; + }; + + /** + * Normalize a value, based on its currently set unit(s) + * @memberof Unit + * @param {number | BigNumber | Fraction | boolean} value + * @return {number | BigNumber | Fraction | boolean} normalized value + * @private + */ + Unit.prototype._normalize = function (value) { + var unitValue, unitOffset, unitPower, unitPrefixValue; + var convert; + + if (value == null || this.units.length === 0) { + return value; + } + else if (this._isDerived()) { + // This is a derived unit, so do not apply offsets. + // For example, with J kg^-1 degC^-1 you would NOT want to apply the offset. + var res = value; + convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed + + for(var i=0; i < this.units.length; i++) { + unitValue = convert(this.units[i].unit.value); + unitPrefixValue = convert(this.units[i].prefix.value); + unitPower = convert(this.units[i].power); + res = multiply(res, pow(multiply(unitValue, unitPrefixValue), unitPower)); + } + + return res; + } + else { + // This is a single unit of power 1, like kg or degC + convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed + + unitValue = convert(this.units[0].unit.value); + unitOffset = convert(this.units[0].unit.offset); + unitPrefixValue = convert(this.units[0].prefix.value); + + return multiply(add(value, unitOffset), multiply(unitValue, unitPrefixValue)); + } + }; + + /** + * Denormalize a value, based on its currently set unit(s) + * @memberof Unit + * @param {number} value + * @param {number} [prefixValue] Optional prefix value to be used (ignored if this is a derived unit) + * @return {number} denormalized value + * @private + */ + Unit.prototype._denormalize = function (value, prefixValue) { + var unitValue, unitOffset, unitPower, unitPrefixValue; + var convert; + + if (value == null || this.units.length === 0) { + return value; + } + else if (this._isDerived()) { + // This is a derived unit, so do not apply offsets. + // For example, with J kg^-1 degC^-1 you would NOT want to apply the offset. + // Also, prefixValue is ignored--but we will still use the prefix value stored in each unit, since kg is usually preferable to g unless the user decides otherwise. + var res = value; + convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed + + for (var i = 0; i < this.units.length; i++) { + unitValue = convert(this.units[i].unit.value); + unitPrefixValue = convert(this.units[i].prefix.value); + unitPower = convert(this.units[i].power); + res = divide(res, pow(multiply(unitValue, unitPrefixValue), unitPower)); + } + + return res; + } + else { + // This is a single unit of power 1, like kg or degC + convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed + + unitValue = convert(this.units[0].unit.value); + unitPrefixValue = convert(this.units[0].prefix.value); + unitOffset = convert(this.units[0].unit.offset); + + if (prefixValue == undefined) { + return subtract(divide(divide(value, unitValue), unitPrefixValue), unitOffset); + } + else { + return subtract(divide(divide(value, unitValue), prefixValue), unitOffset); + } + } + }; + + /** + * Find a unit from a string + * @memberof Unit + * @param {string} str A string like 'cm' or 'inch' + * @returns {Object | null} result When found, an object with fields unit and + * prefix is returned. Else, null is returned. + * @private + */ + function _findUnit(str) { + + // First, match units names exactly. For example, a user could define 'mm' as 10^-4 m, which is silly, but then we would want 'mm' to match the user-defined unit. + if(UNITS.hasOwnProperty(str)) { + var unit = UNITS[str]; + var prefix = unit.prefixes['']; + return { + unit: unit, + prefix: prefix + } + } + + for (var name in UNITS) { + if (UNITS.hasOwnProperty(name)) { + if (endsWith(str, name)) { + var unit = UNITS[name]; + var prefixLen = (str.length - name.length); + var prefixName = str.substring(0, prefixLen); + var prefix = unit.prefixes.hasOwnProperty(prefixName) + ? unit.prefixes[prefixName] + : undefined; + if (prefix !== undefined) { + // store unit, prefix, and value + return { + unit: unit, + prefix: prefix + }; + } + } + } + } + + return null; + } + + /** + * Test if the given expression is a unit. + * The unit can have a prefix but cannot have a value. + * @memberof Unit + * @param {string} name A string to be tested whether it is a value less unit. + * The unit can have prefix, like "cm" + * @return {boolean} true if the given string is a unit + */ + Unit.isValuelessUnit = function (name) { + return (_findUnit(name) != null); + }; + + /** + * check if this unit has given base unit + * If this unit is a derived unit, this will ALWAYS return false, since by definition base units are not derived. + * @memberof Unit + * @param {BASE_UNITS | string | undefined} base + */ + Unit.prototype.hasBase = function (base) { + + if(typeof(base) === "string") { + base = BASE_UNITS[base]; + } + + if(!base) + return false; + + + // All dimensions must be the same + for(var i=0; i 1e-12) { + return false; + } + } + return true; + + }; + + /** + * Check if this unit has a base or bases equal to another base or bases + * For derived units, the exponent on each base also must match + * @memberof Unit + * @param {Unit} other + * @return {boolean} true if equal base + */ + Unit.prototype.equalBase = function (other) { + // All dimensions must be the same + for(var i=0; i 1e-12) { + return false; + } + } + return true; + }; + + /** + * Check if this unit equals another unit + * @memberof Unit + * @param {Unit} other + * @return {boolean} true if both units are equal + */ + Unit.prototype.equals = function (other) { + return (this.equalBase(other) && equal(this.value, other.value)); + }; + + /** + * Multiply this unit with another one + * @memberof Unit + * @param {Unit} other + * @return {Unit} product of this unit and the other unit + */ + Unit.prototype.multiply = function (other) { + var res = this.clone(); + + for(var i = 0; i 1e-12) { + if(currentUnitSystem.hasOwnProperty(baseDim)) { + proposedUnitList.push({ + unit: currentUnitSystem[baseDim].unit, + prefix: currentUnitSystem[baseDim].prefix, + power: this.dimensions[i] || 0 + }); + } + else { + missingBaseDim = true; + } + } + } + + // Is the proposed unit list "simpler" than the existing one? + if(proposedUnitList.length < this.units.length && !missingBaseDim) { + // Replace this unit list with the proposed list + this.units = proposedUnitList; + } + } + } + + this.isUnitListSimplified = true; + }; + + Unit.prototype.toSI = function() { + + var ret = this.clone(); + + var proposedUnitList = []; + for(var i=0; i 1e-12) { + if(UNIT_SYSTEMS["si"].hasOwnProperty(baseDim)) { + proposedUnitList.push({ + unit: UNIT_SYSTEMS["si"][baseDim].unit, + prefix: UNIT_SYSTEMS["si"][baseDim].prefix, + power: ret.dimensions[i] || 0 + }); + } + else { + throw new Error("Cannot express custom unit " + baseDim + " in SI units"); + } + } + } + + // Replace this unit list with the proposed list + ret.units = proposedUnitList; + + ret.isUnitListSimplified = true; + + return ret; + }; + + /** + * Get a string representation of the units of this Unit, without the value. + * @memberof Unit + * @return {string} + */ + Unit.prototype.formatUnits = function () { + + // Lazy evaluation of the unit list + this.simplifyUnitListLazy(); + + var strNum = ""; + var strDen = ""; + var nNum = 0; + var nDen = 0; + + for(var i=0; i 0) { + nNum++; + strNum += " " + this.units[i].prefix.name + this.units[i].unit.name; + if(Math.abs(this.units[i].power - 1.0) > 1e-15) { + strNum += "^" + this.units[i].power; + } + } + else if(this.units[i].power < 0) { + nDen++; + } + } + + if(nDen > 0) { + for(var i=0; i 0) { + strDen += " " + this.units[i].prefix.name + this.units[i].unit.name; + if(Math.abs(this.units[i].power + 1.0) > 1e-15) { + strDen += "^" + (-this.units[i].power); + } + } + else { + strDen += " " + this.units[i].prefix.name + this.units[i].unit.name; + strDen += "^" + (this.units[i].power); + } + } + } + } + // Remove leading " " + strNum = strNum.substr(1); + strDen = strDen.substr(1); + + // Add parans for better copy/paste back into the eval, for example, or for better pretty print formatting + if(nNum > 1 && nDen > 0) { + strNum = "(" + strNum + ")"; + } + if(nDen > 1 && nNum > 0) { + strDen = "(" + strDen + ")"; + } + + var str = strNum; + if(nNum > 0 && nDen > 0) { + str += " / "; + } + str += strDen; + + return str; + }; + + /** + * Get a string representation of the Unit, with optional formatting options. + * @memberof Unit + * @param {Object | number | Function} [options] Formatting options. See + * lib/utils/number:format for a + * description of the available + * options. + * @return {string} + */ + Unit.prototype.format = function (options) { + + // Simplfy the unit list, if necessary + this.simplifyUnitListLazy(); + + // Apply some custom logic for handling VA and VAR. The goal is to express the value of the unit as a real value, if possible. Otherwise, use a real-valued unit instead of a complex-valued one. + var isImaginary = false; + var isReal = true; + if(typeof(this.value) !== 'undefined' && this.value !== null && type.isComplex(this.value)) { + // TODO: Make this better, for example, use relative magnitude of re and im rather than absolute + isImaginary = Math.abs(this.value.re) < 1e-14; + isReal = Math.abs(this.value.im) < 1e-14; + } + + for(var i in this.units) { + if(this.units[i].unit) { + if(this.units[i].unit.name === 'VA' && isImaginary) { + this.units[i].unit = UNITS["VAR"]; + } + else if(this.units[i].unit.name === 'VAR' && !isImaginary) { + this.units[i].unit = UNITS["VA"]; + } + } + } + + + // Now apply the best prefix + // Units must have only one unit and not have the fixPrefix flag set + if (this.units.length === 1 && !this.fixPrefix) { + // Units must have integer powers, otherwise the prefix will change the + // outputted value by not-an-integer-power-of-ten + if (Math.abs(this.units[0].power - Math.round(this.units[0].power)) < 1e-14) { + // Apply the best prefix + this.units[0].prefix = this._bestPrefix(); + } + } + + + var value = this._denormalize(this.value); + var str = (this.value !== null) ? format(value, options || {}) : ''; + var unitStr = this.formatUnits(); + if(this.value && type.isComplex(this.value)) { + str = "(" + str + ")"; // Surround complex values with ( ) to enable better parsing + } + if(unitStr.length > 0 && str.length > 0) { + str += " "; + } + str += unitStr; + + return str; + }; + + /** + * Calculate the best prefix using current value. + * @memberof Unit + * @returns {Object} prefix + * @private + */ + Unit.prototype._bestPrefix = function () { + if (this.units.length !== 1) { + throw new Error("Can only compute the best prefix for single units with integer powers, like kg, s^2, N^-1, and so forth!"); + } + if (Math.abs(this.units[0].power - Math.round(this.units[0].power)) >= 1e-14) { + throw new Error("Can only compute the best prefix for single units with integer powers, like kg, s^2, N^-1, and so forth!"); + } + + // find the best prefix value (resulting in the value of which + // the absolute value of the log10 is closest to zero, + // though with a little offset of 1.2 for nicer values: you get a + // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ... + + // Note: the units value can be any numeric type, but to find the best + // prefix it's enough to work with limited precision of a regular number + // Update: using mathjs abs since we also allow complex numbers + var absValue = this.value !== null ? abs(this.value) : 0; + var absUnitValue = abs(this.units[0].unit.value); + var bestPrefix = this.units[0].prefix; + if (absValue === 0) { + return bestPrefix; + } + var power = this.units[0].power; + var bestDiff = Math.log(absValue / Math.pow(bestPrefix.value * absUnitValue, power)) / Math.LN10 - 1.2; + if(bestDiff > -2.200001 && bestDiff < 1.800001) return bestPrefix; // Allow the original prefix + bestDiff = Math.abs(bestDiff); + var prefixes = this.units[0].unit.prefixes; + for (var p in prefixes) { + if (prefixes.hasOwnProperty(p)) { + var prefix = prefixes[p]; + if (prefix.scientific) { + + var diff = Math.abs( + Math.log(absValue / Math.pow(prefix.value * absUnitValue, power)) / Math.LN10 - 1.2); + + if (diff < bestDiff + || (diff === bestDiff && prefix.name.length < bestPrefix.name.length)) { + // choose the prefix with the smallest diff, or if equal, choose the one + // with the shortest name (can happen with SHORTLONG for example) + bestPrefix = prefix; + bestDiff = diff; + } + } + } + } + + return bestPrefix; + }; + + /** + * Returns an array of units whose sum is equal to this unit + * @memberof Unit + * @param {Array} [parts] An array of strings or valueless units. + * + * Example: + * + * var u = new Unit(1, 'm'); + * u.splitUnit(['feet', 'inch']); + * [ 3 feet, 3.3700787401575 inch ] + * + * @return {Array} An array of units. + */ + Unit.prototype.splitUnit = function(parts) { + + var x = this.clone(); + var ret = []; + for(var i=0; i= '0' && c <= '9'); + }; + + if(i === 0 && !isValidAlpha(c)) + throw new Error('Invalid unit name (must begin with alpha character): "' + name + '"'); + + if(i > 0 && !( isValidAlpha(c) + || isDigit(c))) + throw new Error('Invalid unit name (only alphanumeric characters are allowed): "' + name + '"'); + + } + } + + /** + * Wrapper around createUnitSingle. + * Example: + * createUnit({ + * foo: { }, + * bar: { + * definition: 'kg/foo', + * aliases: ['ba', 'barr', 'bars'], + * offset: 200 + * }, + * baz: '4 bar' + * }, + * { + * override: true; + * }); + * @param {object} obj Object map. Each key becomes a unit which is defined by its value. + * @param {object} options + */ + Unit.createUnit = function(obj, options) { + + if(typeof(obj) !== 'object') { + throw new TypeError("createUnit expects first parameter to be of type 'Object'"); + } + + // Remove all units and aliases we are overriding + if(options && options.override) { + for(var key in obj) { + if(obj.hasOwnProperty(key)) { + Unit.deleteUnit(key); + } + if(obj[key].aliases) { + for(var i=0; i=0;i--) { - reti = []; - Ai = A[i]; - for(k=r-1;k>=0;k--) { - accum = 0; - BTk = BT[k]; - for(j in Ai) { - if(!(Ai.hasOwnProperty(j))) continue; - if(j in BTk) { accum += Ai[j]*BTk[j]; } - } - if(accum) reti[k] = accum; + catch (ex) { + ex.message = 'Could not create unit "' + name + '" from "' + definition + '": ' + ex.message; + throw(ex); } - ret[i] = reti; - } - return ret; -}; + } + else if(definition && definition.type === 'Unit') { + defUnit = definition.clone(); + } -numeric.sdotMV = function dotMV(A,x) { - var p = A.length, Ai, i,j; - var ret = Array(p), accum; - for(i=p-1;i>=0;i--) { - Ai = A[i]; - accum = 0; - for(j in Ai) { - if(!(Ai.hasOwnProperty(j))) continue; - if(x[j]) accum += Ai[j]*x[j]; - } - if(accum) ret[i] = accum; - } - return ret; -}; + aliases = aliases || []; + offset = offset || 0; + if(prefixes && prefixes.toUpperCase) + prefixes = PREFIXES[prefixes.toUpperCase()] || PREFIXES.NONE; + else + prefixes = PREFIXES.NONE; -numeric.sdotVM = function dotMV(x,A) { - var i,j,Ai,alpha; - var ret = []; - for(i in x) { - if(!x.hasOwnProperty(i)) continue; - Ai = A[i]; - alpha = x[i]; - for(j in Ai) { - if(!Ai.hasOwnProperty(j)) continue; - if(!ret[j]) { ret[j] = 0; } - ret[j] += alpha*Ai[j]; + + // If defUnit is null, it is because the user did not + // specify a defintion. So create a new base dimension. + var newUnit = {}; + if(!defUnit) { + // Add a new base dimension + var baseName = name + "_STUFF"; // foo --> foo_STUFF, or the essence of foo + if(BASE_DIMENSIONS.indexOf(baseName) >= 0) { + throw new Error('Cannot create new base unit "' + name + '": a base unit with that name already exists (and cannot be overridden)'); } - } - return ret; -}; + BASE_DIMENSIONS.push(baseName); -numeric.sdotVV = function dotVV(x,y) { - var i,ret=0; - for(i in x) { if(x[i] && y[i]) ret+= x[i]*y[i]; } - return ret; -}; - -numeric.sdot = function dot(A,B) { - var m = numeric.sdim(A).length, n = numeric.sdim(B).length; - var k = m*1000+n; - switch(k) { - case 0: return A*B; - case 1001: return numeric.sdotVV(A,B); - case 2001: return numeric.sdotMV(A,B); - case 1002: return numeric.sdotVM(A,B); - case 2002: return numeric.sdotMM(A,B); - default: throw new Error('numeric.sdot not implemented for tensors of order '+m+' and '+n); - } -}; - -numeric.sscatter = function scatter(V) { - var n = V[0].length, Vij, i, j, m = V.length, A = [], Aj; - for(i=n-1;i>=0;--i) { - if(!V[m-1][i]) continue; - Aj = A; - for(j=0;j=0;--i) ret[i] = []; - } - for(i=n;i>=0;--i) ret[i].push(k[i]); - ret[n+1].push(Ai); - } - } else gather(Ai,ret,k); + // Push 0 onto existing base units + for(var b in BASE_UNITS) { + if(BASE_UNITS.hasOwnProperty(b)) { + BASE_UNITS[b].dimensions[BASE_DIMENSIONS.length-1] = 0; + } } - } - if(k.length>n) k.pop(); - return ret; -}; - -// 6. Coordinate matrices -numeric.cLU = function LU(A) { - var I = A[0], J = A[1], V = A[2]; - var p = I.length, m=0, i,j,k,a,b,c; - for(i=0;im) m=I[i]; - m++; - var L = Array(m), U = Array(m), left = numeric.rep([m],Infinity), right = numeric.rep([m],-Infinity); - var Ui, Uj,alpha; - for(k=0;kright[i]) right[i] = j; - } - for(i=0;i right[i+1]) right[i+1] = right[i]; } - for(i=m-1;i>=1;i--) { if(left[i] 1e-12) { + match = false; + break; + } } - } - foo = L[i]; - for(j=a;j=0;i--) { - while(Uj[k] > i) { - ret[i] -= Uv[k]*ret[Uj[k]]; - k--; - } - ret[i] /= Uv[k]; - k--; - } - return ret; -}; - -numeric.cgrid = function grid(n,shape) { - if(typeof n === "number") n = [n,n]; - var ret = numeric.rep(n,-1); - var i,j,count; - if(typeof shape !== "function") { - switch(shape) { - case 'L': - shape = function(i,j) { return (i>=n[0]/2 || j foo_STUFF, or the essence of foo + // Add the new base unit + var newBaseUnit = { dimensions: defUnit.dimensions.slice(0) }; + newBaseUnit.key = baseName; + BASE_UNITS[baseName] = newBaseUnit; + + currentUnitSystem[baseName] = { + unit: newUnit, + prefix: PREFIXES.NONE[''] + }; + + newUnit.base = baseName; } - } - count=0; - for(i=1;iN) N = Ai[k]; } - N++; - ret = numeric.rep([N],0); - for(k=0;k1) { - mid = floor((p+q)/2); - if(x[mid] <= x0) p = mid; - else q = mid; - } - return this._at(x0,p); - } - var n = x0.length, i, ret = Array(n); - for(i=n-1;i!==-1;--i) ret[i] = this.at(x0[i]); - return ret; -}; -numeric.Spline.prototype.diff = function diff() { - var x = this.x; - var yl = this.yl; - var yr = this.yr; - var kl = this.kl; - var kr = this.kr; - var n = yl.length; - var i,dx,dy; - var zl = kl, zr = kr, pl = Array(n), pr = Array(n); - var add = numeric.add, mul = numeric.mul, div = numeric.div, sub = numeric.sub; - for(i=n-1;i!==-1;--i) { - dx = x[i+1]-x[i]; - dy = sub(yr[i+1],yl[i]); - pl[i] = div(add(mul(dy, 6),mul(kl[i],-4*dx),mul(kr[i+1],-2*dx)),dx*dx); - pr[i+1] = div(add(mul(dy,-6),mul(kl[i], 2*dx),mul(kr[i+1], 4*dx)),dx*dx); - } - return new numeric.Spline(x,zl,zr,pl,pr); -}; -numeric.Spline.prototype.roots = function roots() { - function sqr(x) { return x*x; } - var ret = []; - var x = this.x, yl = this.yl, yr = this.yr, kl = this.kl, kr = this.kr; - if(typeof yl[0] === "number") { - yl = [yl]; - yr = [yr]; - kl = [kl]; - kr = [kr]; - } - var m = yl.length,n=x.length-1,i,j,k; - var ai,bi,ci,di, ret = Array(m),ri,k0,k1,y0,y1,A,B,D,dx,cx,stops,z0,z1,zm,t0,t1,tm; - var sqrt = Math.sqrt; - for(i=0;i!==m;++i) { - ai = yl[i]; - bi = yr[i]; - ci = kl[i]; - di = kr[i]; - ri = []; - for(j=0;j!==n;j++) { - if(j>0 && bi[j]*ai[j]<0) ri.push(x[j]); - dx = (x[j+1]-x[j]); - cx = x[j]; - y0 = ai[j]; - y1 = bi[j+1]; - k0 = ci[j]/dx; - k1 = di[j+1]/dx; - D = sqr(k0-k1+3*(y0-y1)) + 12*k1*y0; - A = k1+3*y0+2*k0-3*y1; - B = 3*(k1+k0+2*(y0-y1)); - if(D<=0) { - z0 = A/B; - if(z0>x[j] && z0x[j] && z0x[j] && z10) { - t0 = t1; - z0 = z1; - continue; - } - var side = 0; - while(1) { - tm = (z0*t1-z1*t0)/(z0-z1); - if(tm <= t0 || tm >= t1) { break; } - zm = this._at(tm,j); - if(zm*z1>0) { - t1 = tm; - z1 = zm; - if(side === -1) z0*=0.5; - side = -1; - } else if(zm*z0>0) { - t0 = tm; - z0 = zm; - if(side === 1) z1*=0.5; - side = 1; - } else break; - } - ri.push(tm); - t0 = stops[k+1]; - z0 = this._at(t0, j); - } - if(z1 === 0) ri.push(t1); + alias.name = aliasName; + Unit.UNITS[aliasName] = alias; + } + + return new Unit(null, name); + }; + + Unit.deleteUnit = function(name) { + delete Unit.UNITS[name]; + }; + + // expose arrays with prefixes, dimensions, units, systems + Unit.PREFIXES = PREFIXES; + Unit.BASE_DIMENSIONS = BASE_DIMENSIONS; + Unit.BASE_UNITS = BASE_UNITS; + Unit.UNIT_SYSTEMS = UNIT_SYSTEMS; + Unit.UNITS = UNITS; + + return Unit; + } + + var name$265 = 'Unit'; + var path$65 = 'type'; + var factory_1$277 = factory$278; + var math$20 = true; // request access to the math namespace + + var Unit = { + name: name$265, + path: path$65, + factory: factory_1$277, + math: math$20 + }; + + function factory$279 (type, config, load, typed) { + /** + * Create a unit. Depending on the passed arguments, the function + * will create and return a new math.type.Unit object. + * When a matrix is provided, all elements will be converted to units. + * + * Syntax: + * + * math.unit(unit : string) + * math.unit(value : number, unit : string) + * + * Examples: + * + * var a = math.unit(5, 'cm'); // returns Unit 50 mm + * var b = math.unit('23 kg'); // returns Unit 23 kg + * a.to('m'); // returns Unit 0.05 m + * + * See also: + * + * bignumber, boolean, complex, index, matrix, number, string, createUnit + * + * @param {* | Array | Matrix} args A number and unit. + * @return {Unit | Array | Matrix} The created unit + */ + + var unit = typed('unit', { + 'Unit': function (x) { + return x.clone(); + }, + + 'string': function (x) { + if (type.Unit.isValuelessUnit(x)) { + return new type.Unit(null, x); // a pure unit } - ret[i] = ri; + + return type.Unit.parse(x); // a unit with value, like '5cm' + }, + + 'number | BigNumber | Fraction | Complex, string': function (value, unit) { + return new type.Unit(value, unit); + }, + + 'Array | Matrix': function (x) { + return deepMap(x, unit); + } + }); + + unit.toTex = { + 1: '\\left(${args[0]}\\right)', + 2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)' + }; + + return unit; + } + + var name$266 = 'unit'; + var factory_1$278 = factory$279; + + var unit$2 = { + name: name$266, + factory: factory_1$278 + }; + + function factory$280 (type, config, load, typed) { + /** + * Create a user-defined unit and register it with the Unit type. + * + * Syntax: + * + * math.createUnit({ + * baseUnit1: { + * aliases: [string, ...] + * prefixes: object + * }, + * unit2: { + * definition: string, + * aliases: [string, ...] + * prefixes: object, + * offset: number + * }, + * unit3: string // Shortcut + * }) + * + * // Another shortcut: + * math.createUnit(string, unit : string, [object]) + * + * Examples: + * + * math.createUnit('foo'); + * math.createUnit('knot', {definition: '0.514444444 m/s', aliases: ['knots', 'kt', 'kts']}); + * math.createUnit('mph', '1 mile/hour'); + * + * @param {string} name The name of the new unit. Must be unique. Example: 'knot' + * @param {string, Unit} definition Definition of the unit in terms of existing units. For example, '0.514444444 m / s'. + * @param {Object} options (optional) An object containing any of the following properties: + * - `prefixes {string}` "none", "short", "long", "binary_short", or "binary_long". The default is "none". + * - `aliases {Array}` Array of strings. Example: ['knots', 'kt', 'kts'] + * - `offset {Numeric}` An offset to apply when converting from the unit. For example, the offset for celsius is 273.15. Default is 0. + * + * See also: + * + * unit + * + * @return {Unit} The new unit + */ + var createUnit = typed('createUnit', { + + // General function signature. First parameter is an object where each property is the definition of a new unit. The object keys are the unit names and the values are the definitions. The values can be objects, strings, or Units. If a property is an empty object or an empty string, a new base unit is created. The second parameter is the options. + 'Object, Object': function(obj, options) { + return type.Unit.createUnit(obj, options); + }, + + // Same as above but without the options. + 'Object': function(obj) { + return type.Unit.createUnit(obj, {}); + }, + + // Shortcut method for creating one unit. + 'string, Unit | string | Object, Object': function (name, def, options) { + var obj = {}; + obj[name] = def; + return type.Unit.createUnit(obj, options); + }, + + // Same as above but without the options. + 'string, Unit | string | Object': function (name, def) { + var obj = {}; + obj[name] = def; + return type.Unit.createUnit(obj, {}); + }, + + // Without a definition, creates a base unit. + 'string': function (name) { + var obj = {}; + obj[name] = {}; + return type.Unit.createUnit(obj, {}); + }, + }); + + return createUnit; + } + + var name$267 = 'createUnit'; + var factory_1$279 = factory$280; + + var createUnit$1 = { + name: name$267, + factory: factory_1$279 + }; + + function factory$281 (type, config, load, typed) { + + /** + * Split a unit in an array of units whose sum is equal to the original unit. + * + * Syntax: + * + * splitUnit(unit: Unit, parts: Array.) + * + * Example: + * + * math.splitUnit(new Unit(1, 'm'), ['feet', 'inch']); + * // [ 3 feet, 3.3700787401575 inch ] + * + * See also: + * + * unit + * + * @param {Array} [parts] An array of strings or valueless units. + * @return {Array} An array of units. + */ + var splitUnit = typed('splitUnit', { + 'Unit, Array': function(unit, parts) { + return unit.splitUnit(parts); + } + }); + + return splitUnit; + + } + + var name$268 = 'splitUnit'; + var factory_1$280 = factory$281; + + var splitUnit$1 = { + name: name$268, + factory: factory_1$280 + }; + + var lazy$5 = object.lazy; + + + function factory$282 (type, config, load, typed, math) { + + // helper function to create a unit with a fixed prefix + function fixedUnit(str) { + var unit = type.Unit.parse(str); + unit.fixPrefix = true; + return unit; } - if(typeof this.yl[0] === "number") return ret[0]; - return ret; -}; -numeric.spline = function spline(x,y,k1,kn) { - var n = x.length, b = [], dx = [], dy = []; - var i; - var sub = numeric.sub,mul = numeric.mul,add = numeric.add; - for(i=n-2;i>=0;i--) { dx[i] = x[i+1]-x[i]; dy[i] = sub(y[i+1],y[i]); } - if(typeof k1 === "string" || typeof kn === "string") { - k1 = kn = "periodic"; - } - // Build sparse tridiagonal system - var T = [[],[],[]]; - switch(typeof k1) { - case "undefined": - b[0] = mul(3/(dx[0]*dx[0]),dy[0]); - T[0].push(0,0); - T[1].push(0,1); - T[2].push(2/dx[0],1/dx[0]); - break; - case "string": - b[0] = add(mul(3/(dx[n-2]*dx[n-2]),dy[n-2]),mul(3/(dx[0]*dx[0]),dy[0])); - T[0].push(0,0,0); - T[1].push(n-2,0,1); - T[2].push(1/dx[n-2],2/dx[n-2]+2/dx[0],1/dx[0]); - break; - default: - b[0] = k1; - T[0].push(0); - T[1].push(0); - T[2].push(1); - break; + + // Source: http://www.wikiwand.com/en/Physical_constant + + // Universal constants + setLazyConstant$1(math, 'speedOfLight', function () {return fixedUnit('299792458 m s^-1')}); + setLazyConstant$1(math, 'gravitationConstant', function () {return fixedUnit('6.6738480e-11 m^3 kg^-1 s^-2')}); + setLazyConstant$1(math, 'planckConstant', function () {return fixedUnit('6.626069311e-34 J s')}); + setLazyConstant$1(math, 'reducedPlanckConstant',function () {return fixedUnit('1.05457172647e-34 J s')}); + + // Electromagnetic constants + setLazyConstant$1(math, 'magneticConstant', function () {return fixedUnit('1.2566370614e-6 N A^-2')}); + setLazyConstant$1(math, 'electricConstant', function () {return fixedUnit('8.854187817e-12 F m^-1')}); + setLazyConstant$1(math, 'vacuumImpedance', function () {return fixedUnit('376.730313461 ohm')}); + setLazyConstant$1(math, 'coulomb', function () {return fixedUnit('8.9875517873681764e9 N m^2 C^-2')}); + setLazyConstant$1(math, 'elementaryCharge', function () {return fixedUnit('1.60217656535e-19 C')}); + setLazyConstant$1(math, 'bohrMagneton', function () {return fixedUnit('9.2740096820e-24 J T^-1')}); + setLazyConstant$1(math, 'conductanceQuantum', function () {return fixedUnit('7.748091734625e-5 S')}); + setLazyConstant$1(math, 'inverseConductanceQuantum', function () {return fixedUnit('12906.403721742 ohm')}); + setLazyConstant$1(math, 'magneticFluxQuantum', function () {return fixedUnit('2.06783375846e-15 Wb')}); + setLazyConstant$1(math, 'nuclearMagneton', function () {return fixedUnit('5.0507835311e-27 J T^-1')}); + setLazyConstant$1(math, 'klitzing', function () {return fixedUnit('25812.807443484 ohm')}); + //setLazyConstant(math, 'josephson', function () {return fixedUnit('4.8359787011e-14 Hz V^-1')}); // TODO: support for Hz needed + + // Atomic and nuclear constants + setLazyConstant$1(math, 'bohrRadius', function () {return fixedUnit('5.291772109217e-11 m')}); + setLazyConstant$1(math, 'classicalElectronRadius', function () {return fixedUnit('2.817940326727e-15 m')}); + setLazyConstant$1(math, 'electronMass', function () {return fixedUnit('9.1093829140e-31 kg')}); + setLazyConstant$1(math, 'fermiCoupling', function () {return fixedUnit('1.1663645e-5 GeV^-2')}); + setLazyConstant$1(math, 'fineStructure', function () {return 7.297352569824e-3}); + setLazyConstant$1(math, 'hartreeEnergy', function () {return fixedUnit('4.3597443419e-18 J')}); + setLazyConstant$1(math, 'protonMass', function () {return fixedUnit('1.67262177774e-27 kg')}); + setLazyConstant$1(math, 'deuteronMass', function () {return fixedUnit('3.3435830926e-27 kg')}); + setLazyConstant$1(math, 'neutronMass', function () {return fixedUnit('1.6749271613e-27 kg')}); + setLazyConstant$1(math, 'quantumOfCirculation', function () {return fixedUnit('3.636947552024e-4 m^2 s^-1')}); + setLazyConstant$1(math, 'rydberg', function () {return fixedUnit('10973731.56853955 m^-1')}); + setLazyConstant$1(math, 'thomsonCrossSection', function () {return fixedUnit('6.65245873413e-29 m^2')}); + setLazyConstant$1(math, 'weakMixingAngle', function () {return 0.222321}); + setLazyConstant$1(math, 'efimovFactor', function () {return 22.7}); + + // Physico-chemical constants + setLazyConstant$1(math, 'atomicMass', function () {return fixedUnit('1.66053892173e-27 kg')}); + setLazyConstant$1(math, 'avogadro', function () {return fixedUnit('6.0221412927e23 mol^-1')}); + setLazyConstant$1(math, 'boltzmann', function () {return fixedUnit('1.380648813e-23 J K^-1')}); + setLazyConstant$1(math, 'faraday', function () {return fixedUnit('96485.336521 C mol^-1')}); + setLazyConstant$1(math, 'firstRadiation', function () {return fixedUnit('3.7417715317e-16 W m^2')}); + // setLazyConstant(math, 'spectralRadiance', function () {return fixedUnit('1.19104286953e-16 W m^2 sr^-1')}); // TODO spectralRadiance + setLazyConstant$1(math, 'loschmidt', function () {return fixedUnit('2.686780524e25 m^-3')}); + setLazyConstant$1(math, 'gasConstant', function () {return fixedUnit('8.314462175 J K^-1 mol^-1')}); + setLazyConstant$1(math, 'molarPlanckConstant', function () {return fixedUnit('3.990312717628e-10 J s mol^-1')}); + setLazyConstant$1(math, 'molarVolume', function () {return fixedUnit('2.241396820e-10 m^3 mol^-1')}); + setLazyConstant$1(math, 'sackurTetrode', function () {return -1.164870823}); + setLazyConstant$1(math, 'secondRadiation', function () {return fixedUnit('1.438777013e-2 m K')}); + setLazyConstant$1(math, 'stefanBoltzmann', function () {return fixedUnit('5.67037321e-8 W m^-2 K^-4')}); + setLazyConstant$1(math, 'wienDisplacement', function () {return fixedUnit('2.897772126e-3 m K')}); + + // Adopted values + setLazyConstant$1(math, 'molarMass', function () {return fixedUnit('1e-3 kg mol^-1')}); + setLazyConstant$1(math, 'molarMassC12', function () {return fixedUnit('1.2e-2 kg mol^-1')}); + setLazyConstant$1(math, 'gravity', function () {return fixedUnit('9.80665 m s^-2')}); + // atm is defined in Unit.js + + // Natural units + setLazyConstant$1(math, 'planckLength', function () {return fixedUnit('1.61619997e-35 m')}); + setLazyConstant$1(math, 'planckMass', function () {return fixedUnit('2.1765113e-8 kg')}); + setLazyConstant$1(math, 'planckTime', function () {return fixedUnit('5.3910632e-44 s')}); + setLazyConstant$1(math, 'planckCharge', function () {return fixedUnit('1.87554595641e-18 C')}); + setLazyConstant$1(math, 'planckTemperature', function () {return fixedUnit('1.41683385e+32 K')}); + + } + + // create a lazy constant in both math and mathWithTransform + function setLazyConstant$1 (math, name, resolver) { + lazy$5(math, name, resolver); + lazy$5(math.expression.mathWithTransform, name, resolver); + } + + var factory_1$281 = factory$282; + var lazy_1$2 = false; // no lazy loading of constants, the constants themselves are lazy when needed + var math$21 = true; // request access to the math namespace + + var physicalConstants = { + factory: factory_1$281, + lazy: lazy_1$2, + math: math$21 + }; + + var unit$3 = [ + // type + Unit, + + // construction function + unit$2, + + // create new units + createUnit$1, + + // split units + splitUnit$1, + + // physical constants + physicalConstants + ]; + + var type$1 = [ + bignumber$1, + boolean_1, + chain$1, + complex$3, + fraction$3, + matrix$1, + number$3, + resultset, + string$6, + unit$3 + ]; + + var version$1 = '4.4.2'; + + function factory$283 (type, config, load, typed, math) { + // listen for changed in the configuration, automatically reload + // constants when needed + math.on('config', function (curr, prev) { + if (curr.number !== prev.number) { + factory$283(type, config, load, typed, math); + } + }); + + setConstant$1(math, 'true', true); + setConstant$1(math, 'false', false); + setConstant$1(math, 'null', null); + setConstant$1(math, 'uninitialized', 'Error: Constant uninitialized is removed since v4.0.0. Use null instead'); + + if (config.number === 'BigNumber') { + setConstant$1(math, 'Infinity', new type.BigNumber(Infinity)); + setConstant$1(math, 'NaN', new type.BigNumber(NaN)); + + setLazyConstant$2(math, 'pi', function () {return constants.pi(type.BigNumber)}); + setLazyConstant$2(math, 'tau', function () {return constants.tau(type.BigNumber)}); + setLazyConstant$2(math, 'e', function () {return constants.e(type.BigNumber)}); + setLazyConstant$2(math, 'phi', function () {return constants.phi(type.BigNumber)}); // golden ratio, (1+sqrt(5))/2 + + // uppercase constants (for compatibility with built-in Math) + setLazyConstant$2(math, 'E', function () {return math.e;}); + setLazyConstant$2(math, 'LN2', function () {return new type.BigNumber(2).ln();}); + setLazyConstant$2(math, 'LN10', function () {return new type.BigNumber(10).ln()}); + setLazyConstant$2(math, 'LOG2E', function () {return new type.BigNumber(1).div(new type.BigNumber(2).ln());}); + setLazyConstant$2(math, 'LOG10E', function () {return new type.BigNumber(1).div(new type.BigNumber(10).ln())}); + setLazyConstant$2(math, 'PI', function () {return math.pi}); + setLazyConstant$2(math, 'SQRT1_2', function () {return new type.BigNumber('0.5').sqrt()}); + setLazyConstant$2(math, 'SQRT2', function () {return new type.BigNumber(2).sqrt()}); } - for(i=1;i20) { throw new Error("Numerical gradient fails"); } - x0[i] = x[i]+h; - f1 = f(x0); - x0[i] = x[i]-h; - f2 = f(x0); - x0[i] = x[i]; - if(isNaN(f1) || isNaN(f2)) { h/=16; continue; } - J[i] = (f1-f2)/(2*h); - t0 = x[i]-h; - t1 = x[i]; - t2 = x[i]+h; - d1 = (f1-f0)/h; - d2 = (f0-f2)/h; - N = max(abs(J[i]),abs(f0),abs(f1),abs(f2),abs(t0),abs(t1),abs(t2),1e-8); - errest = min(max(abs(d1-J[i]),abs(d2-J[i]),abs(d1-d2))/N,h/N); - if(errest>eps) { h/=16; } - else break; - } + + // complex i + setConstant$1(math, 'i', type.Complex.I); + + // meta information + setConstant$1(math, 'version', version$1); + } + + // create a constant in both math and mathWithTransform + function setConstant$1(math, name, value) { + math[name] = value; + math.expression.mathWithTransform[name] = value; + } + + // create a lazy constant in both math and mathWithTransform + function setLazyConstant$2 (math, name, resolver) { + object.lazy(math, name, resolver); + object.lazy(math.expression.mathWithTransform, name, resolver); + } + + var factory_1$282 = factory$283; + var lazy$6 = false; // no lazy loading of constants, the constants themselves are lazy when needed + var math$22 = true; // request access to the math namespace + + var constants$2 = { + factory: factory_1$282, + lazy: lazy$6, + math: math$22 + }; + + var lib$1 = [ + type$1, // data types (Matrix, Complex, Unit, ...) + constants$2, // constants + expression, // expression parsing + _function$3, // functions + json, // serialization utility (math.json.reviver) + error // errors + ]; + + /** + * math.js factory function. Creates a new instance of math.js + * + * @param {Object} [config] Available configuration options: + * {number} epsilon + * Minimum relative difference between two + * compared values, used by all comparison functions. + * {string} matrix + * A string 'matrix' (default) or 'array'. + * {string} number + * A string 'number' (default), 'bignumber', or + * 'fraction' + * {number} precision + * The number of significant digits for BigNumbers. + * Not applicable for Numbers. + * {boolean} predictable + * Predictable output type of functions. When true, + * output type depends only on the input types. When + * false (default), output type can vary depending + * on input values. For example `math.sqrt(-4)` + * returns `complex('2i')` when predictable is false, and + * returns `NaN` when true. + */ + function create$3 (config) { + // create a new math.js instance + var math = core$1.create(config); + math.create = create$3; + + // import data types, functions, constants, expression parser, etc. + math['import'](lib$1); + + return math; + } + + // return a new instance of math.js + var mathjs = create$3(); + + var node$1 = mathjs.expression.node; + + const operators$2 = { + "+": function(operands) { return new node$1.OperatorNode('+', 'add', operands);}, + "*": function(operands) { return new node$1.OperatorNode('*', 'multiply', operands);}, + "/": function(operands) { return new node$1.OperatorNode('/', 'divide', operands);}, + "-": function(operands) { return new node$1.OperatorNode('-', 'unaryMinus', [operands[0]]);}, + "^": function(operands) { return new node$1.OperatorNode('^', 'pow', operands);}, + //"prime": function(operands) { return operands[0] + "'"; }, + //"tuple": function(operands) { return '\\left( ' + operands.join( ', ' ) + ' \\right)';}, + //"array": function(operands) { return '\\left[ ' + operands.join( ', ' ) + ' \\right]';}, + //"set": function(operands) { return '\\left\\{ ' + operands.join( ', ' ) + ' \\right\\}';}, + "vector": function(operands) { return new node$1.ArrayNode(operands);}, + //"interval": function(operands) { return '\\left( ' + operands.join( ', ' ) + ' \\right)';}, + "and": function(operands) { return new node$1.OperatorNode('and', 'and', operands);}, + "or": function(operands) { return new node$1.OperatorNode('or', 'or', operands);}, + "not": function(operands) { return new node$1.OperatorNode('not', 'not', [operands[0]]);}, + "<": function(operands) { return new node$1.OperatorNode('<', 'smaller', operands);}, + ">": function(operands) { return new node$1.OperatorNode('>', 'larger', operands);}, + "le": function(operands) { return new node$1.OperatorNode('<=', 'smallerEq', operands);}, + "ge": function(operands) { return new node$1.OperatorNode('>=', 'largerEq', operands);}, + "ne": function(operands) { return new node$1.OperatorNode('!=', 'unequal', operands);}, + //"union": function (operands) { return operands.join(' \\cup '); }, + //"intersect": function (operands) { return operands.join(' \\cap '); }, + }; + + class astToMathjs { + constructor({ mathjs: mathjs$$1 = null } = {}) { + if(mathjs$$1) + node$1 = mathjs$$1.expression.node; } - return J; -}; - -numeric.uncmin = function uncmin(f,x0,tol,gradient,maxit,callback,options) { - var grad = numeric.gradient; - if(typeof options === "undefined") { options = {}; } - if(typeof tol === "undefined") { tol = 1e-8; } - if(typeof gradient === "undefined") { gradient = function(x) { return grad(f,x); }; } - if(typeof maxit === "undefined") maxit = 1000; - x0 = numeric.clone(x0); - var n = x0.length; - var f0 = f(x0),f1,df0; - if(isNaN(f0)) throw new Error('uncmin: f(x0) is a NaN!'); - var max = Math.max, norm2 = numeric.norm2; - tol = max(tol,numeric.epsilon); - var step,g0,g1,H1 = options.Hinv || numeric.identity(n); - var dot = numeric.dot, inv = numeric.inv, sub = numeric.sub, add = numeric.add, ten = numeric.tensor, div = numeric.div, mul = numeric.mul; - var all = numeric.all, isfinite = numeric.isFinite, neg = numeric.neg; - var it=0,s,x1,y,Hy,ys,t,nstep; - var msg = ""; - g0 = gradient(x0); - while(it= 0.1*t*df0 || isNaN(f1)) { - t *= 0.5; - ++it; - continue; - } - break; + + convert(tree) { + if (typeof tree === 'number' ) { + if(Number.isFinite(tree)) + return new node$1.ConstantNode(tree); + if(Number.isNaN(tree)) + return new node$1.SymbolNode('NaN'); + if(tree < 0) + return operators$2['-']([new node$1.SymbolNode('Infinity')]); + return new node$1.SymbolNode('Infinity'); + } + + if (typeof tree === 'string') { + return new node$1.SymbolNode(tree); + } + + if (typeof tree === 'boolean') + throw Error("no support for boolean"); + + if (!Array.isArray(tree)) + throw Error("Invalid ast"); + + const operator = tree[0]; + const operands = tree.slice(1); + + if(operator === "apply") { + if(typeof operands[0] !== 'string') + throw Error("Non string functions not implemented for conversion to mathjs"); + + if(operands[0] === "factorial") + return new node$1.OperatorNode('!', 'factorial',[this.convert(operands[1])]); + + const f = new node$1.SymbolNode(operands[0]); + const args = operands[1]; + let f_args; + + if (args[0] === 'tuple') + f_args = args.slice(1).map(function(v,i) { return this.convert(v); }.bind(this)); + else + f_args = [this.convert(args)]; + + return new node$1.FunctionNode(f, f_args); + } + + if(operator === 'lts' || operator === 'gts') { + const args = operands[0]; + const strict = operands[1]; + + if(args[0] !== 'tuple' || strict[0] !== 'tuple') + // something wrong if args or strict are not tuples + throw new Error("Badly formed ast"); + + const arg_nodes = args.slice(1).map(function(v,i) { return this.convert(v); }.bind(this)); + + let comparisons = []; + for(let i=1; i< args.length-1; i++) { + if(strict[i]) { + if(operator === 'lts') + comparisons.push(new node$1.OperatorNode('<', 'smaller', arg_nodes.slice(i-1, i+1))); + else + comparisons.push(new node$1.OperatorNode('>', 'larger', arg_nodes.slice(i-1, i+1))); + }else{ + if(operator === 'lts') + comparisons.push(new node$1.OperatorNode('<=', 'smallerEq', arg_nodes.slice(i-1, i+1))); + else + comparisons.push(new node$1.OperatorNode('>=', 'largerEq', arg_nodes.slice(i-1, i+1))); + } } - if(t*nstep < tol) { msg = "Line search step size smaller than tol"; break; } - if(it === maxit) { msg = "maxit reached during line search"; break; } - g1 = gradient(x1); - y = sub(g1,g0); - ys = dot(y,s); - Hy = dot(H1,y); - H1 = sub(add(H1, - mul( - (ys+dot(y,Hy))/(ys*ys), - ten(s,s) )), - div(add(ten(Hy,s),ten(s,Hy)),ys)); - x0 = x1; - f0 = f1; - g0 = g1; - ++it; - } - return {solution: x0, f: f0, gradient: g0, invHessian: H1, iterations:it, message: msg}; -}; - -// 10. Ode solver (Dormand-Prince) -numeric.Dopri = function Dopri(x,y,f,ymid,iterations,msg,events) { - this.x = x; - this.y = y; - this.f = f; - this.ymid = ymid; - this.iterations = iterations; - this.events = events; - this.message = msg; -}; -numeric.Dopri.prototype._at = function _at(xi,j) { - function sqr(x) { return x*x; } - var sol = this; - var xs = sol.x; - var ys = sol.y; - var k1 = sol.f; - var ymid = sol.ymid; - var n = xs.length; - var x0,x1,xh,y0,y1,yh,xi; - var h; - var c = 0.5; - var add = numeric.add, mul = numeric.mul,sub = numeric.sub, p,q,w; - x0 = xs[j]; - x1 = xs[j+1]; - y0 = ys[j]; - y1 = ys[j+1]; - h = x1-x0; - xh = x0+c*h; - yh = ymid[j]; - p = sub(k1[j ],mul(y0,1/(x0-xh)+2/(x0-x1))); - q = sub(k1[j+1],mul(y1,1/(x1-xh)+2/(x1-x0))); - w = [sqr(xi - x1) * (xi - xh) / sqr(x0 - x1) / (x0 - xh), - sqr(xi - x0) * sqr(xi - x1) / sqr(x0 - xh) / sqr(x1 - xh), - sqr(xi - x0) * (xi - xh) / sqr(x1 - x0) / (x1 - xh), - (xi - x0) * sqr(xi - x1) * (xi - xh) / sqr(x0-x1) / (x0 - xh), - (xi - x1) * sqr(xi - x0) * (xi - xh) / sqr(x0-x1) / (x1 - xh)]; - return add(add(add(add(mul(y0,w[0]), - mul(yh,w[1])), - mul(y1,w[2])), - mul( p,w[3])), - mul( q,w[4])); -}; -numeric.Dopri.prototype.at = function at(x) { - var i,j,k,floor = Math.floor; - if(typeof x !== "number") { - var n = x.length, ret = Array(n); - for(i=n-1;i!==-1;--i) { - ret[i] = this.at(x[i]); + let result = new node$1.OperatorNode('and', 'and', comparisons.slice(0,2)); + for(let i=2; i1) { - k = floor(0.5*(i+j)); - if(x0[k] <= x) i = k; - else j = k; - } - return this._at(x,i); -}; - -numeric.dopri = function dopri(x0,x1,y0,f,tol,maxit,event) { - if(typeof tol === "undefined") { tol = 1e-6; } - if(typeof maxit === "undefined") { maxit = 1000; } - var xs = [x0], ys = [y0], k1 = [f(x0,y0)], k2,k3,k4,k5,k6,k7, ymid = []; - var A2 = 1/5; - var A3 = [3/40,9/40]; - var A4 = [44/45,-56/15,32/9]; - var A5 = [19372/6561,-25360/2187,64448/6561,-212/729]; - var A6 = [9017/3168,-355/33,46732/5247,49/176,-5103/18656]; - var b = [35/384,0,500/1113,125/192,-2187/6784,11/84]; - var bm = [0.5*6025192743/30085553152, - 0, - 0.5*51252292925/65400821598, - 0.5*-2691868925/45128329728, - 0.5*187940372067/1594534317056, - 0.5*-1776094331/19743644256, - 0.5*11237099/235043384]; - var c = [1/5,3/10,4/5,8/9,1,1]; - var e = [-71/57600,0,71/16695,-71/1920,17253/339200,-22/525,1/40]; - var i = 0,er,j; - var h = (x1-x0)/10; - var it = 0; - var add = numeric.add, mul = numeric.mul, y1,erinf; - var min = Math.min, abs = Math.abs, norminf = numeric.norminf,pow = Math.pow; - var any = numeric.any, lt = numeric.lt, and = numeric.and, sub = numeric.sub; - var e0, e1, ev; - var ret = new numeric.Dopri(xs,ys,k1,ymid,-1,""); - if(typeof event === "function") e0 = event(x0,y0); - while(x0x1) h = x1-x0; - k2 = f(x0+c[0]*h, add(y0,mul( A2*h,k1[i]))); - k3 = f(x0+c[1]*h, add(add(y0,mul(A3[0]*h,k1[i])),mul(A3[1]*h,k2))); - k4 = f(x0+c[2]*h, add(add(add(y0,mul(A4[0]*h,k1[i])),mul(A4[1]*h,k2)),mul(A4[2]*h,k3))); - k5 = f(x0+c[3]*h, add(add(add(add(y0,mul(A5[0]*h,k1[i])),mul(A5[1]*h,k2)),mul(A5[2]*h,k3)),mul(A5[3]*h,k4))); - k6 = f(x0+c[4]*h,add(add(add(add(add(y0,mul(A6[0]*h,k1[i])),mul(A6[1]*h,k2)),mul(A6[2]*h,k3)),mul(A6[3]*h,k4)),mul(A6[4]*h,k5))); - y1 = add(add(add(add(add(y0,mul(k1[i],h*b[0])),mul(k3,h*b[2])),mul(k4,h*b[3])),mul(k5,h*b[4])),mul(k6,h*b[5])); - k7 = f(x0+h,y1); - er = add(add(add(add(add(mul(k1[i],h*e[0]),mul(k3,h*e[2])),mul(k4,h*e[3])),mul(k5,h*e[4])),mul(k6,h*e[5])),mul(k7,h*e[6])); - if(typeof er === "number") erinf = abs(er); - else erinf = norminf(er); - if(erinf > tol) { // reject - h = 0.2*h*pow(tol/erinf,0.25); - if(x0+h === x0) { - ret.msg = "Step size became too small"; - break; - } - continue; + + if(comparisons.length === 1) + return comparisons[0]; + + let result = new node$1.OperatorNode('and', 'and', comparisons.slice(0,2)); + for(let i=2; i0) xi = min(xi,(sr*e1[j]*xl-sl*e0[j]*xr)/(sr*e1[j]-sl*e0[j])); - } - } - if(xi <= xl || xi >= xr) break; - yi = ret._at(xi, i-1); - ei = event(xi,yi); - en = and(lt(e0,0),lt(0,ei)); - if(any(en)) { - xr = xi; - e1 = ei; - ev = en; - sr = 1.0; - if(side === -1) sl *= 0.5; - else sl = 1.0; - side = -1; - } else { - xl = xi; - e0 = ei; - sl = 1.0; - if(side === 1) sr *= 0.5; - else sr = 1.0; - side = 1; - } - } - y1 = ret._at(0.5*(x0+xi),i-1); - ret.f[i] = f(xi,yi); - ret.x[i] = xi; - ret.y[i] = yi; - ret.ymid[i-1] = y1; - ret.events = ev; - ret.iterations = it; - return ret; - } + if((typeof x !== 'number') && (typeof x !== 'string')) + throw Error("Set membership non-string variables not implemented for conversion to mathjs"); + x = this.convert(x); + + if(interval[0] !== 'interval') + throw Error("Set membership in non-intervals not implemented for conversion to mathjs"); + + let args = interval[1]; + let closed = interval[2]; + if(args[0] !== 'tuple' || closed[0] !== 'tuple') + throw new Error("Badly formed ast"); + + let a = this.convert(args[1]); + let b = this.convert(args[2]); + + let comparisons = []; + if(closed[1]) + comparisons.push(new node$1.OperatorNode('>=', 'largerEq', [x,a])); + else + comparisons.push(new node$1.OperatorNode('>', 'larger', [x,a])); + if(closed[2]) + comparisons.push(new node$1.OperatorNode('<=', 'smallerEq', [x,b])); + else + comparisons.push(new node$1.OperatorNode('<', 'smaller', [x,b])); + + let result = new node$1.OperatorNode('and', 'and', comparisons); + + if(operator === 'notin' || operator === 'notni') + result = new node$1.OperatorNode('not', 'not', [result]); + + return result; + } + + if(operator === 'subset' || operator === 'notsubset' || + operator === 'superset' || operator === 'notsuperset') { + + let big, small; + if(operator === 'subset' || operator === 'notsubset') { + small = operands[0]; + big = operands[1]; + }else{ + small = operands[1]; + big = operands[0]; + } + if(small[0] !== 'interval' || big[0] !== 'interval') + throw Error("Set containment of non-intervals not implemented for conversion to mathjs"); + + let small_args = small[1]; + let small_closed = small[2]; + let big_args = big[1]; + let big_closed = big[2]; + if(small_args[0] !== 'tuple' || small_closed[0] !== 'tuple' || + big_args[0] !== 'tuple' || big_closed[0] !== 'tuple') + throw Error("Badly formed ast"); + + let small_a = this.convert(small_args[1]); + let small_b = this.convert(small_args[2]); + let big_a = this.convert(big_args[1]); + let big_b = this.convert(big_args[2]); + + let comparisons = []; + if(small_closed[1] && !big_closed[1]) + comparisons.push(new node$1.OperatorNode('>', 'larger',[small_a,big_a])); + else + comparisons.push(new node$1.OperatorNode('>=', 'largerEq',[small_a,big_a])); + + if(small_closed[2] && !big_closed[2]) + comparisons.push(new node$1.OperatorNode('<', 'smaller',[small_b,big_b])); + else + comparisons.push(new node$1.OperatorNode('<=', 'smallerEq',[small_b,big_b])); + + let result = new node$1.OperatorNode('and', 'and', comparisons); + + if(operator === 'notsubset' || operator === 'notsuperset') + result = new node$1.OperatorNode('not', 'not', [result]); + + return result; + } + + if(operator === 'matrix') { + // Convert matrices into nested array nodes + // Will become matrix on eval + + let size = operands[0]; + let nrows = size[1]; + let ncols = size[2]; + + let entries = operands[1]; + + if(!Number.isInteger(nrows) || !Number.isInteger(ncols)) + throw Error('Matrix must have integer dimensions'); + + let result = []; + + for(let i=1; i <= nrows; i++) { + let row = []; + for(let j=1; j <= ncols; j++) { + row.push(this.convert(entries[i][j])); + } + result.push(new node$1.ArrayNode(row)); } - x0 += h; - y0 = y1; - e0 = e1; - h = min(0.8*h*pow(tol/erinf,0.25),4*h); - } - ret.iterations = it; - return ret; -}; - -// 11. Ax = b -numeric.LU = function(A, fast) { - fast = fast || false; - - var abs = Math.abs; - var i, j, k, absAjk, Akk, Ak, Pk, Ai; - var max; - var n = A.length, n1 = n-1; - var P = new Array(n); - if(!fast) A = numeric.clone(A); - - for (k = 0; k < n; ++k) { - Pk = k; - Ak = A[k]; - max = abs(Ak[k]); - for (j = k + 1; j < n; ++j) { - absAjk = abs(A[j][k]); - if (max < absAjk) { - max = absAjk; - Pk = j; - } - } - P[k] = Pk; - - if (Pk != k) { - A[k] = A[Pk]; - A[Pk] = Ak; - Ak = A[k]; - } - Akk = Ak[k]; + return new node$1.ArrayNode(result); - for (i = k + 1; i < n; ++i) { - A[i][k] /= Akk; - } + } - for (i = k + 1; i < n; ++i) { - Ai = A[i]; - for (j = k + 1; j < n1; ++j) { - Ai[j] -= Ai[k] * Ak[j]; - ++j; - Ai[j] -= Ai[k] * Ak[j]; + if (operator in operators$2) { + return operators$2[operator]( + operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); } - if(j===n1) Ai[j] -= Ai[k] * Ak[j]; + + throw Error("Operator " + operator + " not implemented for conversion to mathjs"); + } + + } - return { - LU: A, - P: P + var function_normalizations = { + ln: 'log', + arccos: 'acos', + arccosh: 'acosh', + arcsin: 'asin', + arcsinh: 'asinh', + arctan: 'atan', + arctanh: 'atanh', + arcsec: 'asec', + arcsech: 'asech', + arccsc: 'acsc', + arccsch: 'acsch', + arccot: 'acot', + arccoth: 'acoth', + cosec: 'csc', }; -}; -numeric.LUsolve = function LUsolve(LUP, b) { - var i, j; - var LU = LUP.LU; - var n = LU.length; - var x = numeric.clone(b); - var P = LUP.P; - var Pi, LUi, tmp; + function normalize_function_names(expr_or_tree) { + // replace "ln" with "log" + // "arccos" with "acos", etc. + // e^x with exp(x) + // sqrt(x) with x^0.5 - for (i=n-1;i!==-1;--i) x[i] = b[i]; - for (i = 0; i < n; ++i) { - Pi = P[i]; - if (P[i] !== i) { - tmp = x[i]; - x[i] = x[Pi]; - x[Pi] = tmp; - } + var tree = get_tree(expr_or_tree); + + if (!Array.isArray(tree)) + return tree; + + var operator = tree[0]; + var operands = tree.slice(1); + + if (operator === 'apply') { + if (operands[0] === 'sqrt') { + return ['^', normalize_function_names(operands[1]), 0.5]; + } - LUi = LU[i]; - for (j = 0; j < i; ++j) { - x[i] -= x[j] * LUi[j]; + var result = normalize_function_names_sub(operands[0]); + result = ['apply', result]; + + var args = operands.slice(1).map(function (v) { + return normalize_function_names(v); + }); + + if (args.length > 1) + args = ['tuple'].concat(args); + else + args = args[0]; + + result.push(args); + + return result; } + + if (operator === '^' && operands[0] === 'e' && math$19.define_e) + return ['apply', 'exp', normalize_function_names(operands[1])]; + + return [operator].concat(operands.map(function (v) { + return normalize_function_names(v) + })); } - for (i = n - 1; i >= 0; --i) { - LUi = LU[i]; - for (j = i + 1; j < n; ++j) { - x[i] -= x[j] * LUi[j]; + function normalize_function_names_sub(tree) { + + if (typeof tree === 'string') { + if (tree in function_normalizations) + return function_normalizations[tree]; + return tree; } - x[i] /= LUi[i]; + if (!Array.isArray(tree)) + return tree; + + var operator = tree[0]; + var operands = tree.slice(1); + + var result = [operator].concat(operands.map(function (v) { + return normalize_function_names_sub(v); + })); + + return result; } - return x; -}; -numeric.solve = function solve(A,b,fast) { return numeric.LUsolve(numeric.LU(A,fast), b); }; -// 12. Linear programming -numeric.echelonize = function echelonize(A) { - var s = numeric.dim(A), m = s[0], n = s[1]; - var I = numeric.identity(m); - var P = Array(m); - var i,j,k,l,Ai,Ii,Z,a; - var abs = Math.abs; - var diveq = numeric.diveq; - A = numeric.clone(A); - for(i=0;ia1) alpha = a1; - g = add(c,mul(alpha,p)); - H = dot(A1,A0); - for(i=m-1;i!==-1;--i) H[i][i] += 1; - d = solve(H,div(g,alpha),true); - var t0 = div(z,dot(A,d)); - var t = 1.0; - for(i=n-1;i!==-1;--i) if(t0[i]<0) t = min(t,-0.999*t0[i]); - y = sub(x,mul(d,t)); - z = sub(b,dot(A,y)); - if(!all(gt(z,0))) return { solution: x, message: "", iterations: count }; - x = y; - if(alpha=0) unbounded = false; - else unbounded = true; - } - if(unbounded) return { solution: y, message: "Unbounded", iterations: count }; - } - return { solution: x, message: "maximum iteration count exceeded", iterations:count }; -}; - -numeric._solveLP = function _solveLP(c,A,b,tol,maxit) { - var m = c.length, n = b.length,y; - var sum = numeric.sum, log = numeric.log, mul = numeric.mul, sub = numeric.sub, dot = numeric.dot, div = numeric.div, add = numeric.add; - var c0 = numeric.rep([m],0).concat([1]); - var J = numeric.rep([n,1],-1); - var A0 = numeric.blockMatrix([[A , J ]]); - var b0 = b; - var y = numeric.rep([m],0).concat(Math.max(0,numeric.sup(numeric.neg(b)))+1); - var x0 = numeric.__solveLP(c0,A0,b0,tol,maxit,y,false); - var x = numeric.clone(x0.solution); - x.length = m; - var foo = numeric.inf(sub(b,dot(A,x))); - if(foo<0) { return { solution: NaN, message: "Infeasible", iterations: x0.iterations }; } - var ret = numeric.__solveLP(c, A, b, tol, maxit-x0.iterations, x, true); - ret.iterations += x0.iterations; - return ret; -}; - -numeric.solveLP = function solveLP(c,A,b,Aeq,beq,tol,maxit) { - if(typeof maxit === "undefined") maxit = 1000; - if(typeof tol === "undefined") tol = numeric.epsilon; - if(typeof Aeq === "undefined") return numeric._solveLP(c,A,b,tol,maxit); - var m = Aeq.length, n = Aeq[0].length, o = A.length; - var B = numeric.echelonize(Aeq); - var flags = numeric.rep([n],0); - var P = B.P; - var Q = []; - var i; - for(i=P.length-1;i!==-1;--i) flags[P[i]] = 1; - for(i=n-1;i!==-1;--i) if(flags[i]===0) Q.push(i); - var g = numeric.getRange; - var I = numeric.linspace(0,m-1), J = numeric.linspace(0,o-1); - var Aeq2 = g(Aeq,I,Q), A1 = g(A,J,P), A2 = g(A,J,Q), dot = numeric.dot, sub = numeric.sub; - var A3 = dot(A1,B.I); - var A4 = sub(A2,dot(A3,Aeq2)), b4 = sub(b,dot(A3,beq)); - var c1 = Array(P.length), c2 = Array(Q.length); - for(i=P.length-1;i!==-1;--i) c1[i] = c[P[i]]; - for(i=Q.length-1;i!==-1;--i) c2[i] = c[Q[i]]; - var c4 = sub(c2,dot(c1,dot(B.I,Aeq2))); - var S = numeric._solveLP(c4,A4,b4,tol,maxit); - var x2 = S.solution; - if(x2!==x2) return S; - var x1 = dot(B.I,sub(beq,dot(Aeq2,x2))); - var x = Array(c.length); - for(i=P.length-1;i!==-1;--i) x[P[i]] = x1[i]; - for(i=Q.length-1;i!==-1;--i) x[Q[i]] = x2[i]; - return { solution: x, message:S.message, iterations: S.iterations }; -}; - -numeric.MPStoLP = function MPStoLP(MPS) { - if(MPS instanceof String) { MPS.split('\n'); } - var state = 0; - var states = ['Initial state','NAME','ROWS','COLUMNS','RHS','BOUNDS','ENDATA']; - var n = MPS.length; - var i,j,z,N=0,rows = {}, sign = [], rl = 0, vars = {}, nv = 0; - var name; - var c = [], A = [], b = []; - function err(e) { throw new Error('MPStoLP: '+e+'\nLine '+i+': '+MPS[i]+'\nCurrent state: '+states[state]+'\n'); } - for(i=0;i -// -// Math.seedrandom('yipee'); Sets Math.random to a function that is -// initialized using the given explicit seed. -// -// Math.seedrandom(); Sets Math.random to a function that is -// seeded using the current time, dom state, -// and other accumulated local entropy. -// The generated seed string is returned. -// -// Math.seedrandom('yowza', true); -// Seeds using the given explicit seed mixed -// together with accumulated entropy. -// -// -// Seeds using physical random bits downloaded -// from random.org. -// -// Seeds using urandom bits from call.jsonlib.com, -// which is faster than random.org. -// -// Examples: -// -// Math.seedrandom("hello"); // Use "hello" as the seed. -// document.write(Math.random()); // Always 0.5463663768140734 -// document.write(Math.random()); // Always 0.43973793770592234 -// var rng1 = Math.random; // Remember the current prng. -// -// var autoseed = Math.seedrandom(); // New prng with an automatic seed. -// document.write(Math.random()); // Pretty much unpredictable. -// -// Math.random = rng1; // Continue "hello" prng sequence. -// document.write(Math.random()); // Always 0.554769432473455 -// -// Math.seedrandom(autoseed); // Restart at the previous seed. -// document.write(Math.random()); // Repeat the 'unpredictable' value. -// -// Notes: -// -// Each time seedrandom('arg') is called, entropy from the passed seed -// is accumulated in a pool to help generate future seeds for the -// zero-argument form of Math.seedrandom, so entropy can be injected over -// time by calling seedrandom with explicit data repeatedly. -// -// On speed - This javascript implementation of Math.random() is about -// 3-10x slower than the built-in Math.random() because it is not native -// code, but this is typically fast enough anyway. Seeding is more expensive, -// especially if you use auto-seeding. Some details (timings on Chrome 4): -// -// Our Math.random() - avg less than 0.002 milliseconds per call -// seedrandom('explicit') - avg less than 0.5 milliseconds per call -// seedrandom('explicit', true) - avg less than 2 milliseconds per call -// seedrandom() - avg about 38 milliseconds per call -// -// LICENSE (BSD): -// -// Copyright 2010 David Bau, all rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of this module nor the names of its contributors may -// be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -/** - * All code is in an anonymous closure to keep the global namespace clean. - * - * @param {number=} overflow - * @param {number=} startdenom - */ - -// Patched by Seb so that seedrandom.js does not pollute the Math object. -// My tests suggest that doing Math.trouble = 1 makes Math lookups about 5% -// slower. -numeric.seedrandom = { pow:Math.pow, random:Math.random }; - -(function (pool, math, width, chunks, significance, overflow, startdenom) { - - -// -// seedrandom() -// This is the seedrandom function described above. -// -math['seedrandom'] = function seedrandom(seed, use_entropy) { - var key = []; - var arc4; - - // Flatten the seed string or build one from local entropy if needed. - seed = mixkey(flatten( - use_entropy ? [seed, pool] : - arguments.length ? seed : - [new Date().getTime(), pool, window], 3), key); - - // Use the seed to initialize an ARC4 generator. - arc4 = new ARC4(key); - - // Mix the randomness into accumulated entropy. - mixkey(arc4.S, pool); - - // Override Math.random - - // This function returns a random double in [0, 1) that contains - // randomness in every bit of the mantissa of the IEEE 754 value. - - math['random'] = function random() { // Closure to return a random double: - var n = arc4.g(chunks); // Start with a numerator n < 2 ^ 48 - var d = startdenom; // and denominator d = 2 ^ 48. - var x = 0; // and no 'extra last byte'. - while (n < significance) { // Fill up all significant digits by - n = (n + x) * width; // shifting numerator and - d *= width; // denominator and generating a - x = arc4.g(1); // new least-significant-byte. - } - while (n >= overflow) { // To avoid rounding up, before adding - n /= 2; // last byte, shift everything - d /= 2; // right using integer math until - x >>>= 1; // we have exactly the desired bits. - } - return (n + x) / d; // Form the number within [0, 1). - }; - - // Return the seed that was used - return seed; -}; - -// -// ARC4 -// -// An ARC4 implementation. The constructor takes a key in the form of -// an array of at most (width) integers that should be 0 <= x < (width). -// -// The g(count) method returns a pseudorandom integer that concatenates -// the next (count) outputs from ARC4. Its return value is a number x -// that is in the range 0 <= x < (width ^ count). -// -/** @constructor */ -function ARC4(key) { - var t, u, me = this, keylen = key.length; - var i = 0, j = me.i = me.j = me.m = 0; - me.S = []; - me.c = []; - - // The empty key [] is treated as [0]. - if (!keylen) { key = [keylen++]; } - - // Set up S using the standard key scheduling algorithm. - while (i < width) { me.S[i] = i++; } - for (i = 0; i < width; i++) { - t = me.S[i]; - j = lowbits(j + t + key[i % keylen]); - u = me.S[j]; - me.S[i] = u; - me.S[j] = t; - } - - // The "g" method returns the next (count) outputs as one number. - me.g = function getnext(count) { - var s = me.S; - var i = lowbits(me.i + 1); var t = s[i]; - var j = lowbits(me.j + t); var u = s[j]; - s[i] = u; - s[j] = t; - var r = s[lowbits(t + u)]; - while (--count) { - i = lowbits(i + 1); t = s[i]; - j = lowbits(j + t); u = s[j]; - s[i] = u; - s[j] = t; - r = r * width + s[lowbits(t + u)]; - } - me.i = i; - me.j = j; - return r; - }; - // For robust unpredictability discard an initial batch of values. - // See http://www.rsa.com/rsalabs/node.asp?id=2009 - me.g(width); -} - -// -// flatten() -// Converts an object tree to nested arrays of strings. -// -/** @param {Object=} result - * @param {string=} prop - * @param {string=} typ */ -function flatten(obj, depth, result, prop, typ) { - result = []; - typ = typeof(obj); - if (depth && typ == 'object') { - for (prop in obj) { - if (prop.indexOf('S') < 5) { // Avoid FF3 bug (local/sessionStorage) - try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} - } + function normalize_applied_functions(expr_or_tree) { + // normalize applied functions + // so that primes and powers occur outside function application + + var tree = get_tree(expr_or_tree); + + if (!Array.isArray(tree)) + return tree; + + var operator = tree[0]; + var operands = tree.slice(1); + + if (operator === 'apply') { + let result = strip_function_names(operands[0]); + let f_applied = ['apply', result.tree, operands[1]]; + for (let i = 0; i < result.n_primes; i++) + f_applied = ['prime', f_applied]; + + if (result.exponent !== undefined) + f_applied = ['^', f_applied, result.exponent]; + + return f_applied } + + var result = [operator].concat(operands.map(function (v, i) { return normalize_applied_functions(v); })); + return result; } - return (result.length ? result : obj + (typ != 'string' ? '\0' : '')); -} - -// -// mixkey() -// Mixes a string seed into a key that is an array of integers, and -// returns a shortened string seed that is equivalent to the result key. -// -/** @param {number=} smear - * @param {number=} j */ -function mixkey(seed, key, smear, j) { - seed += ''; // Ensure the seed is a string - smear = 0; - for (j = 0; j < seed.length; j++) { - key[lowbits(j)] = - lowbits((smear ^= key[lowbits(j)] * 19) + seed.charCodeAt(j)); - } - seed = ''; - for (j in key) { seed += String.fromCharCode(key[j]); } - return seed; -} - -// -// lowbits() -// A quick "n mod width" for width a power of 2. -// -function lowbits(n) { return n & (width - 1); } - -// -// The following constants are related to IEEE 754 limits. -// -startdenom = math.pow(width, chunks); -significance = math.pow(2, significance); -overflow = significance * 2; - -// -// When seedrandom.js is loaded, we immediately mix a few bits -// from the built-in RNG into the entropy pool. Because we do -// not want to intefere with determinstic PRNG state later, -// seedrandom will not call math.random on its own again after -// initialization. -// -mixkey(math.random(), pool); - -// End anonymous scope, and pass initial values. -}( - [], // pool: entropy pool starts empty - numeric.seedrandom, // math: package containing random, pow, and seedrandom - 256, // width: each RC4 output is 0 <= x < 256 - 6, // chunks: at least six RC4 outputs for each double - 52 // significance: there are 52 significant digits in a double - )); -/* This file is a slightly modified version of quadprog.js from Alberto Santini. - * It has been slightly modified by Sébastien Loisel to make sure that it handles - * 0-based Arrays instead of 1-based Arrays. - * License is in resources/LICENSE.quadprog */ -(function(exports) { - -function base0to1(A) { - if(typeof A !== "object") { return A; } - var ret = [], i,n=A.length; - for(i=0;i meq) { - work[l] = sum; - } else { - work[l] = -Math.abs(sum); - if (sum > 0) { - for (j = 1; j <= n; j = j + 1) { - amat[j][i] = -amat[j][i]; - } - bvec[i] = -bvec[i]; - } - } - } + } - for (i = 1; i <= nact; i = i + 1) { - work[iwsv + iact[i]] = 0; - } + var astToMathjs$1 = new astToMathjs({mathjs: math$19 }); - nvl = 0; - temp = 0; - for (i = 1; i <= q; i = i + 1) { - if (work[iwsv + i] < temp * work[iwnbv + i]) { - nvl = i; - temp = work[iwsv + i] / work[iwnbv + i]; - } - } - if (nvl === 0) { - return 999; - } + const f = function(expr_or_tree) { + var tree = get_tree(expr_or_tree); + + var mt = factorial_to_gamma_function( + astToMathjs$1.convert( + normalize_function_names( + normalize_applied_functions( + tree + ) + ) + ) + ); + + return mt.eval.bind(mt); + }; - return 0; + const evaluate = function(expr, bindings) { + return f(expr)(bindings); + }; + + // export const finite_field_evaluate = function(expr, bindings, modulus) { + // return parser.ast.to.finiteField( expr.tree, modulus )( bindings ); + // }; + + const evaluate_to_constant = function(expr_or_tree) { + // evaluate to number by converting tree to number + // and calling without arguments + + // return null if couldn't evaluate to constant (e.g., contains a variable) + // otherwise returns constant + // NOTE: constant could be a math.js complex number object + + var tree = get_tree(expr_or_tree); + + if(typeof tree === "number") { + return tree; + }else if(typeof tree === "string") { + if(tree === "pi" && math$19.define_pi) { + return Math.PI; + }else if(tree === "e" && math$19.define_e) { + return Math.E; + }else if(tree === "i" && math$19.define_i) { + return { re: 0, im: 1}; + } + return null; } - function fn_goto_55() { - for (i = 1; i <= n; i = i + 1) { - sum = 0; - for (j = 1; j <= n; j = j + 1) { - sum = sum + dmat[j][i] * amat[j][nvl]; - } - work[i] = sum; - } + var num=null; + try { + var the_f = f(expr_or_tree); + num = the_f(); + } + catch (e) {} + return num; + }; + + function factorial_to_gamma_function(math_tree) { + // convert factorial to gamma function + // so that can evaluate at complex numbers + var transformed = math_tree.transform(function (node, path, parent) { + if(node.isOperatorNode && node.op === "!" && node.fn === "factorial") { + var args = [new math$19.expression.node.OperatorNode( + '+', 'add', [node.args[0], + new math$19.expression.node.ConstantNode(1)])]; + return new math$19.expression.node.FunctionNode( + new math$19.expression.node.SymbolNode("gamma"),args); + } + else { + return node; + } + }); + return transformed; + } - l1 = iwzv; - for (i = 1; i <= n; i = i + 1) { - work[l1 + i] = 0; - } - for (j = nact + 1; j <= n; j = j + 1) { - for (i = 1; i <= n; i = i + 1) { - work[l1 + i] = work[l1 + i] + dmat[i][j] * work[j]; - } - } + var evaluation = /*#__PURE__*/Object.freeze({ + f: f, + evaluate: evaluate, + evaluate_to_constant: evaluate_to_constant + }); - t1inf = true; - for (i = nact; i >= 1; i = i - 1) { - sum = work[i]; - l = iwrm + (i * (i + 3)) / 2; - l1 = l - i; - for (j = i + 1; j <= nact; j = j + 1) { - sum = sum - work[l] * work[iwrv + j]; - l = l + j; - } - sum = sum / work[l1]; - work[iwrv + i] = sum; - if (iact[i] < meq) { - // continue; - break; - } - if (sum < 0) { - // continue; - break; - } - t1inf = false; - it1 = i; - } + // functions that map from one set to another + var functions$1 = { + C: {}, + R: {}, + nonzeroC: {}, + nonneg: {}, + pos: {}, + }; + + functions$1.C.nonneg = ["abs"]; + functions$1.C.nonzero = ["exp"]; + functions$1.C.R = ["abs", "arg"]; + functions$1.C.C = ["abs", "arg", "exp", "sign", "cos", "cosh", "sin", "sinh", + "erf", "sqrt", "log", "ln", "log10"]; + functions$1.R.pos = ["exp"]; + functions$1.R.nonneg = ["abs", "exp", "arg"]; + functions$1.R.R = ["abs", "arg", "exp", "sign", "cos", "cosh", "sin", "sinh", + "erf"]; + functions$1.R.Z = ["sign"]; + functions$1.nonzeroC.pos = ["abs"]; + functions$1.nonneg.nonneg = ["abs", "exp", "arg", "sqrt", "erf"]; + functions$1.nonzeroC.nonzero = ["abs"]; + functions$1.nonneg.R = [...new Set(functions$1.R.R.concat( + functions$1.nonneg.nonneg))]; + functions$1.pos.pos = ["abs", "exp", "sqrt", "erf"]; + functions$1.pos.nonneg = functions$1.pos.pos; + functions$1.pos.nonzero = ["abs", "exp", "sqrt", "erf"]; + functions$1.pos.R = functions$1.nonneg.R.concat(["log", "ln", "log10"]); + + + function negate_adjust(result, negate_assumptions) { + if(result) + return !negate_assumptions; + if(result===false) + return negate_assumptions; + return undefined + } + + function narrow_assumptions(assumptions, original_assumptions) { + // find part of original assumptions after remove assumptions + + if(!Array.isArray(original_assumptions)) + return []; + + var operator = original_assumptions[0]; + var operands = original_assumptions.slice(1); + if(operator !== 'and') + return []; + + var remaining_assumptions = []; + + for(var i=0; i= nact + 1; i = i - 1) { - if (work[i] === 0) { - // continue; - break; - } - gc = Math.max(Math.abs(work[i - 1]), Math.abs(work[i])); - gs = Math.min(Math.abs(work[i - 1]), Math.abs(work[i])); - if (work[i - 1] >= 0) { - temp = Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); - } else { - temp = -Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); - } - gc = work[i - 1] / temp; - gs = work[i] / temp; + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions(tree); + if(!Array.isArray(assume)) + return undefined; + + let assume_with_negations = assume; + + let assume_operator = assume[0]; + let assume_operands = assume.slice(1); + + let negate_assumptions = false; + while(assume_operator === 'not') { + negate_assumptions = !negate_assumptions; + assume = assume_operands[0]; + if(!Array.isArray(assume)) + return undefined; + assume_operator = assume[0]; + assume_operands = assume.slice(1); + } - if (gc === 1) { - // continue; - break; - } - if (gc === 0) { - work[i - 1] = gs * temp; - for (j = 1; j <= n; j = j + 1) { - temp = dmat[j][i - 1]; - dmat[j][i - 1] = dmat[j][i]; - dmat[j][i] = temp; - } - } else { - work[i - 1] = temp; - nu = gs / (1 + gc); - for (j = 1; j <= n; j = j + 1) { - temp = gc * dmat[j][i - 1] + gs * dmat[j][i]; - dmat[j][i] = nu * (dmat[j][i - 1] + temp) - dmat[j][i]; - dmat[j][i - 1] = temp; - - } - } - } - work[l] = work[nact]; - } - } else { - sum = -bvec[nvl]; - for (j = 1; j <= n; j = j + 1) { - sum = sum + sol[j] * amat[j][nvl]; - } - if (nvl > meq) { - work[iwsv + nvl] = sum; - } else { - work[iwsv + nvl] = -Math.abs(sum); - if (sum > 0) { - for (j = 1; j <= n; j = j + 1) { - amat[j][nvl] = -amat[j][nvl]; - } - bvec[nvl] = -bvec[nvl]; - } - } - // GOTO 700 - return 700; - } - } + if(assume_operator === 'in') + if(assume_operands[0]===tree && assume_operands[1] === 'Z') + return negate_adjust(true, negate_assumptions); + if(assume_operator === 'notin') + if(assume_operands[0]===tree && assume_operands[1] === 'Z') + return negate_adjust(false, negate_assumptions); - return 0; - } - function fn_goto_797() { - l = iwrm + (it1 * (it1 + 1)) / 2 + 1; - l1 = l + it1; - if (work[l1] === 0) { - // GOTO 798 - return 798; - } - gc = Math.max(Math.abs(work[l1 - 1]), Math.abs(work[l1])); - gs = Math.min(Math.abs(work[l1 - 1]), Math.abs(work[l1])); - if (work[l1 - 1] >= 0) { - temp = Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); - } else { - temp = -Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); - } - gc = work[l1 - 1] / temp; - gs = work[l1] / temp; + // haven't negated, then determining tree is not real or complex + // means it is not an integer + if(negate_assumptions===false) { + if(assume_operator === 'notin') { + if(assume_operands[0]===tree && assume_operands[1] === 'R') + return false; + if(assume_operands[0]===tree && assume_operands[1] === 'C') + return false; + } + } + // if have negated, then determining tree is real or complex + // means it is not an integer + else { + if(assume_operator === 'in') { + if(assume_operands[0]===tree && assume_operands[1] === 'R') + return false; + if(assume_operands[0]===tree && assume_operands[1] === 'Z') + return false; + } + } + // assume equality has been expanded so that has two arguments + if((assume_operator === '=' && !negate_assumptions) || + (assume_operator === 'ne' && negate_assumptions)) { + // if assumption is "tree=something" + // check if something is integer + // (but without the assumption to avoid infinite loop) + + let new_assumptions = narrow_assumptions(assume_with_negations, + original_assumptions); + if(assume_operands[0]===tree) + return is_integer_ast(assume_operands[1], new_assumptions); + if(assume_operands[1]===tree) + return is_integer_ast(assume_operands[0], new_assumptions); + } - if (gc === 1) { - // GOTO 798 - return 798; - } - if (gc === 0) { - for (i = it1 + 1; i <= nact; i = i + 1) { - temp = work[l1 - 1]; - work[l1 - 1] = work[l1]; - work[l1] = temp; - l1 = l1 + i; - } - for (i = 1; i <= n; i = i + 1) { - temp = dmat[i][it1]; - dmat[i][it1] = dmat[i][it1 + 1]; - dmat[i][it1 + 1] = temp; - } - } else { - nu = gs / (1 + gc); - for (i = it1 + 1; i <= nact; i = i + 1) { - temp = gc * work[l1 - 1] + gs * work[l1]; - work[l1] = nu * (work[l1 - 1] + temp) - work[l1]; - work[l1 - 1] = temp; - l1 = l1 + i; - } - for (i = 1; i <= n; i = i + 1) { - temp = gc * dmat[i][it1] + gs * dmat[i][it1 + 1]; - dmat[i][it1 + 1] = nu * (dmat[i][it1] + temp) - dmat[i][it1 + 1]; - dmat[i][it1] = temp; - } - } + // if isn't a simple And or Or, just give up + if(assume_operator !== 'and' && assume_operator !== 'or') + return undefined; - return 0; - } + // shouldn't have negated assumptions + if(negate_assumptions) + return undefined; - function fn_goto_798() { - l1 = l - it1; - for (i = 1; i <= it1; i = i + 1) { - work[l1] = work[l]; - l = l + 1; - l1 = l1 + 1; - } + // if more than two operands, unflatten + // (OK, since not attempting logic where only combined restrictions + // lead to a passing test) + if(assume_operands.length > 2) { + assume = unflattenRight(assume); + assume_operands = assume.slice(1); + } - work[iwuv + it1] = work[iwuv + it1 + 1]; - iact[it1] = iact[it1 + 1]; - it1 = it1 + 1; - if (it1 < nact) { - // GOTO 797 - return 797; - } + let result_left = is_integer_ast(tree, assume_operands[0], + original_assumptions); + let result_right = is_integer_ast(tree, assume_operands[1], + original_assumptions); + return simple_assumption_combination(assume_operator, result_left, + result_right) + } - return 0; - } + if(Array.isArray(tree)) { - function fn_goto_799() { - work[iwuv + nact] = work[iwuv + nact + 1]; - work[iwuv + nact + 1] = 0; - iact[nact] = 0; - nact = nact - 1; - iter[2] = iter[2] + 1; + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions([variables(tree)]); - return 0; - } + let operator = tree[0]; + let operands = tree.slice(1); - go = 0; - while (true) { - go = fn_goto_50(); - if (go === 999) { - return; - } - while (true) { - go = fn_goto_55(); - if (go === 0) { - break; - } - if (go === 999) { - return; - } - if (go === 700) { - if (it1 === nact) { - fn_goto_799(); - } else { - while (true) { - fn_goto_797(); - go = fn_goto_798(); - if (go !== 797) { - break; - } - } - fn_goto_799(); - } - } - } - } + if(operator === '-') + return is_integer_ast(operands[0], assume, original_assumptions); -} + if(operator === '*') { -function solveQP(Dmat, dvec, Amat, bvec, meq, factorized) { - Dmat = base0to1(Dmat); - dvec = base0to1(dvec); - Amat = base0to1(Amat); - var i, n, q, - nact, r, - crval = [], iact = [], sol = [], work = [], iter = [], - message; + let all_integers = operands.every( + function (v) { + return is_integer_ast(v, assume, original_assumptions); + }); - meq = meq || 0; - factorized = factorized ? base0to1(factorized) : [undefined, 0]; - bvec = bvec ? base0to1(bvec) : []; + if(all_integers) + return true; + else { + return undefined; - // In Fortran the array index starts from 1 - n = Dmat.length - 1; - q = Amat[1].length - 1; + } + } - if (!bvec) { - for (i = 1; i <= q; i = i + 1) { - bvec[i] = 0; - } - } - for (i = 1; i <= q; i = i + 1) { - iact[i] = 0; - } - nact = 0; - r = Math.min(n, q); - for (i = 1; i <= n; i = i + 1) { - sol[i] = 0; - } - crval[1] = 0; - for (i = 1; i <= (2 * n + (r * (r + 5)) / 2 + 2 * q + 1); i = i + 1) { - work[i] = 0; - } - for (i = 1; i <= 2; i = i + 1) { - iter[i] = 0; - } + if(operator === '^') { - qpgen2(Dmat, dvec, n, n, sol, crval, Amat, - bvec, n, q, meq, iact, nact, iter, work, factorized); + let base_nonzero = is_nonzero_ast(operands[0], assume, + original_assumptions); - message = ""; - if (factorized[1] === 1) { - message = "constraints are inconsistent, no solution!"; - } - if (factorized[1] === 2) { - message = "matrix D in quadratic function is not positive definite!"; - } + if(!base_nonzero) { + // if base is NaN, return false + if(Number.isNaN(operands[0])) + return false; - return { - solution: base1to0(sol), - value: base1to0(crval), - unconstrained_solution: base1to0(dvec), - iterations: base1to0(iter), - iact: base1to0(iact), - message: message - }; -} -exports.solveQP = solveQP; -}(numeric)); -/* -Shanti Rao sent me this routine by private email. I had to modify it -slightly to work on Arrays instead of using a Matrix object. -It is apparently translated from http://stitchpanorama.sourceforge.net/Python/svd.py -*/ - -numeric.svd= function svd(A) { - var temp; -//Compute the thin SVD from G. H. Golub and C. Reinsch, Numer. Math. 14, 403-420 (1970) - var prec= numeric.epsilon; //Math.pow(2,-52) // assumes double prec - var tolerance= 1.e-64/prec; - var itmax= 50; - var c=0; - var i=0; - var j=0; - var k=0; - var l=0; - - var u= numeric.clone(A); - var m= u.length; - - var n= u[0].length; - - if (m < n) throw "Need more rows than columns" - - var e = new Array(n); - var q = new Array(n); - for (i=0; i b) - return a*Math.sqrt(1.0+(b*b/a/a)) - else if (b == 0.0) - return a - return b*Math.sqrt(1.0+(a*a/b/b)) - } - - //Householder's reduction to bidiagonal form - - var f= 0.0; - var g= 0.0; - var h= 0.0; - var x= 0.0; - var y= 0.0; - var z= 0.0; - var s= 0.0; - - for (i=0; i < n; i++) - { - e[i]= g; - s= 0.0; - l= i+1; - for (j=i; j < m; j++) - s += (u[j][i]*u[j][i]); - if (s <= tolerance) - g= 0.0; - else - { - f= u[i][i]; - g= Math.sqrt(s); - if (f >= 0.0) g= -g; - h= f*g-s; - u[i][i]=f-g; - for (j=l; j < n; j++) - { - s= 0.0; - for (k=i; k < m; k++) - s += u[k][i]*u[k][j]; - f= s/h; - for (k=i; k < m; k++) - u[k][j]+=f*u[k][i]; - } - } - q[i]= g; - s= 0.0; - for (j=l; j < n; j++) - s= s + u[i][j]*u[i][j]; - if (s <= tolerance) - g= 0.0; - else - { - f= u[i][i+1]; - g= Math.sqrt(s); - if (f >= 0.0) g= -g; - h= f*g - s; - u[i][i+1] = f-g; - for (j=l; j < n; j++) e[j]= u[i][j]/h; - for (j=l; j < m; j++) - { - s=0.0; - for (k=l; k < n; k++) - s += (u[j][k]*u[i][k]); - for (k=l; k < n; k++) - u[j][k]+=s*e[k]; - } - } - y= Math.abs(q[i])+Math.abs(e[i]); - if (y>x) - x=y; - } - - // accumulation of right hand gtransformations - for (i=n-1; i != -1; i+= -1) - { - if (g != 0.0) - { - h= g*u[i][i+1]; - for (j=l; j < n; j++) - v[j][i]=u[i][j]/h; - for (j=l; j < n; j++) - { - s=0.0; - for (k=l; k < n; k++) - s += u[i][k]*v[k][j]; - for (k=l; k < n; k++) - v[k][j]+=(s*v[k][i]); - } - } - for (j=l; j < n; j++) - { - v[i][j] = 0; - v[j][i] = 0; - } - v[i][i] = 1; - g= e[i]; - l= i; - } - - // accumulation of left hand transformations - for (i=n-1; i != -1; i+= -1) - { - l= i+1; - g= q[i]; - for (j=l; j < n; j++) - u[i][j] = 0; - if (g != 0.0) - { - h= u[i][i]*g; - for (j=l; j < n; j++) - { - s=0.0; - for (k=l; k < m; k++) s += u[k][i]*u[k][j]; - f= s/h; - for (k=i; k < m; k++) u[k][j]+=f*u[k][i]; - } - for (j=i; j < m; j++) u[j][i] = u[j][i]/g; - } - else - for (j=i; j < m; j++) u[j][i] = 0; - u[i][i] += 1; - } - - // diagonalization of the bidiagonal form - prec= prec*x; - for (k=n-1; k != -1; k+= -1) - { - for (var iteration=0; iteration < itmax; iteration++) - { // test f splitting - var test_convergence = false; - for (l=k; l != -1; l+= -1) - { - if (Math.abs(e[l]) <= prec) - { test_convergence= true; - break - } - if (Math.abs(q[l-1]) <= prec) - break - } - if (!test_convergence) - { // cancellation of e[l] if l>0 - c= 0.0; - s= 1.0; - var l1= l-1; - for (i =l; i= itmax-1) - throw 'Error: no convergence.' - // shift from bottom 2x2 minor - x= q[l]; - y= q[k-1]; - g= e[k-1]; - h= e[k]; - f= ((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); - g= pythag(f,1.0); - if (f < 0.0) - f= ((x-z)*(x+z)+h*(y/(f-g)-h))/x; - else - f= ((x-z)*(x+z)+h*(y/(f+g)-h))/x; - // next QR transformation - c= 1.0; - s= 1.0; - for (i=l+1; i< k+1; i++) - { - g= e[i]; - y= q[i]; - h= s*g; - g= c*g; - z= pythag(f,h); - e[i-1]= z; - c= f/z; - s= h/z; - f= x*c+g*s; - g= -x*s+g*c; - h= y*s; - y= y*c; - for (j=0; j < n; j++) - { - x= v[j][i-1]; - z= v[j][i]; - v[j][i-1] = x*c+z*s; - v[j][i] = -x*s+z*c; - } - z= pythag(f,h); - q[i-1]= z; - c= f/z; - s= h/z; - f= c*g+s*y; - x= -s*g+c*y; - for (j=0; j < m; j++) - { - y= u[j][i-1]; - z= u[j][i]; - u[j][i-1] = y*c+z*s; - u[j][i] = -y*s+z*c; - } - } - e[l]= 0.0; - e[k]= f; - q[k]= x; - } - } - - //vt= transpose(v) - //return (u,q,vt) - for (i=0;i= 0; j--) - { - if (q[j] < q[i]) - { - // writeln(i,'-',j) - c = q[j]; - q[j] = q[i]; - q[i] = c; - for(k=0;k math.pow === pow_strict_f; + } + else { // nonzero base + let pow_nonzero = is_nonzero_ast(operands[1], assume, + original_assumptions); + if(pow_nonzero === false) { + // infinity^0 is undefined + if(operands[0] === Infinity || operands[0] === -Infinity) + return false; - Object.defineProperty(math, 'pow_strict', { - get: is_pow_strict, - set: set_pow_strict, - }); + return true; // nonzero^0 + } - math.pow_strict = true; + } + let base_integer = is_integer_ast(operands[0], assume, + original_assumptions); + let pow_integer = is_integer_ast(operands[1], assume, + original_assumptions); - function set_define_e(bool) { - if(bool) - math.config({define_e: true}); - else - math.config({define_e: false}); - } - var get_define_e = () => math.config().define_e!==false; - function set_define_i(bool) { - if(bool) - math.config({define_i: true}); - else - math.config({define_i: false}); - } - var get_define_i = () => math.config().define_i!==false; - function set_define_pi(bool) { - if(bool) - math.config({define_pi: true}); - else - math.config({define_pi: false}); - } - var get_define_pi = () => math.config().define_pi!==false; + if(!base_integer) + return base_integer; - Object.defineProperty(math, 'define_e', { - get: get_define_e, - set: set_define_e, - }); - Object.defineProperty(math, 'define_i', { - get: get_define_i, - set: set_define_i, - }); - Object.defineProperty(math, 'define_pi', { - get: get_define_pi, - set: set_define_pi, - }); + if(!pow_integer) + return undefined; // don't check for cases like 9^(1/2) - return math; -} + let pow_nonneg= is_positive_ast(operands[1], assume, false, + original_assumptions); -// return a new instance of math.js -var math$19 = create$2(); + if(pow_nonneg) + return true; + else + return undefined; -function leaves( tree, include_subscripts ) { - if(!Array.isArray(tree)) - return [tree]; - var operator = tree[0]; - var operands = tree.slice(1); + } + if(operator === '+') { + + let n_non_integers=0; + + for(let i=0; i < operands.length; i++) { + let result = is_integer_ast(operands[i], assume, + original_assumptions); + + if(result === false) { + if(n_non_integers > 0) + return undefined; + n_non_integers += 1; + } + if(result === undefined) + return undefined; + } + + if(n_non_integers === 0) + return true; + else // only one non-integer + return false; + } - if(include_subscripts && operator === '_') { - if(typeof operands[0] === "string" && - ((typeof operands[1] === "string") || (typeof operands[1] === "number"))) - return [operands[0] + "_"+ operands[1]]; - } - if(operator === "apply") { - operands = tree.slice(2); - } - if(operands.length === 0) - return []; + // check for functions that map certain sets to integers + if(operator === 'apply') { + if(functions$1.C.Z && functions$1.C.Z.includes(operands[0]) && + is_complex_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.R.Z && functions$1.R.Z.includes(operands[0]) && + is_real_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.nonzeroC.Z && functions$1.nonzeroC.Z.includes(operands[0]) + && is_nonzero_ast(operands[1], assume, original_assumptions) + && is_complex_ast(operands[1], assume, original_assumptions) + ) + return true; + if(functions$1.nonneg.Z && functions$1.nonneg.Z.includes(operands[0]) && + is_positive_ast(operands[1], assume, false, original_assumptions)) + return true; + if(functions$1.pos.Z && functions$1.pos.Z.includes(operands[0]) && + is_positive_ast(operands[1], assume, true, original_assumptions)) + return true; + return undefined; + } - return operands.map( function(v,i) { return leaves(v, include_subscripts); } ) - .reduce( function(a,b) { return a.concat(b); } ); + if(operator === '/' || operator === 'prime') + return undefined; -} + // other operators don't return numbers + return false; + } -function variables( expr_or_tree, include_subscripts = false ) { + return false; + } - var tree = get_tree(expr_or_tree); - var result = leaves( tree, include_subscripts ); + function is_real_ast(tree, assumptions, original_assumptions) { + // see description of is_real - result = result.filter( function(v,i) { - return (typeof v === 'string') && - (math$19.define_e || (v !== "e")) && - (math$19.define_pi || (v !== "pi")) && - (math$19.define_i || (v !== "i")); - }); + if(typeof assumptions !== 'object') + assumptions = []; - result = result.filter(function(itm,i,a){ - return i === result.indexOf(itm); - }); + if(original_assumptions===undefined) + original_assumptions = assumptions; - return result; -} + if(typeof tree === 'number') + return Number.isFinite(tree); -function operators_list( tree ) { - if (!Array.isArray(tree)) - return []; + // if can convert to constant, evaluate directly + var c = evaluate_to_constant(tree); - var operator = tree[0]; - var operands = tree.slice(1); + if(c !== null) { + if(typeof c === 'number') { + return Number.isFinite(c); + } + return false; + } - if(operator === "apply") { - operands = tree.slice(2); - } - if(operands.length === 0) - return [operator]; + if(typeof tree === 'string') { - return [operator].concat( - operands.map( function(v,i) { return operators_list(v); } ) - .reduce( function(a,b) { return a.concat(b); } )); + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions(tree); -} + if(!Array.isArray(assume)) + return undefined; -function operators$1( expr_or_tree ) { + let assume_with_negations = assume; - var tree = get_tree(expr_or_tree); + let assume_operator = assume[0]; + let assume_operands = assume.slice(1); - var result = operators_list( tree ); + let negate_assumptions = false; + while(assume_operator === 'not') { + negate_assumptions = !negate_assumptions; + assume = assume_operands[0]; + if(!Array.isArray(assume)) + return undefined; + assume_operator = assume[0]; + assume_operands = assume.slice(1); + } - result = result.filter( function(v,i) { - return (v !== 'apply'); - }); + if(assume_operator === 'in') + if(assume_operands[0]===tree && assume_operands[1] === 'R') + return negate_adjust(true, negate_assumptions); + if(assume_operator === 'notin') + if(assume_operands[0]===tree && assume_operands[1] === 'R') + return negate_adjust(false, negate_assumptions); + // haven't negated, then determining tree is integer means it is real + if(negate_assumptions===false) { + if(assume_operator === 'in') + if(assume_operands[0]===tree && assume_operands[1] === 'Z') + return true; + } + // if have negated, then determining tree is not integer, + // means it is an integer, hence real + else { + if(assume_operator === 'notin') + if(assume_operands[0]===tree && assume_operands[1] === 'Z') + return true; + } - result = result.filter(function(itm,i,a){ - return i === result.indexOf(itm); - }); + // if assumptions is an inequality involving variable + // then return true + if(assume_operator === '<' || assume_operator === 'le') { - return result; -} + let variables_in_inequality = variables(assume); + let functions_in_inequality = functions(assume); -function functions_list( tree ) { - if (typeof tree === 'number') { - return []; - } + if(variables_in_inequality.indexOf(tree) !== -1 + && functions_in_inequality.length === 0) + return true; // don't negate adjust + } - if (typeof tree === 'string') { - return []; - } + // assume equality has been expanded so that has two arguments + if((assume_operator === '=' && !negate_assumptions) || + (assume_operator === 'ne' && negate_assumptions)) { + // if assumption is "tree=something" + // check if something is real + // (but without the assumption to avoid infinite loop) + + let new_assumptions = narrow_assumptions(assume_with_negations, + original_assumptions); + if(assume_operands[0]===tree) + return is_real_ast(assume_operands[1], new_assumptions); + if(assume_operands[1]===tree) + return is_real_ast(assume_operands[0], new_assumptions); + } - if (typeof tree === 'boolean') { - return []; - } - var operator = tree[0]; - var operands = tree.slice(1); + // if isn't a simple And or Or, just give up + if(assume_operator !== 'and' && assume_operator !== 'or') + return undefined; - var functions = []; - if(operator === "apply") { - functions = [operands[0]]; - operands = tree.slice(2); - } + // shouldn't have negated assumptions + if(negate_assumptions) + return undefined; - return functions.concat( - operands.map( function(v,i) { return functions_list(v); } ) - .reduce( function(a,b) { return a.concat(b); } )); + // if more than two operands, unflatten + // (OK, since not attempting logic where only combined restrictions + // lead to a passing test) + if(assume_operands.length > 2) { + assume = unflattenRight(assume); + assume_operands = assume.slice(1); + } -} + let result_left = is_real_ast(tree, assume_operands[0], + original_assumptions); + let result_right = is_real_ast(tree, assume_operands[1], + original_assumptions); -function functions( expr_or_tree ) { + return simple_assumption_combination(assume_operator, result_left, + result_right) + } - var tree = get_tree(expr_or_tree); + if(Array.isArray(tree)) { - var result = functions_list( tree ); + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions([variables(tree)]); - result = result.filter(function(itm,i,a){ - return i === result.indexOf(itm); - }); - return result; -} - -var variables$1 = /*#__PURE__*/Object.freeze({ - variables: variables, - operators: operators$1, - functions: functions -}); - -var underscore = createCommonjsModule(function (module, exports) { -// Underscore.js 1.8.3 -// http://underscorejs.org -// (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors -// Underscore may be freely distributed under the MIT license. - -(function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `exports` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var - push = ArrayProto.push, - slice = ArrayProto.slice, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind, - nativeCreate = Object.create; - - // Naked function reference for surrogate-prototype-swapping. - var Ctor = function(){}; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { - if (obj instanceof _) return obj; - if (!(this instanceof _)) return new _(obj); - this._wrapped = obj; - }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object. - { - if ('object' !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } + let operator = tree[0]; + let operands = tree.slice(1); - // Current version. - _.VERSION = '1.8.3'; + if(operator === '-') { + return is_real_ast(operands[0], assume, original_assumptions); + } + if(operator === '*' || operator === '+') { + + // if more than two terms, unflatten + if(operands.length > 2) { + tree = unflattenRight(tree); + operands = tree.slice(1); + } + + if(operator==='*') { + // one confirmed zero factor makes product zero + if((is_nonzero_ast(operands[0], assume, original_assumptions) + === false) || + (is_nonzero_ast(operands[1], assume, original_assumptions) + === false)) + return true; + } + + let left_real = is_real_ast(operands[0], assume, + original_assumptions); + let right_real = is_real_ast(operands[1], assume, + original_assumptions); + + if(left_real && right_real) + return true; + + // can confirm that is not real + // if one term/factor is real and the other is not real + if((left_real && right_real===false) || + (right_real && left_real===false)) + return false + + return undefined; - // Internal function that returns an efficient (for current engines) version - // of the passed-in callback, to be repeatedly applied in other Underscore - // functions. - var optimizeCb = function(func, context, argCount) { - if (context === void 0) return func; - switch (argCount == null ? 3 : argCount) { - case 1: return function(value) { - return func.call(context, value); - }; - case 2: return function(value, other) { - return func.call(context, value, other); - }; - case 3: return function(value, index, collection) { - return func.call(context, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(context, accumulator, value, index, collection); - }; - } - return function() { - return func.apply(context, arguments); - }; - }; + } - // A mostly-internal function to generate callbacks that can be applied - // to each element in a collection, returning the desired result — either - // identity, an arbitrary callback, a property matcher, or a property accessor. - var cb = function(value, context, argCount) { - if (value == null) return _.identity; - if (_.isFunction(value)) return optimizeCb(value, context, argCount); - if (_.isObject(value)) return _.matcher(value); - return _.property(value); - }; - _.iteratee = function(value, context) { - return cb(value, context, Infinity); - }; + if(operator === '^') { - // An internal function for creating assigner functions. - var createAssigner = function(keysFunc, undefinedOnly) { - return function(obj) { - var length = arguments.length; - if (length < 2 || obj == null) return obj; - for (var index = 1; index < length; index++) { - var source = arguments[index], - keys = keysFunc(source), - l = keys.length; - for (var i = 0; i < l; i++) { - var key = keys[i]; - if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; - } - } - return obj; - }; - }; + let base_nonzero = is_nonzero_ast(operands[0], assume, + original_assumptions); + let pow_positive = is_positive_ast(operands[1], assume, true, + original_assumptions); - // An internal function for creating a new object that inherits from another. - var baseCreate = function(prototype) { - if (!_.isObject(prototype)) return {}; - if (nativeCreate) return nativeCreate(prototype); - Ctor.prototype = prototype; - var result = new Ctor; - Ctor.prototype = null; - return result; - }; + if(!base_nonzero) { + // if base is NaN, return false + if(Number.isNaN(operands[0])) + return false; - var property = function(key) { - return function(obj) { - return obj == null ? void 0 : obj[key]; - }; - }; + if(pow_positive) { + if(base_nonzero === false) + return true; // 0^positive + } + else { + return undefined; // (possibly zero)^(possibly nonpositive) + } + + } + else { // nonzero base + let pow_nonzero = is_nonzero_ast(operands[1], assume, + original_assumptions); + if(pow_nonzero === false) { + // infinity^0 is undefined + if(operands[0] === Infinity || operands[0] === -Infinity) + return false; + + return true; // nonzero^0 + } + + } + + let base_real = is_real_ast(operands[0], assume, + original_assumptions); + let pow_real = is_real_ast(operands[1], assume, + original_assumptions); + + if(!(base_real && pow_real)) + return undefined; + + let base_nonnegative = is_positive_ast(operands[0], assume, false, + original_assumptions); + + if(!base_nonnegative) { + // if base might be negative + // then power must be an integer + // (already excluded 0^0) + + let pow_integer = is_integer_ast(operands[1], assume, + original_assumptions); + if(pow_integer) + return true; + else + return undefined + } + + let base_positive = is_positive_ast(operands[0], assume, true, + original_assumptions); + + if(!base_positive) { + // if base might be zero + // then power must be positive + if(pow_positive) + return true; + else + return undefined; + } + + // base is positive, power is real + return true; - // Helper for collection methods to determine whether a collection - // should be iterated as an array or as an object - // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength - // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 - var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; - var getLength = property('length'); - var isArrayLike = function(collection) { - var length = getLength(collection); - return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; - }; + } - // Collection Functions - // -------------------- + if(operator === '/') { + // if can't be sure denominator is nonzero + if(!is_nonzero_ast(operands[1], assume, original_assumptions)) + return undefined; - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles raw objects in addition to array-likes. Treats all - // sparse array-likes as if they were dense. - _.each = _.forEach = function(obj, iteratee, context) { - iteratee = optimizeCb(iteratee, context); - var i, length; - if (isArrayLike(obj)) { - for (i = 0, length = obj.length; i < length; i++) { - iteratee(obj[i], i, obj); - } - } else { - var keys = _.keys(obj); - for (i = 0, length = keys.length; i < length; i++) { - iteratee(obj[keys[i]], keys[i], obj); - } - } - return obj; - }; + // zero numerator + if(is_nonzero_ast(operands[0], assume, original_assumptions) === false) + return true; - // Return the results of applying the iteratee to each element. - _.map = _.collect = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length, - results = Array(length); - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - results[index] = iteratee(obj[currentKey], currentKey, obj); - } - return results; - }; + if(!(is_real_ast(operands[0], assume, original_assumptions) + && is_real_ast(operands[1], assume, original_assumptions))) + return undefined; - // Create a reducing function iterating left or right. - function createReduce(dir) { - // Optimized iterator function as using arguments.length - // in the main function will deoptimize the, see #1991. - function iterator(obj, iteratee, memo, keys, index, length) { - for (; index >= 0 && index < length; index += dir) { - var currentKey = keys ? keys[index] : index; - memo = iteratee(memo, obj[currentKey], currentKey, obj); - } - return memo; - } + return true; - return function(obj, iteratee, memo, context) { - iteratee = optimizeCb(iteratee, context, 4); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length, - index = dir > 0 ? 0 : length - 1; - // Determine the initial value if none is provided. - if (arguments.length < 3) { - memo = obj[keys ? keys[index] : index]; - index += dir; + } + + // check for functions that map certain sets to reals + if(operator === 'apply') { + if(functions$1.C.R && functions$1.C.R.includes(operands[0]) && + is_complex_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.R.R && functions$1.R.R.includes(operands[0]) && + is_real_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.nonzeroC.R && functions$1.nonzeroC.R.includes(operands[0]) + && is_nonzero_ast(operands[1], assume, original_assumptions) + && is_complex_ast(operands[1], assume, original_assumptions) + ) + return true; + if(functions$1.nonneg.R && functions$1.nonneg.R.includes(operands[0]) && + is_positive_ast(operands[1], assume, false, original_assumptions)) + return true; + if(functions$1.pos.R && functions$1.pos.R.includes(operands[0]) && + is_positive_ast(operands[1], assume, true, original_assumptions)) + return true; + return undefined; + } + + if(operator === 'prime') + return undefined; + + // other operators don't return numbers + return false; } - return iterator(obj, iteratee, memo, keys, index, length); - }; + + return false; } - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. - _.reduce = _.foldl = _.inject = createReduce(1); - // The right-associative version of reduce, also known as `foldr`. - _.reduceRight = _.foldr = createReduce(-1); + function is_complex_ast(tree, assumptions, original_assumptions) { + // see description of is_complex - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, predicate, context) { - var key; - if (isArrayLike(obj)) { - key = _.findIndex(obj, predicate, context); - } else { - key = _.findKey(obj, predicate, context); - } - if (key !== void 0 && key !== -1) return obj[key]; - }; + if(typeof assumptions !== 'object') + assumptions = []; - // Return all the elements that pass a truth test. - // Aliased as `select`. - _.filter = _.select = function(obj, predicate, context) { - var results = []; - predicate = cb(predicate, context); - _.each(obj, function(value, index, list) { - if (predicate(value, index, list)) results.push(value); - }); - return results; - }; + if(original_assumptions===undefined) + original_assumptions = assumptions; - // Return all the elements for which a truth test fails. - _.reject = function(obj, predicate, context) { - return _.filter(obj, _.negate(cb(predicate)), context); - }; + if(typeof tree === 'number') + return Number.isFinite(tree); - // Determine whether all of the elements match a truth test. - // Aliased as `all`. - _.every = _.all = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length; - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - if (!predicate(obj[currentKey], currentKey, obj)) return false; - } - return true; - }; + // if can convert to constant, evaluate directly + var c = evaluate_to_constant(tree); + if(c !== null) { + if(typeof c === 'number') { + return Number.isFinite(c); + } + if(c.re !== undefined && Number.isFinite(c.re) + && c.im !== undefined && Number.isFinite(c.im) ) + return true; - // Determine if at least one element in the object matches a truth test. - // Aliased as `any`. - _.some = _.any = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length; - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - if (predicate(obj[currentKey], currentKey, obj)) return true; - } - return false; - }; + return false; + } - // Determine if the array or object contains a given item (using `===`). - // Aliased as `includes` and `include`. - _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { - if (!isArrayLike(obj)) obj = _.values(obj); - if (typeof fromIndex != 'number' || guard) fromIndex = 0; - return _.indexOf(obj, item, fromIndex) >= 0; - }; + if(typeof tree === 'string') { - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - var isFunc = _.isFunction(method); - return _.map(obj, function(value) { - var func = isFunc ? method : value[method]; - return func == null ? func : func.apply(value, args); - }); - }; + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions(tree); - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, _.property(key)); - }; + if(!Array.isArray(assume)) + return undefined; - // Convenience version of a common use case of `filter`: selecting only objects - // containing specific `key:value` pairs. - _.where = function(obj, attrs) { - return _.filter(obj, _.matcher(attrs)); - }; + let assume_with_negations = assume; - // Convenience version of a common use case of `find`: getting the first object - // containing specific `key:value` pairs. - _.findWhere = function(obj, attrs) { - return _.find(obj, _.matcher(attrs)); - }; + let assume_operator = assume[0]; + let assume_operands = assume.slice(1); - // Return the maximum element (or element-based computation). - _.max = function(obj, iteratee, context) { - var result = -Infinity, lastComputed = -Infinity, - value, computed; - if (iteratee == null && obj != null) { - obj = isArrayLike(obj) ? obj : _.values(obj); - for (var i = 0, length = obj.length; i < length; i++) { - value = obj[i]; - if (value > result) { - result = value; - } - } - } else { - iteratee = cb(iteratee, context); - _.each(obj, function(value, index, list) { - computed = iteratee(value, index, list); - if (computed > lastComputed || computed === -Infinity && result === -Infinity) { - result = value; - lastComputed = computed; - } - }); - } - return result; - }; + let negate_assumptions = false; + while(assume_operator === 'not') { + negate_assumptions = !negate_assumptions; + assume = assume_operands[0]; + if(!Array.isArray(assume)) + return undefined; + assume_operator = assume[0]; + assume_operands = assume.slice(1); + } - // Return the minimum element (or element-based computation). - _.min = function(obj, iteratee, context) { - var result = Infinity, lastComputed = Infinity, - value, computed; - if (iteratee == null && obj != null) { - obj = isArrayLike(obj) ? obj : _.values(obj); - for (var i = 0, length = obj.length; i < length; i++) { - value = obj[i]; - if (value < result) { - result = value; - } - } - } else { - iteratee = cb(iteratee, context); - _.each(obj, function(value, index, list) { - computed = iteratee(value, index, list); - if (computed < lastComputed || computed === Infinity && result === Infinity) { - result = value; - lastComputed = computed; - } - }); - } - return result; - }; + if(assume_operator === 'in') + if(assume_operands[0]===tree && assume_operands[1] === 'C') + return negate_adjust(true, negate_assumptions); + if(assume_operator === 'notin') + if(assume_operands[0]===tree && assume_operands[1] === 'C') + return negate_adjust(false, negate_assumptions); + // haven't negated, then determining tree is integer or real + // means it is complex + if(negate_assumptions===false) { + if(assume_operator === 'in') { + if(assume_operands[0]===tree && assume_operands[1] === 'Z') + return true; + if(assume_operands[0]===tree && assume_operands[1] === 'R') + return true; + } + } + // if have negated, then determining tree is not integer or not real, + // means it is an integer/real, hence complex + else { + if(assume_operator === 'notin') { + if(assume_operands[0]===tree && assume_operands[1] === 'Z') + return true; + if(assume_operands[0]===tree && assume_operands[1] === 'R') + return true; + } + } + + // if assumptions is an inequality involving variable + // then must be real, hence complex, so return true + if(assume_operator === '<' || assume_operator === 'le') { - // Shuffle a collection, using the modern version of the - // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). - _.shuffle = function(obj) { - var set = isArrayLike(obj) ? obj : _.values(obj); - var length = set.length; - var shuffled = Array(length); - for (var index = 0, rand; index < length; index++) { - rand = _.random(0, index); - if (rand !== index) shuffled[index] = shuffled[rand]; - shuffled[rand] = set[index]; - } - return shuffled; - }; + let variables_in_inequality = variables(assume); + let functions_in_inequality = functions(assume); - // Sample **n** random values from a collection. - // If **n** is not specified, returns a single random element. - // The internal `guard` argument allows it to work with `map`. - _.sample = function(obj, n, guard) { - if (n == null || guard) { - if (!isArrayLike(obj)) obj = _.values(obj); - return obj[_.random(obj.length - 1)]; - } - return _.shuffle(obj).slice(0, Math.max(0, n)); - }; + if(variables_in_inequality.indexOf(tree) !== -1 + && functions_in_inequality.length === 0) + return true; // don't negate adjust + } - // Sort the object's values by a criterion produced by an iteratee. - _.sortBy = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - return _.pluck(_.map(obj, function(value, index, list) { - return { - value: value, - index: index, - criteria: iteratee(value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria; - var b = right.criteria; - if (a !== b) { - if (a > b || a === void 0) return 1; - if (a < b || b === void 0) return -1; + // assume equality has been expanded so that has two arguments + if((assume_operator === '=' && !negate_assumptions) || + (assume_operator === 'ne' && negate_assumptions)) { + // if assumption is "tree=something" + // check if something is complex + // (but without the assumption to avoid infinite loop) + + let new_assumptions = narrow_assumptions(assume_with_negations, + original_assumptions); + if(assume_operands[0]===tree) + return is_complex_ast(assume_operands[1], new_assumptions); + if(assume_operands[1]===tree) + return is_complex_ast(assume_operands[0], new_assumptions); + } + + // if isn't a simple And or Or, just give up + if(assume_operator !== 'and' && assume_operator !== 'or') + return undefined; + + // shouldn't have negated assumptions + if(negate_assumptions) + return undefined; + + // if more than two operands, unflatten + // (OK, since not attempting logic where only combined restrictions + // lead to a passing test) + if(assume_operands.length > 2) { + assume = unflattenRight(assume); + assume_operands = assume.slice(1); + } + + let result_left = is_complex_ast(tree, assume_operands[0], + original_assumptions); + let result_right = is_complex_ast(tree, assume_operands[1], + original_assumptions); + return simple_assumption_combination(assume_operator, result_left, + result_right) } - return left.index - right.index; - }), 'value'); - }; - // An internal function used for aggregate "group by" operations. - var group = function(behavior) { - return function(obj, iteratee, context) { - var result = {}; - iteratee = cb(iteratee, context); - _.each(obj, function(value, index) { - var key = iteratee(value, index, obj); - behavior(result, value, key); - }); - return result; - }; - }; + if(Array.isArray(tree)) { - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = group(function(result, value, key) { - if (_.has(result, key)) result[key].push(value); else result[key] = [value]; - }); + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions([variables(tree)]); - // Indexes the object's values by a criterion, similar to `groupBy`, but for - // when you know that your index values will be unique. - _.indexBy = group(function(result, value, key) { - result[key] = value; - }); - // Counts instances of an object that group by a certain criterion. Pass - // either a string attribute to count by, or a function that returns the - // criterion. - _.countBy = group(function(result, value, key) { - if (_.has(result, key)) result[key]++; else result[key] = 1; - }); + let operator = tree[0]; + let operands = tree.slice(1); - // Safely create a real, live array from anything iterable. - _.toArray = function(obj) { - if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (isArrayLike(obj)) return _.map(obj, _.identity); - return _.values(obj); - }; + if(operator === '-') + return is_complex_ast(operands[0], assume, original_assumptions); - // Return the number of elements in an object. - _.size = function(obj) { - if (obj == null) return 0; - return isArrayLike(obj) ? obj.length : _.keys(obj).length; - }; + if(operator === '*' || operator === '+') { - // Split a collection into two arrays: one whose elements all satisfy the given - // predicate, and one whose elements all do not satisfy the predicate. - _.partition = function(obj, predicate, context) { - predicate = cb(predicate, context); - var pass = [], fail = []; - _.each(obj, function(value, key, obj) { - (predicate(value, key, obj) ? pass : fail).push(value); - }); - return [pass, fail]; - }; + if(operator==='*') { + // one confirmed zero factor makes product zero + if(!operands.every(v => is_nonzero_ast(v, assume, original_assumptions) !== false)) + return true; + } - // Array Functions - // --------------- + let all_complex = operands.every(v => is_complex_ast(v, assume, original_assumptions)); - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head` and `take`. The **guard** check - // allows it to work with `_.map`. - _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; - if (n == null || guard) return array[0]; - return _.initial(array, array.length - n); - }; + if(all_complex) + return true; + else { + return undefined; - // Returns everything but the last entry of the array. Especially useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. - _.initial = function(array, n, guard) { - return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); - }; + } + } - // Get the last element of an array. Passing **n** will return the last N - // values in the array. - _.last = function(array, n, guard) { - if (array == null) return void 0; - if (n == null || guard) return array[array.length - 1]; - return _.rest(array, Math.max(0, array.length - n)); - }; + if(operator === '^') { - // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. - // Especially useful on the arguments object. Passing an **n** will return - // the rest N values in the array. - _.rest = _.tail = _.drop = function(array, n, guard) { - return slice.call(array, n == null || guard ? 1 : n); - }; + let base_nonzero = is_nonzero_ast(operands[0], assume, + original_assumptions); + let pow_positive = is_positive_ast(operands[1], assume, true, + original_assumptions); - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, _.identity); - }; + if(!base_nonzero) { - // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, strict, startIndex) { - var output = [], idx = 0; - for (var i = startIndex || 0, length = getLength(input); i < length; i++) { - var value = input[i]; - if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { - //flatten current level of array or arguments object - if (!shallow) value = flatten(value, shallow, strict); - var j = 0, len = value.length; - output.length += len; - while (j < len) { - output[idx++] = value[j++]; - } - } else if (!strict) { - output[idx++] = value; - } - } - return output; - }; + // if base is NaN, return false + if(Number.isNaN(operands[0])) + return false; - // Flatten out an array, either recursively (by default), or just one level. - _.flatten = function(array, shallow) { - return flatten(array, shallow, false); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iteratee, context) { - if (!_.isBoolean(isSorted)) { - context = iteratee; - iteratee = isSorted; - isSorted = false; - } - if (iteratee != null) iteratee = cb(iteratee, context); - var result = []; - var seen = []; - for (var i = 0, length = getLength(array); i < length; i++) { - var value = array[i], - computed = iteratee ? iteratee(value, i, array) : value; - if (isSorted) { - if (!i || seen !== computed) result.push(value); - seen = computed; - } else if (iteratee) { - if (!_.contains(seen, computed)) { - seen.push(computed); - result.push(value); - } - } else if (!_.contains(result, value)) { - result.push(value); - } - } - return result; - }; + if(pow_positive) { + if(base_nonzero === false) + return true; // 0^positive + } + else { + return undefined; // (possibly zero)^(possibly nonpositive) + } + + } + else { // nonzero base + let pow_nonzero = is_nonzero_ast(operands[1], assume, + original_assumptions); + if(pow_nonzero === false) { + // infinity^0 is undefined + if(operands[0] === Infinity || operands[0] === -Infinity) + return false; + + return true; // nonzero^0 + } + + } + + let base_complex = is_complex_ast(operands[0], assume, + original_assumptions); + let pow_complex = is_complex_ast(operands[1], assume, + original_assumptions); + + if(base_complex && pow_complex) + return true; + else + return undefined; - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(flatten(arguments, true, true)); - }; + } - // Produce an array that contains every item shared between all the - // passed-in arrays. - _.intersection = function(array) { - var result = []; - var argsLength = arguments.length; - for (var i = 0, length = getLength(array); i < length; i++) { - var item = array[i]; - if (_.contains(result, item)) continue; - for (var j = 1; j < argsLength; j++) { - if (!_.contains(arguments[j], item)) break; - } - if (j === argsLength) result.push(item); - } - return result; - }; + if(operator === '/') { + // if can't be sure denominator is nonzero + if(!is_nonzero_ast(operands[1], assume, original_assumptions)) + return undefined; - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = flatten(arguments, true, true, 1); - return _.filter(array, function(value){ - return !_.contains(rest, value); - }); - }; + // zero numerator + if(is_nonzero_ast(operands[0], assume, original_assumptions) === false) + return true; - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - return _.unzip(arguments); - }; + if(!(is_complex_ast(operands[0], assume, original_assumptions) + && is_complex_ast(operands[1], assume, original_assumptions))) + return undefined; - // Complement of _.zip. Unzip accepts an array of arrays and groups - // each array's elements on shared indices - _.unzip = function(array) { - var length = array && _.max(array, getLength).length || 0; - var result = Array(length); + return true; - for (var index = 0; index < length; index++) { - result[index] = _.pluck(array, index); - } - return result; - }; + } - // Converts lists into objects. Pass either a single array of `[key, value]` - // pairs, or two parallel arrays of the same length -- one of keys, and one of - // the corresponding values. - _.object = function(list, values) { - var result = {}; - for (var i = 0, length = getLength(list); i < length; i++) { - if (values) { - result[list[i]] = values[i]; - } else { - result[list[i][0]] = list[i][1]; - } - } - return result; - }; + // check for functions that map certain sets to complex numbers + if(operator === 'apply') { + if(functions$1.C.C && functions$1.C.C.includes(operands[0]) && + is_complex_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.R.C && functions$1.R.C.includes(operands[0]) && + is_real_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.nonzeroC.C && functions$1.nonzeroC.C.includes(operands[0]) + && is_nonzero_ast(operands[1], assume, original_assumptions) + && is_complex_ast(operands[1], assume, original_assumptions) + ) + return true; + if(functions$1.nonneg.C && functions$1.nonneg.C.includes(operands[0]) && + is_positive_ast(operands[1], assume, false, original_assumptions)) + return true; + if(functions$1.pos.C && functions$1.pos.C.includes(operands[0]) && + is_positive_ast(operands[1], assume, true, original_assumptions)) + return true; + return undefined; + } - // Generator function to create the findIndex and findLastIndex functions - function createPredicateIndexFinder(dir) { - return function(array, predicate, context) { - predicate = cb(predicate, context); - var length = getLength(array); - var index = dir > 0 ? 0 : length - 1; - for (; index >= 0 && index < length; index += dir) { - if (predicate(array[index], index, array)) return index; + if(operator === 'prime') + return undefined; + + // other operators don't return numbers + return false; } - return -1; - }; + + return false; } - // Returns the first index on an array-like that passes a predicate test - _.findIndex = createPredicateIndexFinder(1); - _.findLastIndex = createPredicateIndexFinder(-1); - // Use a comparator function to figure out the smallest index at which - // an object should be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iteratee, context) { - iteratee = cb(iteratee, context, 1); - var value = iteratee(obj); - var low = 0, high = getLength(array); - while (low < high) { - var mid = Math.floor((low + high) / 2); - if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; - } - return low; - }; + function is_nonzero_ast(tree, assumptions, original_assumptions) { + // see description of is_nonzero - // Generator function to create the indexOf and lastIndexOf functions - function createIndexFinder(dir, predicateFind, sortedIndex) { - return function(array, item, idx) { - var i = 0, length = getLength(array); - if (typeof idx == 'number') { - if (dir > 0) { - i = idx >= 0 ? idx : Math.max(idx + length, i); - } else { - length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; - } - } else if (sortedIndex && idx && length) { - idx = sortedIndex(array, item); - return array[idx] === item ? idx : -1; - } - if (item !== item) { - idx = predicateFind(slice.call(array, i, length), _.isNaN); - return idx >= 0 ? idx + i : -1; + if(typeof assumptions !== 'object') + assumptions = []; + + if(original_assumptions===undefined) + original_assumptions = assumptions; + + if(typeof tree === 'number') { + if(Number.isFinite(tree)) + return tree !== 0; + if(Number.isNaN(tree)) + return undefined; + return true; // consider infinity to be nonzero } - for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { - if (array[idx] === item) return idx; + + // if can convert to constant, evaluate directly + var c = evaluate_to_constant(tree); + if(c !== null) { + if(typeof c === 'number') { + if(Number.isFinite(c)) + return c !== 0; + if(Number.isNaN(c)) + return undefined; + return true; // consider infinity to be nonzero + } + if(c.re !== undefined && c.im !== undefined && + (c.re !== 0 || c.im !== 0) ) + return true; + return undefined; } - return -1; - }; - } - // Return the position of the first occurrence of an item in an array, - // or -1 if the item is not included in the array. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); - _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); + if(typeof tree === 'string') { - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (stop == null) { - stop = start || 0; - start = 0; - } - step = step || 1; + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions(tree); - var length = Math.max(Math.ceil((stop - start) / step), 0); - var range = Array(length); + if(!Array.isArray(assume)) + return undefined; - for (var idx = 0; idx < length; idx++, start += step) { - range[idx] = start; - } + let assume_with_negations = assume; - return range; - }; + let assume_operator = assume[0]; + let assume_operands = assume.slice(1); - // Function (ahem) Functions - // ------------------ - - // Determines whether to execute a function as a constructor - // or a normal function with the provided arguments - var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { - if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); - var self = baseCreate(sourceFunc.prototype); - var result = sourceFunc.apply(self, args); - if (_.isObject(result)) return result; - return self; - }; - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if - // available. - _.bind = function(func, context) { - if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); - var args = slice.call(arguments, 2); - var bound = function() { - return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); - }; - return bound; - }; - - // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. _ acts - // as a placeholder, allowing any combination of arguments to be pre-filled. - _.partial = function(func) { - var boundArgs = slice.call(arguments, 1); - var bound = function() { - var position = 0, length = boundArgs.length; - var args = Array(length); - for (var i = 0; i < length; i++) { - args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; - } - while (position < arguments.length) args.push(arguments[position++]); - return executeBound(func, bound, this, this, args); - }; - return bound; - }; + let negate_assumptions = false; + while(assume_operator === 'not') { + negate_assumptions = !negate_assumptions; + assume = assume_operands[0]; + if(!Array.isArray(assume)) + return undefined; + assume_operator = assume[0]; + assume_operands = assume.slice(1); + } - // Bind a number of an object's methods to that object. Remaining arguments - // are the method names to be bound. Useful for ensuring that all callbacks - // defined on an object belong to it. - _.bindAll = function(obj) { - var i, length = arguments.length, key; - if (length <= 1) throw new Error('bindAll must be passed function names'); - for (i = 1; i < length; i++) { - key = arguments[i]; - obj[key] = _.bind(obj[key], obj); - } - return obj; - }; + let new_assumptions = narrow_assumptions(assume_with_negations, + original_assumptions); - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memoize = function(key) { - var cache = memoize.cache; - var address = '' + (hasher ? hasher.apply(this, arguments) : key); - if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); - return cache[address]; - }; - memoize.cache = {}; - return memoize; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ - return func.apply(null, args); - }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = _.partial(_.delay, _, 1); - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. Normally, the throttled function will run - // as much as it can, without ever going more than once per `wait` duration; - // but if you'd like to disable the execution on the leading edge, pass - // `{leading: false}`. To disable execution on the trailing edge, ditto. - _.throttle = function(func, wait, options) { - var context, args, result; - var timeout = null; - var previous = 0; - if (!options) options = {}; - var later = function() { - previous = options.leading === false ? 0 : _.now(); - timeout = null; - result = func.apply(context, args); - if (!timeout) context = args = null; - }; - return function() { - var now = _.now(); - if (!previous && options.leading === false) previous = now; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0 || remaining > wait) { - if (timeout) { - clearTimeout(timeout); - timeout = null; - } - previous = now; - result = func.apply(context, args); - if (!timeout) context = args = null; - } else if (!timeout && options.trailing !== false) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }; + // assume equality has been expanded so that has two arguments + if((assume_operator === '=' && !negate_assumptions) || + (assume_operator === 'ne' && negate_assumptions)) { + // if assumption is "tree=something" + // check if something is nonzero + // (but without the assumption to avoid infinite loop) + + if(assume_operands[0]===tree) + return is_nonzero_ast(assume_operands[1], new_assumptions); + if(assume_operands[1]===tree) + return is_nonzero_ast(assume_operands[0], new_assumptions); + } - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout, args, context, timestamp, result; + if((assume_operator === 'ne' && !negate_assumptions) || + (assume_operator === '=' && negate_assumptions)) { + // if assumption is "tree!=something" + // check if something is zero + + if(assume_operands[0]===tree) { + if(is_nonzero_ast(assume_operands[1], new_assumptions)===false) + return true + } + if(assume_operands[1]===tree) { + if(is_nonzero_ast(assume_operands[0], new_assumptions)===false) + return true; + } + } - var later = function() { - var last = _.now() - timestamp; + // assume assumptions are ordered so greater than doesn't appear + if(assume_operator === '<') { + if(!negate_assumptions) { + if(assume_operands[0]===tree) { + if(is_negative_ast( + assume_operands[1], new_assumptions, false)) + return true; + } + if(assume_operands[1]===tree) { + if(is_positive_ast( + assume_operands[0], new_assumptions, false)) + return true; + } + } + else { + // negated, becomes ge + if(assume_operands[0]===tree) { + if(is_positive_ast( + assume_operands[1], new_assumptions, true)) + return true; + } + if(assume_operands[1]===tree) { + if(is_negative_ast( + assume_operands[0], new_assumptions, true)) + return true; + } + + } + } + if(assume_operator === 'le') { + if(!negate_assumptions) { + if(assume_operands[0]===tree) { + if(is_negative_ast( + assume_operands[1], new_assumptions, true)) + return true; + } + if(assume_operands[1]===tree) { + if(is_positive_ast( + assume_operands[0], new_assumptions, true)) + return true; + } + } + else { + // negated, so becomes > + if(assume_operands[0]===tree) { + if(is_positive_ast( + assume_operands[1], new_assumptions, false)) + return true; + } + if(assume_operands[1]===tree) { + if(is_negative_ast( + assume_operands[0], new_assumptions, false)) + return true; + } + + } + } - if (last < wait && last >= 0) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) { - result = func.apply(context, args); - if (!timeout) context = args = null; - } - } - }; + // if isn't a simple And or Or, just give up + if(assume_operator !== 'and' && assume_operator !== 'or') + return undefined; - return function() { - context = this; - args = arguments; - timestamp = _.now(); - var callNow = immediate && !timeout; - if (!timeout) timeout = setTimeout(later, wait); - if (callNow) { - result = func.apply(context, args); - context = args = null; + // shouldn't have negated assumptions + if(negate_assumptions) + return undefined; + + // if more than two operands, unflatten + // (OK, since not attempting logic where only combined restrictions + // lead to a passing test) + if(assume_operands.length > 2) { + assume = unflattenRight(assume); + assume_operands = assume.slice(1); + } + + let result_left = is_nonzero_ast(tree, assume_operands[0], + original_assumptions); + let result_right = is_nonzero_ast(tree, assume_operands[1], + original_assumptions); + return simple_assumption_combination(assume_operator, result_left, + result_right) } - return result; - }; - }; + if(Array.isArray(tree)) { - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return _.partial(wrapper, func); - }; + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions([variables(tree)]); + + let operator = tree[0]; + let operands = tree.slice(1); + + if(operator === '-') + return is_nonzero_ast(operands[0], assume, original_assumptions); + + if(operator === '+') { + + // if more than two terms, unflatten + if(operands.length > 2) { + tree = unflattenRight(tree); + operands = tree.slice(1); + } + + // if operands are opposite + // (trees.equal removes duplicate negatives through default_order) + // TODO: check if operands aren't infinite + if(equal$2(operands[0], + simplify$2(['-', operands[1]], + original_assumptions))) + return false; + + // can definitely determine nonzero if one term is zero + // or if both have the same sign + + let nonzero_left = is_nonzero_ast(operands[0], assume, + original_assumptions); + let nonzero_right = is_nonzero_ast(operands[1], assume, + original_assumptions); + + // if one is known to be zero, return result from other + if(nonzero_left===false) + return nonzero_right; + if(nonzero_right===false) + return nonzero_left; + + + // if one of both aren't real + // decide now + let real_left = is_real_ast(operands[0], assume, + original_assumptions); + let real_right = is_real_ast(operands[1], assume, + original_assumptions); + + if(!real_left || !real_right) { + if(real_left===true) { + if(real_right === false) + return true; + return undefined; + } + if(real_right===true) { + if(real_left===false) + return true; + return undefined; + } + return undefined; + } + + // if reach here, both are real + + let nonneg_left = is_positive_ast(operands[0], assume, false, + original_assumptions); + let nonneg_right = is_positive_ast(operands[1], assume, false, + original_assumptions); + + let positive_left = is_positive_ast(operands[0], assume, true, + original_assumptions); + let positive_right = is_positive_ast(operands[1], assume, true, + original_assumptions); + + // positive + nonnegative is nonzero + if( (nonneg_left && positive_right) + || (positive_left && nonneg_right)) + return true; + + // negative + nonpositive is nonzero + if( (nonneg_left===false && positive_right===false) + || (positive_left===false && nonneg_right===false)) + return true; + + + // have terms of both signs (or undefined sign) + // so can't determine if nonzero by this approach + return undefined; + } - // Returns a negated version of the passed-in predicate. - _.negate = function(predicate) { - return function() { - return !predicate.apply(this, arguments); - }; - }; + if(operator === '*') { + let all_nonzero = true; + for(let i=0; i < operands.length; i++) { - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var args = arguments; - var start = args.length - 1; - return function() { - var i = start; - var result = args[start].apply(this, arguments); - while (i--) result = args[i].call(this, result); - return result; - }; - }; + let result = is_nonzero_ast(operands[i], assume, + original_assumptions); - // Returns a function that will only be executed on and after the Nth call. - _.after = function(times, func) { - return function() { - if (--times < 1) { - return func.apply(this, arguments); - } - }; - }; + if(result===false) + return false; // found a zero factor + if(result===undefined) + all_nonzero=false; + } - // Returns a function that will only be executed up to (but not including) the Nth call. - _.before = function(times, func) { - var memo; - return function() { - if (--times > 0) { - memo = func.apply(this, arguments); - } - if (times <= 1) func = null; - return memo; - }; - }; + if(all_nonzero) + return true; + else + return undefined; + } + + if(operator === '/') { + + let result = is_nonzero_ast(operands[0], assume, + original_assumptions); + + if(is_nonzero_ast(operands[1], assume, original_assumptions)) + return result; + else + return undefined; + } + + if(operator === '^') { + + let base_nonzero = is_nonzero_ast(operands[0], assume, + original_assumptions); + + if(!base_nonzero) { + let pow_positive = is_positive_ast(operands[1], assume, true, + original_assumptions); - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = _.partial(_.before, 2); + if(pow_positive && (base_nonzero === false)) + return false; // 0^positive - // Object Functions - // ---------------- + return undefined; + } + else { // nonzero base + // infinity^0 is undefined + if(operands[0] === Infinity || operands[0] === -Infinity) { + let pow_nonzero = is_nonzero_ast(operands[1], assume, + original_assumptions); + if(pow_nonzero === false) + return undefined; + } - // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. - var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); - var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', - 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; + return true; - function collectNonEnumProps(obj, keys) { - var nonEnumIdx = nonEnumerableProps.length; - var constructor = obj.constructor; - var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; + // TODO? positive^(-infinity) =? 0 + } + + } + + // check for functions that map certain sets to nonzeros + if(operator === 'apply') { + if(functions$1.C.nonzero && functions$1.C.nonzero.includes(operands[0]) && + is_complex_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.R.nonzero && functions$1.R.nonzero.includes(operands[0]) && + is_real_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.nonzeroC.nonzero && functions$1.nonzeroC.nonzero.includes(operands[0]) + && is_nonzero_ast(operands[1], assume, original_assumptions) + && is_complex_ast(operands[1], assume, original_assumptions) + ) + return true; + if(functions$1.nonneg.nonzero && functions$1.nonneg.nonzero.includes(operands[0]) && + is_positive_ast(operands[1], assume, false, original_assumptions)) + return true; + if(functions$1.pos.nonzero && functions$1.pos.nonzero.includes(operands[0]) && + is_positive_ast(operands[1], assume, true, original_assumptions)) + return true; + return undefined; + } - // Constructor is a special case. - var prop = 'constructor'; - if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); + if(operator === 'prime') + return undefined; - while (nonEnumIdx--) { - prop = nonEnumerableProps[nonEnumIdx]; - if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { - keys.push(prop); + // other operators don't return numbers + return false; } - } + + return false; } - // Retrieve the names of an object's own properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = function(obj) { - if (!_.isObject(obj)) return []; - if (nativeKeys) return nativeKeys(obj); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys.push(key); - // Ahem, IE < 9. - if (hasEnumBug) collectNonEnumProps(obj, keys); - return keys; - }; - // Retrieve all the property names of an object. - _.allKeys = function(obj) { - if (!_.isObject(obj)) return []; - var keys = []; - for (var key in obj) keys.push(key); - // Ahem, IE < 9. - if (hasEnumBug) collectNonEnumProps(obj, keys); - return keys; - }; + function is_positive_ast(tree, assumptions, strict, original_assumptions) { + // see description of is_nonnegative - // Retrieve the values of an object's properties. - _.values = function(obj) { - var keys = _.keys(obj); - var length = keys.length; - var values = Array(length); - for (var i = 0; i < length; i++) { - values[i] = obj[keys[i]]; - } - return values; - }; + if(typeof assumptions !== 'object') + assumptions = []; - // Returns the results of applying the iteratee to each element of the object - // In contrast to _.map it returns an object - _.mapObject = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - var keys = _.keys(obj), - length = keys.length, - results = {}, - currentKey; - for (var index = 0; index < length; index++) { - currentKey = keys[index]; - results[currentKey] = iteratee(obj[currentKey], currentKey, obj); + if(original_assumptions===undefined) + original_assumptions = assumptions; + + if(strict === undefined) + strict = true; + + if(typeof tree === 'number') { + if(Number.isFinite(tree)) + return (strict ? tree > 0 : tree >= 0); + return false; } - return results; - }; - // Convert an object into a list of `[key, value]` pairs. - _.pairs = function(obj) { - var keys = _.keys(obj); - var length = keys.length; - var pairs = Array(length); - for (var i = 0; i < length; i++) { - pairs[i] = [keys[i], obj[keys[i]]]; - } - return pairs; - }; + var is_real = is_real_ast(tree, assumptions, original_assumptions); + if(!is_real) + return is_real; - // Invert the keys and values of an object. The values must be serializable. - _.invert = function(obj) { - var result = {}; - var keys = _.keys(obj); - for (var i = 0, length = keys.length; i < length; i++) { - result[obj[keys[i]]] = keys[i]; - } - return result; - }; + // if can convert to constant, evaluate directly + var c = evaluate_to_constant(tree); - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; + if(c !== null) { + if(typeof c === 'number') { + if(Number.isFinite(c)) + return (strict ? c > 0 : c >= 0); + return false; + } + return false; + } - // Extend a given object with all the properties in passed-in object(s). - _.extend = createAssigner(_.allKeys); + if(typeof tree === 'string') { - // Assigns a given object with all the own properties in the passed-in object(s) - // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) - _.extendOwn = _.assign = createAssigner(_.keys); + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions(tree); - // Returns the first key on an object that passes a predicate test - _.findKey = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = _.keys(obj), key; - for (var i = 0, length = keys.length; i < length; i++) { - key = keys[i]; - if (predicate(obj[key], key, obj)) return key; - } - }; + if(!Array.isArray(assume)) + return undefined; - // Return a copy of the object only containing the whitelisted properties. - _.pick = function(object, oiteratee, context) { - var result = {}, obj = object, iteratee, keys; - if (obj == null) return result; - if (_.isFunction(oiteratee)) { - keys = _.allKeys(obj); - iteratee = optimizeCb(oiteratee, context); - } else { - keys = flatten(arguments, false, false, 1); - iteratee = function(value, key, obj) { return key in obj; }; - obj = Object(obj); - } - for (var i = 0, length = keys.length; i < length; i++) { - var key = keys[i]; - var value = obj[key]; - if (iteratee(value, key, obj)) result[key] = value; - } - return result; - }; + let assume_with_negations = assume; - // Return a copy of the object without the blacklisted properties. - _.omit = function(obj, iteratee, context) { - if (_.isFunction(iteratee)) { - iteratee = _.negate(iteratee); - } else { - var keys = _.map(flatten(arguments, false, false, 1), String); - iteratee = function(value, key) { - return !_.contains(keys, key); - }; - } - return _.pick(obj, iteratee, context); - }; + let assume_operator = assume[0]; + let assume_operands = assume.slice(1); - // Fill in a given object with default properties. - _.defaults = createAssigner(_.allKeys, true); + let negate_assumptions = false; + while(assume_operator === 'not') { + negate_assumptions = !negate_assumptions; + assume = assume_operands[0]; + if(!Array.isArray(assume)) + return undefined; + assume_operator = assume[0]; + assume_operands = assume.slice(1); + } - // Creates an object that inherits from the given prototype object. - // If additional properties are provided then they will be added to the - // created object. - _.create = function(prototype, props) { - var result = baseCreate(prototype); - if (props) _.extendOwn(result, props); - return result; - }; + let new_assumptions = narrow_assumptions(assume_with_negations, + original_assumptions); + + // assume that equality has been expanded so that + // have only two operands + if((assume_operator === '=' && !negate_assumptions) || + (assume_operator === 'ne' && negate_assumptions)) { + // if assumption is "tree=something" + // check if something is positive + // (but without the assumption to avoid infinite loop) + + if(assume_operands[0]===tree) + return is_positive_ast(assume_operands[1], new_assumptions, + strict); + if(assume_operands[1]===tree) + return is_positive_ast(assume_operands[0], new_assumptions, + strict); + } - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; + // assume assumptions are ordered so greater than doesn't appear + if(assume_operator === '<') { + if(!negate_assumptions) { + if(assume_operands[0]===tree) { + if(is_negative_ast(assume_operands[1], new_assumptions, + false)) + return false; + } + if(assume_operands[1]===tree) { + if(is_positive_ast(assume_operands[0], new_assumptions, + false)) + return true; + } + } + else { + // negated, so becomes ge + if(assume_operands[0]===tree) { + if(is_positive_ast(assume_operands[1], new_assumptions, + strict)) + return true; + } + if(assume_operands[1]===tree) { + if(is_negative_ast(assume_operands[0], new_assumptions, + !strict)) + return false; + } + + } + } + if(assume_operator === 'le') { + if(!negate_assumptions) { + if(assume_operands[0]===tree) { + if(is_negative_ast(assume_operands[1], new_assumptions, + !strict)) + return false; + } + if(assume_operands[1]===tree) { + if(is_positive_ast(assume_operands[0], new_assumptions, + strict)) + return true; + } + } + else { + // negated, so becomes > + if(assume_operands[0]===tree) { + if(is_positive_ast(assume_operands[1], new_assumptions, + false)) + return true; + } + if(assume_operands[1]===tree) { + if(is_negative_ast(assume_operands[0], new_assumptions, + false)) + return false; + } + + } + } - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - // Returns whether an object has a given set of `key:value` pairs. - _.isMatch = function(object, attrs) { - var keys = _.keys(attrs), length = keys.length; - if (object == null) return !length; - var obj = Object(object); - for (var i = 0; i < length; i++) { - var key = keys[i]; - if (attrs[key] !== obj[key] || !(key in obj)) return false; - } - return true; - }; + // if isn't a simple And or Or, just give up + if(assume_operator !== 'and' && assume_operator !== 'or') + return undefined; + // shouldn't have negated assumptions + if(negate_assumptions) + return undefined; - // Internal recursive comparison function for `isEqual`. - var eq = function(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). - if (a === b) return a !== 0 || 1 / a === 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a instanceof _) a = a._wrapped; - if (b instanceof _) b = b._wrapped; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className !== toString.call(b)) return false; - switch (className) { - // Strings, numbers, regular expressions, dates, and booleans are compared by value. - case '[object RegExp]': - // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return '' + a === '' + b; - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. - // Object(NaN) is equivalent to NaN - if (+a !== +a) return +b !== +b; - // An `egal` comparison is performed for other numeric values. - return +a === 0 ? 1 / +a === 1 / b : +a === +b; - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a === +b; - } - - var areArrays = className === '[object Array]'; - if (!areArrays) { - if (typeof a != 'object' || typeof b != 'object') return false; - - // Objects with different constructors are not equivalent, but `Object`s or `Array`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && - _.isFunction(bCtor) && bCtor instanceof bCtor) - && ('constructor' in a && 'constructor' in b)) { - return false; + // if more than two operands, unflatten + // (OK, since not attempting logic where only combined restrictions + // lead to a passing test) + if(assume_operands.length > 2) { + assume = unflattenRight(assume); + assume_operands = assume.slice(1); + } + + let result_left = is_positive_ast(tree, assume_operands[0], strict, + original_assumptions); + let result_right = is_positive_ast(tree, assume_operands[1], strict, + original_assumptions); + return simple_assumption_combination(assume_operator, result_left, + result_right) } - } - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - // Initializing stack of traversed objects. - // It's done here since we only need them for objects and arrays comparison. - aStack = aStack || []; - bStack = bStack || []; - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] === a) return bStack[length] === b; - } + if(Array.isArray(tree)) { - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); + let assume; + if(Array.isArray(assumptions)) + assume = assumptions; + else + assume = assumptions.get_assumptions([variables(tree)]); + + let operator = tree[0]; + let operands = tree.slice(1); + + if(operator === '-') + return is_negative_ast(operands[0], assume, strict, + original_assumptions); + + if(operator === '+') { + + // if more than two terms, unflatten + if(operands.length > 2) { + tree = unflattenRight(tree); + operands = tree.slice(1); + } + + + let nonneg_left = is_positive_ast(operands[0], assume, false, + original_assumptions); + let nonneg_right = is_positive_ast(operands[1], assume, false, + original_assumptions); + + let positive_left = is_positive_ast(operands[0], assume, true, + original_assumptions); + let positive_right = is_positive_ast(operands[1], assume, true, + original_assumptions); + + + if(strict) { + // positive + nonnegative is positive + if( (nonneg_left && positive_right) + || (positive_left && nonneg_right)) + return true; + } + else { + // nonnegative + nonnegative is nonnegative + if(nonneg_left && nonneg_right) + return true; + } + + if(strict) { + // nonpositive + nonpositive is nonpositive + if(positive_left===false && positive_right===false) + return false; + } + else { + // negative + nonpositive is negative + if( (nonneg_left===false && positive_right===false) + || (positive_left===false && nonneg_right===false)) + return false; + } - // Recursively compare objects and arrays. - if (areArrays) { - // Compare array lengths to determine if a deep comparison is necessary. - length = a.length; - if (length !== b.length) return false; - // Deep compare the contents, ignoring non-numeric properties. - while (length--) { - if (!eq(a[length], b[length], aStack, bStack)) return false; - } - } else { - // Deep compare objects. - var keys = _.keys(a), key; - length = keys.length; - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (_.keys(b).length !== length) return false; - while (length--) { - // Deep compare each member - key = keys[length]; - if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return true; - }; + // have terms of both signs (or undefined sign) + // so can't determine if positive or negative by this approach + return undefined; + } - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b); - }; + if(operator === '*') { + // one confirmed zero factor makes product zero + if(!operands.every(v => is_nonzero_ast(v, assume, original_assumptions) !== false)) + return !strict; + + // if more than two terms, unflatten + if(operands.length > 2) { + tree = unflattenRight(tree); + operands = tree.slice(1); + } + + let real_left = is_real_ast(operands[0], assume, + original_assumptions); + let real_right = is_real_ast(operands[1], assume, + original_assumptions); + + // if can't determine if real, can't determine positivity + if(real_left===undefined || real_right===undefined) + return undefined; + + // if one nonreal, return false + // if two nonreals, return undefined + if(real_left===false) { + if(real_right===false) + return undefined; + else + return false; + } + else if(real_right===false) + return false; + + // if reach here, both factors are real + + let nonneg_left = is_positive_ast(operands[0], assume, false, + original_assumptions); + let nonneg_right = is_positive_ast(operands[1], assume, false, + original_assumptions); + + let positive_left = is_positive_ast(operands[0], assume, true, + original_assumptions); + let positive_right = is_positive_ast(operands[1], assume, true, + original_assumptions); + + if(strict) { + // product of two positives or two negatives is positive + if((positive_left && positive_right) + || (nonneg_left === false && nonneg_right === false)) + return true; + + // product of nonnegative and nonpositive is nonpositive + if((positive_left === false && nonneg_right) + || (nonneg_left && positive_right === false)) + return false; + } + else { + // product of two nonnegatives or two nonpositives + // is nonnegative + if((nonneg_left && nonneg_right) + || (positive_left === false && positive_right === false)) + return true; + + // product of positive and negative is negative + if((positive_left && nonneg_right === false) + || (nonneg_left === false && positive_right)) + return false; + } - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (obj == null) return true; - if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; - return _.keys(obj).length === 0; - }; + // couldn't figure out sign via above algorithm + return undefined; - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType === 1); - }; + } - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) === '[object Array]'; - }; + if(operator === '/') { - // Is a given variable an object? - _.isObject = function(obj) { - var type = typeof obj; - return type === 'function' || type === 'object' && !!obj; - }; + // if can't be sure denominator is nonzero + if(!is_nonzero_ast(operands[1], assume, original_assumptions)) + return undefined; - // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. - _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { - _['is' + name] = function(obj) { - return toString.call(obj) === '[object ' + name + ']'; - }; - }); + // zero numerator + if(is_nonzero_ast(operands[0], assume, + original_assumptions) === false) + return !strict; - // Define a fallback version of the method in browsers (ahem, IE < 9), where - // there isn't any inspectable "Arguments" type. - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return _.has(obj, 'callee'); - }; - } + let denom_pos = is_positive_ast(operands[1], assume, true, + original_assumptions); + if(denom_pos === undefined) + return undefined; - // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, - // IE 11 (#1621), and in Safari 8 (#1929). - if (typeof /./ != 'function' && typeof Int8Array != 'object') { - _.isFunction = function(obj) { - return typeof obj == 'function' || false; - }; - } + // if denominator is negative, sign is swapped + // so need opposite strictness for numerator + let numer_strict = denom_pos ? strict : !strict; + let numer_pos = is_positive_ast(operands[0], assume, + numer_strict, + original_assumptions); - // Is a given object a finite number? - _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); - }; + if(numer_pos === undefined) + return undefined; - // Is the given value `NaN`? (NaN is the only number which does not equal itself). - _.isNaN = function(obj) { - return _.isNumber(obj) && obj !== +obj; - }; + if(numer_pos === true) { + if(denom_pos === true) + return true; + else + return false; + } + else { + if(denom_pos === true) + return false; + else + return true; + } + } + if(operator === '^') { + + let base_nonzero = is_nonzero_ast(operands[0], assume, + original_assumptions); + + if(!base_nonzero) { + let pow_positive = is_positive_ast(operands[1], assume, true, + original_assumptions); + + if(pow_positive) { + if(base_nonzero === false) + return !strict; // 0^positive + if(strict) + return undefined // (possibly 0)^positive + } + else { + return undefined; // (possibly zero)^(possibly nonpositive) + } + + } + else { // nonzero base + let pow_nonzero = is_nonzero_ast(operands[1], assume, + original_assumptions); + if(pow_nonzero === false) { + // infinity^0 is undefined + if(operands[0] === Infinity || operands[0] === -Infinity) + return undefined; + + return true; // nonzero^0 + } + + } + + let base_real = is_real_ast(operands[0], assume, + original_assumptions); + + if(base_real !== true) { + return undefined; + } + + let base_positive = is_positive_ast(operands[0], assume, strict, + original_assumptions); + + if(!base_positive) { + // if base could be negative + // (already excluded zero base if strict) + // then only way to be + // positive (non_negative if not strict) + // is if pow is an even integer + + // since haven't implemented is_even, only check + // if have a constant that is an even integer + let pow_over_two = simplify$2(['/', operands[1], 2], + original_assumptions); + if(is_integer_ast(pow_over_two, assume, original_assumptions)) + return true; + + return undefined; + } + + // base must be nonnegative + let pow_real = is_real_ast(operands[1], assume, + original_assumptions); + + if(pow_real) + return true; // since already excluded 0^0 + else + return undefined; - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; - }; + } - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; + // check for functions that map certain sets to nonnegatives + if(operator === 'apply' && !strict) { + if(functions$1.C.nonneg && functions$1.C.nonneg.includes(operands[0]) && + is_complex_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.R.nonneg && functions$1.R.nonneg.includes(operands[0]) && + is_real_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.nonzeroC.nonneg && functions$1.nonzeroC.nonneg.includes(operands[0]) + && is_nonzero_ast(operands[1], assume, original_assumptions) + && is_complex_ast(operands[1], assume, original_assumptions) + ) + return true; + if(functions$1.nonneg.nonneg && functions$1.nonneg.nonneg.includes(operands[0]) && + is_positive_ast(operands[1], assume, false, original_assumptions)) + return true; + if(functions$1.pos.nonneg && functions$1.pos.nonneg.includes(operands[0]) && + is_positive_ast(operands[1], assume, true, original_assumptions)) + return true; + return undefined; + } + // check for functions that map certain sets to integers + if(operator === 'apply' && strict) { + if(functions$1.C.pos && functions$1.C.pos.includes(operands[0]) && + is_complex_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.R.pos && functions$1.R.pos.includes(operands[0]) && + is_real_ast(operands[1], assume, original_assumptions)) + return true; + if(functions$1.nonzeroC.pos && functions$1.nonzeroC.pos.includes(operands[0]) + && is_nonzero_ast(operands[1], assume, original_assumptions) + && is_complex_ast(operands[1], assume, original_assumptions) + ) + return true; + if(functions$1.nonneg.pos && functions$1.nonneg.pos.includes(operands[0]) && + is_positive_ast(operands[1], assume, false, original_assumptions)) + return true; + if(functions$1.pos.pos && functions$1.pos.pos.includes(operands[0]) && + is_positive_ast(operands[1], assume, true, original_assumptions)) + return true; + return undefined; + } + + if(operator === 'prime') + return undefined; - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; + // other operators don't return numbers + return false; + } - // Shortcut function for checking if an object has a given property directly - // on itself (in other words, not on a prototype). - _.has = function(obj, key) { - return obj != null && hasOwnProperty.call(obj, key); - }; + return false; + } - // Utility Functions - // ----------------- + function is_negative_ast(tree, assumptions, strict, original_assumptions) { + if(strict === undefined) + strict = true; - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; + var real = is_real_ast(tree, assumptions, original_assumptions); - // Keep the identity function around for default iteratees. - _.identity = function(value) { - return value; - }; + if(real === true) { + let nonneg = is_positive_ast(tree, assumptions, !strict, + original_assumptions); + if(nonneg === false) + return true; + if(nonneg === true) + return false; + return undefined; + } - // Predicate-generating functions. Often useful outside of Underscore. - _.constant = function(value) { - return function() { - return value; - }; - }; + return real; + } - _.noop = function(){}; + function clean(expr_or_tree) { + var tree = get_tree(expr_or_tree); + return flatten(tree); + } - _.property = property; + function evalf(x, n) { + return parseFloat(number_8(x, n)); + } - // Generates a function for a given object that returns a given property. - _.propertyOf = function(obj) { - return obj == null ? function(){} : function(key) { - return obj[key]; - }; - }; + function collapse_unary_minus(expr_or_tree) { + var tree = get_tree(expr_or_tree); - // Returns a predicate for checking whether an object has a given set of - // `key:value` pairs. - _.matcher = _.matches = function(attrs) { - attrs = _.extendOwn({}, attrs); - return function(obj) { - return _.isMatch(obj, attrs); - }; - }; + if (!Array.isArray(tree)) + return tree; - // Run a function **n** times. - _.times = function(n, iteratee, context) { - var accum = Array(Math.max(0, n)); - iteratee = optimizeCb(iteratee, context, 1); - for (var i = 0; i < n; i++) accum[i] = iteratee(i); - return accum; - }; + var operator = tree[0]; + var operands = tree.slice(1); + operands = operands.map(v => collapse_unary_minus(v)); - // Return a random integer between min and max (inclusive). - _.random = function(min, max) { - if (max == null) { - max = min; - min = 0; + if (operator === "-") { + if (typeof operands[0] === 'number') + return -operands[0]; + // check if operand is a multiplication with that begins with + // a constant. If so combine with constant + if (Array.isArray(operands[0]) && operands[0][0] === '*' + && (typeof operands[0][1] === 'number')) { + return ['*', -operands[0][1]].concat(operands[0].slice(2)); + } + // check if operand is a division with that begins with + // either + /// (A) a constant or + // (B) a multiplication that begins with a constant. + // If so. combine with constant + if (Array.isArray(operands[0]) && operands[0][0] === '/') { + if (typeof operands[0][1] === 'number') + return ['/', -operands[0][1], operands[0][2]]; + if (Array.isArray(operands[0][1]) && operands[0][1][0] === '*' + && (typeof operands[0][1][1] === 'number')) { + return ['/', [ + '*', -operands[0][1][1]].concat(operands[0][1].slice(2)), + operands[0][2]]; + } + } } - return min + Math.floor(Math.random() * (max - min + 1)); - }; - // A (possibly faster) way to get the current timestamp as an integer. - _.now = Date.now || function() { - return new Date().getTime(); - }; + return [operator].concat(operands); + } - // List of HTML entities for escaping. - var escapeMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`' - }; - var unescapeMap = _.invert(escapeMap); + function simplify$2(expr_or_tree, assumptions, max_digits) { + var tree = get_tree(expr_or_tree); - // Functions for escaping and unescaping strings to/from HTML interpolation. - var createEscaper = function(map) { - var escaper = function(match) { - return map[match]; - }; - // Regexes for identifying a key that needs to be escaped - var source = '(?:' + _.keys(map).join('|') + ')'; - var testRegexp = RegExp(source); - var replaceRegexp = RegExp(source, 'g'); - return function(string) { - string = string == null ? '' : '' + string; - return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; - }; - }; - _.escape = createEscaper(escapeMap); - _.unescape = createEscaper(unescapeMap); + if (assumptions === undefined && expr_or_tree.context !== undefined + && expr_or_tree.context.get_assumptions !== undefined) + assumptions = expr_or_tree.context.get_assumptions( + [expr_or_tree.variables()]); - // If the value of the named `property` is a function then invoke it with the - // `object` as context; otherwise, return it. - _.result = function(object, property, fallback) { - var value = object == null ? void 0 : object[property]; - if (value === void 0) { - value = fallback; + tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits, evaluate_functions: true }); + // if already have it down to a number of variable, no need for more simplification + if (!Array.isArray(tree)) { + return tree; } - return _.isFunction(value) ? value.call(object) : value; - }; + tree = simplify_logical(tree, assumptions); + tree = collect_like_terms_factors(tree, assumptions, max_digits); - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; + return tree; + } - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; + function simplify_logical(expr_or_tree, assumptions) { + var tree = get_tree(expr_or_tree); - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /(.)^/; + if (assumptions === undefined && expr_or_tree.context !== undefined + && expr_or_tree.context.get_assumptions !== undefined) + assumptions = expr_or_tree.context.get_assumptions( + [expr_or_tree.variables()]); - // Certain characters need to be escaped so that they can be put into a - // string literal. - var escapes = { - "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; + tree = evaluate_numbers(tree, { assumptions: assumptions }); - var escaper = /\\|'|\r|\n|\u2028|\u2029/g; + tree = unflattenRight(tree); - var escapeChar = function(match) { - return '\\' + escapes[match]; - }; + var transformations = []; + transformations.push([ [ 'not', [ 'not', 'a' ] ], "a"]); + transformations.push([ [ 'not', [ 'and', 'a', 'b' ] ], [ 'or', [ 'not', 'a' ], [ 'not', 'b' ] ] ]); + transformations.push([ [ 'not', [ 'or', 'a', 'b' ] ], [ 'and', [ 'not', 'a' ], [ 'not', 'b' ] ] ]); + transformations.push([ [ 'not', [ '=', 'a', 'b' ] ], [ 'ne', 'a', 'b' ] ]); + transformations.push([ [ 'not', [ 'ne', 'a', 'b' ] ], [ '=', 'a', 'b' ] ]); + transformations.push([ [ 'not', [ '<', 'a', 'b' ] ], [ 'le', 'b', 'a' ] ]); + transformations.push([ [ 'not', [ 'le', 'a', 'b' ] ], [ 'not', [ 'le', 'a', 'b' ] ] ]); + transformations.push([ [ 'not', [ 'in', 'a', 'b' ] ], [ 'notin', 'a', 'b' ] ]); + transformations.push([ [ 'not', [ 'subset', 'a', 'b' ] ], [ 'notsubset', 'a', 'b' ] ]); - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - // NB: `oldSettings` only exists for backwards compatibility. - _.template = function(text, settings, oldSettings) { - if (!settings && oldSettings) settings = oldSettings; - settings = _.defaults({}, settings, _.templateSettings); + tree = applyAllTransformations(tree, transformations, 20); - // Combine delimiters into one regular expression via alternation. - var matcher = RegExp([ - (settings.escape || noMatch).source, - (settings.interpolate || noMatch).source, - (settings.evaluate || noMatch).source - ].join('|') + '|$', 'g'); + tree = flatten(tree); - // Compile the template source, escaping string literals appropriately. - var index = 0; - var source = "__p+='"; - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { - source += text.slice(index, offset).replace(escaper, escapeChar); - index = offset + match.length; + return tree; + } - if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; - } else if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; - } else if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; + function contains_decimal_number(tree) { + if (typeof tree === "string") { + return false; + } + if (typeof tree === "number") { + if (Number.isFinite(tree) && !Number.isInteger(tree)) { + return true; + } else { + return false; } + } + if (!Array.isArray(tree)) { + return false; + } + return tree.slice(1).some(x => contains_decimal_number(x)); + } - // Adobe VMs need the match returned to produce the correct offest. - return match; - }); - source += "';\n"; - - // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - - source = "var __t,__p='',__j=Array.prototype.join," + - "print=function(){__p+=__j.call(arguments,'');};\n" + - source + 'return __p;\n'; - - try { - var render = new Function(settings.variable || 'obj', '_', source); - } catch (e) { - e.source = source; - throw e; + function contains_only_numbers(tree, { include_number_symbols = false } = {}) { + if (typeof tree === "string") { + if (include_number_symbols) { + if (tree === "e" && math$19.define_e) { + return true; + } + if (tree === "pi" && math$19.define_pi) { + return true; + } + } + return false; + } + if (typeof tree === "number") { + return true; } + if (!Array.isArray(tree)) { + return false; + } + return tree.slice(1).every(x => contains_only_numbers(x, { include_number_symbols: include_number_symbols })); + } - var template = function(data) { - return render.call(this, data, _); - }; + function evaluate_numbers_sub(tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero) { + // assume that tree has been sorted to default order (while flattened) + // and then unflattened_right + // returns unflattened tree - // Provide the compiled source as a convenience for precompilation. - var argument = settings.variable || 'obj'; - template.source = 'function(' + argument + '){\n' + source + '}'; + if (tree === undefined) + return tree; - return template; - }; + if (typeof tree === 'number') { + if(set_small_zero > 0 && math$19.abs(tree) < set_small_zero) { + return 0; + } + if(tree === 0) { + return 0; // so that -0 returns 0 + } + return tree; + } - // Add a "chain" function. Start chaining a wrapped Underscore object. - _.chain = function(obj) { - var instance = _(obj); - instance._chain = true; - return instance; - }; + if (evaluate_functions || contains_only_numbers(tree, { include_number_symbols: true })) { - // OOP - // --------------- - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. + var c = evaluate_to_constant(tree); - // Helper function to continue chaining intermediate results. - var result = function(instance, obj) { - return instance._chain ? _(obj).chain() : obj; - }; + if (c !== null) { + if (typeof c === 'number') { + if (Number.isFinite(c)) { + if(set_small_zero > 0 && math$19.abs(c) < set_small_zero) { + return 0; + } + if (max_digits === Infinity) + return c; + if (Number.isInteger(c)) { + if(c === 0) { + return 0; + } + return c; + } - // Add your own custom functions to the Underscore object. - _.mixin = function(obj) { - _.each(_.functions(obj), function(name) { - var func = _[name] = obj[name]; - _.prototype[name] = function() { - var args = [this._wrapped]; - push.apply(args, arguments); - return result(this, func.apply(_, args)); - }; - }); - }; + let c_minround = evalf(c, 14); + let c_round = evalf(c, max_digits); + if (max_digits === 0) { + // interpret 0 max_digits as only accepting integers + // (even though positive max_digits is number of significant digits) + c_round = math$19.round(c); + } + if (c_round === c_minround) { + return c; + } - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); + // if expression already contained a decimal, + // and contains only numbers (no constants like pi) + // return the number + if (contains_decimal_number(tree) && contains_only_numbers(tree)) { + return c; + } - // Add all mutator Array functions to the wrapper. - _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - var obj = this._wrapped; - method.apply(obj, arguments); - if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; - return result(this, obj); - }; - }); + let c_frac = math$19.fraction(c); + let c_frac_d_round = evalf(c_frac.d, 3); - // Add all accessor Array functions to the wrapper. - _.each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - return result(this, method.apply(this._wrapped, arguments)); - }; - }); + if (c_frac.n < 1E4 || (c_frac_d_round === c_frac.d)) { + let c_reconstruct = evalf(c_frac.s * c_frac.n / c_frac.d, 14); + if (c_reconstruct === c_minround) { + if (c_frac.d === 1) { + return c_frac.s * c_frac.n; + } else { + return ['/', c_frac.s * c_frac.n, c_frac.d]; + } + } + } + } + } + } + } - // Extracts the result from a wrapped and chained object. - _.prototype.value = function() { - return this._wrapped; - }; + if (!Array.isArray(tree)) + return tree; - // Provide unwrapping proxy for some methods used in engine operations - // such as arithmetic and JSON stringification. - _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; + var operator = tree[0]; + var operands = tree.slice(1).map(v => evaluate_numbers_sub( + v, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); - _.prototype.toString = function() { - return '' + this._wrapped; - }; + if (operator === '+') { + let left = operands[0]; + let right = operands[1]; - // AMD registration happens at the end for compatibility with AMD loaders - // that may not enforce next-turn semantics on modules. Even though general - // practice for AMD registration is to be anonymous, underscore registers - // as a named module because, like jQuery, it is a base library that is - // popular enough to be bundled in a third party lib, but not be part of - // an AMD load request. Those cases could generate an error when an - // anonymous define() is called outside of a loader request. - if (typeof undefined === 'function' && undefined.amd) { - undefined('underscore', [], function() { - return _; - }); - } -}.call(commonjsGlobal)); -}); -var underscore_1 = underscore._; + if (right === undefined) + return left; -function handleNaNInfinityStringify(key, value) { - if (value !== value) { - return '0/0'; - } + if (typeof left === 'number') { + if (left === 0) + return right; + if (typeof right === 'number') + return left + right; + // check if right is an addition with that begins with + // a constant. If so combine with left + if (Array.isArray(right) && right[0] === '+' + && (typeof right[1] === 'number')) { + return ['+', left + right[1], right[2]]; + } + // check if right is an addition with that ends with + // a constant. If so combine with left + if (!skip_ordering && Array.isArray(right) && right[0] === '+' + && (typeof right[2] === 'number')) { + return ['+', left + right[2], right[1]]; + } - if (value === 1/0) { - return '1/0'; - } + } + if (typeof right === 'number') + if (right === 0) + return left; - if (value === -1/0) { - return '-1/0'; - } + return [operator].concat(operands); + } + if (operator === '-') { + if (typeof operands[0] === 'number') + return -operands[0]; + // check if operand is a multiplication with that begins with + // a constant. If so combine with constant + if (Array.isArray(operands[0]) && operands[0][0] === '*' + && (typeof operands[0][1] === 'number')) { + return ['*', -operands[0][1]].concat(operands[0].slice(2)); + } + // check if operand is a division with that begins with + // either + /// (A) a constant or + // (B) a multiplication that begins with a constant. + // If so. combine with constant + if (Array.isArray(operands[0]) && operands[0][0] === '/') { + if (typeof operands[0][1] === 'number') + return ['/', -operands[0][1], operands[0][2]]; + if (Array.isArray(operands[0][1]) && operands[0][1][0] === '*' + && (typeof operands[0][1][1] === 'number')) { + return ['/', [ + '*', -operands[0][1][1]].concat(operands[0][1].slice(2)), + operands[0][2]]; - return value; -} + } -function handleNaNInfinityParse(key, value) { - if (value === '0/0') { - return 0/0; - } + } - if (value === '1/0') { - return Infinity; - } + return [operator].concat(operands); + } + if (operator === '*') { + let left = operands[0]; + let right = operands[1]; - if (value === '-1/0') { - return -1/0; - } + if (right === undefined) + return left; - return value; -} + if (typeof left === 'number') { + if (isNaN(left)) + return NaN; -function deepClone(s) { - return JSON.parse( - JSON.stringify(s, handleNaNInfinityStringify), - handleNaNInfinityParse); -} + if (typeof right === 'number') + return left * right; -const equal$2 = function(left, right, { - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, -}={}) { - /* - * Return true if left and right are syntactically equal. - * - */ + if (!isFinite(left)) { + if ((left === Infinity && is_negative_ast(right)) + || (left === -Infinity && is_positive_ast(right))) + return -Infinity + if (is_nonzero_ast(right) === false) + return NaN; + return Infinity; + } + if (left === 0) { + return 0; + } + if (left === 1) + return right; - if(!(Array.isArray(left) && Array.isArray(right))) { - if((typeof left) !== (typeof right)) - return false; + if (left === -1) { + return ['-', right]; + } + // check if right is a multiplication with that begins with + // a constant. If so combine with left + if (Array.isArray(right) && right[0] === '*' + && (typeof right[1] === 'number')) { + left = left * right[1]; + right = right[2]; + if (left === 1) + return right; + if (left === -1) + return ['-', right]; + return ['*', left, right]; + } - if(typeof left === "number" && Number.isFinite(left)) { - let tol = 1E-14; - let minAbs = Math.min(Math.abs(left),Math.abs(right)); - if(allowed_error_is_absolute) { - tol *= minAbs; - if(allowed_error_in_numbers > tol) { - tol = allowed_error_in_numbers; + } + if (typeof right === 'number') { + if (isNaN(right)) + return NaN; + if (!isFinite(right)) { + if ((right === Infinity && is_negative_ast(left)) + || (right === -Infinity && is_positive_ast(left))) + return -Infinity + if (is_nonzero_ast(left) === false) + return NaN; + return Infinity; } - }else { - if(allowed_error_in_numbers > tol) { - tol = allowed_error_in_numbers; + if (right === 0) { + return 0; + } + if (right === 1) + return left; + if (right === -1) { + return ['-', left]; + } + // check if left is a multiplication with that begins with + // a constant. If so combine with right + if (Array.isArray(left) && left[0] === '*' + && (typeof left[1] === 'number')) { + right = right * left[1]; + left = left[2]; + if (right === 1) + return left; + if (right === -1) + return ['-', left]; + return ['*', left, right]; } - tol *= minAbs; } - return Math.abs(left-right) <= tol; - } - return (left===right); - } + return [operator].concat(operands); + } - var leftOperator = left[0]; - var leftOperands = left.slice(1); + if (operator === '/') { - var rightOperator = right[0]; - var rightOperands = right.slice(1); + let numer = operands[0]; + let denom = operands[1]; - if (leftOperator !== rightOperator) - return false; + if (typeof numer === 'number') { + if (numer === 0) { + let denom_nonzero = is_nonzero_ast(denom, assumptions); + if (denom_nonzero) + return 0; + if (denom_nonzero === false) + return NaN; // 0/0 + } - if (leftOperands.length !== rightOperands.length) - return false; + if (typeof denom === 'number') { + let quotient = numer / denom; + if (max_digits === Infinity + || math$19.round(quotient, max_digits) === quotient) + return quotient; + else if (denom < 0) + return ['/', -numer, -denom]; + } - if(allowed_error_in_numbers > 0 && !include_error_in_number_exponents && leftOperator === "^") { - let baseEqual = equal$2(leftOperands[0], rightOperands[0], { - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - }); + // check if denom is a multiplication with that begins with + // a constant. If so combine with numerator + if (Array.isArray(denom) && denom[0] === '*' + && (typeof denom[1] === 'number')) { + let quotient = numer / denom[1]; - if(!baseEqual) { - return false; - } - let exponentEqual = equal$2(leftOperands[1], rightOperands[1]); - return exponentEqual; - } + if (max_digits === Infinity + || math$19.round(quotient, max_digits) === quotient) { + return ['/', quotient, denom[2]]; + } + } + } + else if (typeof denom === 'number') { + // check if numer is a multiplication with that begins with + // a constant. If so combine with denominator + if (Array.isArray(numer) && numer[0] === '*' + && (typeof numer[1] === 'number')) { + let quotient = numer[1] / denom; + if (max_digits === Infinity + || math$19.round(quotient, max_digits) === quotient) { + if (quotient === 1) + return numer[2]; + else + return ['*', quotient, numer[2]]; + } + // if denom is negative move negative to number + if (denom < 0) + return ['/', ['*', -numer[1], numer[2]], -denom]; + } + let reciprocal = 1/denom; + if (max_digits === Infinity + || math$19.round(reciprocal, max_digits) === reciprocal) { + return ['*', reciprocal, numer]; + } + // if denominator is negative, negate whole fraction + if (denom < 0) { + if (Array.isArray(numer) && numer[0] === '-') + return ['/', numer[1], -denom]; + else + return ['-', ['/', numer, -denom]]; - return underscore.every( underscore.zip( leftOperands, rightOperands ), - function(pair) { - return equal$2(pair[0], pair[1], { - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - }); - }); -}; + } + } + return [operator].concat(operands); -const match = function( tree, pattern, params) { + } - /* - * Attempt to match the entire tree to given pattern - * - * Returns - * - object describing the bindings of pattern if the entire tree - * was matched with those bindings - * - false if a match was not found - * - * - * In a pattern: - * - operators much match exactly - * - strings that are designed as variables - * must be bound to a subtree - * - numbers and other strings much exactly match - * - * variables, if defined, specifies which strings in pattern are - * wildcards that can be matched to any subtree - * If defined, variables must be an object with - * key: string from pattern which is a wildcard - * values: must be one of the following - * - true: any subtree matches the wildcard - * - a regular expression: subtree must match regular expression - * (a non-string subtree is first passed to JSON.stringify) - * - a function: takes a tree as an argument and - * returns whether or not that tree is a valid match - * - * If variables is not defined, then all variables from pattern - * will be wildcards that match any subtree - * - * If defined, params is an object with keys - * - allow_permutations: if true, check all permutations of operators - * - allow_implicit_identities: an array of variables from pattern - * that can implicitly match the identity of their enclosing - * operator - * - allow_extended_match: if true, then some tree operands can be skipped - * otherwise, all tree operands must be matched + if (operator === '^') { - */ + let base = operands[0]; + let pow = operands[1]; - var allow_extended_match=false; + if (typeof pow === 'number') { + if (pow === 0) { + if (!math$19.pow_strict) + return 1; + let base_nonzero = is_nonzero_ast(base, assumptions); + if (base_nonzero && (base !== Infinity) && (base !== -Infinity)) + return 1; + if (base_nonzero === false) + return NaN; // 0^0 + } + else if (pow === 1) { + return base; + } + else if (typeof base === 'number') { + let result = math$19.pow(base, pow); + if (max_digits === Infinity + || math$19.round(result, max_digits) === result) + return result; - if(params === undefined) - params = {}; - else { - // don't let extended match parameter propagate - if(params.allow_extended_match) { - allow_extended_match=true; - // copy params to new object - params = Object.assign({}, params); - delete params["allow_extended_match"]; + } + } else if (base === 1) { + return 1; + } + return [operator].concat(operands); } + return [operator].concat(operands); } - var variables$$1 = params["variables"]; - if(variables$$1 === undefined) { - variables$$1 = {}; - let vip = variables(pattern); - for(let i=0; i < vip.length;i++ ) { - variables$$1[vip[i]] = true; - } - // add to params, after copying to new object - params = Object.assign({}, params); - params["variables"] = variables$$1; - } + function evaluate_numbers(expr_or_tree, { + assumptions, max_digits, skip_ordering = false, + evaluate_functions = false, + set_small_zero = 0, + } = {}) { - if(pattern in variables$$1) { - // check if tree satisfies any conditions for pattern - let condition = variables$$1[pattern]; - if(condition !== true) { - if(condition instanceof RegExp) { - if(typeof tree === 'string') { - if(!tree.match(condition)) - return false; - } - else { - if(!JSON.stringify(tree).match(condition)) - return false; - } - } - else if(typeof variables$$1[pattern] === 'function') { - if(!variables$$1[pattern](tree)) - return false; - } - else { - return false; - } - } + if (max_digits === undefined || + !(Number.isInteger(max_digits) || max_digits === Infinity)) + max_digits = 0; - // record the whole tree as the match to pattern - let result = {}; - result[pattern] = tree; - return result; - } + if (set_small_zero === true) { + set_small_zero = 1E-14; + } - if(params.allow_permutations) { - // even though order doesn't matter with permutations - // normalize to default order as it orients operators - // such as inequalities and containments to a direction - // that won't be affected by permutations - tree = default_order(tree); - pattern = default_order(pattern); - } + var tree = get_tree(expr_or_tree); - // if pattern isn't an array, the tree must be the pattern to match - // (As there are no variables, there is no binding) - if(!Array.isArray(pattern)) { - if (tree === pattern) - return {}; - else - return false; - } - var treeOperands = allChildren(tree); - var operator=pattern[0]; - var patternOperands = pattern.slice(1); + if (assumptions === undefined && expr_or_tree.context !== undefined + && expr_or_tree.context.get_assumptions !== undefined) + assumptions = expr_or_tree.context.get_assumptions( + [expr_or_tree.variables()]); + + var result; + if (skip_ordering) { + tree = unflattenRight(flatten(tree)); + result = evaluate_numbers_sub( + tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero); + } else { + tree = unflattenRight(default_order(flatten(tree))); + result = default_order(evaluate_numbers_sub( + tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); + // TODO: determine how often have to repeat + result = default_order(evaluate_numbers_sub( + unflattenRight(result), assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); + } - // Since pattern is an array, there is no match if tree isn't an array - // of the same or larger length with the same operator - // (unless some pattern variables can be implicitly set to identities) - if (!Array.isArray(tree) || (tree[0] !== operator) - || (treeOperands.length < patternOperands.length)) { + return flatten(result); + } - if(Array.isArray(params.allow_implicit_identities)) { + function collect_like_terms_factors(expr_or_tree, assumptions, max_digits) { - let result = matchImplicitIdentity(tree, pattern, params); - if(result) - return result; - } + function isNumber(s) { + if (typeof s === 'number') + return true; + if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) + return true; + return false; + } + function isNegativeNumber(s) { + if (typeof s === 'number' && s < 0) + return true; + if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) + return true; + return false; + } + function isNumerical(s) { + if (typeof s === 'number') + return true; + if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) + return true; + let c = evaluate_to_constant(s); + if (typeof c === 'number' && Number.isFinite(c)) + return true; - // if pattern is a multiplication and - // tree is a unary minus of a multiplication - // convert tree to a muliplication with unary minus on first factor - if(operator === '*' && Array.isArray(tree) && tree[0] === '-' - && Array.isArray(tree[1]) && tree[1][0] === '*') { - treeOperands = allChildren(tree[1]); - treeOperands[0] = ['-', treeOperands[0]]; - } - else - return false; - } + return false; - let result = matchOperands(operator, treeOperands, patternOperands, - params, allow_extended_match); + } - if(result) - return result; + var tree = get_tree(expr_or_tree); - if(Array.isArray(params.allow_implicit_identities)) - return matchImplicitIdentity([operator].concat(treeOperands), - pattern, params); - else - return false; -}; + if (assumptions === undefined && expr_or_tree.context !== undefined + && expr_or_tree.context.get_assumptions !== undefined) + assumptions = expr_or_tree.context.get_assumptions( + [expr_or_tree.variables()]); + tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits, evaluate_functions: true }); + var transformations = []; -function matchOperands(operator, treeOperands, patternOperands, params, - allow_extended_match) { + // preliminary transformations + transformations.push([ + [ '/', 'x', [ '^', 'y', 'a' ] ], + [ '*', 'x', [ '^', 'y', [ '-', 'a' ] ] ], + { evaluate_numbers: true, max_digits: max_digits }]); + transformations.push([ + [ '/', 'x', 'y' ], + [ '*', 'x', [ '^', 'y', [ '-', 1 ] ] ], + { evaluate_numbers: true, max_digits: max_digits }]); + tree = applyAllTransformations(tree, transformations, 40); - // treeOperands will match patternOperands only if - // - each pattern operand can be matched by a tree operand - // (or a group of tree operands) - // - if allow_extended_match, then some tree operands can be skipped - // otherwise, all tree operands must be matched - // - if permutations are allowed (calculated from params and operator) - // patterns can be matched in any order - // otherwise, patterns must be matched in order, possibly skipping - // beginning or ending tree operands (if allow_extended_match) - // - all the resulting bindings are consistent, - // meaning they assigned the same match to any - // repeated placeholder in pattern + // collecting like terms and factors + transformations = []; + transformations.push( + [ + [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], + [ '^', 'x', [ '+', 'n', 'm' ] ], + { + variables: { + x: v => is_nonzero_ast(v, assumptions), + n: isNumber, m: isNumber + }, + evaluate_numbers: true, max_digits: max_digits, + allow_implicit_identities: ['m', 'n'], + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [ + [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], + [ '^', 'x', [ '+', 'n', 'm' ] ], + { + variables: { + x: true, + n: v => isNumber(v) && is_positive_ast(v, assumptions), + m: v => isNumber(v) && is_positive_ast(v, assumptions) + }, + evaluate_numbers: true, max_digits: max_digits, + allow_implicit_identities: ['m', 'n'], + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [ + [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], + [ '^', 'x', [ '+', 'n', 'm' ] ], + { + variables: { + x: true, + n: v => isNumber(v) && is_negative_ast(v, assumptions), + m: v => isNumber(v) && is_negative_ast(v, assumptions) + }, + evaluate_numbers: true, max_digits: max_digits, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [ + [ '+', [ '*', 'n', 'x' ], [ '*', 'm', 'x' ] ], + [ '*', [ '+', 'n', 'm' ], 'x' ], + { + variables: { + x: true, + n: isNumber, m: isNumber + }, + evaluate_numbers: true, max_digits: max_digits, + allow_implicit_identities: ['m', 'n'], + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [ + [ '+', [ '*', 'n', 'x' ], [ '-', [ '*', 'm', 'x' ] ] ], + [ '*', [ '+', 'n', [ '-', 'm' ] ], 'x' ], + { + variables: { + x: true, + n: isNumber, m: isNumber + }, + evaluate_numbers: true, max_digits: max_digits, + allow_implicit_identities: ['m', 'n'], + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [ + [ '^', [ '*', 'x', 'y' ], 'a' ], + [ '*', [ '^', 'x', 'a' ], [ '^', 'y', 'a' ] ], + { allow_permutations: true, }] + ); + transformations.push( + [ + [ '^', [ '^', 'x', 'n' ], 'm' ], + [ '^', 'x', [ '*', 'n', 'm' ] ], + { + variables: { + x: true, + n: isNumber, m: isNumber + }, + evaluate_numbers: true, max_digits: max_digits, + allow_permutations: true, + }] + ); + transformations.push([ + [ '-', [ '+', 'a', 'b' ] ], + [ '+', [ '-', 'a' ], [ '-', 'b' ] ] + ]); + + // evaluate any products + // (required since evaluate_numbers needs to be applied separately + // to complicated products to evaluate them as numbers) + transformations.push( + [ + [ '*', 'x', 'y' ], + [ '*', 'x', 'y' ], + { + variables: { x: isNumerical, y: isNumerical }, + evaluate_numbers: true, max_digits: max_digits, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); - var previous_matches = patternOperands.map(v => Object()); - var nPars = patternOperands.length; + tree = applyAllTransformations(tree, transformations, 40); - // TODO: check if commutative - var allow_permutations = false; - if(params.allow_permutations && - (operator === "*" || operator === "+" || operator === "=" - || operator === "and" || operator === "or" || operator === "ne" - || operator === "union" || operator === "intersect")) - allow_permutations=true; + transformations = []; + // redo as division + transformations.push( + [ + [ '*', 'x', [ '^', 'y', [ '-', 'a' ] ] ], + [ '/', 'x', [ '^', 'y', 'a' ] ], + { + allow_extended_match: true, + allow_permutations: true, + evaluate_numbers: true, max_digits: max_digits, + max_group: 1, + }]); + transformations.push([ + [ '*', 'x', [ '^', 'y', 'n' ] ], + [ '/', 'x', [ '^', 'y', [ '-', 'n' ] ] ], + { + variables: { + x: true, y: true, + n: isNegativeNumber + }, + evaluate_numbers: true, max_digits: max_digits, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }]); + tree = applyAllTransformations(tree, transformations, 40); + transformations = []; + // redo as division, try 2 + transformations.push([ + [ '^', 'y', 'n' ], + [ '/', 1, [ '^', 'y', [ '-', 'n' ] ] ], + { + variables: { + y: true, + n: isNegativeNumber + }, + evaluate_numbers: true, max_digits: max_digits, + }]); + tree = applyAllTransformations(tree, transformations, 40); - function matchOps(treeOpIndicesLeft, patternInd, matches) { + transformations = []; + // '*' before '/' and products in denominator + transformations.push([ + [ '*', 'x', [ '/', 'y', 'z' ] ], + [ '/', [ '*', 'x', 'y' ], 'z' ], + { + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }]); + transformations.push([ + [ '/', [ '/', 'x', 'y' ], 'z' ], + [ '/', 'x', [ '*', 'y', 'z' ] ], + { + allow_extended_match: true, + allow_permutations: true, + }]); + transformations.push([ + [ '/', 'x', [ '/', 'y', 'z' ] ], + [ '/', [ '*', 'x', 'z' ], 'y' ], + { + allow_extended_match: true, + allow_permutations: true, + }]); + tree = applyAllTransformations(tree, transformations, 40); - // max group is the maximum number of tree operands that can be matched by a variable - let max_group = 1; - let max_last_group = 1; + tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits }); - // only allow multiple matches by variables for associative operators - if(is_associative[operator]) { - max_group = treeOpIndicesLeft.length - (nPars-patternInd-1); - max_last_group = treeOpIndicesLeft.length; } + return tree; - if(params.max_group !== undefined) - max_group = (params.max_group < max_group) ? params.max_group - : max_group; - if(params.max_last_group !== undefined) - max_last_group = (params.max_last_group < max_last_group) ? params.max_last_group - : max_last_group; + } + function simplify_ratios(expr_or_tree, assumptions) { - let inds_set; + // TODO: actually factor numerator and denominator + // for now, assume factored, other than minus sign - if(!allow_extended_match && patternInd === nPars-1) { - // if no extended match, then the last pattern operand - // must match the remaining tree operands - if(treeOpIndicesLeft.length <= max_last_group) { - inds_set = [treeOpIndicesLeft]; - } - else { - return false; - } - } - else if(allow_permutations) { - inds_set = subsets(treeOpIndicesLeft, max_group); - } - else { - inds_set = []; - for(let i=1; i <= max_group; i++) - inds_set.push(treeOpIndicesLeft.slice(0, i)); + function remove_negative_factors(factors) { - } + var sign_change = 1; - for(let inds of inds_set) { + factors = factors.map(function (v) { + if (typeof v === "number") { + if (v < 0) { + sign_change *= -1; + return -v; + } + return v; + } + if (!Array.isArray(v)) + return v; - let m = previous_matches[patternInd][inds]; + if (v[0] === '-') { + sign_change *= -1; + return v[1]; + } + if (v[0] !== '+') + return v; - if(m === undefined) { + var negate = false; + if ((typeof v[1] === "number") && v[1] < 0) + negate = true; + else if (Array.isArray(v[1]) && v[1][0] === '-') + negate = true; + else if (Array.isArray(v[1]) && v[1][0] === '*' && Number(v[1][1]) < 0) { + negate = true; + } - let treeChunk = inds.reduce(function(a,b) { - return a.concat([treeOperands[b]]);}, []); + if (negate) { + sign_change *= -1; + var v_ops = v.slice(1).map(x => ['-', x]); + return evaluate_numbers(['+'].concat(v_ops)); + } + else + return v; + }); - if(treeChunk.length > 1) - treeChunk= [operator].concat(treeChunk); - else - treeChunk = treeChunk[0]; + return { factors: factors, sign_change: sign_change }; + } - m = match(treeChunk, patternOperands[patternInd], params); + function simplify_ratios_sub(tree, negated) { - previous_matches[patternInd][inds] = m; + if (!Array.isArray(tree)) { + if (negated) { + return ['-', tree]; + } else { + return tree; + } + } - } + var operator = tree[0]; + if (operator === "-") { + return simplify_ratios_sub(tree[1], negated = true); + } + var operands = tree.slice(1).map(v => simplify_ratios_sub(v)); - if(!m) - continue; + if (operator !== '/') { + if (negated) { + return ['-', [operator, ...operands]] + } else { + return [operator, ...operands]; + } + } - // Check consistency of bindings - if (!underscore.every( underscore.intersection( - Object.keys( matches ), - Object.keys( m ) ), - function(k) { - return equal$2(matches[k], m[k]); - })) { - continue; - } + var numer = operands[0]; + var denom = operands[1]; - // combine matches - let combined_matches = Object.assign({}, m); - Object.assign( combined_matches, matches ); + // factor a minus sign from each factor in numerator and denominator + // if it is negative or it is a sum with a negative first term + // (when terms are sorted as though they were not negative) - let treeOpIndices = treeOpIndicesLeft.filter( - v => !inds.includes(v)); + numer = default_order(numer, { ignore_negatives: true }); + var numer_factors; + if (Array.isArray(numer) && numer[0] === '*') + numer_factors = numer.slice(1); + else + numer_factors = [numer]; + var result_n = remove_negative_factors(numer_factors); + numer_factors = result_n["factors"]; + if (negated) { + result_n["sign_change"] *= -1; + } - // if last pattern operand, we're done - if(patternInd === nPars-1) { - let skipped = treeOpIndices.reduce(function(a,b) { - return a.concat([treeOperands[b]]);}, []); + denom = default_order(denom, { ignore_negatives: true }); + var denom_factors; + if (Array.isArray(denom) && denom[0] === '*') + denom_factors = denom.slice(1); + else + denom_factors = [denom]; + var result_d = remove_negative_factors(denom_factors); + denom_factors = result_d["factors"]; - return {matches: combined_matches, skipped: skipped}; - } + if (result_n["sign_change"] * result_d["sign_change"] < 0) + numer_factors[0] = ['-', numer_factors[0]]; - // attempt to match remaining treeOps - // with remaining pattern operands - let results = matchOps(treeOpIndices, patternInd+1, - combined_matches); + if (numer_factors.length === 1) + numer = numer_factors[0]; + else + numer = ['*'].concat(numer_factors); + if (denom_factors.length === 1) + denom = denom_factors[0]; + else + denom = ['*'].concat(denom_factors); - if(results) { - return results; - } - } + return ['/', numer, denom]; - return false; - } + } - var matches = {}; - // create array of 0, 1, ...., treeOperands.length-1 - var treeIndices = [...Array(treeOperands.length).keys()]; + var tree = get_tree(expr_or_tree); - if(allow_permutations) { + if (assumptions === undefined && expr_or_tree.context !== undefined + && expr_or_tree.context.get_assumptions !== undefined) + assumptions = expr_or_tree.context.get_assumptions( + [expr_or_tree.variables()]); - let m = matchOps(treeIndices, 0, {}); + return simplify_ratios_sub(tree); - if(!m) - return false; + } - matches = m.matches; - if(m.skipped.length > 0) - matches['_skipped'] = m.skipped; + var simplify$3 = /*#__PURE__*/Object.freeze({ + clean: clean, + simplify: simplify$2, + simplify_logical: simplify_logical, + evaluate_numbers: evaluate_numbers, + collect_like_terms_factors: collect_like_terms_factors, + collapse_unary_minus: collapse_unary_minus, + simplify_ratios: simplify_ratios, + default_order: default_order + }); - return matches; - } - else { - let maxSkip = allow_extended_match ? treeOperands.length - nPars : 0; - let skipped_before = []; - let m; + function tuples_to_vectors(expr_or_tree) { + // convert tuple to vectors + // except if tuple is argument of a function, gts, lts, or interval - // without permutations, operands can only be skipped - // at beggining or end - // (matchOps will skip at end but not at beginning - // when permutations are not allowed) - for(let initialSkip=0; initialSkip <= maxSkip; initialSkip++ ) { + var tree = get_tree(expr_or_tree); - m = matchOps(treeIndices, 0, {}); + if (typeof tree === 'number') { + return tree; + } - if(m) - break; + if (typeof tree === 'string') { + return tree; + } - treeIndices = treeIndices.slice(1); - skipped_before.push(treeOperands[initialSkip]); - } + if (typeof tree === 'boolean') { + return tree; + } - if(!m) - return false; + var operator = tree[0]; + var operands = tree.slice(1); - matches = m.matches; - if(m.skipped.length > 0) - matches['_skipped'] = m.skipped; - if(skipped_before.length > 0) - matches['_skipped_before'] = skipped_before; - return matches; + if(operator === 'tuple') { + let result = ['vector'].concat( operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); + return result; + } - } -} + if (operator === 'apply') { + if(operands[1][0] === 'tuple') { + // special case for function applied to tuple. + // preserve tuple + let f = tuples_to_vectors(operands[0]); + let f_operands = operands[1].slice(1); + let f_tuple = ['tuple'].concat( f_operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); + return ['apply', f, f_tuple]; + } + // no special case for function applied to single argument + } + else if(operator === 'gts' || operator === 'lts' || operator === 'interval') { + // don't change tuples of gts, lts, or interval + let args = operands[0]; + let booleans = operands[1]; -function matchImplicitIdentity(tree, pattern, params) { + if(args[0] !== 'tuple' || booleans[0] !== 'tuple') + // something wrong if args or strict are not tuples + throw new Error("Badly formed ast"); - var operator = pattern[0]; - var patternOperands = pattern.slice(1); + let args2= ['tuple'].concat( args.slice(1).map( function(v,i) { return tuples_to_vectors(v); } ) ); - // for now, implement implicit identities just - // for addition, multiplication, and exponents - if(!(operator === '+' || operator === '*' || operator === '^')) - return false; + return [operator, args2, booleans]; + } - // find any pattern operand that is allowed to be an implicit identity - var implicit_identity = null; - for(let i=0; i < patternOperands.length; i++) { - let po = patternOperands[i]; - if(typeof po === 'string' && - params.allow_implicit_identities.includes(po)) { - implicit_identity = po; - break; - } + var result = [operator].concat( operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); + return result; } - if(implicit_identity === null) - return false; - - var matches = {}; + function to_intervals(expr_or_tree) { + // convert tuple and arrays of two arguments to intervals + // except if tuple is argument of a function, gts, lts, or interval - // match implicit_identity to the identity of the operator - if(operator === '+') - matches[implicit_identity] = 0; - else - matches[implicit_identity] = 1; + var tree = get_tree(expr_or_tree); - // special case where tree beings with unary - - // and pattern is a multiplication where implicit identity is a factor - if(operator === '*' && patternOperands.includes(implicit_identity) - && Array.isArray(tree) && tree[0] === '-') { - matches[implicit_identity] = -1; - tree = tree[1]; - } + if (typeof tree === 'number') { + return tree; + } - // remove matched variable from pattern - var matched_ind = patternOperands.indexOf(implicit_identity); - patternOperands.splice(matched_ind,1); + if (typeof tree === 'string') { + return tree; + } - // for exponentiation, only allow for identity in exponent - if(operator === '^' && matched_ind === 0) - return false; + if (typeof tree === 'boolean') { + return tree; + } - if(patternOperands.length === 1) { - pattern = patternOperands[0]; - } - else { - pattern = [operator].concat(patternOperands); - } + var operator = tree[0]; + var operands = tree.slice(1); - var m = match(tree, pattern, params); + if(operator === 'tuple' && operands.length === 2) { + // open interval + let result = ['tuple'].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); + result = ['interval', result, ['tuple', false, false]]; + return result; + } + if(operator === 'array' && operands.length === 2) { + // closed interval + let result = ['tuple'].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); + result = ['interval', result, ['tuple', true, true]]; + return result; + } - if (m) { - // Check consistency of bindings - if(implicit_identity in m) { - if(!equal$2(m[implicit_identity], matches[implicit_identity])) - return false; + if (operator === 'apply') { + if(operands[1][0] === 'tuple') { + // special case for function applied to tuple. + // preserve tuple + let f = to_intervals(operands[0]); + let f_operands = operands[1].slice(1); + let f_tuple = ['tuple'].concat( f_operands.map( function(v,i) { return to_intervals(v); } ) ); + return ['apply', f, f_tuple]; } - Object.assign( matches, m); - } else - return false; - - return matches; -} + // no special case for function applied to single argument + } + else if(operator === 'gts' || operator === 'lts' || operator === 'interval') { + // don't change tuples of gts, lts, or interval + let args = operands[0]; + let booleans = operands[1]; + if(args[0] !== 'tuple' || booleans[0] !== 'tuple') + // something wrong if args or strict are not tuples + throw new Error("Badly formed ast"); -const substitute = function( pattern, bindings ) { - if (typeof pattern === 'number' || typeof pattern === "boolean") { - return pattern; - } + let args2= ['tuple'].concat( args.slice(1).map( function(v,i) { return to_intervals(v); } ) ); - if (typeof pattern === 'string') { - if (bindings[pattern] !== undefined) - return deepClone(bindings[pattern]); + return [operator, args2, booleans]; + } - return pattern; + var result = [operator].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); + return result; } - if (Array.isArray(pattern)) { - return [pattern[0]].concat( pattern.slice(1).map( function(p) { - return substitute(p, bindings); - }) ); + function ParseError(message, location) { + this.name = 'ParseError'; + this.message = message || 'Error parsing input'; + this.stack = (new Error()).stack; + this.location = location; } + ParseError.prototype = Object.create(Error.prototype); + ParseError.prototype.constructor = ParseError; - return []; -}; - -const transform$2 = function( tree, F ) { - /* - * Transform the tree function F in a bottom-up fashion - * (calling F at children before parents) - * - * F must be be a function that returns a tree - */ + // lexer class + // + // Processes input string to return tokens + // + // Token rules: + // array of rules to identify tokens + // Rules will be applied in order until a match is found. + // Each rule is an array of two or three elements + // First element: a string to be converted into a regular expression + // Second element: the token type + // Third element (optional): replacement for actual string matched - if (Array.isArray(tree)) { - let new_tree = [tree[0]]; - for( let i=1; i 0; depth-- ) { - old_tree = new_tree; - for(let i=0; i 0 || add_right.length > 0) { - if(Array.isArray(result)) { - if(result[0]===pattern[0]) { - result = result.slice(1); - } - else { - result = [result]; - } - } - result=[pattern[0]].concat( - add_left, result, add_right); - } - - if(params.evaluate_numbers) - result = evaluate_numbers( - result, {max_digits: params.max_digits}); + // regular expression to identify whitespace at beginning + this.initial_whitespace = new RegExp('^(' + whitespace + ')+'); + + // convert first element of each rule to a regular expression that + // starts at the beginning of the string + for(let rule of token_rules) { + this.token_rules.push([new RegExp('^'+rule[0])].concat(rule.slice(1))); + } + } + + set_input(input) { + if(typeof input !== "string") + throw new Error("Input must be a string"); + + this.input = input; + this.location = 0; + } - return result; - } - else { - return subtree; - } - }); + return_state() { + return({ input: this.input, location: this.location }); + } - } + set_state({ input=null, location=0 } = {}) { - if(equal$2(old_tree, new_tree)) { - return new_tree; - } - } + if(input !== null) { + this.input = input; + this.location = location; + } + } + + + advance({ remove_initial_space=true } = {}) { + // Find next token at beginning of input and delete from input. + // Update location to be the position in original input corresponding + // to end of match. + // Return token, which is an array of token type and matched string - return new_tree; -}; -var endsWith = string.endsWith; -var clone$11 = object.clone; + let result = this.initial_whitespace.exec(this.input); + if(result) { + //first find any initial whitespace and adjust location + let n_whitespace = result[0].length; + this.input = this.input.slice(n_whitespace); + this.location += n_whitespace; + + // don't remove initial space, return it as next token + if(!remove_initial_space) { + return { + token_type: "SPACE", + token_text: result[0], + original_text: result[0], + } + } + // otherwise ignore initial space and continue + } + + // check for EOF + if(this.input.length === 0) { + return { + token_type: "EOF", + token_text: "", + original_text: "", + } + } + + // search through each token rule in order, finding first match + result = null; + + for(var rule of this.token_rules) { + result = rule[0].exec(this.input); + + if(result) { + let n_characters = result[0].length; + this.input = this.input.slice(n_characters); + this.location += n_characters; + break; + } + } -function factory$278 (type, config, load, typed, math) { - var add = load(addScalar); - var subtract = load(subtract$1); - var multiply = load(multiplyScalar); - var divide = load(divideScalar); - var pow = load(pow$1); - var abs = load(abs$1); - var fix = load(fix$1); - var round = load(round$1); - var equal = load(equal$1); - var isNumeric = load(isNumeric$1); - var format = load(format$8); - var getTypeOf = load(_typeof$1); - var toNumber = load(number$3); - var Complex = load(Complex_1); + // case that didn't find any matches + if(result === null) { + return { + token_type: "INVALID", + token_text: this.input[0], + original_text: this.input[0], + } + } - /** - * A unit can be constructed in the following ways: - * var a = new Unit(value, name); - * var b = new Unit(null, name); - * var c = Unit.parse(str); - * - * Example usage: - * var a = new Unit(5, 'cm'); // 50 mm - * var b = Unit.parse('23 kg'); // 23 kg - * var c = math.in(a, new Unit(null, 'm'); // 0.05 m - * var d = new Unit(9.81, "m/s^2"); // 9.81 m/s^2 - * - * @class Unit - * @constructor Unit - * @param {number | BigNumber | Fraction | Complex | boolean} [value] A value like 5.2 - * @param {string} [name] A unit name like "cm" or "inch", or a derived unit of the form: "u1[^ex1] [u2[^ex2] ...] [/ u3[^ex3] [u4[^ex4]]]", such as "kg m^2/s^2", where each unit appearing after the forward slash is taken to be in the denominator. "kg m^2 s^-2" is a synonym and is also acceptable. Any of the units can include a prefix. - */ - function Unit(value, name) { - if (!(this instanceof Unit)) { - throw new Error('Constructor must be called with the new operator'); + // found a match, set token + if(rule.length > 2) { + // overwrite text by third element of rule + return { token_type: rule[1], + token_text: rule[2], + original_text: result[0], + }; + } + else { + return { token_type: rule[1], + token_text: result[0], + original_text: result[0], + }; + } } - if (!(value == undefined || isNumeric(value) || type.isComplex(value))) { - throw new TypeError('First parameter in Unit constructor must be number, BigNumber, Fraction, Complex, or undefined'); - } - if (name != undefined && (typeof name !== 'string' || name === '')) { - throw new TypeError('Second parameter in Unit constructor must be a string'); - } + + unput(string) { + // add string to beginning of input and adjust location + + if(typeof string !== "string") + throw new Error("Input must be a string"); + + this.location -= string.length; + this.input = string + this.input; - if (name != undefined) { - var u = Unit.parse(name); - this.units = u.units; - this.dimensions = u.dimensions; - } - else { - this.units = [ - { - unit: UNIT_NONE, - prefix: PREFIXES.NONE, // link to a list with supported prefixes - power: 0 - } - ]; - this.dimensions = []; - for(var i=0; i + * Duane Nykamp + * + * This file is part of a math-expressions library + * + * math-expressions is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or at your option any later version. + * + * math-expressions is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ + + + // UPDATETHIS: Is this grammar still correct? + + /* Grammar: + + statement_list = + statement_list ',' statement | + statement + + statement = + '...' | + statement_a '|' statement_a | + statement_a ':' statement_a | + statement_a + **** statement_a '|' statement_a + used with turning off '|' statement '|' in baseFactor + tried only after parse error encountered + + statement_a = + statement_a 'OR' statement_b | + statement_b + + statement_b = + statement_b 'AND' relation | + relation + + relation = + 'NOT' relation | + '!' relation | + relation '=' expression | + relation 'NE' expression | + relation '<' expression | + relation '>' expression | + relation 'LE' expression | + relation 'GE' expression | + relation 'IN' expression | + relation 'NOTIN' expression | + relation 'NI' expression | + relation 'NOTNI' expression | + relation 'SUBSET' expression | + relation 'NOTSUBSET' expression | + relation 'SUPERSET' expression | + relation 'NOTSUPERSET' expression | + expression + + expression = + expression '+' term | + expression '-' term | + expression 'UNION' term | + expression 'INTERSECT' term | + '+' term | + term + + term = + term '*' factor | + term nonMinusFactor | + term '/' factor | + factor + + baseFactor = + '(' statement_list ')' | + '[' statement_list ']' | + '{' statement_list '}' | + '(' statement ',' statement ']' | + '[' statement ',' statement ')' | + '|' statement '|' | + number | + variable | + modified_function '(' statement_list ')' | + modified_applied_function '(' statement_list ')' | + modified_function | + modified_applied_function factor | + baseFactor '_' baseFactor | + *** modified_applied_function factor + allowed only if allowSimplifiedFunctionApplication==true + *** '|' statement '|' + allowed only at beginning of factor or if not currently in absolute value + + + modified_function = + function | + function '_' baseFactor | + function '_' baseFactor '^' factor | + function '^' factor + function "'" + function '_' baseFactor "'" + function '_' baseFactor "'" '^' factor + function "'" '^' factor + *** where the "'" after the functions can be repeated + + modified_applied_function = + applied_function | + applied_function '_' baseFactor | + applied_function '_' baseFactor '^' factor | + applied_function '^' factor + applied_function "'" + applied_function '_' baseFactor "'" + applied_function '_' baseFactor "'" '^' factor + applied_function "'" '^' factor + *** where the "'" after the applied_functions can be repeated + + nonMinusFactor = + baseFactor | + baseFactor '^' factor | + baseFactor '!' and/or "'" | + baseFactor '!' and/or "'" '^' factor| + *** where '!' and/or "'" indicates arbitrary sequence of "!" and/or "'" + + factor = + '-' factor | + nonMinusFactor - function skipWhitespace() { - while (c == ' ' || c == '\t') { - next(); - } - } + */ - function isDigitDot(c) { - return ((c >= '0' && c <= '9') || c == '.'); - } + // in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, + // it must be at the end or followed a comma, |, ), }, or ] + const sci_notat_exp_regex = '(E[+\\-]?[0-9]+\\s*($|(?=\\,|\\||\\)|\\}|\\])))?'; + + + const text_rules = [ + // in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, + // it must be at the end or followed a |, or a closing ),}, or ] + ['[0-9]+(\\.[0-9]*)?' + sci_notat_exp_regex, 'NUMBER'], + ['\\.[0-9]+' + sci_notat_exp_regex, 'NUMBER'], + ['\\*\\*', '^'], + ['\\*', '*'], // there is some variety in multiplication symbols + ['\\xB7', '*'], // '·' + ['\u00B7', '*'], // '·' + ['\u2022', '*'], // '•' + ['\u22C5', '*'], // '⋅' + ['\u00D7', '*'], // '×' + ['/', '/'], + ['-', '-'], // there is quite some variety with unicode hyphens + ['\u058A', '-'], // '֊' + ['\u05BE', '-'], // '־' + ['\u1806', '-'], // '᠆' + ['\u2010', '-'], // '‐' + ['\u2011', '-'], // '‑' + ['\u2012', '-'], // '‒' + ['\u2013', '-'], // '–' + ['\u2014', '-'], // '—' + ['\u2015', '-'], // '―' + ['\u207B', '-'], // '⁻' + ['\u208B', '-'], // '₋' + ['\u2212', '-'], // '−' + ['\u2E3A', '-'], // '⸺' + ['\u2E3B', '-'], // '⸻' + ['\uFE58', '-'], // '﹘' + ['\uFE63', '-'], // '﹣' + ['\uFF0D', '-'], // '-' + ['\\+', '+'], + ['\\^', '^'], // a few ways to denote exponentiation + ['\u2038', '^'], // '‸' + ['\u028C', '^'], // 'ʌ' + ['\\|', '|'], + ['\\(', '('], + ['\\)', ')'], + ['\\[', '['], + ['\\]', ']'], + ['\\{', '{'], + ['\\}', '}'], + [',', ','], + [':', ':'], + + ['\u03B1', 'VARMULTICHAR', 'alpha'], // 'α' + ['\u03B2', 'VARMULTICHAR', 'beta'], // 'β' + ['\u03D0', 'VARMULTICHAR', 'beta'], // 'ϐ' + ['\u0393', 'VARMULTICHAR', 'Gamma'], // 'Γ' + ['\u03B3', 'VARMULTICHAR', 'gamma'], // 'γ' + ['\u0394', 'VARMULTICHAR', 'Delta'], // 'Δ' + ['\u03B4', 'VARMULTICHAR', 'delta'], // 'δ' + ['\u03B5', 'VARMULTICHAR', 'epsilon'], // 'ε' should this be varepsilon? + ['\u03F5', 'VARMULTICHAR', 'epsilon'], // 'ϵ' + ['\u03B6', 'VARMULTICHAR', 'zeta'], // 'ζ' + ['\u03B7', 'VARMULTICHAR', 'eta'], // 'η' + ['\u0398', 'VARMULTICHAR', 'Theta'], // 'Θ' + ['\u03F4', 'VARMULTICHAR', 'Theta'], // 'ϴ' + ['\u03B8', 'VARMULTICHAR', 'theta'], // 'θ' + ['\u1DBF', 'VARMULTICHAR', 'theta'], // 'ᶿ' + ['\u03D1', 'VARMULTICHAR', 'theta'], // 'ϑ' + ['\u03B9', 'VARMULTICHAR', 'iota'], // 'ι' + ['\u03BA', 'VARMULTICHAR', 'kappa'], // 'κ' + ['\u039B', 'VARMULTICHAR', 'Lambda'], // 'Λ' + ['\u03BB', 'VARMULTICHAR', 'lambda'], // 'λ' + ['\u03BC', 'VARMULTICHAR', 'mu'], // 'μ' + ['\u00B5', 'VARMULTICHAR', 'mu'], // 'µ' should this be micro? + ['\u03BD', 'VARMULTICHAR', 'nu'], // 'ν' + ['\u039E', 'VARMULTICHAR', 'Xi'], // 'Ξ' + ['\u03BE', 'VARMULTICHAR', 'xi'], // 'ξ' + ['\u03A0', 'VARMULTICHAR', 'Pi'], // 'Π' + ['\u03C0', 'VARMULTICHAR', 'pi'], // 'π' + ['\u03D6', 'VARMULTICHAR', 'pi'], // 'ϖ' should this be varpi? + ['\u03C1', 'VARMULTICHAR', 'rho'], // 'ρ' + ['\u03F1', 'VARMULTICHAR', 'rho'], // 'ϱ' should this be varrho? + ['\u03A3', 'VARMULTICHAR', 'Sigma'], // 'Σ' + ['\u03C3', 'VARMULTICHAR', 'sigma'], // 'σ' + ['\u03C2', 'VARMULTICHAR', 'sigma'], // 'ς' should this be varsigma? + ['\u03C4', 'VARMULTICHAR', 'tau'], // 'τ' + ['\u03A5', 'VARMULTICHAR', 'Upsilon'], // 'Υ' + ['\u03C5', 'VARMULTICHAR', 'upsilon'], // 'υ' + ['\u03A6', 'VARMULTICHAR', 'Phi'], // 'Φ' + ['\u03C6', 'VARMULTICHAR', 'phi'], // 'φ' should this be varphi? + ['\u03D5', 'VARMULTICHAR', 'phi'], // 'ϕ' + ['\u03A8', 'VARMULTICHAR', 'Psi'], // 'Ψ' + ['\u03C8', 'VARMULTICHAR', 'psi'], // 'ψ' + ['\u03A9', 'VARMULTICHAR', 'Omega'], // 'Ω' + ['\u03C9', 'VARMULTICHAR', 'omega'], // 'ω' + + + ['oo\\b', 'INFINITY'], + ['OO\\b', 'INFINITY'], + ['infty\\b', 'INFINITY'], + ['infinity\\b', 'INFINITY'], + ['Infinity\\b', 'INFINITY'], + ['\u221E', 'INFINITY'], // '∞' + + ['\u212F', 'VAR', 'e'], // 'ℯ' + + ['\u2660', 'VARMULTICHAR', 'spade'], // '♠' + ['\u2661', 'VARMULTICHAR', 'heart'], // '♡' + ['\u2662', 'VARMULTICHAR', 'diamond'], // '♢' + ['\u2663', 'VARMULTICHAR', 'club'], // '♣' + ['\u2605', 'VARMULTICHAR', 'bigstar'], // '★' + ['\u25EF', 'VARMULTICHAR', 'bigcirc'], // '◯' + ['\u25CA', 'VARMULTICHAR', 'lozenge'], // '◊' + ['\u25B3', 'VARMULTICHAR', 'bigtriangleup'], // '△' + ['\u25BD', 'VARMULTICHAR', 'bigtriangledown'], // '▽' + ['\u29EB', 'VARMULTICHAR', 'blacklozenge'], // '⧫' + ['\u25A0', 'VARMULTICHAR', 'blacksquare'], // '■' + ['\u25B2', 'VARMULTICHAR', 'blacktriangle'], // '▲' + ['\u25BC', 'VARMULTICHAR', 'blacktriangledown'], //'▼' + ['\u25C0', 'VARMULTICHAR', 'blacktriangleleft'], // '◀' + ['\u25B6', 'VARMULTICHAR', 'blacktriangleright'], // '▶' + ['\u25A1', 'VARMULTICHAR', 'Box'], // '□' + ['\u2218', 'VARMULTICHAR', 'circ'], // '∘' + ['\u22C6', 'VARMULTICHAR', 'star'], // '⋆' + + ['and\\b', 'AND'], + ['\\&\\&?', 'AND'], + ['\u2227', 'AND'], // '∧' + + ['or\\b', 'OR'], + ['\u2228', 'OR'], // '∨' + + ['not\\b', 'NOT'], + ['\u00ac', 'NOT'], // '¬' + + ['=', '='], + ['\u1400', '='], // '᐀' + ['\u30A0', '='], // '゠' + ['!=', 'NE'], + ['\u2260', 'NE'], // '≠' + ['<=', 'LE'], + ['\u2264', 'LE'], // '≤' + ['>=', 'GE'], + ['\u2265', 'GE'], // '≥' + ['<', '<'], + ['>', '>'], + + ['elementof\\b', 'IN'], + ['\u2208', 'IN'], // '∈' + + ['notelementof\\b', 'NOTIN'], + ['\u2209', 'NOTIN'], //'∉' + + ['containselement\\b', 'NI'], + ['\u220B', 'NI'], // '∋' + + ['notcontainselement\\b', 'NOTNI'], + ['\u220C', 'NOTNI'], // '∌' + + ['subset\\b', 'SUBSET'], + ['\u2282', 'SUBSET'], // '⊂' + + ['notsubset\\b', 'NOTSUBSET'], + ['\u2284', 'NOTSUBSET'], // '⊄' + + ['superset\\b', 'SUPERSET'], + ['\u2283', 'SUPERSET'], // '⊃' + + ['notsuperset\\b', 'NOTSUPERSET'], + ['\u2285', 'NOTSUPERSET'], //'⊅' + + ['union\\b', 'UNION'], + ['\u222A', 'UNION'], // '∪' + + ['intersect\\b', 'INTERSECT'], + ['\u2229', 'INTERSECT'], //'∩' + + ['!', '!'], + ['\'', '\''], + ['_', '_'], + ['\\.\\.\\.', 'LDOTS'], + ['[a-zA-Z∂][a-zA-Z∂0-9]*', 'VAR'], // include ∂ in VAR + ]; - function isDigit(c) { - return ((c >= '0' && c <= '9')); - } - function next() { - index++; - c = text.charAt(index); - } + // defaults for parsers if not overridden by context - function revert(oldIndex) { - index = oldIndex; - c = text.charAt(index); - } + // if true, allowed applied functions to omit parentheses around argument + // if false, omitting parentheses will lead to a Parse Error + const allowSimplifiedFunctionApplicationDefault = true; - function parseNumber() { - var number = ''; - var oldIndex; - oldIndex = index; + // if true, split multicharacter symbols into a product of letters + const splitSymbolsDefault = true; - if (c == '+') { - next(); - } - else if (c == '-') { - number += c; - next(); - } + // symbols that won't be split into a product of letters if splitSymbols==true + const unsplitSymbolsDefault = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega']; - if (!isDigitDot(c)) { - // a + or - must be followed by a digit - revert(oldIndex); - return null; - } + // Applied functions must be given an argument so that + // they are applied to the argument + const appliedFunctionSymbolsDefault = ["abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg', 'conj']; - // 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(); + // Functions could have an argument, in which case they are applied + // or, if they don't have an argument in parentheses, then they are treated + // like a variable, except that trailing ^ and ' have higher precedence + const functionSymbolsDefault = ['f', 'g']; + + // Parse Leibniz notation + const parseLeibnizNotationDefault = true; + + + class textToAst { + constructor({ + allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplicationDefault, + splitSymbols = splitSymbolsDefault, + unsplitSymbols = unsplitSymbolsDefault, + appliedFunctionSymbols = appliedFunctionSymbolsDefault, + functionSymbols = functionSymbolsDefault, + parseLeibnizNotation = parseLeibnizNotationDefault, + } = {}) { + this.allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplication; + this.splitSymbols = splitSymbols; + this.unsplitSymbols = unsplitSymbols; + this.appliedFunctionSymbols = appliedFunctionSymbols; + this.functionSymbols = functionSymbols; + this.parseLeibnizNotation = parseLeibnizNotation; + + this.lexer = new lexer(text_rules); + + } + + advance(params) { + this.token = this.lexer.advance(params); + if (this.token.token_type === 'INVALID') { + throw new ParseError("Invalid symbol '" + this.token.original_text + "'", + this.lexer.location); } } - while (isDigit(c)) { - number += c; - next(); + + return_state() { + return ({ + lexer_state: this.lexer.return_state(), + token: Object.assign({}, this.token) + }); } - // check for exponential notation like "2.3e-4" or "1.23e50" - if (c == 'E' || c == 'e') { - // The grammar branches here. This could either be part of an exponent or the start of a unit that begins with the letter e, such as "4exabytes" + set_state(state) { + this.lexer.set_state(state.lexer_state); + this.token = Object.assign({}, state.token); + } - var tentativeNumber = ''; - var tentativeIndex = index; - tentativeNumber += c; - next(); + convert(input) { - if (c == '+' || c == '-') { - tentativeNumber += c; - next(); - } + this.lexer.set_input(input); + this.advance(); - // Scientific notation MUST be followed by an exponent (otherwise we assume it is not scientific notation) - if (!isDigit(c)) { - // The e or E must belong to something else, so return the number without the e or E. - revert(tentativeIndex); - return number; - } - - // We can now safely say that this is scientific notation. - number = number + tentativeNumber; - while (isDigit(c)) { - number += c; - next(); + var result = this.statement_list(); + + if (this.token.token_type !== 'EOF') { + throw new ParseError("Invalid location of '" + this.token.original_text + "'", + this.lexer.location); } + + return flatten$18(result); + } - return number; - } - function parseUnit() { - var unitName = ''; + statement_list() { - // Alphanumeric characters only; matches [a-zA-Z0-9] - var code = text.charCodeAt(index); - while ( (code >= 48 && code <= 57) || - (code >= 65 && code <= 90) || - (code >= 97 && code <= 122)) { - unitName += c; - next(); - code = text.charCodeAt(index); - } + var list = [this.statement()]; - // Must begin with [a-zA-Z] - code = unitName.charCodeAt(0); - if ((code >= 65 && code <= 90) || - (code >= 97 && code <= 122)) { - return unitName || null; - } - else { - return null; - } - } + while (this.token.token_type === ",") { + this.advance(); + list.push(this.statement()); + } - function parseCharacter(toFind) { - if (c === toFind) { - next(); - return toFind; - } - else { - return null; + if (list.length > 1) + list = ['list'].concat(list); + else + list = list[0]; + + return list; } - } - /** - * Parse a string into a unit. The value of the unit is parsed as number, - * BigNumber, or Fraction depending on the math.js config setting `number`. - * - * Throws an exception if the provided string does not contain a valid unit or - * cannot be parsed. - * @memberof Unit - * @param {string} str A string like "5.2 inch", "4e2 cm/s^2" - * @return {Unit} unit - */ - Unit.parse = function (str, options) { - options = options || {}; - text = str; - index = -1; - c = ''; + statement({ inside_absolute_value = 0 } = {}) { - if (typeof text !== 'string') { - throw new TypeError('Invalid argument in Unit.parse, string expected'); - } + // three periods ... can be a statement by itself + if (this.token.token_type === 'LDOTS') { + this.advance(); + return ['ldots']; + } - var unit = new Unit(); - unit.units = []; + var original_state; - var powerMultiplierCurrent = 1; - var expectingUnit = false; + try { - // A unit should follow this pattern: - // [number] ...[ [*/] unit[^number] ] - // unit[^number] ... [ [*/] unit[^number] ] + original_state = this.return_state(); - // Rules: - // number is any floating point number. - // unit is any alphanumeric string beginning with an alpha. Units with names like e3 should be avoided because they look like the exponent of a floating point number! - // The string may optionally begin with a number. - // Each unit may optionally be followed by ^number. - // Whitespace or a forward slash is recommended between consecutive units, although the following technically is parseable: - // 2m^2kg/s^2 - // it is not good form. If a unit starts with e, then it could be confused as a floating point number: - // 4erg + let lhs = this.statement_a({ inside_absolute_value: inside_absolute_value }); - next(); - skipWhitespace(); + if (this.token.token_type !== ':') + return lhs; - // Optional number at the start of the string - var valueStr = parseNumber(); - var value = null; - if(valueStr) { - if (config.number === 'BigNumber') { - value = new type.BigNumber(valueStr); - } - else if (config.number === 'Fraction') { - value = new type.Fraction(valueStr); - } - else { // number - value = parseFloat(valueStr); - } + this.advance(); - skipWhitespace(); // Whitespace is not required here + let rhs = this.statement_a(); + + return [':', lhs, rhs]; - // handle multiplication or division right after the value, like '1/s' - if (parseCharacter('*')) { - powerMultiplierCurrent = 1; - expectingUnit = true; - } - else if (parseCharacter('/')) { - powerMultiplierCurrent = -1; - expectingUnit = true; } - } + catch (e) { + try { - // Stack to keep track of powerMultipliers applied to each parentheses group - var powerMultiplierStack = []; + // if ran into problem parsing statement + // then try again with ignoring absolute value + // and then interpreting bar as a binary operator - // Running product of all elements in powerMultiplierStack - var powerMultiplierStackProduct = 1; + // return state to what it was before attempting to parse statement + this.set_state(original_state); - while (true) { - skipWhitespace(); + let lhs = this.statement_a({ parse_absolute_value: false }); - // Check for and consume opening parentheses, pushing powerMultiplierCurrent to the stack - // A '(' will always appear directly before a unit. - while (c === '(') { - powerMultiplierStack.push(powerMultiplierCurrent); - powerMultiplierStackProduct *= powerMultiplierCurrent; - powerMultiplierCurrent = 1; - next(); - skipWhitespace(); - } + if (this.token.token_type !== '|') { + throw (e); + } - // Is there something here? - if(c) { - var oldC = c; - var uStr = parseUnit(); - if(uStr == null) { - throw new SyntaxError('Unexpected "' + oldC + '" in "' + text + '" at index ' + index.toString()); - } - } - else { - // End of input. - break; - } + this.advance(); - // Verify the unit exists and get the prefix (if any) - var res = _findUnit(uStr); - if(res == null) { - // Unit not found. - throw new SyntaxError('Unit "' + uStr + '" not found.'); - } + let rhs = this.statement_a({ parse_absolute_value: false }); - var power = powerMultiplierCurrent * powerMultiplierStackProduct; - // Is there a "^ number"? - skipWhitespace(); - if (parseCharacter('^')) { - skipWhitespace(); - var p = parseNumber(); - if(p == null) { - // No valid number found for the power! - throw new SyntaxError('In "' + str + '", "^" must be followed by a floating-point number'); + return ['|', lhs, rhs]; + + } + catch (e2) { + throw (e); // throw original error } - power *= p; } + } + + statement_a({ inside_absolute_value = 0, parse_absolute_value = true } = {}) { - // Add the unit to the list - unit.units.push( { - unit: res.unit, - prefix: res.prefix, - power: power + var lhs = this.statement_b({ + inside_absolute_value: inside_absolute_value, + parse_absolute_value: parse_absolute_value }); - for(var i=0; i 1 || Math.abs(this.units[0].power - 1.0) > 1e-15; - }; - /** - * Normalize a value, based on its currently set unit(s) - * @memberof Unit - * @param {number | BigNumber | Fraction | boolean} value - * @return {number | BigNumber | Fraction | boolean} normalized value - * @private - */ - Unit.prototype._normalize = function (value) { - var unitValue, unitOffset, unitPower, unitPrefixValue; - var convert; - if (value == null || this.units.length === 0) { - return value; - } - else if (this._isDerived()) { - // This is a derived unit, so do not apply offsets. - // For example, with J kg^-1 degC^-1 you would NOT want to apply the offset. - var res = value; - convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed + relation(params) { - for(var i=0; i < this.units.length; i++) { - unitValue = convert(this.units[i].unit.value); - unitPrefixValue = convert(this.units[i].prefix.value); - unitPower = convert(this.units[i].power); - res = multiply(res, pow(multiply(unitValue, unitPrefixValue), unitPower)); + if (this.token.token_type === 'NOT' || this.token.token_type === '!') { + this.advance(); + return ['not', this.relation(params)]; } - return res; - } - else { - // This is a single unit of power 1, like kg or degC - convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed + var lhs = this.expression(params); - unitValue = convert(this.units[0].unit.value); - unitOffset = convert(this.units[0].unit.offset); - unitPrefixValue = convert(this.units[0].prefix.value); + while ((this.token.token_type === '=') || (this.token.token_type === 'NE') || + (this.token.token_type === '<') || (this.token.token_type === '>') || + (this.token.token_type === 'LE') || (this.token.token_type === 'GE') || + (this.token.token_type === 'IN') || (this.token.token_type === 'NOTIN') || + (this.token.token_type === 'NI') || (this.token.token_type === 'NOTNI') || + (this.token.token_type === 'SUBSET') || (this.token.token_type === 'NOTSUBSET') || + (this.token.token_type === 'SUPERSET') || (this.token.token_type === 'NOTSUPERSET')) { - return multiply(add(value, unitOffset), multiply(unitValue, unitPrefixValue)); - } - }; + let operation = this.token.token_type.toLowerCase(); - /** - * Denormalize a value, based on its currently set unit(s) - * @memberof Unit - * @param {number} value - * @param {number} [prefixValue] Optional prefix value to be used (ignored if this is a derived unit) - * @return {number} denormalized value - * @private - */ - Unit.prototype._denormalize = function (value, prefixValue) { - var unitValue, unitOffset, unitPower, unitPrefixValue; - var convert; + let inequality_sequence = 0; - if (value == null || this.units.length === 0) { - return value; - } - else if (this._isDerived()) { - // This is a derived unit, so do not apply offsets. - // For example, with J kg^-1 degC^-1 you would NOT want to apply the offset. - // Also, prefixValue is ignored--but we will still use the prefix value stored in each unit, since kg is usually preferable to g unless the user decides otherwise. - var res = value; - convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed + if ((this.token.token_type === '<') || (this.token.token_type === 'LE')) { + inequality_sequence = -1; + } else if ((this.token.token_type === '>') || (this.token.token_type === 'GE')) { + inequality_sequence = 1; + } + + this.advance(); + let rhs = this.expression(params); + + if (inequality_sequence === -1) { + if ((this.token.token_type === '<') || this.token.token_type === 'LE') { + // sequence of multiple < or <= + let strict = ['tuple']; + if (operation === '<') + strict.push(true); + else + strict.push(false); + + let args = ['tuple', lhs, rhs]; + while ((this.token.token_type === '<') || this.token.token_type === 'LE') { + if (this.token.token_type === '<') + strict.push(true); + else + strict.push(false); + + this.advance(); + args.push(this.expression(params)); + } + lhs = ['lts', args, strict]; + } else { + lhs = [operation, lhs, rhs]; + } + + } else if (inequality_sequence === 1) { + if ((this.token.token_type === '>') || this.token.token_type === 'GE') { + // sequence of multiple > or >= + let strict = ['tuple']; + if (operation === '>') + strict.push(true); + else + strict.push(false); + + let args = ['tuple', lhs, rhs]; + while ((this.token.token_type === '>') || this.token.token_type === 'GE') { + if (this.token.token_type === '>') + strict.push(true); + else + strict.push(false); + + this.advance(); + args.push(this.expression(params)); + } + lhs = ['gts', args, strict]; + } else { + lhs = [operation, lhs, rhs]; + } + + } else if (operation === '=') { + lhs = ['=', lhs, rhs]; + + // check for sequence of multiple = + while (this.token.token_type === '=') { + this.advance(); + lhs.push(this.expression(params)); + } + } else { + + lhs = [operation, lhs, rhs]; + } - for (var i = 0; i < this.units.length; i++) { - unitValue = convert(this.units[i].unit.value); - unitPrefixValue = convert(this.units[i].prefix.value); - unitPower = convert(this.units[i].power); - res = divide(res, pow(multiply(unitValue, unitPrefixValue), unitPower)); } - return res; + return lhs; } - else { - // This is a single unit of power 1, like kg or degC - convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed - unitValue = convert(this.units[0].unit.value); - unitPrefixValue = convert(this.units[0].prefix.value); - unitOffset = convert(this.units[0].unit.offset); - if (prefixValue == undefined) { - return subtract(divide(divide(value, unitValue), unitPrefixValue), unitOffset); + expression(params) { + if (this.token.token_type === '+') + this.advance(); + + let negative_begin = false; + if (this.token.token_type === '-') { + negative_begin = true; + this.advance(); } - else { - return subtract(divide(divide(value, unitValue), prefixValue), unitOffset); + + var lhs = this.term(params); + + if (negative_begin) { + lhs = ['-', lhs]; } - } - }; - /** - * Find a unit from a string - * @memberof Unit - * @param {string} str A string like 'cm' or 'inch' - * @returns {Object | null} result When found, an object with fields unit and - * prefix is returned. Else, null is returned. - * @private - */ - function _findUnit(str) { - - // First, match units names exactly. For example, a user could define 'mm' as 10^-4 m, which is silly, but then we would want 'mm' to match the user-defined unit. - if(UNITS.hasOwnProperty(str)) { - var unit = UNITS[str]; - var prefix = unit.prefixes['']; - return { - unit: unit, - prefix: prefix - } - } - - for (var name in UNITS) { - if (UNITS.hasOwnProperty(name)) { - if (endsWith(str, name)) { - var unit = UNITS[name]; - var prefixLen = (str.length - name.length); - var prefixName = str.substring(0, prefixLen); - var prefix = unit.prefixes.hasOwnProperty(prefixName) - ? unit.prefixes[prefixName] - : undefined; - if (prefix !== undefined) { - // store unit, prefix, and value - return { - unit: unit, - prefix: prefix - }; + while ((this.token.token_type === '+') || (this.token.token_type === '-') + || (this.token.token_type === 'UNION') || + (this.token.token_type === 'INTERSECT')) { + + let operation = this.token.token_type.toLowerCase(); + let negative = false; + + if (this.token.token_type === '-') { + operation = '+'; + negative = true; + this.advance(); + } else { + this.advance(); + if (operation === '+' && this.token.token_type === '-') { + negative = true; + this.advance(); } } + let rhs = this.term(params); + if (negative) { + rhs = ['-', rhs]; + } + + lhs = [operation, lhs, rhs]; } + + return lhs; } - return null; - } - /** - * Test if the given expression is a unit. - * The unit can have a prefix but cannot have a value. - * @memberof Unit - * @param {string} name A string to be tested whether it is a value less unit. - * The unit can have prefix, like "cm" - * @return {boolean} true if the given string is a unit - */ - Unit.isValuelessUnit = function (name) { - return (_findUnit(name) != null); - }; + term(params) { + var lhs = this.factor(params); - /** - * check if this unit has given base unit - * If this unit is a derived unit, this will ALWAYS return false, since by definition base units are not derived. - * @memberof Unit - * @param {BASE_UNITS | string | undefined} base - */ - Unit.prototype.hasBase = function (base) { + var keepGoing = false; + + do { + keepGoing = false; + + if (this.token.token_type === '*') { + this.advance(); + lhs = ['*', lhs, this.factor(params)]; + keepGoing = true; + } else if (this.token.token_type === '/') { + this.advance(); + lhs = ['/', lhs, this.factor(params)]; + keepGoing = true; + } else { + // this is the one case where a | could indicate a closing absolute value + let params2 = Object.assign({}, params); + params2.allow_absolute_value_closing = true; + let rhs = this.nonMinusFactor(params2); + if (rhs !== false) { + lhs = ['*', lhs, rhs]; + keepGoing = true; + } + } + } while (keepGoing); - if(typeof(base) === "string") { - base = BASE_UNITS[base]; + return lhs; } - if(!base) - return false; + factor(params) { - // All dimensions must be the same - for(var i=0; i 1e-12) { - return false; + if (this.token.token_type === '-') { + this.advance(); + return ['-', this.factor(params)]; } - } - return true; - }; + var result = this.nonMinusFactor(params); - /** - * Check if this unit has a base or bases equal to another base or bases - * For derived units, the exponent on each base also must match - * @memberof Unit - * @param {Unit} other - * @return {boolean} true if equal base - */ - Unit.prototype.equalBase = function (other) { - // All dimensions must be the same - for(var i=0; i 1e-12) { - return false; + if (result === false) { + if (this.token.token_type === "EOF") { + throw new ParseError("Unexpected end of input", this.lexer.location); + } else { + throw new ParseError("Invalid location of '" + this.token.original_text + "'", + this.lexer.location); + } + } else { + return result; } + } - return true; - }; - /** - * Check if this unit equals another unit - * @memberof Unit - * @param {Unit} other - * @return {boolean} true if both units are equal - */ - Unit.prototype.equals = function (other) { - return (this.equalBase(other) && equal(this.value, other.value)); - }; + nonMinusFactor(params) { - /** - * Multiply this unit with another one - * @memberof Unit - * @param {Unit} other - * @return {Unit} product of this unit and the other unit - */ - Unit.prototype.multiply = function (other) { - var res = this.clone(); - - for(var i = 0; i= 0; i--) { + this.lexer.unput(" "); + this.lexer.unput(result[i]); + } + this.advance(); - other.simplifyUnitListLazy(); + return this.baseFactor({ + inside_absolute_value: inside_absolute_value, + parse_absolute_value: parse_absolute_value, + allow_absolute_value_closing: allow_absolute_value_closing + }); + } else { + this.advance(); + } + } + } else if (this.token.token_type === '(' || this.token.token_type === '[' || + this.token.token_type === '{') { + let token_left = this.token.token_type; + let expected_right, other_right; + if (this.token.token_type === '(') { + expected_right = ')'; + other_right = ']'; + } else if (this.token.token_type === '[') { + expected_right = ']'; + other_right = ')'; + } else { + expected_right = '}'; + other_right = null; + } - if(other._isDerived()) { - return other._denormalize(other.value); - } - else { - return other._denormalize(other.value, other.units[0].prefix.value); - } - }; + this.advance(); + result = this.statement_list(); - /** - * Get a string representation of the unit. - * @memberof Unit - * @return {string} - */ - Unit.prototype.toString = function () { - return this.format(); - }; + let n_elements = 1; + if (result[0] === "list") { + n_elements = result.length - 1; + } - /** - * Get a JSON representation of the unit - * @memberof Unit - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Unit", "value": 2, "unit": "cm", "fixPrefix": false}` - */ - Unit.prototype.toJSON = function () { - return { - mathjs: 'Unit', - value: this._denormalize(this.value), - unit: this.formatUnits(), - fixPrefix: this.fixPrefix - }; - }; + if (this.token.token_type !== expected_right) { + if (n_elements !== 2 || other_right === null) { + throw new ParseError('Expecting ' + expected_right, + this.lexer.location); + } else if (this.token.token_type !== other_right) { + throw new ParseError('Expecting ) or ]', this.lexer.location); + } - /** - * Instantiate a Unit from a JSON object - * @memberof Unit - * @param {Object} json A JSON object structured as: - * `{"mathjs": "Unit", "value": 2, "unit": "cm", "fixPrefix": false}` - * @return {Unit} - */ - Unit.fromJSON = function (json) { - var unit = new Unit(json.value, json.unit); - unit.fixPrefix = json.fixPrefix || false; - return unit; - }; + // half-open interval + result[0] = 'tuple'; + result = ['interval', result]; + let closed; + if (token_left === '(') + closed = ['tuple', false, true]; + else + closed = ['tuple', true, false]; + result.push(closed); + + } else if (n_elements >= 2) { + if (token_left === '(') { + result[0] = 'tuple'; + } else if (token_left === '[') { + result[0] = 'array'; + } else { + result[0] = 'set'; + } + } else if (token_left === '{') { + if (result[0] === '|' || result[0] === ':') { + result = ['set', result]; // set builder notation + } + else { + result = ['set', result]; // singleton set + } + } - /** - * Returns the string representation of the unit. - * @memberof Unit - * @return {string} - */ - Unit.prototype.valueOf = Unit.prototype.toString; + this.advance(); - /** - * Attempt to simplify the list of units for this unit according to the dimensions array and the current unit system. After the call, this Unit will contain a list of the "best" units for formatting. - * Intended to be evaluated lazily. You must set isUnitListSimplified = false before the call! After the call, isUnitListSimplified will be set to true. - */ - Unit.prototype.simplifyUnitListLazy = function() { + } else if (this.token.token_type === '|' && parse_absolute_value && + (inside_absolute_value === 0 || !allow_absolute_value_closing)) { - if (this.isUnitListSimplified || this.value == null) { - return; - } + // allow the opening of an absolute value here if either + // - we aren't already inside an absolute value (inside_absolute_value==0), or + // - we don't allows an absolute value closing + // otherwise, skip this token so that will drop out the factor (and entire statement) + // to where the absolute value will close - var proposedUnitList = []; + inside_absolute_value += 1; - // Search for a matching base - var matchingBase; - for(var key in currentUnitSystem) { - if(this.hasBase(BASE_UNITS[key])) { - matchingBase = key; - break; - } - } + this.advance(); - if(matchingBase === 'NONE') - { - this.units = []; - } - else { - var matchingUnit; - if(matchingBase) { - // Does the unit system have a matching unit? - if(currentUnitSystem.hasOwnProperty(matchingBase)) { - matchingUnit = currentUnitSystem[matchingBase]; + result = this.statement({ inside_absolute_value: inside_absolute_value }); + result = ['apply', 'abs', result]; + + if (this.token.token_type !== '|') { + throw new ParseError('Expecting |', this.lexer.location); } + + this.advance(); } - if(matchingUnit) { - this.units = [{ - unit: matchingUnit.unit, - prefix: matchingUnit.prefix, - power: 1.0 - }]; - } - else { - // Multiple units or units with powers are formatted like this: - // 5 (kg m^2) / (s^3 mol) - // Build an representation from the base units of the current unit system - var missingBaseDim = false; - for(var i=0; i 1e-12) { - if(currentUnitSystem.hasOwnProperty(baseDim)) { - proposedUnitList.push({ - unit: currentUnitSystem[baseDim].unit, - prefix: currentUnitSystem[baseDim].prefix, - power: this.dimensions[i] || 0 - }); - } - else { - missingBaseDim = true; - } - } + + if (this.token.token_type === '_') { + if (result === false) { + throw new ParseError("Invalid location of _", this.lexer.location); } + this.advance(); + let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); - // Is the proposed unit list "simpler" than the existing one? - if(proposedUnitList.length < this.units.length && !missingBaseDim) { - // Replace this unit list with the proposed list - this.units = proposedUnitList; + if (subresult === false) { + if (this.token.token_type === "EOF") { + throw new ParseError("Unexpected end of input", this.lexer.location); + } else { + throw new ParseError("Invalid location of '" + this.token.original_text + "'", + this.lexer.location); + } } + return ['_', result, subresult]; } + + return result; } - this.isUnitListSimplified = true; - }; - Unit.prototype.toSI = function() { + leibniz_notation() { + // attempt to find and return a derivative in Leibniz notation + // if unsuccessful, return false - var ret = this.clone(); + var result = this.token.token_text; - var proposedUnitList = []; - for(var i=0; i 1e-12) { - if(UNIT_SYSTEMS["si"].hasOwnProperty(baseDim)) { - proposedUnitList.push({ - unit: UNIT_SYSTEMS["si"][baseDim].unit, - prefix: UNIT_SYSTEMS["si"][baseDim].prefix, - power: ret.dimensions[i] || 0 - }); + if (!(this.token.token_type === 'VAR' && (result[0] === "d" || result[0] === "∂") + && (result.length === 1 || (result.length === 2 && /[a-zA-Z]/.exec(result[1]))))) { + return false; + } + + // found one of these two possibilities for start of derivative are + // - dx or ∂x (no space, x is a single letter) + // - d or ∂ + + let deriv_symbol = result[0]; + + let n_deriv = 1; + + let var1 = ""; + let var2s = []; + let var2_exponents = []; + + if (result.length === 2) + var1 = result[1]; + else { // result is length 1 + + // since have just a d or ∂ + // must be followed by a ^ or a VARMULTICHAR/VAR with no ∂ + this.advance(); + if (this.token.token_type === 'VARMULTICHAR' || + (this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) + ) { + var1 = this.token.token_text; } + else { - throw new Error("Cannot express custom unit " + baseDim + " in SI units"); + // since not VARMULTICHAR, must be a ^ next + if (this.token.token_type !== '^') { + return false; + } + + // so far have d or ∂ followed by ^ + // must be followed by an integer + this.advance(); + + if (this.token.token_type !== 'NUMBER') { + return false; + } + + n_deriv = parseFloat(this.token.token_text); + if (!Number.isInteger(n_deriv)) { + return false; + } + + // see if next character is single character + this.advance(); + + // either a VAR with no ∂ + // or a VARMULTICHAR + if ((this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) + || this.token.token_type === 'VARMULTICHAR') { + var1 = this.token.token_text; + } + else { + return false; + } } } - } - // Replace this unit list with the proposed list - ret.units = proposedUnitList; + // next character must be a / - ret.isUnitListSimplified = true; + this.advance(); // allow a space this time - return ret; - }; + if (this.token.token_type !== '/') + return false; - /** - * Get a string representation of the units of this Unit, without the value. - * @memberof Unit - * @return {string} - */ - Unit.prototype.formatUnits = function () { + // find sequence of + // derivative symbol followed by a single character or VARMULTICHAR (with no space) + // optionally followed by a ^ and an integer (with no spaces) + // (with spaces allowed between elements of sequence) + // End when sum of exponents meets or exceeds n_deriv + + let exponent_sum = 0; - // Lazy evaluation of the unit list - this.simplifyUnitListLazy(); + this.advance(); // allow space just after the / - var strNum = ""; - var strDen = ""; - var nNum = 0; - var nDen = 0; + while (true) { + + // next must either be + // - a VAR whose first character matches derivative symbol + // and whose second character is a letter, or + // - a single character VAR that matches derivative symbol + // which must be followed by a VARMULTICHAR/VAR with no ∂ - for(var i=0; i 0) { - nNum++; - strNum += " " + this.units[i].prefix.name + this.units[i].unit.name; - if(Math.abs(this.units[i].power - 1.0) > 1e-15) { - strNum += "^" + this.units[i].power; + if (this.token.token_type !== 'VAR' || this.token.token_text[0] !== deriv_symbol) { + return false; } - } - else if(this.units[i].power < 0) { - nDen++; - } - } - if(nDen > 0) { - for(var i=0; i 0) { - strDen += " " + this.units[i].prefix.name + this.units[i].unit.name; - if(Math.abs(this.units[i].power + 1.0) > 1e-15) { - strDen += "^" + (-this.units[i].power); - } - } + if (this.token.token_text.length > 2) { + // Put extra characters back on lexer + this.lexer.unput(this.token.token_text.slice(2)); + + // keep just two character token + this.token.token_text = this.token.token_text.slice(0, 2); + + } + + let token_text = this.token.token_text; + + // derivative symbol and variable together + if (token_text.length === 2) { + if (/[a-zA-Z]/.exec(token_text[1])) + var2s.push(token_text[1]); else { - strDen += " " + this.units[i].prefix.name + this.units[i].unit.name; - strDen += "^" + (this.units[i].power); + return false; } } - } - } - // Remove leading " " - strNum = strNum.substr(1); - strDen = strDen.substr(1); - - // Add parans for better copy/paste back into the eval, for example, or for better pretty print formatting - if(nNum > 1 && nDen > 0) { - strNum = "(" + strNum + ")"; - } - if(nDen > 1 && nNum > 0) { - strDen = "(" + strDen + ")"; - } + else { // token text was just the derivative symbol + this.advance(); - var str = strNum; - if(nNum > 0 && nDen > 0) { - str += " / "; - } - str += strDen; + if (!((this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) + || this.token.token_type === 'VARMULTICHAR')) { + return false; + } + var2s.push(this.token.token_text); + } - return str; - }; + // have derivative and variable, now check for optional ^ followed by number - /** - * Get a string representation of the Unit, with optional formatting options. - * @memberof Unit - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @return {string} - */ - Unit.prototype.format = function (options) { + let this_exponent = 1; - // Simplfy the unit list, if necessary - this.simplifyUnitListLazy(); + let lastWasSpace = false; - // Apply some custom logic for handling VA and VAR. The goal is to express the value of the unit as a real value, if possible. Otherwise, use a real-valued unit instead of a complex-valued one. - var isImaginary = false; - var isReal = true; - if(typeof(this.value) !== 'undefined' && this.value !== null && type.isComplex(this.value)) { - // TODO: Make this better, for example, use relative magnitude of re and im rather than absolute - isImaginary = Math.abs(this.value.re) < 1e-14; - isReal = Math.abs(this.value.im) < 1e-14; - } - - for(var i in this.units) { - if(this.units[i].unit) { - if(this.units[i].unit.name === 'VA' && isImaginary) { - this.units[i].unit = UNITS["VAR"]; + this.advance({ remove_initial_space: false }); + // if last token was a space advance to next non-space token + if (this.token.token_type === "SPACE") { + lastWasSpace = true; + this.advance(); } - else if(this.units[i].unit.name === 'VAR' && !isImaginary) { - this.units[i].unit = UNITS["VA"]; + + if (this.token.token_type === '^') { + + this.advance(); + + if (this.token.token_type !== 'NUMBER') { + return false; + } + + this_exponent = parseFloat(this.token.token_text); + if (!Number.isInteger(this_exponent)) { + return false; + } + + lastWasSpace = false; + + this.advance({ remove_initial_space: false }); + // if last token was a space advance to next non-space token + if (this.token.token_type === "SPACE") { + lastWasSpace = true; + this.advance(); + } + + } + var2_exponents.push(this_exponent); + exponent_sum += this_exponent; + + if (exponent_sum > n_deriv) { + return false; } - } - } + // possibly found derivative + if (exponent_sum === n_deriv) { - // Now apply the best prefix - // Units must have only one unit and not have the fixPrefix flag set - if (this.units.length === 1 && !this.fixPrefix) { - // Units must have integer powers, otherwise the prefix will change the - // outputted value by not-an-integer-power-of-ten - if (Math.abs(this.units[0].power - Math.round(this.units[0].power)) < 1e-14) { - // Apply the best prefix - this.units[0].prefix = this._bestPrefix(); - } - } + // check to make sure next token isn't another VAR or VARMULTICHAR + // in this case, the derivative isn't separated from what follows + if (!lastWasSpace && (this.token.token_type === "VAR" || this.token.token_type === "VARMULTICHAR")) { + return false; + } + // found derivative! - var value = this._denormalize(this.value); - var str = (this.value !== null) ? format(value, options || {}) : ''; - var unitStr = this.formatUnits(); - if(this.value && type.isComplex(this.value)) { - str = "(" + str + ")"; // Surround complex values with ( ) to enable better parsing - } - if(unitStr.length > 0 && str.length > 0) { - str += " "; - } - str += unitStr; + // if last token was a space advance to next non-space token + if (this.token.token_type === "SPACE") + this.advance(); - return str; - }; + let result_name = "derivative_leibniz"; + if (deriv_symbol === "∂") + result_name = "partial_" + result_name; - /** - * Calculate the best prefix using current value. - * @memberof Unit - * @returns {Object} prefix - * @private - */ - Unit.prototype._bestPrefix = function () { - if (this.units.length !== 1) { - throw new Error("Can only compute the best prefix for single units with integer powers, like kg, s^2, N^-1, and so forth!"); - } - if (Math.abs(this.units[0].power - Math.round(this.units[0].power)) >= 1e-14) { - throw new Error("Can only compute the best prefix for single units with integer powers, like kg, s^2, N^-1, and so forth!"); - } - - // find the best prefix value (resulting in the value of which - // the absolute value of the log10 is closest to zero, - // though with a little offset of 1.2 for nicer values: you get a - // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ... - - // Note: the units value can be any numeric type, but to find the best - // prefix it's enough to work with limited precision of a regular number - // Update: using mathjs abs since we also allow complex numbers - var absValue = this.value !== null ? abs(this.value) : 0; - var absUnitValue = abs(this.units[0].unit.value); - var bestPrefix = this.units[0].prefix; - if (absValue === 0) { - return bestPrefix; - } - var power = this.units[0].power; - var bestDiff = Math.log(absValue / Math.pow(bestPrefix.value * absUnitValue, power)) / Math.LN10 - 1.2; - if(bestDiff > -2.200001 && bestDiff < 1.800001) return bestPrefix; // Allow the original prefix - bestDiff = Math.abs(bestDiff); - var prefixes = this.units[0].unit.prefixes; - for (var p in prefixes) { - if (prefixes.hasOwnProperty(p)) { - var prefix = prefixes[p]; - if (prefix.scientific) { + result = [result_name]; - var diff = Math.abs( - Math.log(absValue / Math.pow(prefix.value * absUnitValue, power)) / Math.LN10 - 1.2); + if (n_deriv === 1) + result.push(var1); + else + result.push(["tuple", var1, n_deriv]); - if (diff < bestDiff - || (diff === bestDiff && prefix.name.length < bestPrefix.name.length)) { - // choose the prefix with the smallest diff, or if equal, choose the one - // with the shortest name (can happen with SHORTLONG for example) - bestPrefix = prefix; - bestDiff = diff; + let r2 = []; + for (let i = 0; i < var2s.length; i += 1) { + if (var2_exponents[i] === 1) + r2.push(var2s[i]); + else + r2.push(["tuple", var2s[i], var2_exponents[i]]); } + r2 = ["tuple"].concat(r2); + + result.push(r2); + + return result; } } } + } - return bestPrefix; - }; + var textToAst$1 = new textToAst(); - /** - * Returns an array of units whose sum is equal to this unit - * @memberof Unit - * @param {Array} [parts] An array of strings or valueless units. - * - * Example: - * - * var u = new Unit(1, 'm'); - * u.splitUnit(['feet', 'inch']); - * [ 3 feet, 3.3700787401575 inch ] - * - * @return {Array} An array of units. - */ - Unit.prototype.splitUnit = function(parts) { - var x = this.clone(); - var ret = []; - for(var i=0; i', x, a]); + } + if(closed[2]) { + if(negate) + comparisons.push(['>', x, b]); + else + comparisons.push(['le', x, b]); + } + else { + if(negate) + comparisons.push(['ge', x, b]); + else + comparisons.push(['<', x, b]); + } - // Time - s: { - name: 's', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - min: { - name: 'min', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 60, - offset: 0 - }, - h: { - name: 'h', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 3600, - offset: 0 - }, - second: { - name: 'second', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - sec: { - name: 'sec', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - minute: { - name: 'minute', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 60, - offset: 0 - }, - hour: { - name: 'hour', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 3600, - offset: 0 - }, - day: { - name: 'day', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 86400, - offset: 0 - }, - week: { - name: 'week', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 7*86400, - offset: 0 - }, - month: { - name: 'month', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 2629800, //1/12th of Julian year - offset: 0 - }, - year: { - name: 'year', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 31557600, //Julian year - offset: 0 - }, - decade: { - name: 'decade', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 315576000, //Julian decade - offset: 0 - }, - century: { - name: 'century', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 3155760000, //Julian century - offset: 0 - }, - millennium: { - name: 'millennium', - base: BASE_UNITS.TIME, - prefixes: PREFIXES.NONE, - value: 31557600000, //Julian millennium - offset: 0 - }, + let result; + if(negate) + result = ['or'].concat(comparisons); + else + result = ['and'].concat(comparisons); - // Frequency - hertz: { - name: 'Hertz', - base: BASE_UNITS.FREQUENCY, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0, - reciprocal: true - }, - Hz: { - name: 'Hz', - base: BASE_UNITS.FREQUENCY, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0, - reciprocal: true - }, + return result; + } - // Angle - rad: { - name: 'rad', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - radian: { - name: 'radian', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - // deg = rad / (2*pi) * 360 = rad / 0.017453292519943295769236907684888 - deg: { - name: 'deg', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.SHORT, - value: null, // will be filled in by calculateAngleValues() - offset: 0 - }, - degree: { - name: 'degree', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.LONG, - value: null, // will be filled in by calculateAngleValues() - offset: 0 - }, - // grad = rad / (2*pi) * 400 = rad / 0.015707963267948966192313216916399 - grad: { - name: 'grad', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.SHORT, - value: null, // will be filled in by calculateAngleValues() - offset: 0 - }, - gradian: { - name: 'gradian', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.LONG, - value: null, // will be filled in by calculateAngleValues() - offset: 0 - }, - // cycle = rad / (2*pi) = rad / 6.2831853071795864769252867665793 - cycle: { - name: 'cycle', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.NONE, - value: null, // will be filled in by calculateAngleValues() - offset: 0 - }, - // arcsec = rad / (3600 * (360 / 2 * pi)) = rad / 0.0000048481368110953599358991410235795 - arcsec: { - name: 'arcsec', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.NONE, - value: null, // will be filled in by calculateAngleValues() - offset: 0 - }, - // arcmin = rad / (60 * (360 / 2 * pi)) = rad / 0.00029088820866572159615394846141477 - arcmin: { - name: 'arcmin', - base: BASE_UNITS.ANGLE, - prefixes: PREFIXES.NONE, - value: null, // will be filled in by calculateAngleValues() - offset: 0 - }, - - // Electric current - A: { - name: 'A', - base: BASE_UNITS.CURRENT, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - ampere: { - name: 'ampere', - base: BASE_UNITS.CURRENT, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, + // convert interval containment to inequalities + if(operator === 'subset' || operator === 'notsubset' || + operator === 'superset' || operator === 'notsuperset') { - // Temperature - // K(C) = °C + 273.15 - // K(F) = (°F + 459.67) / 1.8 - // K(R) = °R / 1.8 - K: { - name: 'K', - base: BASE_UNITS.TEMPERATURE, - prefixes: PREFIXES.NONE, - value: 1, - offset: 0 - }, - degC: { - name: 'degC', - base: BASE_UNITS.TEMPERATURE, - prefixes: PREFIXES.NONE, - value: 1, - offset: 273.15 - }, - degF: { - name: 'degF', - base: BASE_UNITS.TEMPERATURE, - prefixes: PREFIXES.NONE, - value: 1 / 1.8, - offset: 459.67 - }, - degR: { - name: 'degR', - base: BASE_UNITS.TEMPERATURE, - prefixes: PREFIXES.NONE, - value: 1 / 1.8, - offset: 0 - }, - kelvin: { - name: 'kelvin', - base: BASE_UNITS.TEMPERATURE, - prefixes: PREFIXES.NONE, - value: 1, - offset: 0 - }, - celsius: { - name: 'celsius', - base: BASE_UNITS.TEMPERATURE, - prefixes: PREFIXES.NONE, - value: 1, - offset: 273.15 - }, - fahrenheit: { - name: 'fahrenheit', - base: BASE_UNITS.TEMPERATURE, - prefixes: PREFIXES.NONE, - value: 1 / 1.8, - offset: 459.67 - }, - rankine: { - name: 'rankine', - base: BASE_UNITS.TEMPERATURE, - prefixes: PREFIXES.NONE, - value: 1 / 1.8, - offset: 0 - }, + let negate=false; + if(operator === 'notsubset' || operator === 'notsuperset') + negate=true; - // amount of substance - mol: { - name: 'mol', - base: BASE_UNITS.AMOUNT_OF_SUBSTANCE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - mole: { - name: 'mole', - base: BASE_UNITS.AMOUNT_OF_SUBSTANCE, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, + let small, big; + if(operator === 'subset' || operator === 'notsubset') { + small = operands[0]; + big = operands[1]; + } + else { + small = operands[1]; + big = operands[0]; + } - // luminous intensity - cd: { - name: 'cd', - base: BASE_UNITS.LUMINOUS_INTENSITY, - prefixes: PREFIXES.NONE, - value: 1, - offset: 0 - }, - candela: { - name: 'candela', - base: BASE_UNITS.LUMINOUS_INTENSITY, - prefixes: PREFIXES.NONE, - value: 1, - offset: 0 - }, - // TODO: units STERADIAN - //{name: 'sr', base: BASE_UNITS.STERADIAN, prefixes: PREFIXES.NONE, value: 1, offset: 0}, - //{name: 'steradian', base: BASE_UNITS.STERADIAN, prefixes: PREFIXES.NONE, value: 1, offset: 0}, - - // Force - N: { - name: 'N', - base: BASE_UNITS.FORCE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - newton: { - name: 'newton', - base: BASE_UNITS.FORCE, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - dyn: { - name: 'dyn', - base: BASE_UNITS.FORCE, - prefixes: PREFIXES.SHORT, - value: 0.00001, - offset: 0 - }, - dyne: { - name: 'dyne', - base: BASE_UNITS.FORCE, - prefixes: PREFIXES.LONG, - value: 0.00001, - offset: 0 - }, - lbf: { - name: 'lbf', - base: BASE_UNITS.FORCE, - prefixes: PREFIXES.NONE, - value: 4.4482216152605, - offset: 0 - }, - poundforce: { - name: 'poundforce', - base: BASE_UNITS.FORCE, - prefixes: PREFIXES.NONE, - value: 4.4482216152605, - offset: 0 - }, - kip: { - name: 'kip', - base: BASE_UNITS.FORCE, - prefixes: PREFIXES.LONG, - value: 4448.2216, - offset: 0 - }, - - // Energy - J: { - name: 'J', - base: BASE_UNITS.ENERGY, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - joule: { - name: 'joule', - base: BASE_UNITS.ENERGY, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - erg: { - name: 'erg', - base: BASE_UNITS.ENERGY, - prefixes: PREFIXES.NONE, - value: 1e-7, - offset: 0 - }, - Wh: { - name: 'Wh', - base: BASE_UNITS.ENERGY, - prefixes: PREFIXES.SHORT, - value: 3600, - offset: 0 - }, - BTU: { - name: 'BTU', - base: BASE_UNITS.ENERGY, - prefixes: PREFIXES.BTU, - value: 1055.05585262, - offset: 0 - }, - eV: { - name: 'eV', - base: BASE_UNITS.ENERGY, - prefixes: PREFIXES.SHORT, - value: 1.602176565e-19, - offset: 0 - }, - electronvolt: { - name: 'electronvolt', - base: BASE_UNITS.ENERGY, - prefixes: PREFIXES.LONG, - value: 1.602176565e-19, - offset: 0 - }, + // convert any tuples/arrays of length two to intervals + small = to_intervals(small); + big = to_intervals(big); + + // if not interval, don't transform + if(small[0] !== 'interval' || big[0] !== 'interval') + return ast; + + let small_args = small[1]; + let small_closed = small[2]; + let big_args = big[1]; + let big_closed = big[2]; + if(small_args[0] !== 'tuple' || small_closed[0] !== 'tuple' || + big_args[0] !== 'tuple' || big_closed[0] !== 'tuple') + throw new Error("Badly formed ast"); + + let small_a = small_args[1]; + let small_b = small_args[2]; + let big_a = big_args[1]; + let big_b = big_args[2]; + + let comparisons = []; + if(small_closed[1] && !big_closed[1]) { + if(negate) + comparisons.push(['le', small_a,big_a]); + else + comparisons.push(['>', small_a,big_a]); + } + else { + if(negate) + comparisons.push(['<', small_a,big_a]); + else + comparisons.push(['ge', small_a,big_a]); + } + if(small_closed[2] && !big_closed[2]) { + if(negate) + comparisons.push(['ge', small_b,big_b]); + else + comparisons.push(['<', small_b,big_b]); + } + else { + if(negate) + comparisons.push(['>',small_b,big_b]); + else + comparisons.push(['le',small_b,big_b]); + } + let result; + if(negate) + result = ['or'].concat(comparisons); + else + result = ['and'].concat(comparisons); + + return result; + } - // Power - W: { - name: 'W', - base: BASE_UNITS.POWER, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - watt: { - name: 'watt', - base: BASE_UNITS.POWER, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - hp: { - name: 'hp', - base: BASE_UNITS.POWER, - prefixes: PREFIXES.NONE, - value: 745.6998715386, - offset: 0 - }, + return ast; + } - // Electrical power units - VAR: { - name: 'VAR', - base: BASE_UNITS.POWER, - prefixes: PREFIXES.SHORT, - value: Complex.I, - offset: 0 - }, - - VA: { - name: 'VA', - base: BASE_UNITS.POWER, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, + function substitute$1(pattern, bindings) { + var pattern_tree = get_tree(pattern); - // Pressure - Pa: { - name: 'Pa', - base: BASE_UNITS.PRESSURE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - psi: { - name: 'psi', - base: BASE_UNITS.PRESSURE, - prefixes: PREFIXES.NONE, - value: 6894.75729276459, - offset: 0 - }, - atm: { - name: 'atm', - base: BASE_UNITS.PRESSURE, - prefixes: PREFIXES.NONE, - value: 101325, - offset: 0 - }, - bar: { - name: 'bar', - base: BASE_UNITS.PRESSURE, - prefixes: PREFIXES.SHORTLONG, - value: 100000, - offset: 0 - }, - torr: { - name: 'torr', - base: BASE_UNITS.PRESSURE, - prefixes: PREFIXES.NONE, - value: 133.322, - offset: 0 - }, - mmHg: { - name: 'mmHg', - base: BASE_UNITS.PRESSURE, - prefixes: PREFIXES.NONE, - value: 133.322, - offset: 0 - }, - mmH2O: { - name: 'mmH2O', - base: BASE_UNITS.PRESSURE, - prefixes: PREFIXES.NONE, - value: 9.80665, - offset: 0 - }, - cmH2O: { - name: 'cmH2O', - base: BASE_UNITS.PRESSURE, - prefixes: PREFIXES.NONE, - value: 98.0665, - offset: 0 - }, + var bindings_tree = {}; + for(let b in bindings) { + bindings_tree[b] = get_tree(bindings[b]); + } - // Electric charge - coulomb: { - name: 'coulomb', - base: BASE_UNITS.ELECTRIC_CHARGE, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - C: { - name: 'C', - base: BASE_UNITS.ELECTRIC_CHARGE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - // Electric capacitance - farad: { - name: 'farad', - base: BASE_UNITS.ELECTRIC_CAPACITANCE, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - F: { - name: 'F', - base: BASE_UNITS.ELECTRIC_CAPACITANCE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - // Electric potential - volt: { - name: 'volt', - base: BASE_UNITS.ELECTRIC_POTENTIAL, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - V: { - name: 'V', - base: BASE_UNITS.ELECTRIC_POTENTIAL, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - // Electric resistance - ohm: { - name: 'ohm', - base: BASE_UNITS.ELECTRIC_RESISTANCE, - prefixes: PREFIXES.SHORTLONG, // Both Mohm and megaohm are acceptable - value: 1, - offset: 0 - }, - /* - * Unicode breaks in browsers if charset is not specified - Ω: { - name: 'Ω', - base: BASE_UNITS.ELECTRIC_RESISTANCE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - */ - // Electric inductance - henry: { - name: 'henry', - base: BASE_UNITS.ELECTRIC_INDUCTANCE, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - H: { - name: 'H', - base: BASE_UNITS.ELECTRIC_INDUCTANCE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - // Electric conductance - siemens: { - name: 'siemens', - base: BASE_UNITS.ELECTRIC_CONDUCTANCE, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - S: { - name: 'S', - base: BASE_UNITS.ELECTRIC_CONDUCTANCE, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - // Magnetic flux - weber: { - name: 'weber', - base: BASE_UNITS.MAGNETIC_FLUX, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - Wb: { - name: 'Wb', - base: BASE_UNITS.MAGNETIC_FLUX, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, - // Magnetic flux density - tesla: { - name: 'tesla', - base: BASE_UNITS.MAGNETIC_FLUX_DENSITY, - prefixes: PREFIXES.LONG, - value: 1, - offset: 0 - }, - T: { - name: 'T', - base: BASE_UNITS.MAGNETIC_FLUX_DENSITY, - prefixes: PREFIXES.SHORT, - value: 1, - offset: 0 - }, + return substitute(pattern_tree, bindings_tree); - // Binary - b: { - name: 'b', - base: BASE_UNITS.BIT, - prefixes: PREFIXES.BINARY_SHORT, - value: 1, - offset: 0 - }, - bits: { - name: 'bits', - base: BASE_UNITS.BIT, - prefixes: PREFIXES.BINARY_LONG, - value: 1, - offset: 0 - }, - B: { - name: 'B', - base: BASE_UNITS.BIT, - prefixes: PREFIXES.BINARY_SHORT, - value: 8, - offset: 0 - }, - bytes: { - name: 'bytes', - base: BASE_UNITS.BIT, - prefixes: PREFIXES.BINARY_LONG, - value: 8, - offset: 0 - } - }; - - // aliases (formerly plurals) - var ALIASES = { - meters: 'meter', - inches: 'inch', - feet: 'foot', - yards: 'yard', - miles: 'mile', - links: 'link', - rods: 'rod', - chains: 'chain', - angstroms: 'angstrom', - - lt: 'l', - litres: 'litre', - liter: 'litre', - liters: 'litre', - teaspoons: 'teaspoon', - tablespoons: 'tablespoon', - minims: 'minim', - fluiddrams: 'fluiddram', - fluidounces: 'fluidounce', - gills: 'gill', - cups: 'cup', - pints: 'pint', - quarts: 'quart', - gallons: 'gallon', - beerbarrels: 'beerbarrel', - oilbarrels: 'oilbarrel', - hogsheads: 'hogshead', - gtts: 'gtt', - - grams: 'gram', - tons: 'ton', - tonnes: 'tonne', - grains: 'grain', - drams: 'dram', - ounces: 'ounce', - poundmasses: 'poundmass', - hundredweights: 'hundredweight', - sticks: 'stick', - lb: 'lbm', - lbs: 'lbm', - - kips: 'kip', - - acres: 'acre', - hectares: 'hectare', - sqfeet: 'sqft', - sqyard: 'sqyd', - sqmile: 'sqmi', - sqmiles: 'sqmi', - - mmhg: 'mmHg', - mmh2o: 'mmH2O', - cmh2o: 'cmH2O', - - seconds: 'second', - secs: 'second', - minutes: 'minute', - mins: 'minute', - hours: 'hour', - hr: 'hour', - hrs: 'hour', - days: 'day', - weeks: 'week', - months: 'month', - years: 'year', - decades: 'decade', - centuries: 'century', - millennia: 'millennium', - - hertz: 'hertz', - - radians: 'radian', - degrees: 'degree', - gradians: 'gradian', - cycles: 'cycle', - arcsecond: 'arcsec', - arcseconds: 'arcsec', - arcminute: 'arcmin', - arcminutes: 'arcmin', - - BTUs: 'BTU', - watts: 'watt', - joules: 'joule', - - amperes: 'ampere', - coulombs: 'coulomb', - volts: 'volt', - ohms: 'ohm', - farads: 'farad', - webers: 'weber', - teslas: 'tesla', - electronvolts: 'electronvolt', - moles: 'mole' + } - }; + function substitute_component(pattern, component, value) { + let pattern_tree = get_tree(pattern); + let value_tree = get_tree(value); - /** - * Calculate the values for the angle units. - * Value is calculated as number or BigNumber depending on the configuration - * @param {{number: 'number' | 'BigNumber'}} config - */ - function calculateAngleValues (config) { - if (config.number === 'BigNumber') { - var pi = constants.pi(type.BigNumber); - UNITS.rad.value = new type.BigNumber(1); - UNITS.deg.value = pi.div(180); // 2 * pi / 360; - UNITS.grad.value = pi.div(200); // 2 * pi / 400; - UNITS.cycle.value = pi.times(2); // 2 * pi - UNITS.arcsec.value = pi.div(648000); // 2 * pi / 360 / 3600 - UNITS.arcmin.value = pi.div(10800); // 2 * pi / 360 / 60 + if(typeof component === "number") { + component = [component]; } - else { // number - UNITS.rad.value = 1; - UNITS.deg.value = Math.PI / 180; // 2 * pi / 360; - UNITS.grad.value = Math.PI / 200; // 2 * pi / 400; - UNITS.cycle.value = Math.PI * 2; // 2 * pi - UNITS.arcsec.value = Math.PI / 648000; // 2 * pi / 360 / 3600; - UNITS.arcmin.value = Math.PI / 10800; // 2 * pi / 360 / 60; + else if(!Array.isArray(component)) { + throw Error("Invalid substitute_component: " + component); } - // copy to the full names of the angles - UNITS.radian.value = UNITS.rad.value; - UNITS.degree.value = UNITS.deg.value; - UNITS.gradian.value = UNITS.grad.value; - } - // apply the angle values now - calculateAngleValues(config); + let container_operators = ["list", "tuple", "vector", "array"]; - // recalculate the values on change of configuration - math.on('config', function (curr, prev) { - if (curr.number !== prev.number) { - calculateAngleValues(curr); - } - }); + return substitute_component_sub(pattern_tree, component, value_tree); - /** - * A unit system is a set of dimensionally independent base units plus a set of derived units, formed by multiplication and division of the base units, that are by convention used with the unit system. - * A user perhaps could issue a command to select a preferred unit system, or use the default (see below). - * Auto unit system: The default unit system is updated on the fly anytime a unit is parsed. The corresponding unit in the default unit system is updated, so that answers are given in the same units the user supplies. - */ - var UNIT_SYSTEMS = { - si: { - // Base units - NONE: {unit: UNIT_NONE, prefix: PREFIXES.NONE['']}, - LENGTH: {unit: UNITS.m, prefix: PREFIXES.SHORT['']}, - MASS: {unit: UNITS.g, prefix: PREFIXES.SHORT['k']}, - TIME: {unit: UNITS.s, prefix: PREFIXES.SHORT['']}, - CURRENT: {unit: UNITS.A, prefix: PREFIXES.SHORT['']}, - TEMPERATURE: {unit: UNITS.K, prefix: PREFIXES.SHORT['']}, - LUMINOUS_INTENSITY: {unit: UNITS.cd, prefix: PREFIXES.SHORT['']}, - AMOUNT_OF_SUBSTANCE: {unit: UNITS.mol, prefix: PREFIXES.SHORT['']}, - ANGLE: {unit: UNITS.rad, prefix: PREFIXES.SHORT['']}, - BIT: {unit: UNITS.bit, prefix: PREFIXES.SHORT['']}, - - // Derived units - FORCE: {unit: UNITS.N, prefix: PREFIXES.SHORT['']}, - ENERGY: {unit: UNITS.J, prefix: PREFIXES.SHORT['']}, - POWER: {unit: UNITS.W, prefix: PREFIXES.SHORT['']}, - PRESSURE: {unit: UNITS.Pa, prefix: PREFIXES.SHORT['']}, - ELECTRIC_CHARGE: {unit: UNITS.C, prefix: PREFIXES.SHORT['']}, - ELECTRIC_CAPACITANCE: {unit: UNITS.F, prefix: PREFIXES.SHORT['']}, - ELECTRIC_POTENTIAL: {unit: UNITS.V, prefix: PREFIXES.SHORT['']}, - ELECTRIC_RESISTANCE: {unit: UNITS.ohm, prefix: PREFIXES.SHORT['']}, - ELECTRIC_INDUCTANCE: {unit: UNITS.H, prefix: PREFIXES.SHORT['']}, - ELECTRIC_CONDUCTANCE: {unit: UNITS.S, prefix: PREFIXES.SHORT['']}, - MAGNETIC_FLUX: {unit: UNITS.Wb, prefix: PREFIXES.SHORT['']}, - MAGNETIC_FLUX_DENSITY: {unit: UNITS.T, prefix: PREFIXES.SHORT['']}, - FREQUENCY: {unit: UNITS.Hz, prefix: PREFIXES.SHORT['']} - } - }; - - // Clone to create the other unit systems - UNIT_SYSTEMS.cgs = JSON.parse(JSON.stringify(UNIT_SYSTEMS.si)); - UNIT_SYSTEMS.cgs.LENGTH = {unit: UNITS.m, prefix: PREFIXES.SHORT['c']}; - UNIT_SYSTEMS.cgs.MASS = {unit: UNITS.g, prefix: PREFIXES.SHORT['']}; - UNIT_SYSTEMS.cgs.FORCE = {unit: UNITS.dyn, prefix: PREFIXES.SHORT['']}; - UNIT_SYSTEMS.cgs.ENERGY = {unit: UNITS.erg, prefix: PREFIXES.NONE['']}; - // there are wholly 4 unique cgs systems for electricity and magnetism, - // so let's not worry about it unless somebody complains - - UNIT_SYSTEMS.us = JSON.parse(JSON.stringify(UNIT_SYSTEMS.si)); - UNIT_SYSTEMS.us.LENGTH = {unit: UNITS.ft, prefix: PREFIXES.NONE['']}; - UNIT_SYSTEMS.us.MASS = {unit: UNITS.lbm, prefix: PREFIXES.NONE['']}; - UNIT_SYSTEMS.us.TEMPERATURE = {unit: UNITS.degF, prefix: PREFIXES.NONE['']}; - UNIT_SYSTEMS.us.FORCE = {unit: UNITS.lbf, prefix: PREFIXES.NONE['']}; - UNIT_SYSTEMS.us.ENERGY = {unit: UNITS.BTU, prefix: PREFIXES.BTU['']}; - UNIT_SYSTEMS.us.POWER = {unit: UNITS.hp, prefix: PREFIXES.NONE['']}; - UNIT_SYSTEMS.us.PRESSURE = {unit: UNITS.psi, prefix: PREFIXES.NONE['']}; - - // Add additional unit systems here. - - - - // Choose a unit system to seed the auto unit system. - UNIT_SYSTEMS.auto = JSON.parse(JSON.stringify(UNIT_SYSTEMS.si)); - - // Set the current unit system - var currentUnitSystem = UNIT_SYSTEMS.auto; - /** - * Set a unit system for formatting derived units. - * @param {string} [name] The name of the unit system. - */ - Unit.setUnitSystem = function(name) { - if(UNIT_SYSTEMS.hasOwnProperty(name)) { - currentUnitSystem = UNIT_SYSTEMS[name]; - } - else { - throw new Error('Unit system ' + name + ' does not exist. Choices are: ' + Object.keys(UNIT_SYSTEMS).join(', ')); - } - }; + function substitute_component_sub(tree, component, value_tree) { - /** - * Return the current unit system. - * @return {string} The current unit system. - */ - Unit.getUnitSystem = function() { - for(var key in UNIT_SYSTEMS) { - if(UNIT_SYSTEMS[key] === currentUnitSystem) { - return key; + if(component.length === 0) { + return value; + } + if(!Array.isArray(tree)) { + throw Error("Invalid substitute_component: expected list, tuple, vector, or array"); } - } - }; - /** - * Converters to convert from number to an other numeric type like BigNumber - * or Fraction - */ - Unit.typeConverters = { - BigNumber: function (x) { - return new type.BigNumber(x + ''); // stringify to prevent constructor error - }, + let operator = tree[0]; + let operands = tree.slice(1); - Fraction: function (x) { - return new type.Fraction(x); - }, + if(!container_operators.includes(operator)) { + throw Error("Invalid substitute_component: expected list, tuple, vector, or array"); + } - Complex: function (x) { - return x; - }, + let ind = component[0]; + if(ind < 0 || ind > operands.length-1) { + throw Error("Invalid substitute_component: component out of range"); + } + let new_components = component.slice(1); + let result = substitute_component_sub(operands[ind], new_components, value_tree); - number: function (x) { - return x; + return [operator, ...operands.slice(0,ind), result, ...operands.slice(ind+1)]; } - }; - /** - * Retrieve the right convertor function corresponding with the type - * of provided exampleValue. - * - * @param {string} type A string 'number', 'BigNumber', or 'Fraction' - * In case of an unknown type, - * @return {Function} - */ - Unit._getNumberConverter = function (type) { - if (!Unit.typeConverters[type]) { - throw new TypeError('Unsupported type "' + type + '"'); + } + + function get_component(pattern, component) { + let pattern_tree = get_tree(pattern); + + if(typeof component === "number") { + component = [component]; + } + else if(!Array.isArray(component)) { + throw Error("Invalid get_component: " + component); } - return Unit.typeConverters[type]; - }; + let container_operators = ["list", "tuple", "vector", "array"]; - // Add dimensions to each built-in unit - for (var key in UNITS) { - var unit = UNITS[key]; - unit.dimensions = unit.base.dimensions; - } + return get_component_sub(pattern_tree, component); - // Create aliases - for (var name in ALIASES) { - if(ALIASES.hasOwnProperty(name)) { - var unit = UNITS[ALIASES[name]]; - var alias = {}; - for(var key in unit) { - if(unit.hasOwnProperty(key)) { - alias[key] = unit[key]; - } + + function get_component_sub(tree, component) { + + if(component.length === 0) { + return tree; } - alias.name = name; - UNITS[name] = alias; - } - } - function assertUnitNameIsValid(name) { - for(var i=0; i= '0' && c <= '9'); - }; + let operator = tree[0]; + let operands = tree.slice(1); - if(i === 0 && !isValidAlpha(c)) - throw new Error('Invalid unit name (must begin with alpha character): "' + name + '"'); + if(!container_operators.includes(operator)) { + throw Error("Invalid get_component: expected list, tuple, vector, or array"); + } - if(i > 0 && !( isValidAlpha(c) - || isDigit(c))) - throw new Error('Invalid unit name (only alphanumeric characters are allowed): "' + name + '"'); + let ind = component[0]; + if(ind < 0 || ind > operands.length-1) { + throw Error("Invalid get_component: component out of range"); + } + let new_components = component.slice(1); + return get_component_sub(operands[ind], new_components); } + } - /** - * Wrapper around createUnitSingle. - * Example: - * createUnit({ - * foo: { }, - * bar: { - * definition: 'kg/foo', - * aliases: ['ba', 'barr', 'bars'], - * offset: 200 - * }, - * baz: '4 bar' - * }, - * { - * override: true; - * }); - * @param {object} obj Object map. Each key becomes a unit which is defined by its value. - * @param {object} options - */ - Unit.createUnit = function(obj, options) { - - if(typeof(obj) !== 'object') { - throw new TypeError("createUnit expects first parameter to be of type 'Object'"); - } + var transformation = /*#__PURE__*/Object.freeze({ + expand: expand, + expand_relations: expand_relations, + substitute: substitute$1, + substitute_component: substitute_component, + get_component: get_component + }); - // Remove all units and aliases we are overriding - if(options && options.override) { - for(var key in obj) { - if(obj.hasOwnProperty(key)) { - Unit.deleteUnit(key); - } - if(obj[key].aliases) { - for(var i=0; i' || operator === 'ge')) + return undefined; - if(definition && typeof(definition) === 'string' && !defUnit) { - try { - defUnit = Unit.parse(definition, {allowNoUnits: true}); - } - catch (ex) { - ex.message = 'Could not create unit "' + name + '" from "' + definition + '": ' + ex.message; - throw(ex); - } - } - else if(definition && definition.type === 'Unit') { - defUnit = definition.clone(); - } - aliases = aliases || []; - offset = offset || 0; - if(prefixes && prefixes.toUpperCase) - prefixes = PREFIXES[prefixes.toUpperCase()] || PREFIXES.NONE; - else - prefixes = PREFIXES.NONE; + // set equal to zero, as lhs = 0 + var lhs = simplify$2(['+', operands[0], ['-', operands[1]]], + assumptions); + var no_var = tree => !variables(tree).includes(variable); - // If defUnit is null, it is because the user did not - // specify a defintion. So create a new base dimension. - var newUnit = {}; - if(!defUnit) { - // Add a new base dimension - var baseName = name + "_STUFF"; // foo --> foo_STUFF, or the essence of foo - if(BASE_DIMENSIONS.indexOf(baseName) >= 0) { - throw new Error('Cannot create new base unit "' + name + '": a base unit with that name already exists (and cannot be overridden)'); - } - BASE_DIMENSIONS.push(baseName); + // factor out variable + var transformation = [ + ['+', ['*', '_a', variable], ['*', '_b', variable]], + ['*', ['+', '_a', '_b'], variable], + {variables: {_a: no_var, _b: no_var}, + allow_permutations: true, + allow_extended_match: true, + allow_implicit_identities: ['_a', '_b'], + evaluate_numbers: true, - // Push 0 onto existing base units - for(var b in BASE_UNITS) { - if(BASE_UNITS.hasOwnProperty(b)) { - BASE_UNITS[b].dimensions[BASE_DIMENSIONS.length-1] = 0; - } - } + }]; - // Add the new base unit - var newBaseUnit = { dimensions: [] }; - for(var i=0; i 1e-12) { - match = false; - break; - } - } - if(match) { - anyMatch = true; - break; - } - } - } - if(!anyMatch) { - var baseName = name + "_STUFF"; // foo --> foo_STUFF, or the essence of foo - // Add the new base unit - var newBaseUnit = { dimensions: defUnit.dimensions.slice(0) }; - newBaseUnit.key = baseName; - BASE_UNITS[baseName] = newBaseUnit; - currentUnitSystem[baseName] = { - unit: newUnit, - prefix: PREFIXES.NONE[''] - }; + var match$$1 = match(lhs, pattern, params); - newUnit.base = baseName; - } - } + if(!match$$1) + return undefined; // not linear in variable - Unit.UNITS[name] = newUnit; + var a = simplify$2(match$$1['_a']); + var b = simplify$2(match$$1['_b']); - for (var i=0; i') + operator = '<'; + else + operator = 'le'; - // expose arrays with prefixes, dimensions, units, systems - Unit.PREFIXES = PREFIXES; - Unit.BASE_DIMENSIONS = BASE_DIMENSIONS; - Unit.BASE_UNITS = BASE_UNITS; - Unit.UNIT_SYSTEMS = UNIT_SYSTEMS; - Unit.UNITS = UNITS; + return [operator, variable, result]; + } - return Unit; -} + var solve = /*#__PURE__*/Object.freeze({ + solve_linear: solve_linear + }); -var name$265 = 'Unit'; -var path$65 = 'type'; -var factory_1$277 = factory$278; -var math$20 = true; // request access to the math namespace + function clean_assumptions(tree, known) { + // normalize order and operators of assumptions in tree, + // remove any duplicates or those in known + // return ast or undefined if no assumptions found -var Unit = { - name: name$265, - path: path$65, - factory: factory_1$277, - math: math$20 -}; + if(!Array.isArray(tree) || tree.length === 0) + return tree; -function factory$279 (type, config, load, typed) { - /** - * Create a unit. Depending on the passed arguments, the function - * will create and return a new math.type.Unit object. - * When a matrix is provided, all elements will be converted to units. - * - * Syntax: - * - * math.unit(unit : string) - * math.unit(value : number, unit : string) - * - * Examples: - * - * var a = math.unit(5, 'cm'); // returns Unit 50 mm - * var b = math.unit('23 kg'); // returns Unit 23 kg - * a.to('m'); // returns Unit 0.05 m - * - * See also: - * - * bignumber, boolean, complex, index, matrix, number, string, createUnit - * - * @param {* | Array | Matrix} args A number and unit. - * @return {Unit | Array | Matrix} The created unit - */ + tree= flatten( + default_order( + simplify_logical( + expand_relations(tree) + ) + ) + ); - var unit = typed('unit', { - 'Unit': function (x) { - return x.clone(); - }, + // check for duplicates (within tree or already in known) + var operator=tree[0]; + var operands=tree.slice(1); + + if(operator === 'and' || operator === 'or') { + // remove duplicates, using trees.equal + operands = operands.reduce(function (a,b) { + if(a.every(function(v) { return !equal$2(v,b)})) + a.push(b); + return a; + },[]); + + // if known exists, filter out those + if(operator === 'and' && known && Array.isArray(known)) { + let known_operands; + if(known[0] === 'and') + known_operands = known.slice(1); + else + known_operands = [known]; - 'string': function (x) { - if (type.Unit.isValuelessUnit(x)) { - return new type.Unit(null, x); // a pure unit + operands = operands.filter( + v => known_operands.every(u => !equal$2(u, v)) + ); + + } + + if(operands.length === 1) + tree = operands[0]; + else + tree = [operator].concat(operands); } - return type.Unit.parse(x); // a unit with value, like '5cm' - }, + // check if whole thing is known + if(operator !== 'and' && known && Array.isArray(known)) { + let known_operands; + if(known[0] === 'and') + known_operands = known.slice(1); + else + known_operands = [known]; - 'number | BigNumber | Fraction | Complex, string': function (value, unit) { - return new type.Unit(value, unit); - }, + if(!known_operands.every(u => !equal$2(u, tree))) + return undefined; + } - 'Array | Matrix': function (x) { - return deepMap(x, unit); - } - }); + return tree; + } - unit.toTex = { - 1: '\\left(${args[0]}\\right)', - 2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)' - }; - return unit; -} + function calculate_derived_assumptions(assumptions, tree) { + // Calculate all assumptions on variables within tree that + // can be derived from the assumptions within tree, + // eliminating any assumptions that are already recorded + // in byvar or generic of assumptions + // + // if tree is undefined, calculate assumptions that can be + // derived from all given assumptions -var name$266 = 'unit'; -var factory_1$278 = factory$279; -var unit$2 = { - name: name$266, - factory: factory_1$278 -}; + if(tree === undefined) { + tree = []; + for(let v in assumptions.byvar) { + let a = assumptions.byvar[v]; + if(a.length > 0) + tree.push(a); + } + if(tree.length === 0) + return {}; -function factory$280 (type, config, load, typed) { - /** - * Create a user-defined unit and register it with the Unit type. - * - * Syntax: - * - * math.createUnit({ - * baseUnit1: { - * aliases: [string, ...] - * prefixes: object - * }, - * unit2: { - * definition: string, - * aliases: [string, ...] - * prefixes: object, - * offset: number - * }, - * unit3: string // Shortcut - * }) - * - * // Another shortcut: - * math.createUnit(string, unit : string, [object]) - * - * Examples: - * - * math.createUnit('foo'); - * math.createUnit('knot', {definition: '0.514444444 m/s', aliases: ['knots', 'kt', 'kts']}); - * math.createUnit('mph', '1 mile/hour'); - * - * @param {string} name The name of the new unit. Must be unique. Example: 'knot' - * @param {string, Unit} definition Definition of the unit in terms of existing units. For example, '0.514444444 m / s'. - * @param {Object} options (optional) An object containing any of the following properties: - * - `prefixes {string}` "none", "short", "long", "binary_short", or "binary_long". The default is "none". - * - `aliases {Array}` Array of strings. Example: ['knots', 'kt', 'kts'] - * - `offset {Numeric}` An offset to apply when converting from the unit. For example, the offset for celsius is 273.15. Default is 0. - * - * See also: - * - * unit - * - * @return {Unit} The new unit - */ - var createUnit = typed('createUnit', { + if(tree.length === 1) + tree = tree[0]; + else + tree = ['and'].concat(tree); - // General function signature. First parameter is an object where each property is the definition of a new unit. The object keys are the unit names and the values are the definitions. The values can be objects, strings, or Units. If a property is an empty object or an empty string, a new base unit is created. The second parameter is the options. - 'Object, Object': function(obj, options) { - return type.Unit.createUnit(obj, options); - }, + tree = clean_assumptions(tree); + } - // Same as above but without the options. - 'Object': function(obj) { - return type.Unit.createUnit(obj, {}); - }, + if(!Array.isArray(tree) || tree.length === 0) + return {}; - // Shortcut method for creating one unit. - 'string, Unit | string | Object, Object': function (name, def, options) { - var obj = {}; - obj[name] = def; - return type.Unit.createUnit(obj, options); - }, + var operator = tree[0]; + var operands = tree.slice(1); - // Same as above but without the options. - 'string, Unit | string | Object': function (name, def) { - var obj = {}; - obj[name] = def; - return type.Unit.createUnit(obj, {}); - }, + if(operator === 'and' || operator === 'or') { + let results = operands.map(function (v) { + return calculate_derived_assumptions(assumptions, v); + }); + + // array of all vars found in at least one result + let allvars = [...new Set(results.reduce( + (a,b) => [...a, ...Object.keys(b)], []))]; + + let derived = {}; + + for(let v of allvars) { + let res = results.reduce(function (a,b) { + if(b[v] !== undefined) + a.push(b[v]); + return a; + },[]); + + + // for OR, add only if obtain result for each operand + if(operator === 'and' || res.length === results.length) { + let new_derived = derived[v]; + if(new_derived === undefined) { + if(res.length > 1) + new_derived = [operator].concat(res); + else + new_derived = res[0]; + } + else { + if(res.length > 1) + new_derived = ['and', new_derived, + [operator].concat(res)]; + else + new_derived = ['and', new_derived, res[0]]; + } + + derived[v] = clean_assumptions( + new_derived, + get_assumptions(assumptions, v, {omit_derived: true})); + } + } - // Without a definition, creates a base unit. - 'string': function (name) { - var obj = {}; - obj[name] = {}; - return type.Unit.createUnit(obj, {}); - }, - }); + return derived; + } + // Shouldn't get a NOT of (in)equality after simplifying logical + // if(operator === 'not') { + // let results = calculate_derived_assumptions(assumptions, operands[0]); + // for(let v of Object.keys(results)) { + // derived[v] = ['not', results[v]]; + // } + // return derived; + // } + + let derived = {}; + + if(operator === '=' || operator === 'ne' || + operator === '<' || operator === 'le' || + operator === 'in' || operator === 'subset' || + operator === 'notin' || operator === 'notsubset' + ) { + + var addressed_assumption = false; + + // calculate derived if one side is equal to a variable + for(let ind = 0; ind < 2; ind++) { + let v = operands[ind]; + let other = operands[1-ind]; + let other_var = variables(other); + if((typeof v !== 'string') || other_var.length === 0 + || other_var.includes(v)) + continue; + + addressed_assumption = true; + + // look for any assumptions that from other that + // do not contain a v + var adjusted_op = operator; + if(ind === 1) { + if(operator === '<') + adjusted_op = '>'; + else if(operator === 'le') + adjusted_op = 'ge'; + else if(operator === 'in') + adjusted_op = 'ni'; + else if(operator === 'subset') + adjusted_op = 'superset'; + else if(operator === 'notin') + adjusted_op = 'notni'; + else if(operator === 'notsubset') + adjusted_op = 'notsuperset'; + } + let result = get_assumptions_for_expr( + assumptions, other, [v]); + + // combine with results for expr, if compatible + result = combine_assumptions(v, adjusted_op, other, result); + + if(result !== undefined) { + let new_derived = derived[v]; + + if(new_derived === undefined) { + new_derived = result; + } + else { + new_derived = ['and', new_derived, result]; + } + + derived[v] = clean_assumptions( + new_derived, get_assumptions( + assumptions, v, {omit_derived: true})); + + } - return createUnit; -} + } + if(addressed_assumption) + return derived; + } -var name$267 = 'createUnit'; -var factory_1$279 = factory$280; + // if wasn't able to combine expressions, just add any assumptions + // on the operands + let results = []; -var createUnit$1 = { - name: name$267, - factory: factory_1$279 -}; + for(let op of operands) { + let res = get_assumptions_for_expr(assumptions, op, []); + if(res !== undefined) + results.push(res); + } -function factory$281 (type, config, load, typed) { + if(results.length === 0) + return {}; - /** - * Split a unit in an array of units whose sum is equal to the original unit. - * - * Syntax: - * - * splitUnit(unit: Unit, parts: Array.) - * - * Example: - * - * math.splitUnit(new Unit(1, 'm'), ['feet', 'inch']); - * // [ 3 feet, 3.3700787401575 inch ] - * - * See also: - * - * unit - * - * @param {Array} [parts] An array of strings or valueless units. - * @return {Array} An array of units. - */ - var splitUnit = typed('splitUnit', { - 'Unit, Array': function(unit, parts) { - return unit.splitUnit(parts); - } - }); + if(results.length === 1) + results = results[0]; + else + results = ['and'].concat(results); - return splitUnit; + for(let v of variables(tree)) { + derived[v] = clean_assumptions( + results, get_assumptions( + assumptions, v, {omit_derived: true})); + } -} + return derived; -var name$268 = 'splitUnit'; -var factory_1$280 = factory$281; + } -var splitUnit$1 = { - name: name$268, - factory: factory_1$280 -}; + function get_assumptions_for_expr(assumptions, expr, exclude_variables) { + // return any assumptions that can be calculated for expression expr + // that don't include exclude_variables + // + // The assumptions will be given directly in terms of expr when possible. -var lazy$5 = object.lazy; + let variables$$1 = variables(expr); -function factory$282 (type, config, load, typed, math) { + // filter out any of the excluded variables + variables$$1 = variables$$1.filter(v => !exclude_variables.includes(v)); - // helper function to create a unit with a fixed prefix - function fixedUnit(str) { - var unit = type.Unit.parse(str); - unit.fixPrefix = true; - return unit; - } + if(variables$$1.length === 0) + return undefined; - // Source: http://www.wikiwand.com/en/Physical_constant - - // Universal constants - setLazyConstant$1(math, 'speedOfLight', function () {return fixedUnit('299792458 m s^-1')}); - setLazyConstant$1(math, 'gravitationConstant', function () {return fixedUnit('6.6738480e-11 m^3 kg^-1 s^-2')}); - setLazyConstant$1(math, 'planckConstant', function () {return fixedUnit('6.626069311e-34 J s')}); - setLazyConstant$1(math, 'reducedPlanckConstant',function () {return fixedUnit('1.05457172647e-34 J s')}); - - // Electromagnetic constants - setLazyConstant$1(math, 'magneticConstant', function () {return fixedUnit('1.2566370614e-6 N A^-2')}); - setLazyConstant$1(math, 'electricConstant', function () {return fixedUnit('8.854187817e-12 F m^-1')}); - setLazyConstant$1(math, 'vacuumImpedance', function () {return fixedUnit('376.730313461 ohm')}); - setLazyConstant$1(math, 'coulomb', function () {return fixedUnit('8.9875517873681764e9 N m^2 C^-2')}); - setLazyConstant$1(math, 'elementaryCharge', function () {return fixedUnit('1.60217656535e-19 C')}); - setLazyConstant$1(math, 'bohrMagneton', function () {return fixedUnit('9.2740096820e-24 J T^-1')}); - setLazyConstant$1(math, 'conductanceQuantum', function () {return fixedUnit('7.748091734625e-5 S')}); - setLazyConstant$1(math, 'inverseConductanceQuantum', function () {return fixedUnit('12906.403721742 ohm')}); - setLazyConstant$1(math, 'magneticFluxQuantum', function () {return fixedUnit('2.06783375846e-15 Wb')}); - setLazyConstant$1(math, 'nuclearMagneton', function () {return fixedUnit('5.0507835311e-27 J T^-1')}); - setLazyConstant$1(math, 'klitzing', function () {return fixedUnit('25812.807443484 ohm')}); - //setLazyConstant(math, 'josephson', function () {return fixedUnit('4.8359787011e-14 Hz V^-1')}); // TODO: support for Hz needed - - // Atomic and nuclear constants - setLazyConstant$1(math, 'bohrRadius', function () {return fixedUnit('5.291772109217e-11 m')}); - setLazyConstant$1(math, 'classicalElectronRadius', function () {return fixedUnit('2.817940326727e-15 m')}); - setLazyConstant$1(math, 'electronMass', function () {return fixedUnit('9.1093829140e-31 kg')}); - setLazyConstant$1(math, 'fermiCoupling', function () {return fixedUnit('1.1663645e-5 GeV^-2')}); - setLazyConstant$1(math, 'fineStructure', function () {return 7.297352569824e-3}); - setLazyConstant$1(math, 'hartreeEnergy', function () {return fixedUnit('4.3597443419e-18 J')}); - setLazyConstant$1(math, 'protonMass', function () {return fixedUnit('1.67262177774e-27 kg')}); - setLazyConstant$1(math, 'deuteronMass', function () {return fixedUnit('3.3435830926e-27 kg')}); - setLazyConstant$1(math, 'neutronMass', function () {return fixedUnit('1.6749271613e-27 kg')}); - setLazyConstant$1(math, 'quantumOfCirculation', function () {return fixedUnit('3.636947552024e-4 m^2 s^-1')}); - setLazyConstant$1(math, 'rydberg', function () {return fixedUnit('10973731.56853955 m^-1')}); - setLazyConstant$1(math, 'thomsonCrossSection', function () {return fixedUnit('6.65245873413e-29 m^2')}); - setLazyConstant$1(math, 'weakMixingAngle', function () {return 0.222321}); - setLazyConstant$1(math, 'efimovFactor', function () {return 22.7}); - - // Physico-chemical constants - setLazyConstant$1(math, 'atomicMass', function () {return fixedUnit('1.66053892173e-27 kg')}); - setLazyConstant$1(math, 'avogadro', function () {return fixedUnit('6.0221412927e23 mol^-1')}); - setLazyConstant$1(math, 'boltzmann', function () {return fixedUnit('1.380648813e-23 J K^-1')}); - setLazyConstant$1(math, 'faraday', function () {return fixedUnit('96485.336521 C mol^-1')}); - setLazyConstant$1(math, 'firstRadiation', function () {return fixedUnit('3.7417715317e-16 W m^2')}); - // setLazyConstant(math, 'spectralRadiance', function () {return fixedUnit('1.19104286953e-16 W m^2 sr^-1')}); // TODO spectralRadiance - setLazyConstant$1(math, 'loschmidt', function () {return fixedUnit('2.686780524e25 m^-3')}); - setLazyConstant$1(math, 'gasConstant', function () {return fixedUnit('8.314462175 J K^-1 mol^-1')}); - setLazyConstant$1(math, 'molarPlanckConstant', function () {return fixedUnit('3.990312717628e-10 J s mol^-1')}); - setLazyConstant$1(math, 'molarVolume', function () {return fixedUnit('2.241396820e-10 m^3 mol^-1')}); - setLazyConstant$1(math, 'sackurTetrode', function () {return -1.164870823}); - setLazyConstant$1(math, 'secondRadiation', function () {return fixedUnit('1.438777013e-2 m K')}); - setLazyConstant$1(math, 'stefanBoltzmann', function () {return fixedUnit('5.67037321e-8 W m^-2 K^-4')}); - setLazyConstant$1(math, 'wienDisplacement', function () {return fixedUnit('2.897772126e-3 m K')}); - - // Adopted values - setLazyConstant$1(math, 'molarMass', function () {return fixedUnit('1e-3 kg mol^-1')}); - setLazyConstant$1(math, 'molarMassC12', function () {return fixedUnit('1.2e-2 kg mol^-1')}); - setLazyConstant$1(math, 'gravity', function () {return fixedUnit('9.80665 m s^-2')}); - // atm is defined in Unit.js - - // Natural units - setLazyConstant$1(math, 'planckLength', function () {return fixedUnit('1.61619997e-35 m')}); - setLazyConstant$1(math, 'planckMass', function () {return fixedUnit('2.1765113e-8 kg')}); - setLazyConstant$1(math, 'planckTime', function () {return fixedUnit('5.3910632e-44 s')}); - setLazyConstant$1(math, 'planckCharge', function () {return fixedUnit('1.87554595641e-18 C')}); - setLazyConstant$1(math, 'planckTemperature', function () {return fixedUnit('1.41683385e+32 K')}); - -} - -// create a lazy constant in both math and mathWithTransform -function setLazyConstant$1 (math, name, resolver) { - lazy$5(math, name, resolver); - lazy$5(math.expression.mathWithTransform, name, resolver); -} - -var factory_1$281 = factory$282; -var lazy_1$2 = false; // no lazy loading of constants, the constants themselves are lazy when needed -var math$21 = true; // request access to the math namespace - -var physicalConstants = { - factory: factory_1$281, - lazy: lazy_1$2, - math: math$21 -}; - -var unit$3 = [ - // type - Unit, - - // construction function - unit$2, - - // create new units - createUnit$1, - - // split units - splitUnit$1, - - // physical constants - physicalConstants -]; - -var type$1 = [ - bignumber$1, - boolean_1, - chain$1, - complex$3, - fraction$3, - matrix$1, - number$3, - resultset, - string$6, - unit$3 -]; - -var version$1 = '4.4.2'; - -function factory$283 (type, config, load, typed, math) { - // listen for changed in the configuration, automatically reload - // constants when needed - math.on('config', function (curr, prev) { - if (curr.number !== prev.number) { - factory$283(type, config, load, typed, math); - } - }); + function isNumber(s) { + if (typeof s === 'number') + return true; + if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) + return true; + return false; + } - setConstant$1(math, 'true', true); - setConstant$1(math, 'false', false); - setConstant$1(math, 'null', null); - setConstant$1(math, 'uninitialized', 'Error: Constant uninitialized is removed since v4.0.0. Use null instead'); - - if (config.number === 'BigNumber') { - setConstant$1(math, 'Infinity', new type.BigNumber(Infinity)); - setConstant$1(math, 'NaN', new type.BigNumber(NaN)); - - setLazyConstant$2(math, 'pi', function () {return constants.pi(type.BigNumber)}); - setLazyConstant$2(math, 'tau', function () {return constants.tau(type.BigNumber)}); - setLazyConstant$2(math, 'e', function () {return constants.e(type.BigNumber)}); - setLazyConstant$2(math, 'phi', function () {return constants.phi(type.BigNumber)}); // golden ratio, (1+sqrt(5))/2 - - // uppercase constants (for compatibility with built-in Math) - setLazyConstant$2(math, 'E', function () {return math.e;}); - setLazyConstant$2(math, 'LN2', function () {return new type.BigNumber(2).ln();}); - setLazyConstant$2(math, 'LN10', function () {return new type.BigNumber(10).ln()}); - setLazyConstant$2(math, 'LOG2E', function () {return new type.BigNumber(1).div(new type.BigNumber(2).ln());}); - setLazyConstant$2(math, 'LOG10E', function () {return new type.BigNumber(1).div(new type.BigNumber(10).ln())}); - setLazyConstant$2(math, 'PI', function () {return math.pi}); - setLazyConstant$2(math, 'SQRT1_2', function () {return new type.BigNumber('0.5').sqrt()}); - setLazyConstant$2(math, 'SQRT2', function () {return new type.BigNumber(2).sqrt()}); - } - else { - setConstant$1(math, 'Infinity', Infinity); - setConstant$1(math, 'NaN', NaN); - - setConstant$1(math, 'pi', Math.PI); - setConstant$1(math, 'tau', Math.PI * 2); - setConstant$1(math, 'e', Math.E); - setConstant$1(math, 'phi', 1.61803398874989484820458683436563811772030917980576286213545); // golden ratio, (1+sqrt(5))/2 - - // uppercase constants (for compatibility with built-in Math) - setConstant$1(math, 'E', math.e); - setConstant$1(math, 'LN2', Math.LN2); - setConstant$1(math, 'LN10', Math.LN10); - setConstant$1(math, 'LOG2E', Math.LOG2E); - setConstant$1(math, 'LOG10E', Math.LOG10E); - setConstant$1(math, 'PI', math.pi); - setConstant$1(math, 'SQRT1_2', Math.SQRT1_2); - setConstant$1(math, 'SQRT2', Math.SQRT2); - } - - // complex i - setConstant$1(math, 'i', type.Complex.I); - - // meta information - setConstant$1(math, 'version', version$1); -} - -// create a constant in both math and mathWithTransform -function setConstant$1(math, name, value) { - math[name] = value; - math.expression.mathWithTransform[name] = value; -} - -// create a lazy constant in both math and mathWithTransform -function setLazyConstant$2 (math, name, resolver) { - object.lazy(math, name, resolver); - object.lazy(math.expression.mathWithTransform, name, resolver); -} - -var factory_1$282 = factory$283; -var lazy$6 = false; // no lazy loading of constants, the constants themselves are lazy when needed -var math$22 = true; // request access to the math namespace - -var constants$2 = { - factory: factory_1$282, - lazy: lazy$6, - math: math$22 -}; - -var lib$1 = [ - type$1, // data types (Matrix, Complex, Unit, ...) - constants$2, // constants - expression, // expression parsing - _function$3, // functions - json, // serialization utility (math.json.reviver) - error // errors -]; - -/** - * math.js factory function. Creates a new instance of math.js - * - * @param {Object} [config] Available configuration options: - * {number} epsilon - * Minimum relative difference between two - * compared values, used by all comparison functions. - * {string} matrix - * A string 'matrix' (default) or 'array'. - * {string} number - * A string 'number' (default), 'bignumber', or - * 'fraction' - * {number} precision - * The number of significant digits for BigNumbers. - * Not applicable for Numbers. - * {boolean} predictable - * Predictable output type of functions. When true, - * output type depends only on the input types. When - * false (default), output type can vary depending - * on input values. For example `math.sqrt(-4)` - * returns `complex('2i')` when predictable is false, and - * returns `NaN` when true. - */ -function create$3 (config) { - // create a new math.js instance - var math = core$1.create(config); - math.create = create$3; - - // import data types, functions, constants, expression parser, etc. - math['import'](lib$1); - - return math; -} - -// return a new instance of math.js -var mathjs = create$3(); - -var node$1 = mathjs.expression.node; - -const operators$2 = { - "+": function(operands) { return new node$1.OperatorNode('+', 'add', operands);}, - "*": function(operands) { return new node$1.OperatorNode('*', 'multiply', operands);}, - "/": function(operands) { return new node$1.OperatorNode('/', 'divide', operands);}, - "-": function(operands) { return new node$1.OperatorNode('-', 'unaryMinus', [operands[0]]);}, - "^": function(operands) { return new node$1.OperatorNode('^', 'pow', operands);}, - //"prime": function(operands) { return operands[0] + "'"; }, - //"tuple": function(operands) { return '\\left( ' + operands.join( ', ' ) + ' \\right)';}, - //"array": function(operands) { return '\\left[ ' + operands.join( ', ' ) + ' \\right]';}, - //"set": function(operands) { return '\\left\\{ ' + operands.join( ', ' ) + ' \\right\\}';}, - "vector": function(operands) { return new node$1.ArrayNode(operands);}, - //"interval": function(operands) { return '\\left( ' + operands.join( ', ' ) + ' \\right)';}, - "and": function(operands) { return new node$1.OperatorNode('and', 'and', operands);}, - "or": function(operands) { return new node$1.OperatorNode('or', 'or', operands);}, - "not": function(operands) { return new node$1.OperatorNode('not', 'not', [operands[0]]);}, - "<": function(operands) { return new node$1.OperatorNode('<', 'smaller', operands);}, - ">": function(operands) { return new node$1.OperatorNode('>', 'larger', operands);}, - "le": function(operands) { return new node$1.OperatorNode('<=', 'smallerEq', operands);}, - "ge": function(operands) { return new node$1.OperatorNode('>=', 'largerEq', operands);}, - "ne": function(operands) { return new node$1.OperatorNode('!=', 'unequal', operands);}, - //"union": function (operands) { return operands.join(' \\cup '); }, - //"intersect": function (operands) { return operands.join(' \\cap '); }, -}; - -class astToMathjs { - constructor({ mathjs: mathjs$$1 = null } = {}) { - if(mathjs$$1) - node$1 = mathjs$$1.expression.node; - } - - convert(tree) { - if (typeof tree === 'number' ) { - if(Number.isFinite(tree)) - return new node$1.ConstantNode(tree); - if(Number.isNaN(tree)) - return new node$1.SymbolNode('NaN'); - if(tree < 0) - return operators$2['-']([new node$1.SymbolNode('Infinity')]); - return new node$1.SymbolNode('Infinity'); - } + // will proccess assumptions in case where variables are linear in expr + var pattern = ['_b']; + var implicit_identities = ['_b']; + var match_vars = {_b: isNumber}; + var coeff_mapping = {}; + for(let i=0; i < variables$$1.length; i++) { + let a = '_a' + i; + coeff_mapping[variables$$1[i]] = a; + pattern.push(['*', a, variables$$1[i]]); + implicit_identities.push(a); + match_vars[a] = isNumber; + } + + pattern = ['+'].concat(pattern); + + var m = match(expr, pattern, + {variables: match_vars, + allow_permutations: true, + allow_extended_match: false, + allow_implicit_identities: implicit_identities, + max_group: 1}); + + if(!m) { + // if not linear, get assumptions for each variable of expr + let results = []; + for(let v of variables(expr)) { + let res = get_assumptions_for_expr( + assumptions, v, exclude_variables); + if(res !== undefined) + results.push(res); + } + if(results.length === 0) + return undefined; + if(results.length === 1) + return results[0]; + return ['and'].concat(results); + } - if (typeof tree === 'string') { - return new node$1.SymbolNode(tree); - } + for(let v of variables$$1) + coeff_mapping[v] = m[coeff_mapping[v]]; + + let identity = false; + if(m["_b"] === 0 && m["_a0"] === 1 && variables$$1.length === 1) + identity = true; - if (typeof tree === 'boolean') - throw Error("no support for boolean"); + // find all assumptions involving variables but excluding exclude_variables + var new_assumptions; + new_assumptions = get_assumptions( + assumptions, [variables$$1], {exclude_variables: exclude_variables}); - if (!Array.isArray(tree)) - throw Error("Invalid ast"); + if(new_assumptions === undefined) + return undefined; - const operator = tree[0]; - const operands = tree.slice(1); + return clean_assumptions(process_additional_assumptions(new_assumptions)); - if(operator === "apply") { - if(typeof operands[0] !== 'string') - throw Error("Non string functions not implemented for conversion to mathjs"); - if(operands[0] === "factorial") - return new node$1.OperatorNode('!', 'factorial',[this.convert(operands[1])]); + function process_additional_assumptions(new_as) { - const f = new node$1.SymbolNode(operands[0]); - const args = operands[1]; - let f_args; + if(!Array.isArray(new_as)) + return undefined; - if (args[0] === 'tuple') - f_args = args.slice(1).map(function(v,i) { return this.convert(v); }.bind(this)); - else - f_args = [this.convert(args)]; + var operator = new_as[0]; + var operands = new_as.slice(1); - return new node$1.FunctionNode(f, f_args); - } + if(operator === 'and' || operator === 'or') { + let results = operands + .map(process_additional_assumptions) + .filter(v => v !== undefined); - if(operator === 'lts' || operator === 'gts') { - const args = operands[0]; - const strict = operands[1]; + if(results.length === 0) + return undefined; + if(operator === 'or') { + if(results.length === operands.length) + return ['or'].concat(results); + else + return undefined; + } + if(results.length === 1) + return results[0]; + else + return ['and'].concat(results); + } - if(args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); + // can ignore NOTs, as simplify_logical should remove + // any before (in)equalities or containments + + if(!(['=', 'ne', '<', 'le'].includes(operator) || + (['in', 'notin', 'subset', 'notsubset'].includes(operator) + && identity))) { + + let new_exclude = exclude_variables.concat(variables(expr)); + let results = []; + for(let v of variables(new_as)) { + if(new_exclude.includes(v)) + continue; + let res = get_assumptions_for_expr(assumptions, v, new_exclude); + if(res !== undefined) + results.push(res); + } + if(results.length === 0) + return new_as; + if(results.length === 1) + return ['and', new_as, results[0]]; + return ['and', new_as].concat(results); + } - const arg_nodes = args.slice(1).map(function(v,i) { return this.convert(v); }.bind(this)); + let results = []; + + for(let ind=0; ind <= 1; ind++) { + let next_var = operands[ind]; + let next_rhs = operands[1-ind]; + + if((typeof next_var === 'string') && variables$$1.includes(next_var)) { + + var bindings = {}; + bindings[next_var] = next_rhs; + var new_expr = simplify$2(substitute(expr, bindings)); + + // may need to flip operator if it is an inequality + // Two factors could induce flipping + // - coefficient from expr is negative + // - switched sides in next inequality (ind === 1) + // The factors could cancel each other out + var flip = false; + var operator_eff = operator; + if((ind === 1 && coeff_mapping[next_var] > 0) || + (ind === 0 && coeff_mapping[next_var] < 0)) { + if(operator === '<') { + flip = true; + operator_eff = '>'; + } + else if(operator === 'le') { + flip = true; + operator_eff = 'ge'; + } + else if(operator === 'in') { + flip = true; + operator_eff = 'ni'; + } + else if(operator === 'subset') { + flip = true; + operator_eff = 'superset'; + } + else if(operator === 'notin') { + flip = true; + operator_eff = 'notni'; + } + else if(operator === 'notsubset') { + flip = true; + operator_eff = 'notsuperset'; + } + } + + if(flip) + results.push([operator, new_expr, expr]); + else + results.push([operator, expr, new_expr]); + + // look for more assumptions + let new_exclude = exclude_variables.concat([next_var]); + let res = get_assumptions_for_expr( + assumptions, new_expr, new_exclude); + // combine with results for expr, if compatible + res = combine_assumptions(expr, operator_eff, new_expr, res); + + if(res !== undefined) + results.push(res); + + } + } - let comparisons = []; - for(let i=1; i< args.length-1; i++) { - if(strict[i]) { - if(operator === 'lts') - comparisons.push(new node$1.OperatorNode('<', 'smaller', arg_nodes.slice(i-1, i+1))); - else - comparisons.push(new node$1.OperatorNode('>', 'larger', arg_nodes.slice(i-1, i+1))); - }else{ - if(operator === 'lts') - comparisons.push(new node$1.OperatorNode('<=', 'smallerEq', arg_nodes.slice(i-1, i+1))); - else - comparisons.push(new node$1.OperatorNode('>=', 'largerEq', arg_nodes.slice(i-1, i+1))); - } + if(results.length === 1) + return results[0]; + else if(results.length > 1) + return ['and'].concat(results); + + // didn't address assumption + let new_exclude = exclude_variables.concat(variables(expr)); + results = []; + for(let v of variables(new_as)) { + if(new_exclude.includes(v)) + continue; + let res = get_assumptions_for_expr(assumptions, v, new_exclude); + if(res !== undefined) + results.push(res); + } + if(results.length === 0) + return new_as; + if(results.length === 1) + return ['and', new_as, results[0]]; + return ['and', new_as].concat(results); } - let result = new node$1.OperatorNode('and', 'and', comparisons.slice(0,2)); - for(let i=2; i', 'ge', 'in', 'notin', 'ni', 'notni', + 'subset', 'notsubset', 'superset', 'notsuperset'].includes(op1)) + return new_as; - if(comparisons.length === 1) - return comparisons[0]; + if(!Array.isArray(new_as)) + return undefined; - let result = new node$1.OperatorNode('and', 'and', comparisons.slice(0,2)); - for(let i=2; i combine_assumptions(expr1, op1, expr2, v)) + .filter(v => v !== undefined); - let x, interval; - if(operator === 'in' || operator === 'notin') { - x = operands[0]; - interval = operands[1]; - }else{ - x = operands[1]; - interval = operands[0]; + if(results.length === 0) + return undefined; + if(op2 === 'or') { + if(results.length === operands2.length) + return [['or'].concat(results)]; + else + return undefined; + } + if(results.length === 1) + return results[0]; + else + return ['and'].concat(results); + } + + if(!['=', 'ne', '<', 'le', 'in', 'notin', 'subset', 'notsubset'] + .includes(op2)) + return new_as; + + var op2_eff = op2; + var rhs; + if(equal$2(operands2[0], expr2)) { + rhs = operands2[1]; + } + else if(equal$2(operands2[1], expr2)) { + rhs = operands2[0]; + if(op2 === '<') + op2_eff = '>'; + else if(op2 === 'le') + op2_eff = 'ge'; + else if(op2 === 'in') + op2_eff = 'ni'; + else if(op2 === 'notin') + op2_eff = 'notni'; + else if(op2 === 'subset') + op2_eff = 'superset'; + else if(op2 === 'notsubset') + op2_eff = 'notsuperset'; + } + else { + return new_as; } - if((typeof x !== 'number') && (typeof x !== 'string')) - throw Error("Set membership non-string variables not implemented for conversion to mathjs"); - x = this.convert(x); - - if(interval[0] !== 'interval') - throw Error("Set membership in non-intervals not implemented for conversion to mathjs"); - - let args = interval[1]; - let closed = interval[2]; - if(args[0] !== 'tuple' || closed[0] !== 'tuple') - throw new Error("Badly formed ast"); - let a = this.convert(args[1]); - let b = this.convert(args[2]); - let comparisons = []; - if(closed[1]) - comparisons.push(new node$1.OperatorNode('>=', 'largerEq', [x,a])); + // determined operator of combined expression + var combined_op; + if(op1 === '=') + combined_op = op2_eff; + else if(op2_eff === '=') + combined_op = op1; + else if(op1 === '<') { + if(op2_eff === '<' || op2_eff === 'le') + combined_op = '<'; + else if(op2_eff === 'in' || op2_eff === 'notin') + return new_as; + else + return undefined; // incompatible operators + } + else if(op1 === 'le') { + if(op2_eff === '<') + combined_op = '<'; + else if(op2_eff === 'le') + combined_op = 'le'; + else if(op2_eff === 'in' || op2_eff === 'notin') + return new_as; + else + return undefined; // incompatible operators + } + else if(op1 === '>') { + if(op2_eff === '>' || op2_eff === 'ge') + combined_op = '>'; + else if(op2_eff === 'in' || op2_eff === 'notin') + return new_as; + else + return undefined; // incompatible operators + } + else if(op1 === 'ge') { + if(op2_eff === '>') + combined_op = '>'; + else if(op2_eff === 'ge') + combined_op = 'ge'; + else if(op2_eff === 'in' || op2_eff === 'notin') + return new_as; + else + return undefined; // incompatible operators + } + else if(op1 === 'in') { + if(op2_eff === 'subset') + combined_op = 'in'; + else + return undefined; // incompatible operators + } + else if(op1 === 'notin') { + if(op2_eff === 'superset') + combined_op = 'notin'; + else + return undefined; // incompatible operators + } + else if(op1 === 'ni') { + if(op2_eff === 'notin') + combined_op = 'notsubset'; + else + return undefined; // incompatible operators + } + else if(op1 === 'notni') { + if(op2_eff === 'in') + combined_op = 'notsuperset'; + else + return undefined; // incompatible operators + } + else if(op1 === 'subset') { + if(op2_eff === 'subset') + combined_op = 'subset'; + else if(op2_eff === 'notni') + combined_op = 'notni'; + else if(op2_eff === 'notsuperset') + combined_op = 'notsuperset'; + else + return undefined; // incompatible operators + } + else if(op1 === 'notsubset') { + if(op2_eff === 'superset') + combined_op = 'notsubset'; + else + return undefined; // incompatible operators + } + else if(op1 === 'superset') { + if(op2_eff === 'superset') + combined_op = 'superset'; + else if(op2_eff === 'ni') + combined_op = 'ni'; + else if(op2_eff === 'notsubset') + combined_op = 'notsubset'; + else + return undefined; // incompatible operators + } + else if(op1 === 'notsuperset') { + if(op2_eff === 'subset') + combined_op = 'notsuperset'; + else + return undefined; // incompatible operators + } else - comparisons.push(new node$1.OperatorNode('>', 'larger', [x,a])); - if(closed[2]) - comparisons.push(new node$1.OperatorNode('<=', 'smallerEq', [x,b])); + return undefined; + + + if(combined_op === '>') + return ['<', rhs, expr1]; + else if(combined_op === 'ge') + return ['le', rhs, expr1]; + else if(combined_op === 'ni') + return ['in', rhs, expr1]; + else if(combined_op === 'notni') + return ['notin', rhs, expr1]; + else if(combined_op === 'superset') + return ['subset', rhs, expr1]; + else if(combined_op === 'notsuperset') + return ['notsubset', rhs, expr1]; else - comparisons.push(new node$1.OperatorNode('<', 'smaller', [x,b])); + return [combined_op, expr1, rhs]; - let result = new node$1.OperatorNode('and', 'and', comparisons); - - if(operator === 'notin' || operator === 'notni') - result = new node$1.OperatorNode('not', 'not', [result]); + } - return result; - } - if(operator === 'subset' || operator === 'notsubset' || - operator === 'superset' || operator === 'notsuperset') { + function filter_assumptions_from_tree(tree, exclude_variables) { + // return an ast if found in tree assumptions without exclude_variables + // otherwise return undefined - let big, small; - if(operator === 'subset' || operator === 'notsubset') { - small = operands[0]; - big = operands[1]; - }else{ - small = operands[1]; - big = operands[0]; + if(!Array.isArray(tree) || tree.length === 0) { + return undefined; } - if(small[0] !== 'interval' || big[0] !== 'interval') - throw Error("Set containment of non-intervals not implemented for conversion to mathjs"); - let small_args = small[1]; - let small_closed = small[2]; - let big_args = big[1]; - let big_closed = big[2]; - if(small_args[0] !== 'tuple' || small_closed[0] !== 'tuple' || - big_args[0] !== 'tuple' || big_closed[0] !== 'tuple') - throw Error("Badly formed ast"); + if(!Array.isArray(exclude_variables)) + exclude_variables = [exclude_variables]; + + var operator = tree[0]; + var operands = tree.slice(1); - let small_a = this.convert(small_args[1]); - let small_b = this.convert(small_args[2]); - let big_a = this.convert(big_args[1]); - let big_b = this.convert(big_args[2]); + if(operator === 'and') { - let comparisons = []; - if(small_closed[1] && !big_closed[1]) - comparisons.push(new node$1.OperatorNode('>', 'larger',[small_a,big_a])); - else - comparisons.push(new node$1.OperatorNode('>=', 'largerEq',[small_a,big_a])); + var a= operands.map(function (v) { + return filter_assumptions_from_tree(v, exclude_variables); + }); - if(small_closed[2] && !big_closed[2]) - comparisons.push(new node$1.OperatorNode('<', 'smaller',[small_b,big_b])); - else - comparisons.push(new node$1.OperatorNode('<=', 'smallerEq',[small_b,big_b])); + a=a.filter(v => v !== undefined); - let result = new node$1.OperatorNode('and', 'and', comparisons); + if(a.length === 0) + return undefined; + else if(a.length === 1) + return a[0]; + else + return ['and'].concat(a); + } - if(operator === 'notsubset' || operator === 'notsuperset') - result = new node$1.OperatorNode('not', 'not', [result]); + // if no intersection between exclude variables and variables in tree + // return tree + var tree_variables = variables(tree); + var contains_excluded = exclude_variables.filter( + (v) => tree_variables.includes(v)).length > 0; - return result; - } + if(!contains_excluded) + return tree; + else + return undefined; + } + + + function get_assumptions_sub(assumptions, variables$$1, exclude_variables, + omit_derived) { + // return an ast if found assumptions involving variables + // otherwise return undefined + + if(!Array.isArray(variables$$1)) + variables$$1 = [variables$$1]; + + var a = []; + + // add assumptions specified by each variable + variables$$1.forEach(function (v) { + // get assumption from byvar and derived, if exist + if(assumptions.byvar[v] || assumptions.derived[v]) { + if(assumptions.byvar[v] && assumptions.byvar[v].length > 0) { + // only get assumptions that don't contain + // exclude variables + var byvar = filter_assumptions_from_tree( + assumptions.byvar[v], exclude_variables); + if(byvar !== undefined) + a.push(byvar); + } + if(assumptions.derived[v] && assumptions.derived[v].length > 0 + && !omit_derived) { + // only get derived assumptions that don't contain + // exclude variables + var da = filter_assumptions_from_tree( + assumptions.derived[v], exclude_variables); + if(da !== undefined) + a.push(da); + } + } + // if byvar and derived are undefined, + // then get assumptions from generic + else if(assumptions['generic'].length > 0) { + // if generic contains any variables other than x + // don't substitute those back into generic + if(v === 'x' || + !variables(assumptions['generic']).includes(v)) + a.push(substitute(assumptions['generic'], {x: v})); + } + }); - if(operator === 'matrix') { - // Convert matrices into nested array nodes - // Will become matrix on eval + if(a.length === 1) + a=a[0]; + else if(a.length > 1) + a=['and'].concat(a); - let size = operands[0]; - let nrows = size[1]; - let ncols = size[2]; + if(a.length > 0) + return clean_assumptions(a); + else + return undefined + + } + + function get_assumptions(assumptions, variables_or_expr, params) { + // return an ast if found assumptions + // otherwise return undefined + // + // variables_or_expr + // - if a string or an array of an array, find assumptions on + // each of the variables represented by those strings + // directly from byvar and derived or from generic + // - if an ast, then + // - calculate assumptions of the expression itself, if possible, or + // - calculate assumptions on the variables of the expression. + + // include any additional assumptions + // involving new variables found in assumptions + + if(params === undefined) + params = {}; + + var exclude_variables = params.exclude_variables; + if(exclude_variables === undefined) + exclude_variables = []; + else if(!Array.isArray(exclude_variables)) + exclude_variables = [exclude_variables]; + + var variables$$1; + var tree = get_tree(variables_or_expr); + + // if string, have a variable + if(typeof tree === "string") + variables$$1 = [tree]; + else if(!Array.isArray(tree)) + return undefined; + else if(Array.isArray(tree[0])) + // if array containing array, is list of variables + variables$$1 = tree[0]; + + + if(variables$$1) + return get_assumptions_sub(assumptions, variables$$1, + exclude_variables, params.omit_derived); + else + return get_assumptions_for_expr(assumptions, tree, exclude_variables) - let entries = operands[1]; + } - if(!Number.isInteger(nrows) || !Number.isInteger(ncols)) - throw Error('Matrix must have integer dimensions'); - let result = []; + function add_assumption(assumptions, expr_or_tree, exclude_generic) { + // add assumption in tree to assumptions + // if !exclude_generic, then add any generic assumptions to + // variables if they don't have previous assumptions + // return 1 if added assumption or 0 otherwise - for(let i=1; i <= nrows; i++) { - let row = []; - for(let j=1; j <= ncols; j++) { - row.push(this.convert(entries[i][j])); - } - result.push(new node$1.ArrayNode(row)); - } + var tree = get_tree(expr_or_tree); - return new node$1.ArrayNode(result); + if(!Array.isArray(tree)) + return 0; - } + tree = clean_assumptions(simplify$2(tree,assumptions)); - if (operator in operators$2) { - return operators$2[operator]( - operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); - } + var added = add_assumption_sub(assumptions, tree, exclude_generic); - throw Error("Operator " + operator + " not implemented for conversion to mathjs"); + if(added) + assumptions.derived = calculate_derived_assumptions(assumptions); + return added; } -} + function add_assumption_sub(assumptions, tree, exclude_generic) { + // add assumption in tree to assumptions + // if !exclude_generic, then add any generic assumptions to + // variables if they don't have previous assumptions + // return number of assumptions added -var function_normalizations = { - ln: 'log', - arccos: 'acos', - arccosh: 'acosh', - arcsin: 'asin', - arcsinh: 'asinh', - arctan: 'atan', - arctanh: 'atanh', - arcsec: 'asec', - arcsech: 'asech', - arccsc: 'acsc', - arccsch: 'acsch', - arccot: 'acot', - arccoth: 'acoth', - cosec: 'csc', -}; + // if tree is an 'and', call once for each operand + // so that assumptions can be separated by variable + if(tree[0] === 'and') { + var results = tree.slice(1).map( + v => add_assumption_sub(assumptions, v, exclude_generic)); + return results.reduce(function (a,b) { return a + b;}); + } -function normalize_function_names(expr_or_tree) { - // replace "ln" with "log" - // "arccos" with "acos", etc. - // e^x with exp(x) - // sqrt(x) with x^0.5 + var variables$$1 = variables(tree); - var tree = get_tree(expr_or_tree); + if(variables$$1.length === 0) + return 0; - if (!Array.isArray(tree)) - return tree; + let n_added = 0; - var operator = tree[0]; - var operands = tree.slice(1); + if(!exclude_generic && assumptions['generic'].length > 0) { + // check to see if any assumptions already for each variable + // if not, start by assigning generic assumptions + variables$$1.forEach(function (v) { + if(assumptions.byvar[v] === undefined) { - if (operator === 'apply') { - if (operands[0] === 'sqrt') { - return ['^', normalize_function_names(operands[1]), 0.5]; - } + // no previous assumptions, so + // include add assumption for v corresponding to generic + // unless non-x v is explicitly in generic + if(v === 'x' || + !variables(assumptions['generic']).includes(v)) { + add_assumption_sub( + assumptions, + substitute(assumptions['generic'], {x: v}), + true); + n_added += 1; + } - var result = normalize_function_names_sub(operands[0]); - result = ['apply', result]; + } + }); - var args = operands.slice(1).map(function (v) { - return normalize_function_names(v); - }); + } - if (args.length > 1) - args = ['tuple'].concat(args); - else - args = args[0]; - result.push(args); + // attempt to solve for each variable + for(let variable of variables$$1) { - return result; - } + // solve using current state of assumptions + let solved = solve_linear(tree, variable, assumptions); - if (operator === '^' && operands[0] === 'e' && math$19.define_e) - return ['apply', 'exp', normalize_function_names(operands[1])]; + let new_a = tree; + if(solved) + new_a = solved; - return [operator].concat(operands.map(function (v) { - return normalize_function_names(v) - })); -} + let current_a = assumptions['byvar'][variable]; -function normalize_function_names_sub(tree) { + if(current_a !== undefined && current_a.length !== 0) + new_a = ['and', current_a, new_a]; - if (typeof tree === 'string') { - if (tree in function_normalizations) - return function_normalizations[tree]; - return tree; - } + new_a = clean_assumptions(new_a); - if (!Array.isArray(tree)) - return tree; + if(!equal$2(new_a, current_a)) { + assumptions['byvar'][variable] = new_a; + n_added +=1; + } + } - var operator = tree[0]; - var operands = tree.slice(1); + return n_added; - var result = [operator].concat(operands.map(function (v) { - return normalize_function_names_sub(v); - })); + } - return result; -} + function add_generic_assumption(assumptions, expr_or_tree) { + // add assumption in expr_or_tree to generic assumptions + // tree must contain the variable x + // the variable x represents any variable for which + // assumptions aren't specifically assigned -function normalize_applied_functions(expr_or_tree) { - // normalize applied functions - // so that primes and powers occur outside function application + // return 1 if added assumption or 0 otherwise - var tree = get_tree(expr_or_tree); + var tree = get_tree(expr_or_tree); - if (!Array.isArray(tree)) - return tree; + if(!Array.isArray(tree)) + return 0; - var operator = tree[0]; - var operands = tree.slice(1); + tree = clean_assumptions(simplify$2(tree,assumptions)); - if (operator === 'apply') { - let result = strip_function_names(operands[0]); - let f_applied = ['apply', result.tree, operands[1]]; - for (let i = 0; i < result.n_primes; i++) - f_applied = ['prime', f_applied]; + var added = add_generic_assumption_sub(assumptions, tree); - if (result.exponent !== undefined) - f_applied = ['^', f_applied, result.exponent]; + if(added) + assumptions.derived = calculate_derived_assumptions(assumptions); - return f_applied + return added; } - var result = [operator].concat(operands.map(function (v, i) { return normalize_applied_functions(v); })); - return result; -} + function add_generic_assumption_sub(assumptions, tree) { + // if tree is an 'and', call once for each operand + // so that assumptions involving one variable can be separated + if(tree[0] === 'and') { + var results = tree.slice(1).map( + v => add_generic_assumption_sub(assumptions, v)); + return results.reduce(function (a,b) { return a + b;}); + } -function strip_function_names(tree) { - // strip primes and powers off tree - - if (!Array.isArray(tree)) - return { tree: tree, n_primes: 0 }; + var variables$$1 = variables(tree); - var operator = tree[0]; - var operands = tree.slice(1); + if(!variables$$1.includes('x')) + return 0; + // attempt to solve for x + // solve using current state of assumptions + let solved = solve_linear(tree, 'x', assumptions); - if (operator === '^') { - let result = strip_function_names(operands[0]); - let exponent = normalize_applied_functions(operands[1]); + let new_a = tree; + if(solved) + new_a = solved; - result.exponent = exponent; - return result; - } + let current_a = assumptions['generic']; - if (operator === "prime") { - let result = strip_function_names(operands[0]); - result.n_primes += 1; - return result; - } + if(current_a.length !== 0) + new_a = ['and', current_a, new_a]; - return { tree: normalize_applied_functions(tree), n_primes: 0 }; -} + new_a = clean_assumptions(new_a); + if(equal$2(new_a, current_a)) { + return 0; + } -function substitute_abs(expr_or_tree) { + assumptions['generic'] = new_a; - var tree = get_tree(expr_or_tree); + return 1; + } - if (!Array.isArray(tree)) - return tree; - var operator = tree[0]; - var operands = tree.slice(1); + function remove_assumption(assumptions, expr_or_tree) { - if (operator === "apply" && operands[0] === 'abs') { - return ['^', ['^', substitute_abs(operands[1]), 2], 0.5]; - } + var tree=get_tree(expr_or_tree); - return [operator].concat(operands.map(function (v) { - return substitute_abs(v); - })); -} + if(!Array.isArray(tree)) + return 0; + tree = clean_assumptions(simplify$2(tree,assumptions)); -function constants_to_floats(expr_or_tree) { + var removed = remove_assumption_sub(assumptions, tree); - var tree = get_tree(expr_or_tree); + if(removed) + assumptions.derived = calculate_derived_assumptions(assumptions); - if(!(math$19.define_e || math$19.define_pi)) { - return tree; - } - if(typeof tree === "string") { - if(tree === "e") { - if(math$19.define_e) { - return math$19.e; - } - } else if(tree === "pi") { - if(math$19.define_pi) { - return math$19.pi; - } - } - return tree; - } + return removed; - if(!Array.isArray(tree)) { - return tree; } - let operator = tree[0]; - let operands = tree.slice(1); - - // don't convert exponential function - if(operator === "^" && operands[0] === "e") { - return ["^", "e", constants_to_floats(operands[1])]; - } - return [operator, ...operands.map(constants_to_floats)] + function remove_assumption_sub(assumptions, tree) { -} -var astToMathjs$1 = new astToMathjs({mathjs: math$19 }); + // if tree is an 'and', call once for each operand + // so that assumptions can be separated by variable + if(tree[0] === 'and') { + var results = tree.slice(1).map(v => remove_assumption_sub( + assumptions, v)); + return results.reduce(function (a,b) { return a+b;}); + } -const f = function(expr_or_tree) { - var tree = get_tree(expr_or_tree); - - var mt = factorial_to_gamma_function( - astToMathjs$1.convert( - normalize_function_names( - normalize_applied_functions( - tree - ) - ) - ) - ); - - return mt.eval.bind(mt); -}; + var variables$$1 = variables(tree); -const evaluate = function(expr, bindings) { - return f(expr)(bindings); -}; + if(variables$$1.length === 0) + return 0; -// export const finite_field_evaluate = function(expr, bindings, modulus) { -// return parser.ast.to.finiteField( expr.tree, modulus )( bindings ); -// }; + var n_removed = 0; -const evaluate_to_constant = function(expr_or_tree) { - // evaluate to number by converting tree to number - // and calling without arguments + // attempt to solve for each variable + for(let variable of variables$$1) { - // return null if couldn't evaluate to constant (e.g., contains a variable) - // otherwise returns constant - // NOTE: constant could be a math.js complex number object + // solve using current state of assumptions + let solved = solve_linear(tree, variable, assumptions); - var tree = get_tree(expr_or_tree); + let current = assumptions['byvar'][variable]; - if(typeof tree === "number") { - return tree; - }else if(typeof tree === "string") { - if(tree === "pi" && math$19.define_pi) { - return Math.PI; - }else if(tree === "e" && math$19.define_e) { - return Math.E; - }else if(tree === "i" && math$19.define_i) { - return { re: 0, im: 1}; - } - return null; - } + // didn't find any assumptions to remove + if(!current || current.length === 0) { + continue; + } - var num=null; - try { - var the_f = f(expr_or_tree); - num = the_f(); - } - catch (e) {} - return num; -}; - -function factorial_to_gamma_function(math_tree) { - // convert factorial to gamma function - // so that can evaluate at complex numbers - var transformed = math_tree.transform(function (node, path, parent) { - if(node.isOperatorNode && node.op === "!" && node.fn === "factorial") { - var args = [new math$19.expression.node.OperatorNode( - '+', 'add', [node.args[0], - new math$19.expression.node.ConstantNode(1)])]; - return new math$19.expression.node.FunctionNode( - new math$19.expression.node.SymbolNode("gamma"),args); - } - else { - return node; - } - }); - return transformed; -} - -var evaluation = /*#__PURE__*/Object.freeze({ - f: f, - evaluate: evaluate, - evaluate_to_constant: evaluate_to_constant -}); - -// functions that map from one set to another -var functions$1 = { - C: {}, - R: {}, - nonzeroC: {}, - nonneg: {}, - pos: {}, -}; - -functions$1.C.nonneg = ["abs"]; -functions$1.C.nonzero = ["exp"]; -functions$1.C.R = ["abs", "arg"]; -functions$1.C.C = ["abs", "arg", "exp", "sign", "cos", "cosh", "sin", "sinh", - "erf", "sqrt", "log", "ln", "log10"]; -functions$1.R.pos = ["exp"]; -functions$1.R.nonneg = ["abs", "exp", "arg"]; -functions$1.R.R = ["abs", "arg", "exp", "sign", "cos", "cosh", "sin", "sinh", - "erf"]; -functions$1.R.Z = ["sign"]; -functions$1.nonzeroC.pos = ["abs"]; -functions$1.nonneg.nonneg = ["abs", "exp", "arg", "sqrt", "erf"]; -functions$1.nonzeroC.nonzero = ["abs"]; -functions$1.nonneg.R = [...new Set(functions$1.R.R.concat( - functions$1.nonneg.nonneg))]; -functions$1.pos.pos = ["abs", "exp", "sqrt", "erf"]; -functions$1.pos.nonneg = functions$1.pos.pos; -functions$1.pos.nonzero = ["abs", "exp", "sqrt", "erf"]; -functions$1.pos.R = functions$1.nonneg.R.concat(["log", "ln", "log10"]); - - -function negate_adjust(result, negate_assumptions) { - if(result) - return !negate_assumptions; - if(result===false) - return negate_assumptions; - return undefined -} + // remove any occurence of tree from current + let operator=current[0]; + let operands=current.slice(1); + + let n_op = operands.length; + + let result; + + if(operator === 'and') { + // remove any match, using trees.equal + operands = operands.filter( + v => !(equal$2(v, tree) || equal$2(v,solved))); + + if(operands.length === 0) { + result = []; + } + else if(operands.length === 1) { + result = operands[0]; + } + else if(operands.length < n_op) { + result = [operator].concat(operands); + } + else { + // didn't find anything to remove + continue + } + } + else { + if(equal$2(current, tree) || equal$2(current, solved)) { + result = []; + } + else { + // didn't find anything to remove + continue; + } + } -function narrow_assumptions(assumptions, original_assumptions) { - // find part of original assumptions after remove assumptions + n_removed += 1; + assumptions['byvar'][variable] = result; - if(!Array.isArray(original_assumptions)) - return []; + } - var operator = original_assumptions[0]; - var operands = original_assumptions.slice(1); - if(operator !== 'and') - return []; + return n_removed; - var remaining_assumptions = []; + } - for(var i=0; i 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_integer_ast(tree, assume_operands[0], - original_assumptions); - let result_right = is_integer_ast(tree, assume_operands[1], - original_assumptions); - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') - return is_integer_ast(operands[0], assume, original_assumptions); - - if(operator === '*') { - - let all_integers = operands.every( - function (v) { - return is_integer_ast(v, assume, original_assumptions); - }); - - if(all_integers) - return true; - else { - return undefined; - - } - } - - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - - if(!base_nonzero) { - // if base is NaN, return false - if(Number.isNaN(operands[0])) - return false; - - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(pow_positive) { - if(base_nonzero === false) - return true; // 0^positive - } - else { - return undefined; // (possibly zero)^(possibly nonpositive) - } - - } - else { // nonzero base - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) { - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) - return false; - - return true; // nonzero^0 - } - - } - - let base_integer = is_integer_ast(operands[0], assume, - original_assumptions); - let pow_integer = is_integer_ast(operands[1], assume, - original_assumptions); - - if(!base_integer) - return base_integer; - - if(!pow_integer) - return undefined; // don't check for cases like 9^(1/2) - - let pow_nonneg= is_positive_ast(operands[1], assume, false, - original_assumptions); - - if(pow_nonneg) - return true; - else - return undefined; - - - } - if(operator === '+') { - - let n_non_integers=0; - - for(let i=0; i < operands.length; i++) { - let result = is_integer_ast(operands[i], assume, - original_assumptions); - - if(result === false) { - if(n_non_integers > 0) - return undefined; - n_non_integers += 1; - } - if(result === undefined) - return undefined; - } - - if(n_non_integers === 0) - return true; - else // only one non-integer - return false; - } - - - // check for functions that map certain sets to integers - if(operator === 'apply') { - if(functions$1.C.Z && functions$1.C.Z.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.Z && functions$1.R.Z.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.Z && functions$1.nonzeroC.Z.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.Z && functions$1.nonneg.Z.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.Z && functions$1.pos.Z.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === '/' || operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } - - return false; -} - - -function is_real_ast(tree, assumptions, original_assumptions) { - // see description of is_real - - if(typeof assumptions !== 'object') - assumptions = []; - - if(original_assumptions===undefined) - original_assumptions = assumptions; - - if(typeof tree === 'number') - return Number.isFinite(tree); - - // if can convert to constant, evaluate directly - var c = evaluate_to_constant(tree); - - if(c !== null) { - if(typeof c === 'number') { - return Number.isFinite(c); - } - return false; - } - - if(typeof tree === 'string') { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions(tree); - - if(!Array.isArray(assume)) - return undefined; - - let assume_with_negations = assume; - - let assume_operator = assume[0]; - let assume_operands = assume.slice(1); - - let negate_assumptions = false; - while(assume_operator === 'not') { - negate_assumptions = !negate_assumptions; - assume = assume_operands[0]; - if(!Array.isArray(assume)) - return undefined; - assume_operator = assume[0]; - assume_operands = assume.slice(1); - } - - if(assume_operator === 'in') - if(assume_operands[0]===tree && assume_operands[1] === 'R') - return negate_adjust(true, negate_assumptions); - if(assume_operator === 'notin') - if(assume_operands[0]===tree && assume_operands[1] === 'R') - return negate_adjust(false, negate_assumptions); - // haven't negated, then determining tree is integer means it is real - if(negate_assumptions===false) { - if(assume_operator === 'in') - if(assume_operands[0]===tree && assume_operands[1] === 'Z') - return true; - } - // if have negated, then determining tree is not integer, - // means it is an integer, hence real - else { - if(assume_operator === 'notin') - if(assume_operands[0]===tree && assume_operands[1] === 'Z') - return true; - } - - // if assumptions is an inequality involving variable - // then return true - if(assume_operator === '<' || assume_operator === 'le') { - - let variables_in_inequality = variables(assume); - let functions_in_inequality = functions(assume); - - if(variables_in_inequality.indexOf(tree) !== -1 - && functions_in_inequality.length === 0) - return true; // don't negate adjust - } - - // assume equality has been expanded so that has two arguments - if((assume_operator === '=' && !negate_assumptions) || - (assume_operator === 'ne' && negate_assumptions)) { - // if assumption is "tree=something" - // check if something is real - // (but without the assumption to avoid infinite loop) - - let new_assumptions = narrow_assumptions(assume_with_negations, - original_assumptions); - if(assume_operands[0]===tree) - return is_real_ast(assume_operands[1], new_assumptions); - if(assume_operands[1]===tree) - return is_real_ast(assume_operands[0], new_assumptions); - } - - - // if isn't a simple And or Or, just give up - if(assume_operator !== 'and' && assume_operator !== 'or') - return undefined; - - // shouldn't have negated assumptions - if(negate_assumptions) - return undefined; - - // if more than two operands, unflatten - // (OK, since not attempting logic where only combined restrictions - // lead to a passing test) - if(assume_operands.length > 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_real_ast(tree, assume_operands[0], - original_assumptions); - let result_right = is_real_ast(tree, assume_operands[1], - original_assumptions); - - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') { - return is_real_ast(operands[0], assume, original_assumptions); - } - if(operator === '*' || operator === '+') { - - // if more than two terms, unflatten - if(operands.length > 2) { - tree = unflattenRight(tree); - operands = tree.slice(1); - } - - if(operator==='*') { - // one confirmed zero factor makes product zero - if((is_nonzero_ast(operands[0], assume, original_assumptions) - === false) || - (is_nonzero_ast(operands[1], assume, original_assumptions) - === false)) - return true; - } - - let left_real = is_real_ast(operands[0], assume, - original_assumptions); - let right_real = is_real_ast(operands[1], assume, - original_assumptions); - - if(left_real && right_real) - return true; - - // can confirm that is not real - // if one term/factor is real and the other is not real - if((left_real && right_real===false) || - (right_real && left_real===false)) - return false - - return undefined; - - } - - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(!base_nonzero) { - // if base is NaN, return false - if(Number.isNaN(operands[0])) - return false; - - if(pow_positive) { - if(base_nonzero === false) - return true; // 0^positive - } - else { - return undefined; // (possibly zero)^(possibly nonpositive) - } - - } - else { // nonzero base - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) { - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) - return false; - - return true; // nonzero^0 - } - - } - - let base_real = is_real_ast(operands[0], assume, - original_assumptions); - let pow_real = is_real_ast(operands[1], assume, - original_assumptions); - - if(!(base_real && pow_real)) - return undefined; - - let base_nonnegative = is_positive_ast(operands[0], assume, false, - original_assumptions); - - if(!base_nonnegative) { - // if base might be negative - // then power must be an integer - // (already excluded 0^0) - - let pow_integer = is_integer_ast(operands[1], assume, - original_assumptions); - if(pow_integer) - return true; - else - return undefined - } - - let base_positive = is_positive_ast(operands[0], assume, true, - original_assumptions); - - if(!base_positive) { - // if base might be zero - // then power must be positive - if(pow_positive) - return true; - else - return undefined; - } - - // base is positive, power is real - return true; - - } - - if(operator === '/') { - // if can't be sure denominator is nonzero - if(!is_nonzero_ast(operands[1], assume, original_assumptions)) - return undefined; - - // zero numerator - if(is_nonzero_ast(operands[0], assume, original_assumptions) === false) - return true; - - if(!(is_real_ast(operands[0], assume, original_assumptions) - && is_real_ast(operands[1], assume, original_assumptions))) - return undefined; - - return true; - - } - - // check for functions that map certain sets to reals - if(operator === 'apply') { - if(functions$1.C.R && functions$1.C.R.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.R && functions$1.R.R.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.R && functions$1.nonzeroC.R.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.R && functions$1.nonneg.R.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.R && functions$1.pos.R.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } + if(!Array.isArray(tree)) + return 0; - return false; -} - - -function is_complex_ast(tree, assumptions, original_assumptions) { - // see description of is_complex - - if(typeof assumptions !== 'object') - assumptions = []; - - if(original_assumptions===undefined) - original_assumptions = assumptions; - - if(typeof tree === 'number') - return Number.isFinite(tree); - - // if can convert to constant, evaluate directly - var c = evaluate_to_constant(tree); - if(c !== null) { - if(typeof c === 'number') { - return Number.isFinite(c); - } - if(c.re !== undefined && Number.isFinite(c.re) - && c.im !== undefined && Number.isFinite(c.im) ) - return true; - - return false; - } - - if(typeof tree === 'string') { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions(tree); - - if(!Array.isArray(assume)) - return undefined; - - let assume_with_negations = assume; - - let assume_operator = assume[0]; - let assume_operands = assume.slice(1); - - let negate_assumptions = false; - while(assume_operator === 'not') { - negate_assumptions = !negate_assumptions; - assume = assume_operands[0]; - if(!Array.isArray(assume)) - return undefined; - assume_operator = assume[0]; - assume_operands = assume.slice(1); - } - - if(assume_operator === 'in') - if(assume_operands[0]===tree && assume_operands[1] === 'C') - return negate_adjust(true, negate_assumptions); - if(assume_operator === 'notin') - if(assume_operands[0]===tree && assume_operands[1] === 'C') - return negate_adjust(false, negate_assumptions); - // haven't negated, then determining tree is integer or real - // means it is complex - if(negate_assumptions===false) { - if(assume_operator === 'in') { - if(assume_operands[0]===tree && assume_operands[1] === 'Z') - return true; - if(assume_operands[0]===tree && assume_operands[1] === 'R') - return true; - } - } - // if have negated, then determining tree is not integer or not real, - // means it is an integer/real, hence complex - else { - if(assume_operator === 'notin') { - if(assume_operands[0]===tree && assume_operands[1] === 'Z') - return true; - if(assume_operands[0]===tree && assume_operands[1] === 'R') - return true; - } - } - - // if assumptions is an inequality involving variable - // then must be real, hence complex, so return true - if(assume_operator === '<' || assume_operator === 'le') { - - let variables_in_inequality = variables(assume); - let functions_in_inequality = functions(assume); - - if(variables_in_inequality.indexOf(tree) !== -1 - && functions_in_inequality.length === 0) - return true; // don't negate adjust - } - - // assume equality has been expanded so that has two arguments - if((assume_operator === '=' && !negate_assumptions) || - (assume_operator === 'ne' && negate_assumptions)) { - // if assumption is "tree=something" - // check if something is complex - // (but without the assumption to avoid infinite loop) - - let new_assumptions = narrow_assumptions(assume_with_negations, - original_assumptions); - if(assume_operands[0]===tree) - return is_complex_ast(assume_operands[1], new_assumptions); - if(assume_operands[1]===tree) - return is_complex_ast(assume_operands[0], new_assumptions); - } - - // if isn't a simple And or Or, just give up - if(assume_operator !== 'and' && assume_operator !== 'or') - return undefined; - - // shouldn't have negated assumptions - if(negate_assumptions) - return undefined; - - // if more than two operands, unflatten - // (OK, since not attempting logic where only combined restrictions - // lead to a passing test) - if(assume_operands.length > 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_complex_ast(tree, assume_operands[0], - original_assumptions); - let result_right = is_complex_ast(tree, assume_operands[1], - original_assumptions); - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') - return is_complex_ast(operands[0], assume, original_assumptions); - - if(operator === '*' || operator === '+') { - - if(operator==='*') { - // one confirmed zero factor makes product zero - if(!operands.every(v => is_nonzero_ast(v, assume, original_assumptions) !== false)) - return true; - } - - let all_complex = operands.every(v => is_complex_ast(v, assume, original_assumptions)); - - if(all_complex) - return true; - else { - return undefined; - - } - } - - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(!base_nonzero) { - - // if base is NaN, return false - if(Number.isNaN(operands[0])) - return false; - - if(pow_positive) { - if(base_nonzero === false) - return true; // 0^positive - } - else { - return undefined; // (possibly zero)^(possibly nonpositive) - } - - } - else { // nonzero base - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) { - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) - return false; - - return true; // nonzero^0 - } - - } - - let base_complex = is_complex_ast(operands[0], assume, - original_assumptions); - let pow_complex = is_complex_ast(operands[1], assume, - original_assumptions); - - if(base_complex && pow_complex) - return true; - else - return undefined; - - } - - if(operator === '/') { - // if can't be sure denominator is nonzero - if(!is_nonzero_ast(operands[1], assume, original_assumptions)) - return undefined; - - // zero numerator - if(is_nonzero_ast(operands[0], assume, original_assumptions) === false) - return true; - - if(!(is_complex_ast(operands[0], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions))) - return undefined; - - return true; - - } + tree = clean_assumptions(simplify$2(tree,assumptions)); - // check for functions that map certain sets to complex numbers - if(operator === 'apply') { - if(functions$1.C.C && functions$1.C.C.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.C && functions$1.R.C.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.C && functions$1.nonzeroC.C.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.C && functions$1.nonneg.C.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.C && functions$1.pos.C.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } + var removed = remove_generic_assumption_sub(assumptions, tree); - return false; -} - - -function is_nonzero_ast(tree, assumptions, original_assumptions) { - // see description of is_nonzero - - if(typeof assumptions !== 'object') - assumptions = []; - - if(original_assumptions===undefined) - original_assumptions = assumptions; - - if(typeof tree === 'number') { - if(Number.isFinite(tree)) - return tree !== 0; - if(Number.isNaN(tree)) - return undefined; - return true; // consider infinity to be nonzero - } - - // if can convert to constant, evaluate directly - var c = evaluate_to_constant(tree); - if(c !== null) { - if(typeof c === 'number') { - if(Number.isFinite(c)) - return c !== 0; - if(Number.isNaN(c)) - return undefined; - return true; // consider infinity to be nonzero - } - if(c.re !== undefined && c.im !== undefined && - (c.re !== 0 || c.im !== 0) ) - return true; - return undefined; - } - - if(typeof tree === 'string') { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions(tree); - - if(!Array.isArray(assume)) - return undefined; - - let assume_with_negations = assume; - - let assume_operator = assume[0]; - let assume_operands = assume.slice(1); - - let negate_assumptions = false; - while(assume_operator === 'not') { - negate_assumptions = !negate_assumptions; - assume = assume_operands[0]; - if(!Array.isArray(assume)) - return undefined; - assume_operator = assume[0]; - assume_operands = assume.slice(1); - } - - let new_assumptions = narrow_assumptions(assume_with_negations, - original_assumptions); - - // assume equality has been expanded so that has two arguments - if((assume_operator === '=' && !negate_assumptions) || - (assume_operator === 'ne' && negate_assumptions)) { - // if assumption is "tree=something" - // check if something is nonzero - // (but without the assumption to avoid infinite loop) - - if(assume_operands[0]===tree) - return is_nonzero_ast(assume_operands[1], new_assumptions); - if(assume_operands[1]===tree) - return is_nonzero_ast(assume_operands[0], new_assumptions); - } - - if((assume_operator === 'ne' && !negate_assumptions) || - (assume_operator === '=' && negate_assumptions)) { - // if assumption is "tree!=something" - // check if something is zero - - if(assume_operands[0]===tree) { - if(is_nonzero_ast(assume_operands[1], new_assumptions)===false) - return true - } - if(assume_operands[1]===tree) { - if(is_nonzero_ast(assume_operands[0], new_assumptions)===false) - return true; - } - } - - // assume assumptions are ordered so greater than doesn't appear - if(assume_operator === '<') { - if(!negate_assumptions) { - if(assume_operands[0]===tree) { - if(is_negative_ast( - assume_operands[1], new_assumptions, false)) - return true; - } - if(assume_operands[1]===tree) { - if(is_positive_ast( - assume_operands[0], new_assumptions, false)) - return true; - } - } - else { - // negated, becomes ge - if(assume_operands[0]===tree) { - if(is_positive_ast( - assume_operands[1], new_assumptions, true)) - return true; - } - if(assume_operands[1]===tree) { - if(is_negative_ast( - assume_operands[0], new_assumptions, true)) - return true; - } - - } - } - if(assume_operator === 'le') { - if(!negate_assumptions) { - if(assume_operands[0]===tree) { - if(is_negative_ast( - assume_operands[1], new_assumptions, true)) - return true; - } - if(assume_operands[1]===tree) { - if(is_positive_ast( - assume_operands[0], new_assumptions, true)) - return true; - } - } - else { - // negated, so becomes > - if(assume_operands[0]===tree) { - if(is_positive_ast( - assume_operands[1], new_assumptions, false)) - return true; - } - if(assume_operands[1]===tree) { - if(is_negative_ast( - assume_operands[0], new_assumptions, false)) - return true; - } - - } - } - - // if isn't a simple And or Or, just give up - if(assume_operator !== 'and' && assume_operator !== 'or') - return undefined; - - // shouldn't have negated assumptions - if(negate_assumptions) - return undefined; - - // if more than two operands, unflatten - // (OK, since not attempting logic where only combined restrictions - // lead to a passing test) - if(assume_operands.length > 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_nonzero_ast(tree, assume_operands[0], - original_assumptions); - let result_right = is_nonzero_ast(tree, assume_operands[1], - original_assumptions); - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') - return is_nonzero_ast(operands[0], assume, original_assumptions); - - if(operator === '+') { - - // if more than two terms, unflatten - if(operands.length > 2) { - tree = unflattenRight(tree); - operands = tree.slice(1); - } - - // if operands are opposite - // (trees.equal removes duplicate negatives through default_order) - // TODO: check if operands aren't infinite - if(equal$2(operands[0], - simplify$2(['-', operands[1]], - original_assumptions))) - return false; - - // can definitely determine nonzero if one term is zero - // or if both have the same sign - - let nonzero_left = is_nonzero_ast(operands[0], assume, - original_assumptions); - let nonzero_right = is_nonzero_ast(operands[1], assume, - original_assumptions); - - // if one is known to be zero, return result from other - if(nonzero_left===false) - return nonzero_right; - if(nonzero_right===false) - return nonzero_left; - - - // if one of both aren't real - // decide now - let real_left = is_real_ast(operands[0], assume, - original_assumptions); - let real_right = is_real_ast(operands[1], assume, - original_assumptions); - - if(!real_left || !real_right) { - if(real_left===true) { - if(real_right === false) - return true; - return undefined; - } - if(real_right===true) { - if(real_left===false) - return true; - return undefined; - } - return undefined; - } - - // if reach here, both are real - - let nonneg_left = is_positive_ast(operands[0], assume, false, - original_assumptions); - let nonneg_right = is_positive_ast(operands[1], assume, false, - original_assumptions); - - let positive_left = is_positive_ast(operands[0], assume, true, - original_assumptions); - let positive_right = is_positive_ast(operands[1], assume, true, - original_assumptions); - - // positive + nonnegative is nonzero - if( (nonneg_left && positive_right) - || (positive_left && nonneg_right)) - return true; - - // negative + nonpositive is nonzero - if( (nonneg_left===false && positive_right===false) - || (positive_left===false && nonneg_right===false)) - return true; - - - // have terms of both signs (or undefined sign) - // so can't determine if nonzero by this approach - return undefined; - } - - if(operator === '*') { - let all_nonzero = true; - for(let i=0; i < operands.length; i++) { - - let result = is_nonzero_ast(operands[i], assume, - original_assumptions); - - if(result===false) - return false; // found a zero factor - if(result===undefined) - all_nonzero=false; - } - - if(all_nonzero) - return true; - else - return undefined; - } - - if(operator === '/') { - - let result = is_nonzero_ast(operands[0], assume, - original_assumptions); - - if(is_nonzero_ast(operands[1], assume, original_assumptions)) - return result; - else - return undefined; - } - - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - - if(!base_nonzero) { - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(pow_positive && (base_nonzero === false)) - return false; // 0^positive - - return undefined; - } - else { // nonzero base - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) { - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) - return undefined; - } - - return true; - - // TODO? positive^(-infinity) =? 0 - } - - } - - // check for functions that map certain sets to nonzeros - if(operator === 'apply') { - if(functions$1.C.nonzero && functions$1.C.nonzero.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.nonzero && functions$1.R.nonzero.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.nonzero && functions$1.nonzeroC.nonzero.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.nonzero && functions$1.nonneg.nonzero.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.nonzero && functions$1.pos.nonzero.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } + if(removed) + assumptions.derived = calculate_derived_assumptions(assumptions); - return false; -} - - -function is_positive_ast(tree, assumptions, strict, original_assumptions) { - // see description of is_nonnegative - - if(typeof assumptions !== 'object') - assumptions = []; - - if(original_assumptions===undefined) - original_assumptions = assumptions; - - if(strict === undefined) - strict = true; - - if(typeof tree === 'number') { - if(Number.isFinite(tree)) - return (strict ? tree > 0 : tree >= 0); - return false; - } - - var is_real = is_real_ast(tree, assumptions, original_assumptions); - if(!is_real) - return is_real; - - // if can convert to constant, evaluate directly - var c = evaluate_to_constant(tree); - - if(c !== null) { - if(typeof c === 'number') { - if(Number.isFinite(c)) - return (strict ? c > 0 : c >= 0); - return false; - } - return false; - } - - if(typeof tree === 'string') { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions(tree); - - if(!Array.isArray(assume)) - return undefined; - - let assume_with_negations = assume; - - let assume_operator = assume[0]; - let assume_operands = assume.slice(1); - - let negate_assumptions = false; - while(assume_operator === 'not') { - negate_assumptions = !negate_assumptions; - assume = assume_operands[0]; - if(!Array.isArray(assume)) - return undefined; - assume_operator = assume[0]; - assume_operands = assume.slice(1); - } - - let new_assumptions = narrow_assumptions(assume_with_negations, - original_assumptions); - - // assume that equality has been expanded so that - // have only two operands - if((assume_operator === '=' && !negate_assumptions) || - (assume_operator === 'ne' && negate_assumptions)) { - // if assumption is "tree=something" - // check if something is positive - // (but without the assumption to avoid infinite loop) - - if(assume_operands[0]===tree) - return is_positive_ast(assume_operands[1], new_assumptions, - strict); - if(assume_operands[1]===tree) - return is_positive_ast(assume_operands[0], new_assumptions, - strict); - } - - // assume assumptions are ordered so greater than doesn't appear - if(assume_operator === '<') { - if(!negate_assumptions) { - if(assume_operands[0]===tree) { - if(is_negative_ast(assume_operands[1], new_assumptions, - false)) - return false; - } - if(assume_operands[1]===tree) { - if(is_positive_ast(assume_operands[0], new_assumptions, - false)) - return true; - } - } - else { - // negated, so becomes ge - if(assume_operands[0]===tree) { - if(is_positive_ast(assume_operands[1], new_assumptions, - strict)) - return true; - } - if(assume_operands[1]===tree) { - if(is_negative_ast(assume_operands[0], new_assumptions, - !strict)) - return false; - } - - } - } - if(assume_operator === 'le') { - if(!negate_assumptions) { - if(assume_operands[0]===tree) { - if(is_negative_ast(assume_operands[1], new_assumptions, - !strict)) - return false; - } - if(assume_operands[1]===tree) { - if(is_positive_ast(assume_operands[0], new_assumptions, - strict)) - return true; - } - } - else { - // negated, so becomes > - if(assume_operands[0]===tree) { - if(is_positive_ast(assume_operands[1], new_assumptions, - false)) - return true; - } - if(assume_operands[1]===tree) { - if(is_negative_ast(assume_operands[0], new_assumptions, - false)) - return false; - } - - } - } - - - // if isn't a simple And or Or, just give up - if(assume_operator !== 'and' && assume_operator !== 'or') - return undefined; - - // shouldn't have negated assumptions - if(negate_assumptions) - return undefined; - - // if more than two operands, unflatten - // (OK, since not attempting logic where only combined restrictions - // lead to a passing test) - if(assume_operands.length > 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_positive_ast(tree, assume_operands[0], strict, - original_assumptions); - let result_right = is_positive_ast(tree, assume_operands[1], strict, - original_assumptions); - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') - return is_negative_ast(operands[0], assume, strict, - original_assumptions); - - if(operator === '+') { - - // if more than two terms, unflatten - if(operands.length > 2) { - tree = unflattenRight(tree); - operands = tree.slice(1); - } - - - let nonneg_left = is_positive_ast(operands[0], assume, false, - original_assumptions); - let nonneg_right = is_positive_ast(operands[1], assume, false, - original_assumptions); - - let positive_left = is_positive_ast(operands[0], assume, true, - original_assumptions); - let positive_right = is_positive_ast(operands[1], assume, true, - original_assumptions); - - - if(strict) { - // positive + nonnegative is positive - if( (nonneg_left && positive_right) - || (positive_left && nonneg_right)) - return true; - } - else { - // nonnegative + nonnegative is nonnegative - if(nonneg_left && nonneg_right) - return true; - } - - if(strict) { - // nonpositive + nonpositive is nonpositive - if(positive_left===false && positive_right===false) - return false; - } - else { - // negative + nonpositive is negative - if( (nonneg_left===false && positive_right===false) - || (positive_left===false && nonneg_right===false)) - return false; - } - - // have terms of both signs (or undefined sign) - // so can't determine if positive or negative by this approach - return undefined; - } - - if(operator === '*') { - // one confirmed zero factor makes product zero - if(!operands.every(v => is_nonzero_ast(v, assume, original_assumptions) !== false)) - return !strict; - - // if more than two terms, unflatten - if(operands.length > 2) { - tree = unflattenRight(tree); - operands = tree.slice(1); - } - - let real_left = is_real_ast(operands[0], assume, - original_assumptions); - let real_right = is_real_ast(operands[1], assume, - original_assumptions); - - // if can't determine if real, can't determine positivity - if(real_left===undefined || real_right===undefined) - return undefined; - - // if one nonreal, return false - // if two nonreals, return undefined - if(real_left===false) { - if(real_right===false) - return undefined; - else - return false; - } - else if(real_right===false) - return false; - - // if reach here, both factors are real - - let nonneg_left = is_positive_ast(operands[0], assume, false, - original_assumptions); - let nonneg_right = is_positive_ast(operands[1], assume, false, - original_assumptions); - - let positive_left = is_positive_ast(operands[0], assume, true, - original_assumptions); - let positive_right = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(strict) { - // product of two positives or two negatives is positive - if((positive_left && positive_right) - || (nonneg_left === false && nonneg_right === false)) - return true; - - // product of nonnegative and nonpositive is nonpositive - if((positive_left === false && nonneg_right) - || (nonneg_left && positive_right === false)) - return false; - } - else { - // product of two nonnegatives or two nonpositives - // is nonnegative - if((nonneg_left && nonneg_right) - || (positive_left === false && positive_right === false)) - return true; - - // product of positive and negative is negative - if((positive_left && nonneg_right === false) - || (nonneg_left === false && positive_right)) - return false; - } - - // couldn't figure out sign via above algorithm - return undefined; - - } - - if(operator === '/') { - - // if can't be sure denominator is nonzero - if(!is_nonzero_ast(operands[1], assume, original_assumptions)) - return undefined; - - // zero numerator - if(is_nonzero_ast(operands[0], assume, - original_assumptions) === false) - return !strict; - - let denom_pos = is_positive_ast(operands[1], assume, true, - original_assumptions); - if(denom_pos === undefined) - return undefined; - - // if denominator is negative, sign is swapped - // so need opposite strictness for numerator - let numer_strict = denom_pos ? strict : !strict; - let numer_pos = is_positive_ast(operands[0], assume, - numer_strict, - original_assumptions); - - if(numer_pos === undefined) - return undefined; - - if(numer_pos === true) { - if(denom_pos === true) - return true; - else - return false; - } - else { - if(denom_pos === true) - return false; - else - return true; - } - } - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - - if(!base_nonzero) { - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(pow_positive) { - if(base_nonzero === false) - return !strict; // 0^positive - if(strict) - return undefined // (possibly 0)^positive - } - else { - return undefined; // (possibly zero)^(possibly nonpositive) - } - - } - else { // nonzero base - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) { - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) - return undefined; - - return true; // nonzero^0 - } - - } - - let base_real = is_real_ast(operands[0], assume, - original_assumptions); - - if(base_real !== true) { - return undefined; - } - - let base_positive = is_positive_ast(operands[0], assume, strict, - original_assumptions); - - if(!base_positive) { - // if base could be negative - // (already excluded zero base if strict) - // then only way to be - // positive (non_negative if not strict) - // is if pow is an even integer - - // since haven't implemented is_even, only check - // if have a constant that is an even integer - let pow_over_two = simplify$2(['/', operands[1], 2], - original_assumptions); - if(is_integer_ast(pow_over_two, assume, original_assumptions)) - return true; - - return undefined; - } - - // base must be nonnegative - let pow_real = is_real_ast(operands[1], assume, - original_assumptions); - - if(pow_real) - return true; // since already excluded 0^0 - else - return undefined; - - } - - // check for functions that map certain sets to nonnegatives - if(operator === 'apply' && !strict) { - if(functions$1.C.nonneg && functions$1.C.nonneg.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.nonneg && functions$1.R.nonneg.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.nonneg && functions$1.nonzeroC.nonneg.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.nonneg && functions$1.nonneg.nonneg.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.nonneg && functions$1.pos.nonneg.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - // check for functions that map certain sets to integers - if(operator === 'apply' && strict) { - if(functions$1.C.pos && functions$1.C.pos.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.pos && functions$1.R.pos.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.pos && functions$1.nonzeroC.pos.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.pos && functions$1.nonneg.pos.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.pos && functions$1.pos.pos.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } + return removed; + } - return false; -} -function is_negative_ast(tree, assumptions, strict, original_assumptions) { - if(strict === undefined) - strict = true; + function remove_generic_assumption_sub(assumptions, tree) { - var real = is_real_ast(tree, assumptions, original_assumptions); + // if tree is an 'and', call once for each operand + // so that assumptions involving one variable can be separated + if(tree[0] === 'and') { + var results = tree.slice(1).map(v => remove_generic_assumption_sub( + assumptions, v)); + return results.reduce(function (a,b) { return a+b;}); + } - if(real === true) { - let nonneg = is_positive_ast(tree, assumptions, !strict, - original_assumptions); - if(nonneg === false) - return true; - if(nonneg === true) - return false; - return undefined; - } + var variables$$1 = variables(tree); - return real; -} + if(!variables$$1.includes('x')) + return 0; -function clean(expr_or_tree) { - var tree = get_tree(expr_or_tree); - return flatten(tree); -} + var current = assumptions['generic']; -function evalf(x, n) { - return parseFloat(number_8(x, n)); -} + if(current.length === 0) + return 0; -function collapse_unary_minus(expr_or_tree) { - var tree = get_tree(expr_or_tree); + // solve using current state of assumptions + let solved = solve_linear(tree, 'x', assumptions); - if (!Array.isArray(tree)) - return tree; + // remove any occurence of tree from current + var operator=current[0]; + var operands=current.slice(1); - var operator = tree[0]; - var operands = tree.slice(1); - operands = operands.map(v => collapse_unary_minus(v)); - - if (operator === "-") { - if (typeof operands[0] === 'number') - return -operands[0]; - // check if operand is a multiplication with that begins with - // a constant. If so combine with constant - if (Array.isArray(operands[0]) && operands[0][0] === '*' - && (typeof operands[0][1] === 'number')) { - return ['*', -operands[0][1]].concat(operands[0].slice(2)); - } - // check if operand is a division with that begins with - // either - /// (A) a constant or - // (B) a multiplication that begins with a constant. - // If so. combine with constant - if (Array.isArray(operands[0]) && operands[0][0] === '/') { - if (typeof operands[0][1] === 'number') - return ['/', -operands[0][1], operands[0][2]]; - if (Array.isArray(operands[0][1]) && operands[0][1][0] === '*' - && (typeof operands[0][1][1] === 'number')) { - return ['/', [ - '*', -operands[0][1][1]].concat(operands[0][1].slice(2)), - operands[0][2]]; - } - } - } - - return [operator].concat(operands); -} - -function simplify$2(expr_or_tree, assumptions, max_digits) { - var tree = get_tree(expr_or_tree); - - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); - - tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits, evaluate_functions: true }); - // if already have it down to a number of variable, no need for more simplification - if (!Array.isArray(tree)) { - return tree; - } - tree = simplify_logical(tree, assumptions); - tree = collect_like_terms_factors(tree, assumptions, max_digits); + var n_op = operands.length; - return tree; -} + var result; -function simplify_logical(expr_or_tree, assumptions) { - var tree = get_tree(expr_or_tree); + if(operator === 'and') { + // remove any match, using trees.equal + operands = operands.filter( + v => !(equal$2(v, tree) || equal$2(v,solved))); - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); + if(operands.length === 0) { + result = []; + } + else if(operands.length === 1) { + result = operands[0]; + } + else if(operands.length < n_op) { + result = [operator].concat(operands); + } + else { + // didn't find anything to remove + return 0; + } + } + else { + if(equal$2(current, tree) || equal$2(current, solved)) { + result = []; + } + else { + // didn't find anything to remove + return 0; + } + } - tree = evaluate_numbers(tree, { assumptions: assumptions }); + assumptions['generic'] = result; - tree = unflattenRight(tree); + return 1; + } - var transformations = []; - transformations.push([ [ 'not', [ 'not', 'a' ] ], "a"]); - transformations.push([ [ 'not', [ 'and', 'a', 'b' ] ], [ 'or', [ 'not', 'a' ], [ 'not', 'b' ] ] ]); - transformations.push([ [ 'not', [ 'or', 'a', 'b' ] ], [ 'and', [ 'not', 'a' ], [ 'not', 'b' ] ] ]); - transformations.push([ [ 'not', [ '=', 'a', 'b' ] ], [ 'ne', 'a', 'b' ] ]); - transformations.push([ [ 'not', [ 'ne', 'a', 'b' ] ], [ '=', 'a', 'b' ] ]); - transformations.push([ [ 'not', [ '<', 'a', 'b' ] ], [ 'le', 'b', 'a' ] ]); - transformations.push([ [ 'not', [ 'le', 'a', 'b' ] ], [ 'not', [ 'le', 'a', 'b' ] ] ]); - transformations.push([ [ 'not', [ 'in', 'a', 'b' ] ], [ 'notin', 'a', 'b' ] ]); - transformations.push([ [ 'not', [ 'subset', 'a', 'b' ] ], [ 'notsubset', 'a', 'b' ] ]); - tree = applyAllTransformations(tree, transformations, 20); + function initialize_assumptions() { + var assumptions = {}; + assumptions['byvar'] = {}; + assumptions['derived'] = {}; + assumptions['generic'] = []; + assumptions['not_commutative'] = []; + assumptions['get_assumptions'] = function(v, params) { + return get_assumptions(assumptions, v, params); + }; + assumptions['add_assumption'] = function(v, exclude_generic) { + return add_assumption(assumptions, v, exclude_generic); + }; + assumptions['add_generic_assumption'] = function(v) { + return add_generic_assumption(assumptions, v); + }; + assumptions['remove_assumption'] = function(v) { + return remove_assumption(assumptions, v); + }; + assumptions['remove_generic_assumption'] = function(v) { + return remove_generic_assumption(assumptions, v); + }; - tree = flatten(tree); + return assumptions; + } - return tree; -} + /* + * convert syntax trees back to LaTeX code + * + * Copyright 2014-2017 by + * Jim Fowler + * Duane Nykamp + * + * This file is part of a math-expressions library + * + * math-expressions is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or at your option any later version. + * + * math-expressions is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ -function contains_decimal_number(tree) { - if (typeof tree === "string") { - return false; - } - if (typeof tree === "number") { - if (Number.isFinite(tree) && !Number.isInteger(tree)) { - return true; - } else { - return false; - } - } - if (!Array.isArray(tree)) { - return false; - } - return tree.slice(1).some(x => contains_decimal_number(x)); -} -function contains_only_numbers(tree, { include_number_symbols = false } = {}) { - if (typeof tree === "string") { - if (include_number_symbols) { - if (tree === "e" && math$19.define_e) { - return true; - } - if (tree === "pi" && math$19.define_pi) { - return true; - } - } - return false; - } - if (typeof tree === "number") { - return true; - } - if (!Array.isArray(tree)) { - return false; - } - return tree.slice(1).every(x => contains_only_numbers(x, { include_number_symbols: include_number_symbols })); -} + const operators$3 = { + "+": function(operands) { + return operands.join(' '); + }, + "-": function(operands) { + return "- " + operands[0]; + }, + "*": function(operands) { + return operands.join(" "); + }, + "/": function(operands) { + return "\\frac{" + operands[0] + "}{" + operands[1] + "}"; + }, + "_": function(operands) { + return operands[0] + "_{" + operands[1] + "}"; + }, + "^": function(operands) { + return operands[0] + "^{" + operands[1] + "}"; + }, + "prime": function(operands) { + return operands[0] + "'"; + }, + "tuple": function(operands) { + return '\\left( ' + operands.join(', ') + ' \\right)'; + }, + "array": function(operands) { + return '\\left[ ' + operands.join(', ') + ' \\right]'; + }, + "list": function(operands) { + return operands.join(', '); + }, + "set": function(operands) { + return '\\left\\{ ' + operands.join(', ') + ' \\right\\}'; + }, + "vector": function(operands) { + return '\\left( ' + operands.join(', ') + ' \\right)'; + }, + "interval": function(operands) { + return '\\left( ' + operands.join(', ') + ' \\right)'; + }, + "matrix": function(operands) { + return '\\left( ' + operands.join(', ') + ' \\right)'; + }, + "and": function(operands) { + return operands.join(' \\land '); + }, + "or": function(operands) { + return operands.join(' \\lor '); + }, + "not": function(operands) { + return '\\lnot ' + operands[0]; + }, + "=": function(operands) { + return operands.join(' = '); + }, + "<": function(operands) { + return operands.join(' < '); + }, + ">": function(operands) { + return operands.join(' > '); + }, + "lts": function(operands) { + return operands.join(' < '); + }, + "gts": function(operands) { + return operands.join(' > '); + }, + "le": function(operands) { + return operands.join(' \\le '); + }, + "ge": function(operands) { + return operands.join(' \\ge '); + }, + "ne": function(operands) { + return operands.join(' \\ne '); + }, + "in": function(operands) { + return operands[0] + " \\in " + operands[1]; + }, + "notin": function(operands) { + return operands[0] + " \\notin " + operands[1]; + }, + "ni": function(operands) { + return operands[0] + " \\ni " + operands[1]; + }, + "notni": function(operands) { + return operands[0] + " \\not\\ni " + operands[1]; + }, + "subset": function(operands) { + return operands[0] + " \\subset " + operands[1]; + }, + "notsubset": function(operands) { + return operands[0] + " \\not\\subset " + operands[1]; + }, + "superset": function(operands) { + return operands[0] + " \\supset " + operands[1]; + }, + "notsuperset": function(operands) { + return operands[0] + " \\not\\supset " + operands[1]; + }, + "union": function(operands) { + return operands.join(' \\cup '); + }, + "intersect": function(operands) { + return operands.join(' \\cap '); + }, + "derivative_leibniz": function (operands) { + return "\\frac{d" + operands[0] + "}{d" + operands[1] + "}"; + }, + "partial_derivative_leibniz": function (operands) { + return "\\frac{d" + operands[0] + "}{d" + operands[1] + "}"; + }, + "|": function (operands) { + return operands[0] + " \\mid " + operands[1]; + }, + ":": function (operands) { + return operands[0] + " : " + operands[1]; + }, + }; -function evaluate_numbers_sub(tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero) { - // assume that tree has been sorted to default order (while flattened) - // and then unflattened_right - // returns unflattened tree + // defaults for parsers if not overridden by context - if (tree === undefined) - return tree; - if (typeof tree === 'number') { - if(set_small_zero > 0 && math$19.abs(tree) < set_small_zero) { - return 0; + // allowed multicharacter latex symbols + // in addition to the below applied function symbols + const allowedLatexSymbolsDefault = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'partial', "abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg']; + + const matrixEnvironmentDefault = 'bmatrix'; + + class astToLatex { + + constructor({ + allowedLatexSymbols=allowedLatexSymbolsDefault, + matrixEnvironment=matrixEnvironmentDefault, + } = {}){ + this.allowedLatexSymbols = allowedLatexSymbols; + this.matrixEnvironment = matrixEnvironment; } - if(tree === 0) { - return 0; // so that -0 returns 0 + + convert(tree) { + return this.statement(tree); } - return tree; - } - if (evaluate_functions || contains_only_numbers(tree, { include_number_symbols: true })) { + statement(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.single_statement(tree); + } - var c = evaluate_to_constant(tree); + var operator = tree[0]; + var operands = tree.slice(1); - if (c !== null) { - if (typeof c === 'number') { - if (Number.isFinite(c)) { - if(set_small_zero > 0 && math$19.abs(c) < set_small_zero) { - return 0; - } - if (max_digits === Infinity) - return c; - if (Number.isInteger(c)) { - if(c === 0) { - return 0; - } - return c; - } + if(operator === 'ldots') + return '\\ldots'; - let c_minround = evalf(c, 14); - let c_round = evalf(c, max_digits); - if (max_digits === 0) { - // interpret 0 max_digits as only accepting integers - // (even though positive max_digits is number of significant digits) - c_round = math$19.round(c); - } - if (c_round === c_minround) { - return c; - } + if ((!(operator in operators$3)) && operator !== "apply") + throw new Error("Badly formed ast: operator " + operator + " not recognized."); - // if expression already contained a decimal, - // and contains only numbers (no constants like pi) - // return the number - if (contains_decimal_number(tree) && contains_only_numbers(tree)) { - return c; - } + if (operator === 'and' || operator === 'or') { + return operators$3[operator](operands.map(function(v, i) { + let result = this.single_statement(v); + // for clarity, add parenthesis unless result is + // single quantity (with no spaces) or already has parens + if (result.toString().match(/ /) && + (!(result.toString().match(/^\\left\(.*\\right\)$/)))) + return '\\left(' + result + '\\right)'; + else + return result; + }.bind(this))); + } + return this.single_statement(tree); + } + + single_statement(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.expression(tree); + } - let c_frac = math$19.fraction(c); - let c_frac_d_round = evalf(c_frac.d, 3); + var operator = tree[0]; + var operands = tree.slice(1); - if (c_frac.n < 1E4 || (c_frac_d_round === c_frac.d)) { - let c_reconstruct = evalf(c_frac.s * c_frac.n / c_frac.d, 14); - if (c_reconstruct === c_minround) { - if (c_frac.d === 1) { - return c_frac.s * c_frac.n; - } else { - return ['/', c_frac.s * c_frac.n, c_frac.d]; - } + if (operator === 'not') { + return operators$3[operator](operands.map(function(v, i) { + let result = this.single_statement(v); + // for clarity, add parenthesis unless result is + // single quantity (with no spaces) or already has parens + if (result.toString().match(/ /) && + (!(result.toString().match(/^\\left\(.*\\right\)$/)))) + return '\\left(' + result + '\\right)'; + else + return result; + }.bind(this))); + } + + if ((operator === '=') || (operator === 'ne') || + (operator === '<') || (operator === '>') || + (operator === 'le') || (operator === 'ge') || + (operator === 'in') || (operator === 'notin') || + (operator === 'ni') || (operator === 'notni') || + (operator === 'subset') || (operator === 'notsubset') || + (operator === 'superset') || (operator === 'notsuperset')) { + return operators$3[operator](operands.map(function(v, i) { + return this.expression(v); + }.bind(this))); + } + + if (operator === 'lts' || operator === 'gts') { + let args = operands[0]; + let strict = operands[1]; + + if (args[0] !== 'tuple' || strict[0] !== 'tuple') + // something wrong if args or strict are not tuples + throw new Error("Badly formed ast"); + + let result = this.expression(args[1]); + for (let i = 1; i < args.length - 1; i++) { + if (strict[i]) { + if (operator === 'lts') + result += " < "; + else + result += " > "; + } + else { + if (operator === 'lts') { + result += " \\le "; + } + else { + result += " \\ge "; } } + result += this.expression(args[i + 1]); } + return result; } - } - } - - if (!Array.isArray(tree)) - return tree; - var operator = tree[0]; - var operands = tree.slice(1).map(v => evaluate_numbers_sub( - v, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); + return this.expression(tree); + } - if (operator === '+') { - let left = operands[0]; - let right = operands[1]; + expression(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.term(tree); + } - if (right === undefined) - return left; + var operator = tree[0]; + var operands = tree.slice(1); - if (typeof left === 'number') { - if (left === 0) - return right; - if (typeof right === 'number') - return left + right; - // check if right is an addition with that begins with - // a constant. If so combine with left - if (Array.isArray(right) && right[0] === '+' - && (typeof right[1] === 'number')) { - return ['+', left + right[1], right[2]]; - } - // check if right is an addition with that ends with - // a constant. If so combine with left - if (!skip_ordering && Array.isArray(right) && right[0] === '+' - && (typeof right[2] === 'number')) { - return ['+', left + right[2], right[1]]; + if (operator === '+') { + return operators$3[operator](operands.map(function(v, i) { + if (i > 0) + return this.termWithPlusIfNotNegated(v); + else + return this.term(v); + }.bind(this))); } - } - if (typeof right === 'number') - if (right === 0) - return left; + if ((operator === 'union') || (operator === 'intersect')) { + return operators$3[operator](operands.map(function(v, i) { + return this.term(v); + }.bind(this))); + } - return [operator].concat(operands); - } - if (operator === '-') { - if (typeof operands[0] === 'number') - return -operands[0]; - // check if operand is a multiplication with that begins with - // a constant. If so combine with constant - if (Array.isArray(operands[0]) && operands[0][0] === '*' - && (typeof operands[0][1] === 'number')) { - return ['*', -operands[0][1]].concat(operands[0].slice(2)); + return this.term(tree); } - // check if operand is a division with that begins with - // either - /// (A) a constant or - // (B) a multiplication that begins with a constant. - // If so. combine with constant - if (Array.isArray(operands[0]) && operands[0][0] === '/') { - if (typeof operands[0][1] === 'number') - return ['/', -operands[0][1], operands[0][2]]; - if (Array.isArray(operands[0][1]) && operands[0][1][0] === '*' - && (typeof operands[0][1][1] === 'number')) { - return ['/', [ - '*', -operands[0][1][1]].concat(operands[0][1].slice(2)), - operands[0][2]]; + term(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.factor(tree); } - } + var operator = tree[0]; + var operands = tree.slice(1); - return [operator].concat(operands); - } - if (operator === '*') { - let left = operands[0]; - let right = operands[1]; + if (operator === '-') { + return operators$3[operator](operands.map(function(v, i) { + return this.term(v); + }.bind(this))); + } + if (operator === '*') { + return operators$3[operator](operands.map(function(v, i) { + let result; + if (i > 0) { + result = this.factorWithParenthesesIfNegated(v); + if (result.toString().match(/^[0-9]/)) + return '\\cdot ' + result; + else + return '\\, ' + result + } + else + return this.factor(v); + }.bind(this))); + } - if (right === undefined) - return left; + if (operator === '/') { + return operators$3[operator](operands.map(function(v, i) { + return this.expression(v); + }.bind(this))); + } - if (typeof left === 'number') { - if (isNaN(left)) - return NaN; + return this.factor(tree); + } - if (typeof right === 'number') - return left * right; + simple_factor_or_function_or_parens(tree) { + // return true if + // factor(tree) is a single character + // or tree is a non-negative number not in scientific notation + // or tree is a string + // or tree is a function call other than sqrt + // or factor(tree) is in parens - if (!isFinite(left)) { - if ((left === Infinity && is_negative_ast(right)) - || (left === -Infinity && is_positive_ast(right))) - return -Infinity - if (is_nonzero_ast(right) === false) - return NaN; - return Infinity; - } - if (left === 0) { - return 0; - } - if (left === 1) - return right; + var result = this.factor(tree); - if (left === -1) { - return ['-', right]; - } - // check if right is a multiplication with that begins with - // a constant. If so combine with left - if (Array.isArray(right) && right[0] === '*' - && (typeof right[1] === 'number')) { - left = left * right[1]; - right = right[2]; - if (left === 1) - return right; - if (left === -1) - return ['-', right]; - return ['*', left, right]; + if (result.toString().length === 1 || + (typeof tree === 'string') || + (tree[0] === 'apply' && tree[1] !== "sqrt") || + result.toString().match(/^\\left\(.*\\right\)$/) + ) { + return true; + } else if (typeof tree === "number") { + if(tree >= 0 && !tree.toString().includes('e')) { + return true; + } else { + return false; + } + } else { + return false } - } - if (typeof right === 'number') { - if (isNaN(right)) - return NaN; - if (!isFinite(right)) { - if ((right === Infinity && is_negative_ast(left)) - || (right === -Infinity && is_positive_ast(left))) - return -Infinity - if (is_nonzero_ast(left) === false) - return NaN; - return Infinity; + + stringConvert(string) { + if (string.length > 1) { + if(this.allowedLatexSymbols.includes(string)) + return "\\" + string; + else + return "\\var{" + string + '}'; } - if (right === 0) { - return 0; + return string; + } + + factor(tree) { + if (typeof tree === 'string') { + return this.stringConvert(tree); } - if (right === 1) - return left; - if (right === -1) { - return ['-', left]; - } - // check if left is a multiplication with that begins with - // a constant. If so combine with right - if (Array.isArray(left) && left[0] === '*' - && (typeof left[1] === 'number')) { - right = right * left[1]; - left = left[2]; - if (right === 1) - return left; - if (right === -1) - return ['-', left]; - return ['*', left, right]; + + if (typeof tree === 'number') { + if(tree === Infinity) + return "\\infty"; + else if(tree === -Infinity) + return "-\\infty"; + else { + let numberString = tree.toString(); + let eIndex = numberString.indexOf('e'); + if(eIndex === -1) { + return numberString; + } + let num = numberString.substring(0,eIndex); + let exponent = numberString.substring(eIndex+1); + + return num + " \\cdot 10^{" + exponent + "}"; + } } - } - return [operator].concat(operands); - } + var operator = tree[0]; + var operands = tree.slice(1); - if (operator === '/') { - let numer = operands[0]; - let denom = operands[1]; + if (operator === "^") { + let operand0 = this.factor(operands[0]); - if (typeof numer === 'number') { - if (numer === 0) { - let denom_nonzero = is_nonzero_ast(denom, assumptions); - if (denom_nonzero) - return 0; - if (denom_nonzero === false) - return NaN; // 0/0 - } + // so that f_(st)'^2(x) doesn't get extra parentheses + // (and no longer recognized as function call) + // check for simple factor after removing primes + let remove_primes = operands[0]; + while (remove_primes[0] === 'prime') { + remove_primes = remove_primes[1]; + } - if (typeof denom === 'number') { - let quotient = numer / denom; - if (max_digits === Infinity - || math$19.round(quotient, max_digits) === quotient) - return quotient; - else if (denom < 0) - return ['/', -numer, -denom]; + if (!(this.simple_factor_or_function_or_parens(remove_primes) || + (remove_primes[0] === '_' && (typeof remove_primes[1] === 'string')) + )) + operand0 = '\\left(' + operand0.toString() + '\\right)'; + + return operand0 + '^{' + this.statement(operands[1]) + '}'; } + else if (operator === "_") { + let operand0 = this.factor(operands[0]); + if (!(this.simple_factor_or_function_or_parens(operands[0]))) + operand0 = '\\left(' + operand0.toString() + '\\right)'; - // check if denom is a multiplication with that begins with - // a constant. If so combine with numerator - if (Array.isArray(denom) && denom[0] === '*' - && (typeof denom[1] === 'number')) { - let quotient = numer / denom[1]; + return operand0 + '_{' + this.statement(operands[1]) + '}'; + } + else if (operator === "prime") { + let op = operands[0]; - if (max_digits === Infinity - || math$19.round(quotient, max_digits) === quotient) { - return ['/', quotient, denom[2]]; + let n_primes = 1; + while (op[0] === "prime") { + n_primes += 1; + op = op[1]; } - } - } - else if (typeof denom === 'number') { - // check if numer is a multiplication with that begins with - // a constant. If so combine with denominator - if (Array.isArray(numer) && numer[0] === '*' - && (typeof numer[1] === 'number')) { - let quotient = numer[1] / denom; - if (max_digits === Infinity - || math$19.round(quotient, max_digits) === quotient) { - if (quotient === 1) - return numer[2]; - else - return ['*', quotient, numer[2]]; + + let result = this.factor(op); + + if (!(this.simple_factor_or_function_or_parens(op) || + (op[0] === '_' && (typeof op[1] === 'string')) + )) + result = '\\left(' + result.toString() + '\\right)'; + for (let i = 0; i < n_primes; i++) { + result += "'"; } - // if denom is negative move negative to number - if (denom < 0) - return ['/', ['*', -numer[1], numer[2]], -denom]; + return result; } - let reciprocal = 1/denom; - if (max_digits === Infinity - || math$19.round(reciprocal, max_digits) === reciprocal) { - return ['*', reciprocal, numer]; + else if (operator === "-") { + return operators$3[operator](operands.map(function(v, i) { + return this.factor(v); + }.bind(this))); } - // if denominator is negative, negate whole fraction - if (denom < 0) { - if (Array.isArray(numer) && numer[0] === '-') - return ['/', numer[1], -denom]; - else - return ['-', ['/', numer, -denom]]; + else if (operator === 'tuple' || operator === 'array' || + operator === 'list' || + operator === 'set' || operator === 'vector' || + operator === '|' || operator === ':') { + return operators$3[operator](operands.map(function(v, i) { + return this.statement(v); + }.bind(this))); } - } - return [operator].concat(operands); + else if (operator === 'interval') { - } + let args = operands[0]; + let closed = operands[1]; + if (args[0] !== 'tuple' || closed[0] !== 'tuple') + throw new Error("Badly formed ast"); - if (operator === '^') { + let result = this.statement(args[1]) + ", " + + this.statement(args[2]); - let base = operands[0]; - let pow = operands[1]; + if (closed[1]) + result = '\\left[ ' + result; + else + result = '\\left( ' + result; - if (typeof pow === 'number') { - if (pow === 0) { - if (!math$19.pow_strict) - return 1; - let base_nonzero = is_nonzero_ast(base, assumptions); - if (base_nonzero && (base !== Infinity) && (base !== -Infinity)) - return 1; - if (base_nonzero === false) - return NaN; // 0^0 - } - else if (pow === 1) { - return base; - } - else if (typeof base === 'number') { - let result = math$19.pow(base, pow); - if (max_digits === Infinity - || math$19.round(result, max_digits) === result) - return result; + if (closed[2]) + result = result + ' \\right]'; + else + result = result + ' \\right)'; + + return result; } - } else if (base === 1) { - return 1; - } - return [operator].concat(operands); - } + else if (operator === 'matrix') { + let size = operands[0]; + let args = operands[1]; - return [operator].concat(operands); -} + let result = '\\begin{' + this.matrixEnvironment + '} '; + for(let row = 0; row < size[1]; row += 1) { + for(let col = 0; col < size[2]; col += 1) { + result = result + this.statement(args[row+1][col+1]); + if(col < size[2]-1) + result = result + ' & '; + } + if(row < size[1]-1) + result = result + ' \\\\ '; + } + result = result + ' \\end{' + this.matrixEnvironment + '}'; -function evaluate_numbers(expr_or_tree, { - assumptions, max_digits, skip_ordering = false, - evaluate_functions = false, - set_small_zero = 0, -} = {}) { + return result; - if (max_digits === undefined || - !(Number.isInteger(max_digits) || max_digits === Infinity)) - max_digits = 0; + } + else if(operator === 'derivative_leibniz' || operator === 'partial_derivative_leibniz') { + let deriv_symbol = "d"; + if(operator === 'partial_derivative_leibniz') + deriv_symbol = "\\partial "; - if (set_small_zero === true) { - set_small_zero = 1E-14; - } + let num = operands[0]; + let denom = operands[1]; - var tree = get_tree(expr_or_tree); + let n_deriv = 1; + let var1 = ""; + if(Array.isArray(num)) { + var1 = num[1]; + n_deriv = num[2]; + } + else + var1 = num; + let result = deriv_symbol; + if(n_deriv > 1) + result = result.trimRight() + "^{" + n_deriv + "}" + this.stringConvert(var1); + else { + result = result + this.stringConvert(var1); + } - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); + result = "\\frac{ " + result + " }{ "; - var result; - if (skip_ordering) { - tree = unflattenRight(flatten(tree)); - result = evaluate_numbers_sub( - tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero); - } else { - tree = unflattenRight(default_order(flatten(tree))); - result = default_order(evaluate_numbers_sub( - tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); - // TODO: determine how often have to repeat - result = default_order(evaluate_numbers_sub( - unflattenRight(result), assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); - } + let n_denom = 1; + if(Array.isArray(denom)) { + n_denom = denom.length-1; + } - return flatten(result); -} + for(let i=1; i <= n_denom; i++) { + let denom_part = denom[i]; -function collect_like_terms_factors(expr_or_tree, assumptions, max_digits) { + let exponent = 1; + let var2 = ""; + if(Array.isArray(denom_part)) { + var2 = denom_part[1]; + exponent = denom_part[2]; + } + else + var2 = denom_part; - function isNumber(s) { - if (typeof s === 'number') - return true; - if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) - return true; - return false; - } - function isNegativeNumber(s) { - if (typeof s === 'number' && s < 0) - return true; - if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) - return true; - return false; - } - function isNumerical(s) { - if (typeof s === 'number') - return true; - if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) - return true; - let c = evaluate_to_constant(s); - if (typeof c === 'number' && Number.isFinite(c)) - return true; + result = result + deriv_symbol + this.stringConvert(var2); - return false; + if(exponent > 1) + result = result + "^{" + exponent + "}"; - } + result = result + " "; + + } + result = result + "}"; + return result; + } + else if (operator === 'apply') { - var tree = get_tree(expr_or_tree); + if (operands[0] === 'abs') { + return '\\left|' + this.statement(operands[1]) + '\\right|'; + } - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); + if (operands[0] === "factorial") { + let result = this.factor(operands[1]); + if (this.simple_factor_or_function_or_parens(operands[1]) || + (operands[1][0] === '_' && (typeof operands[1][1] === 'string')) + ) + return result + "!"; + else + return '\\left(' + result.toString() + '\\right)!'; + } - tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits, evaluate_functions: true }); + if (operands[0] === 'sqrt') { + return '\\sqrt{' + this.statement(operands[1]) + '}'; + } - var transformations = []; + let f = this.factor(operands[0]); + let f_args = this.statement(operands[1]); - // preliminary transformations - transformations.push([ - [ '/', 'x', [ '^', 'y', 'a' ] ], - [ '*', 'x', [ '^', 'y', [ '-', 'a' ] ] ], - { evaluate_numbers: true, max_digits: max_digits }]); - transformations.push([ - [ '/', 'x', 'y' ], - [ '*', 'x', [ '^', 'y', [ '-', 1 ] ] ], - { evaluate_numbers: true, max_digits: max_digits }]); - tree = applyAllTransformations(tree, transformations, 40); + if (operands[1][0] !== 'tuple') + f_args = "\\left(" + f_args + "\\right)"; - // collecting like terms and factors - transformations = []; - transformations.push( - [ - [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], - [ '^', 'x', [ '+', 'n', 'm' ] ], - { - variables: { - x: v => is_nonzero_ast(v, assumptions), - n: isNumber, m: isNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_implicit_identities: ['m', 'n'], - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], - [ '^', 'x', [ '+', 'n', 'm' ] ], - { - variables: { - x: true, - n: v => isNumber(v) && is_positive_ast(v, assumptions), - m: v => isNumber(v) && is_positive_ast(v, assumptions) - }, - evaluate_numbers: true, max_digits: max_digits, - allow_implicit_identities: ['m', 'n'], - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], - [ '^', 'x', [ '+', 'n', 'm' ] ], - { - variables: { - x: true, - n: v => isNumber(v) && is_negative_ast(v, assumptions), - m: v => isNumber(v) && is_negative_ast(v, assumptions) - }, - evaluate_numbers: true, max_digits: max_digits, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '+', [ '*', 'n', 'x' ], [ '*', 'm', 'x' ] ], - [ '*', [ '+', 'n', 'm' ], 'x' ], - { - variables: { - x: true, - n: isNumber, m: isNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_implicit_identities: ['m', 'n'], - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '+', [ '*', 'n', 'x' ], [ '-', [ '*', 'm', 'x' ] ] ], - [ '*', [ '+', 'n', [ '-', 'm' ] ], 'x' ], - { - variables: { - x: true, - n: isNumber, m: isNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_implicit_identities: ['m', 'n'], - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '^', [ '*', 'x', 'y' ], 'a' ], - [ '*', [ '^', 'x', 'a' ], [ '^', 'y', 'a' ] ], - { allow_permutations: true, }] - ); - transformations.push( - [ - [ '^', [ '^', 'x', 'n' ], 'm' ], - [ '^', 'x', [ '*', 'n', 'm' ] ], - { - variables: { - x: true, - n: isNumber, m: isNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_permutations: true, - }] - ); - transformations.push([ - [ '-', [ '+', 'a', 'b' ] ], - [ '+', [ '-', 'a' ], [ '-', 'b' ] ] - ]); - - // evaluate any products - // (required since evaluate_numbers needs to be applied separately - // to complicated products to evaluate them as numbers) - transformations.push( - [ - [ '*', 'x', 'y' ], - [ '*', 'x', 'y' ], - { - variables: { x: isNumerical, y: isNumerical }, - evaluate_numbers: true, max_digits: max_digits, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); + return f + f_args; + } + else { + return '\\left(' + this.statement(tree) + '\\right)'; + } + } - tree = applyAllTransformations(tree, transformations, 40); + factorWithParenthesesIfNegated(tree) { + var result = this.factor(tree); - transformations = []; - // redo as division - transformations.push( - [ - [ '*', 'x', [ '^', 'y', [ '-', 'a' ] ] ], - [ '/', 'x', [ '^', 'y', 'a' ] ], - { - allow_extended_match: true, - allow_permutations: true, - evaluate_numbers: true, max_digits: max_digits, - max_group: 1, - }]); - transformations.push([ - [ '*', 'x', [ '^', 'y', 'n' ] ], - [ '/', 'x', [ '^', 'y', [ '-', 'n' ] ] ], - { - variables: { - x: true, y: true, - n: isNegativeNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }]); - tree = applyAllTransformations(tree, transformations, 40); - - transformations = []; - // redo as division, try 2 - transformations.push([ - [ '^', 'y', 'n' ], - [ '/', 1, [ '^', 'y', [ '-', 'n' ] ] ], - { - variables: { - y: true, - n: isNegativeNumber - }, - evaluate_numbers: true, max_digits: max_digits, - }]); - tree = applyAllTransformations(tree, transformations, 40); - - transformations = []; - // '*' before '/' and products in denominator - transformations.push([ - [ '*', 'x', [ '/', 'y', 'z' ] ], - [ '/', [ '*', 'x', 'y' ], 'z' ], - { - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }]); - transformations.push([ - [ '/', [ '/', 'x', 'y' ], 'z' ], - [ '/', 'x', [ '*', 'y', 'z' ] ], - { - allow_extended_match: true, - allow_permutations: true, - }]); - transformations.push([ - [ '/', 'x', [ '/', 'y', 'z' ] ], - [ '/', [ '*', 'x', 'z' ], 'y' ], - { - allow_extended_match: true, - allow_permutations: true, - }]); - tree = applyAllTransformations(tree, transformations, 40); + if (result.toString().match(/^-/)) + return '\\left(' + result.toString() + '\\right)'; - tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits }); + // else + return result; + } - return tree; + termWithPlusIfNotNegated(tree) { + var result = this.term(tree); -} + if (!result.toString().match(/^-/)) + return '+ ' + result.toString(); -function simplify_ratios(expr_or_tree, assumptions) { + // else + return result; + } - // TODO: actually factor numerator and denominator - // for now, assume factored, other than minus sign + } - function remove_negative_factors(factors) { + const textToAst$2 = new textToAst(); + const astToLatex$1 = new astToLatex(); - var sign_change = 1; + var derivatives = { + "sin": textToAst$2.convert('cos x'), + "cos": textToAst$2.convert('-(sin x)'), + "tan": textToAst$2.convert('(sec x)^2'), + "cot": textToAst$2.convert('-((csc x)^2)'), + "sec": textToAst$2.convert('(sec x)*(tan x)'), + "csc": textToAst$2.convert('-(csc x)*(cot x)'), + "sqrt": textToAst$2.convert('1/(2*sqrt(x))'), + "log": textToAst$2.convert('1/x'), + "ln": textToAst$2.convert('1/x'), + "exp": textToAst$2.convert('exp(x)'), + "arcsin": textToAst$2.convert('1/sqrt(1 - x^2)'), + "arccos": textToAst$2.convert('-1/sqrt(1 - x^2)'), + "arctan": textToAst$2.convert('1/(1 + x^2)'), + "arccsc": textToAst$2.convert('-1/(sqrt(-1/x^2 + 1)*x^2)'), + "arcsec": textToAst$2.convert('1/(sqrt(-1/x^2 + 1)*x^2)'), + "arccot": textToAst$2.convert('-1/(1 + x^2)'), + "abs": textToAst$2.convert('abs(x)/x'), + }; - factors = factors.map(function (v) { - if (typeof v === "number") { - if (v < 0) { - sign_change *= -1; - return -v; - } - return v; - } - if (!Array.isArray(v)) - return v; - if (v[0] === '-') { - sign_change *= -1; - return v[1]; - } - if (v[0] !== '+') - return v; + function derivative$2(expr_or_tree,x,story = []) { + var tree = get_tree(expr_or_tree); - var negate = false; - if ((typeof v[1] === "number") && v[1] < 0) - negate = true; - else if (Array.isArray(v[1]) && v[1][0] === '-') - negate = true; - else if (Array.isArray(v[1]) && v[1][0] === '*' && Number(v[1][1]) < 0) { - negate = true; - } + var ddx = '\\frac{d}{d' + x + '} '; - if (negate) { - sign_change *= -1; - var v_ops = v.slice(1).map(x => ['-', x]); - return evaluate_numbers(['+'].concat(v_ops)); + // Derivative of a constant + if (typeof tree === 'number') { + story.push( 'The derivative of a constant is zero, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); + return 0; } - else - return v; - }); - return { factors: factors, sign_change: sign_change }; - } + // Derivative of a more complicated constant + if ((variables(tree)).indexOf(x) < 0) { + story.push( 'The derivative of a constant is zero, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); + return 0; + } - function simplify_ratios_sub(tree, negated) { + // Derivative of a variable + if (typeof tree === 'string') { + if (x === tree) { + story.push( 'We know the derivative of the identity function is one, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 1\\).' ); + return 1; + } - if (!Array.isArray(tree)) { - if (negated) { - return ['-', tree]; - } else { - return tree; + // should never get to this line + // as would have been considered a constant + story.push( 'As far as \\(' + astToLatex$1.convert(x) + '\\) is concerned, \\(' + astToLatex$1.convert(tree) + '\\) is constant, so ' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); + return 0; } - } - var operator = tree[0]; - if (operator === "-") { - return simplify_ratios_sub(tree[1], negated = true); - } - var operands = tree.slice(1).map(v => simplify_ratios_sub(v)); + var operator = tree[0]; + var operands = tree.slice(1); - if (operator !== '/') { - if (negated) { - return ['-', [operator, ...operands]] - } else { - return [operator, ...operands]; + // derivative of sum is sum of derivatives + if ((operator === '+') || (operator === '-') || (operator === '~')) { + story.push( 'Using the sum rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (operands.map( function(v,i) { return ddx + astToLatex$1.convert(v); } )).join( ' + ' ) + '\\).' ); + let result = [operator].concat( operands.map( function(v,i) { return derivative$2(v,x,story); } ) ); + result = simplify$2(result); + story.push( 'So using the sum rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; } - } - var numer = operands[0]; - var denom = operands[1]; + // product rule + if (operator === '*') { + let non_numeric_operands = []; + let numeric_operands = []; - // factor a minus sign from each factor in numerator and denominator - // if it is negative or it is a sum with a negative first term - // (when terms are sorted as though they were not negative) + for( let i=0; i 0) { + if (non_numeric_operands.length === 0) { + story.push( 'Since the derivative of a constant is zero, \\(' + ddx + astToLatex$1.convert( tree ) + ' = 0.\\)' ); + let result = 0; + return result; + } - denom = default_order(denom, { ignore_negatives: true }); - var denom_factors; - if (Array.isArray(denom) && denom[0] === '*') - denom_factors = denom.slice(1); - else - denom_factors = [denom]; - var result_d = remove_negative_factors(denom_factors); - denom_factors = result_d["factors"]; + let remaining = ['*'].concat( non_numeric_operands ); + if (non_numeric_operands.length === 1) + remaining = non_numeric_operands[0]; - if (result_n["sign_change"] * result_d["sign_change"] < 0) - numer_factors[0] = ['-', numer_factors[0]]; - if (numer_factors.length === 1) - numer = numer_factors[0]; - else - numer = ['*'].concat(numer_factors); - if (denom_factors.length === 1) - denom = denom_factors[0]; - else - denom = ['*'].concat(denom_factors); - return ['/', numer, denom]; + if (remaining === x) { + story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (numeric_operands.map( function(v,i) { return astToLatex$1.convert(v); } )).join( ' \\cdot ' ) + '\\).' ); + let result = ['*'].concat( numeric_operands ); + result = simplify$2(result); + return result; + } - } + story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (numeric_operands.map( function(v,i) { return astToLatex$1.convert(v); } )).join( ' \\cdot ' ) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(remaining) + '\\right)\\).' ); + let d = derivative$2(remaining,x,story); + let result = ['*'].concat( numeric_operands.concat( [d] ) ); + result = simplify$2(result); + story.push( 'And so \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } - var tree = get_tree(expr_or_tree); + story.push( 'Using the product rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + + (operands.map( function(v,i) { + return (operands.map( function(w,j) { + if (i === j) + return ddx + '\\left(' + astToLatex$1.convert(v) + '\\right)'; + else + return astToLatex$1.convert(w); + })).join( ' \\cdot ' ) })).join( ' + ' ) + '\\).' ); + + let inner_operands = operands.slice(); + + let result = ['+'].concat( operands.map( function(v,i) { + return ['*'].concat( inner_operands.map( function(w,j) { + if (i === j) { + let d = derivative$2(w,x,story); + // remove terms that have derivative 1 + if (d === 1) + return null; + + return d; + } else { + return w; + } + } ).filter( function(t) { return t != null; } ) ); + } ) ); + result = simplify$2(result); + story.push( 'So using the product rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); + return result; + } - return simplify_ratios_sub(tree); + // quotient rule + if (operator === '/') { + let f = operands[0]; + let g = operands[1]; -} + if ((variables(g)).indexOf(x) < 0) { + story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(['/', 1, g]) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(f) + '\\right)\\).' ); -var simplify$3 = /*#__PURE__*/Object.freeze({ - clean: clean, - simplify: simplify$2, - simplify_logical: simplify_logical, - evaluate_numbers: evaluate_numbers, - collect_like_terms_factors: collect_like_terms_factors, - collapse_unary_minus: collapse_unary_minus, - simplify_ratios: simplify_ratios, - default_order: default_order -}); + let df = derivative$2(f,x,story); + let quotient_rule = textToAst$2.convert('(1/g)*d'); + let result = substitute( quotient_rule, { "d": df, "g": g } ); + result = simplify$2(result); + story.push( 'So \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); -function tuples_to_vectors(expr_or_tree) { - // convert tuple to vectors - // except if tuple is argument of a function, gts, lts, or interval + return result; + } - var tree = get_tree(expr_or_tree); + if ((variables(f)).indexOf(x) < 0) { + if (f !== 1) { + story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(f) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(['/',1,g]) + '\\right)\\).' ); + } - if (typeof tree === 'number') { - return tree; - } + story.push( 'Since \\(\\frac{d}{du} \\frac{1}{u}\\) is \\(\\frac{-1}{u^2}\\), the chain rule gives \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(f) + '\\cdot \\frac{-1}{ ' + astToLatex$1.convert(g) + '^2} \\cdot ' + ddx + astToLatex$1.convert( g ) + "\\)." ); - if (typeof tree === 'string') { - return tree; - } + let a = derivative$2(g,x,story); - if (typeof tree === 'boolean') { - return tree; - } + let quotient_rule = textToAst$2.convert('f * (-a/(g^2))'); + let result = substitute( quotient_rule, { "f": f, "a": a, "g": g } ); + result = simplify$2(result); + story.push( 'So since \\(\\frac{d}{du} \\frac{1}{u}\\) is \\(\\frac{-1}{u^2}\\), the chain rule gives \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - var operator = tree[0]; - var operands = tree.slice(1); + return result; + } - if(operator === 'tuple') { - let result = ['vector'].concat( operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); - return result; - } + story.push( 'Using the quotient rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = \\frac{' + ddx + '\\left(' + astToLatex$1.convert(f) + '\\right) \\cdot ' + astToLatex$1.convert(g) + ' - ' + astToLatex$1.convert(f) + '\\cdot ' + ddx + '\\left(' + astToLatex$1.convert(g) + '\\right)}{ \\left( ' + astToLatex$1.convert(g) + ' \\right)^2} \\).' ); - if (operator === 'apply') { - if(operands[1][0] === 'tuple') { - // special case for function applied to tuple. - // preserve tuple - let f = tuples_to_vectors(operands[0]); - let f_operands = operands[1].slice(1); - let f_tuple = ['tuple'].concat( f_operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); - return ['apply', f, f_tuple]; - } - // no special case for function applied to single argument - } - else if(operator === 'gts' || operator === 'lts' || operator === 'interval') { - // don't change tuples of gts, lts, or interval - let args = operands[0]; - let booleans = operands[1]; + let a = derivative$2(f,x,story); + let b = derivative$2(g,x,story); - if(args[0] !== 'tuple' || booleans[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); + let quotient_rule = textToAst$2.convert('(a * g - f * b)/(g^2)'); - let args2= ['tuple'].concat( args.slice(1).map( function(v,i) { return tuples_to_vectors(v); } ) ); + let result = substitute( quotient_rule, { "a": a, "b": b, "f": f, "g": g } ); + result = simplify$2(result); + story.push( 'So using the quotient rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return [operator, args2, booleans]; - } + return result; + } - var result = [operator].concat( operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); - return result; -} + // power rule + if (operator === '^') { + let base = operands[0]; + let exponent = operands[1]; -function to_intervals(expr_or_tree) { - // convert tuple and arrays of two arguments to intervals - // except if tuple is argument of a function, gts, lts, or interval + if ((variables(exponent)).indexOf(x) < 0) { + if ((typeof base === 'string') && (base === 'x')) { + if (typeof exponent === 'number') { + let power_rule = textToAst$2.convert('n * (f^m)'); + let result = substitute( power_rule, { "n": exponent, "m": exponent - 1, "f": base } ); + result = simplify$2(result); + story.push( 'By the power rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '}\\).' ); + return result; + } - var tree = get_tree(expr_or_tree); + let power_rule = textToAst$2.convert('n * (f^(n-1))'); + let result = substitute( power_rule, { "n": exponent, "f": base } ); + result = simplify$2(result); + story.push( 'By the power rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '}\\).' ); - if (typeof tree === 'number') { - return tree; - } + return result; + } - if (typeof tree === 'string') { - return tree; - } + if (exponent !== 1) { + story.push( 'By the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '} \\cdot ' + ddx + astToLatex$1.convert( base ) + '\\).' ); + } - if (typeof tree === 'boolean') { - return tree; - } + let a = derivative$2(base,x,story); - var operator = tree[0]; - var operands = tree.slice(1); + if (exponent === 1) + return a; - if(operator === 'tuple' && operands.length === 2) { - // open interval - let result = ['tuple'].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); - result = ['interval', result, ['tuple', false, false]]; - return result; - } - if(operator === 'array' && operands.length === 2) { - // closed interval - let result = ['tuple'].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); - result = ['interval', result, ['tuple', true, true]]; - return result; - } + if (typeof exponent === 'number') { + let power_rule = textToAst$2.convert('n * (f^m) * a'); + let result = substitute( power_rule, { "n": exponent, "m": exponent - 1, "f": base, "a" : a } ); + result = simplify$2(result); + story.push( 'So by the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } - if (operator === 'apply') { - if(operands[1][0] === 'tuple') { - // special case for function applied to tuple. - // preserve tuple - let f = to_intervals(operands[0]); - let f_operands = operands[1].slice(1); - let f_tuple = ['tuple'].concat( f_operands.map( function(v,i) { return to_intervals(v); } ) ); - return ['apply', f, f_tuple]; - } - // no special case for function applied to single argument - } - else if(operator === 'gts' || operator === 'lts' || operator === 'interval') { - // don't change tuples of gts, lts, or interval - let args = operands[0]; - let booleans = operands[1]; + let power_rule = textToAst$2.convert('n * (f^(n-1)) * a'); + let result = substitute( power_rule, { "n": exponent, "f": base, "a" : a } ); + result = simplify$2(result); + story.push( 'So by the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } - if(args[0] !== 'tuple' || booleans[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); + if (base === 'e' && math$19.define_e) { + if ((typeof exponent === 'string') && (exponent === x)) { + let power_rule = textToAst$2.convert('e^(f)'); + let result = substitute( power_rule, { "f": exponent } ); + result = simplify$2(result); + story.push( 'The derivative of \\(e^' + astToLatex$1.convert( x ) + '\\) is itself, that is, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( tree ) + '\\).' ); - let args2= ['tuple'].concat( args.slice(1).map( function(v,i) { return to_intervals(v); } ) ); + return result; + } - return [operator, args2, booleans]; - } + story.push( 'Using the rule for \\(e^x\\) and the chain rule, we know \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( tree ) + ' \\cdot ' + ddx + astToLatex$1.convert( exponent ) + '\\).' ); - var result = [operator].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); - return result; -} + let power_rule = textToAst$2.convert('e^(f)*d'); -function ParseError(message, location) { - this.name = 'ParseError'; - this.message = message || 'Error parsing input'; - this.stack = (new Error()).stack; - this.location = location; -} -ParseError.prototype = Object.create(Error.prototype); -ParseError.prototype.constructor = ParseError; - -// lexer class -// -// Processes input string to return tokens -// -// Token rules: -// array of rules to identify tokens -// Rules will be applied in order until a match is found. -// Each rule is an array of two or three elements -// First element: a string to be converted into a regular expression -// Second element: the token type -// Third element (optional): replacement for actual string matched - - -class lexer { - constructor(token_rules, whitespace='\\s') { - - this.input = ''; - this.location = 0; - this.token_rules=[]; - - // regular expression to identify whitespace at beginning - this.initial_whitespace = new RegExp('^(' + whitespace + ')+'); - - // convert first element of each rule to a regular expression that - // starts at the beginning of the string - for(let rule of token_rules) { - this.token_rules.push([new RegExp('^'+rule[0])].concat(rule.slice(1))); - } - } - - set_input(input) { - if(typeof input !== "string") - throw new Error("Input must be a string"); - - this.input = input; - this.location = 0; - } + let d = derivative$2(exponent,x,story); + let result = substitute( power_rule, { "f": exponent, "d": d } ); + result = simplify$2(result); + story.push( 'So using the rule for \\(e^x\\) and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } - return_state() { - return({ input: this.input, location: this.location }); - } + if (typeof base === 'number') { + if ((typeof exponent === 'string') && (exponent === x)) { + let power_rule = textToAst$2.convert('a^(f) * log(a)'); + let result = substitute( power_rule, { "a": base, "f": exponent } ); + result = simplify$2(result); + story.push( 'The derivative of \\(a^' + astToLatex$1.convert( x ) + '\\) is \\(a^{' + astToLatex$1.convert( x ) + '} \\, \\log a\\), that is, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( result ) + '\\).' ); - set_state({ input=null, location=0 } = {}) { + return result; + } - if(input !== null) { - this.input = input; - this.location = location; - } - } - - - advance({ remove_initial_space=true } = {}) { - // Find next token at beginning of input and delete from input. - // Update location to be the position in original input corresponding - // to end of match. - // Return token, which is an array of token type and matched string + let exp_rule = textToAst$2.convert('a^(f) * log(a)'); + let partial_result = substitute( exp_rule, { "a": base, "f": exponent } ); + story.push( 'Using the rule for \\(a^x\\) and the chain rule, we know \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( partial_result ) + ' \\cdot ' + ddx + astToLatex$1.convert( exponent ) + '\\).' ); - let result = this.initial_whitespace.exec(this.input); - if(result) { - //first find any initial whitespace and adjust location - let n_whitespace = result[0].length; - this.input = this.input.slice(n_whitespace); - this.location += n_whitespace; + let power_rule = textToAst$2.convert('a^(b)*log(a)*d'); + let d = derivative$2(exponent,x,story); + let result = substitute( power_rule, { "a": base, "b": exponent, "d": d } ); + result = simplify$2(result); + story.push( 'So using the rule for \\(a^x\\) and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } - // don't remove initial space, return it as next token - if(!remove_initial_space) { - return { - token_type: "SPACE", - token_text: result[0], - original_text: result[0], - } - } + // general case of a function raised to a function + let f = base; + let g = exponent; - // otherwise ignore initial space and continue - } - - // check for EOF - if(this.input.length === 0) { - return { - token_type: "EOF", - token_text: "", - original_text: "", - } - } - - // search through each token rule in order, finding first match - result = null; - - for(var rule of this.token_rules) { - result = rule[0].exec(this.input); - - if(result) { - let n_characters = result[0].length; - this.input = this.input.slice(n_characters); - this.location += n_characters; - break; - } - } + story.push( "Recall the general rule for exponents, namely that \\(\\frac{d}{dx} u(x)^{v(x)} = u(x)^{v(x)} \\cdot \\left( v'(x) \\cdot \\log u(x) + \\frac{v(x) \\cdot u'(x)}{u(x)} \\right)\\). In this case, \\(u(x) = " + astToLatex$1.convert( f ) + "\\) and \\(v(x) = " + astToLatex$1.convert( g ) + "\\)." ); - // case that didn't find any matches - if(result === null) { - return { - token_type: "INVALID", - token_text: this.input[0], - original_text: this.input[0], - } - } + let a = derivative$2(f,x,story); + let b = derivative$2(g,x,story); - // found a match, set token - if(rule.length > 2) { - // overwrite text by third element of rule - return { token_type: rule[1], - token_text: rule[2], - original_text: result[0], - }; - } - else { - return { token_type: rule[1], - token_text: result[0], - original_text: result[0], - }; - } - } + let power_rule = textToAst$2.convert('(f^g)*(b * log(f) + (g * a)/f)'); + let result = substitute( power_rule, { "a": a, "b": b, "f": f, "g": g } ); + result = simplify$2(result); + story.push( 'So by the general rule for exponents, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } - - unput(string) { - // add string to beginning of input and adjust location - - if(typeof string !== "string") - throw new Error("Input must be a string"); + if (operator === "apply" && !(operands[0] in derivatives)) { + // derivative of function whose derivative is not given - this.location -= string.length; - this.input = string + this.input; + let input = operands[1]; - } - -} + story.push( 'By the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(substitute( ["apply",operands[0] + "'","x"], { "x": input } )) + " \\cdot " + ddx + astToLatex$1.convert(input) + '\\).' ); -var is_associative$1 = { '+': true, '*': true, 'and': true, 'or': true, 'union': true, 'intersect': true}; + let result = ['*', + substitute( ["apply",operands[0] + "'","x"], { "x": input } ), + derivative$2( input, x, story )]; + result = simplify$2(result); + story.push( 'So by the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } -function flatten$18(tree) { - - // flatten tree with all associative operators - - if(!Array.isArray(tree)) - return tree; + // chain rule + if ((operator === "apply" && operands[0] in derivatives) || + operator in derivatives) { - var operator = tree[0]; - var operands = tree.slice(1); + let used_apply = false; + if(operator === "apply") { + operator = operands[0]; + operands = operands.slice(1); + used_apply = true; + } - operands = operands.map( function(v,i) { - return flatten$18(v); } ); - - if (is_associative$1[operator]) { - var result = []; - - for( var i=0; i - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - -// UPDATETHIS: Is this grammar still correct? - -/* Grammar: - - statement_list = - statement_list ',' statement | - statement - - statement = - '...' | - statement_a '|' statement_a | - statement_a ':' statement_a | - statement_a - **** statement_a '|' statement_a - used with turning off '|' statement '|' in baseFactor - tried only after parse error encountered - - statement_a = - statement_a 'OR' statement_b | - statement_b - - statement_b = - statement_b 'AND' relation | - relation - - relation = - 'NOT' relation | - '!' relation | - relation '=' expression | - relation 'NE' expression | - relation '<' expression | - relation '>' expression | - relation 'LE' expression | - relation 'GE' expression | - relation 'IN' expression | - relation 'NOTIN' expression | - relation 'NI' expression | - relation 'NOTNI' expression | - relation 'SUBSET' expression | - relation 'NOTSUBSET' expression | - relation 'SUPERSET' expression | - relation 'NOTSUPERSET' expression | - expression - - expression = - expression '+' term | - expression '-' term | - expression 'UNION' term | - expression 'INTERSECT' term | - '+' term | - term - - term = - term '*' factor | - term nonMinusFactor | - term '/' factor | - factor - - baseFactor = - '(' statement_list ')' | - '[' statement_list ']' | - '{' statement_list '}' | - '(' statement ',' statement ']' | - '[' statement ',' statement ')' | - '|' statement '|' | - number | - variable | - modified_function '(' statement_list ')' | - modified_applied_function '(' statement_list ')' | - modified_function | - modified_applied_function factor | - baseFactor '_' baseFactor | - *** modified_applied_function factor - allowed only if allowSimplifiedFunctionApplication==true - *** '|' statement '|' - allowed only at beginning of factor or if not currently in absolute value - - - modified_function = - function | - function '_' baseFactor | - function '_' baseFactor '^' factor | - function '^' factor - function "'" - function '_' baseFactor "'" - function '_' baseFactor "'" '^' factor - function "'" '^' factor - *** where the "'" after the functions can be repeated - - modified_applied_function = - applied_function | - applied_function '_' baseFactor | - applied_function '_' baseFactor '^' factor | - applied_function '^' factor - applied_function "'" - applied_function '_' baseFactor "'" - applied_function '_' baseFactor "'" '^' factor - applied_function "'" '^' factor - *** where the "'" after the applied_functions can be repeated - - nonMinusFactor = - baseFactor | - baseFactor '^' factor | - baseFactor '!' and/or "'" | - baseFactor '!' and/or "'" '^' factor| - *** where '!' and/or "'" indicates arbitrary sequence of "!" and/or "'" - - factor = - '-' factor | - nonMinusFactor - -*/ - -// in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, -// it must be at the end or followed a comma, |, ), }, or ] -const sci_notat_exp_regex = '(E[+\\-]?[0-9]+\\s*($|(?=\\,|\\||\\)|\\}|\\])))?'; - - -const text_rules = [ - // in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, - // it must be at the end or followed a |, or a closing ),}, or ] - ['[0-9]+(\\.[0-9]*)?' + sci_notat_exp_regex, 'NUMBER'], - ['\\.[0-9]+' + sci_notat_exp_regex, 'NUMBER'], - ['\\*\\*', '^'], - ['\\*', '*'], // there is some variety in multiplication symbols - ['\\xB7', '*'], // '·' - ['\u00B7', '*'], // '·' - ['\u2022', '*'], // '•' - ['\u22C5', '*'], // '⋅' - ['\u00D7', '*'], // '×' - ['/', '/'], - ['-', '-'], // there is quite some variety with unicode hyphens - ['\u058A', '-'], // '֊' - ['\u05BE', '-'], // '־' - ['\u1806', '-'], // '᠆' - ['\u2010', '-'], // '‐' - ['\u2011', '-'], // '‑' - ['\u2012', '-'], // '‒' - ['\u2013', '-'], // '–' - ['\u2014', '-'], // '—' - ['\u2015', '-'], // '―' - ['\u207B', '-'], // '⁻' - ['\u208B', '-'], // '₋' - ['\u2212', '-'], // '−' - ['\u2E3A', '-'], // '⸺' - ['\u2E3B', '-'], // '⸻' - ['\uFE58', '-'], // '﹘' - ['\uFE63', '-'], // '﹣' - ['\uFF0D', '-'], // '-' - ['\\+', '+'], - ['\\^', '^'], // a few ways to denote exponentiation - ['\u2038', '^'], // '‸' - ['\u028C', '^'], // 'ʌ' - ['\\|', '|'], - ['\\(', '('], - ['\\)', ')'], - ['\\[', '['], - ['\\]', ']'], - ['\\{', '{'], - ['\\}', '}'], - [',', ','], - [':', ':'], - - ['\u03B1', 'VARMULTICHAR', 'alpha'], // 'α' - ['\u03B2', 'VARMULTICHAR', 'beta'], // 'β' - ['\u03D0', 'VARMULTICHAR', 'beta'], // 'ϐ' - ['\u0393', 'VARMULTICHAR', 'Gamma'], // 'Γ' - ['\u03B3', 'VARMULTICHAR', 'gamma'], // 'γ' - ['\u0394', 'VARMULTICHAR', 'Delta'], // 'Δ' - ['\u03B4', 'VARMULTICHAR', 'delta'], // 'δ' - ['\u03B5', 'VARMULTICHAR', 'epsilon'], // 'ε' should this be varepsilon? - ['\u03F5', 'VARMULTICHAR', 'epsilon'], // 'ϵ' - ['\u03B6', 'VARMULTICHAR', 'zeta'], // 'ζ' - ['\u03B7', 'VARMULTICHAR', 'eta'], // 'η' - ['\u0398', 'VARMULTICHAR', 'Theta'], // 'Θ' - ['\u03F4', 'VARMULTICHAR', 'Theta'], // 'ϴ' - ['\u03B8', 'VARMULTICHAR', 'theta'], // 'θ' - ['\u1DBF', 'VARMULTICHAR', 'theta'], // 'ᶿ' - ['\u03D1', 'VARMULTICHAR', 'theta'], // 'ϑ' - ['\u03B9', 'VARMULTICHAR', 'iota'], // 'ι' - ['\u03BA', 'VARMULTICHAR', 'kappa'], // 'κ' - ['\u039B', 'VARMULTICHAR', 'Lambda'], // 'Λ' - ['\u03BB', 'VARMULTICHAR', 'lambda'], // 'λ' - ['\u03BC', 'VARMULTICHAR', 'mu'], // 'μ' - ['\u00B5', 'VARMULTICHAR', 'mu'], // 'µ' should this be micro? - ['\u03BD', 'VARMULTICHAR', 'nu'], // 'ν' - ['\u039E', 'VARMULTICHAR', 'Xi'], // 'Ξ' - ['\u03BE', 'VARMULTICHAR', 'xi'], // 'ξ' - ['\u03A0', 'VARMULTICHAR', 'Pi'], // 'Π' - ['\u03C0', 'VARMULTICHAR', 'pi'], // 'π' - ['\u03D6', 'VARMULTICHAR', 'pi'], // 'ϖ' should this be varpi? - ['\u03C1', 'VARMULTICHAR', 'rho'], // 'ρ' - ['\u03F1', 'VARMULTICHAR', 'rho'], // 'ϱ' should this be varrho? - ['\u03A3', 'VARMULTICHAR', 'Sigma'], // 'Σ' - ['\u03C3', 'VARMULTICHAR', 'sigma'], // 'σ' - ['\u03C2', 'VARMULTICHAR', 'sigma'], // 'ς' should this be varsigma? - ['\u03C4', 'VARMULTICHAR', 'tau'], // 'τ' - ['\u03A5', 'VARMULTICHAR', 'Upsilon'], // 'Υ' - ['\u03C5', 'VARMULTICHAR', 'upsilon'], // 'υ' - ['\u03A6', 'VARMULTICHAR', 'Phi'], // 'Φ' - ['\u03C6', 'VARMULTICHAR', 'phi'], // 'φ' should this be varphi? - ['\u03D5', 'VARMULTICHAR', 'phi'], // 'ϕ' - ['\u03A8', 'VARMULTICHAR', 'Psi'], // 'Ψ' - ['\u03C8', 'VARMULTICHAR', 'psi'], // 'ψ' - ['\u03A9', 'VARMULTICHAR', 'Omega'], // 'Ω' - ['\u03C9', 'VARMULTICHAR', 'omega'], // 'ω' - - - ['oo\\b', 'INFINITY'], - ['OO\\b', 'INFINITY'], - ['infty\\b', 'INFINITY'], - ['infinity\\b', 'INFINITY'], - ['Infinity\\b', 'INFINITY'], - ['\u221E', 'INFINITY'], // '∞' - - ['\u212F', 'VAR', 'e'], // 'ℯ' - - ['\u2660', 'VARMULTICHAR', 'spade'], // '♠' - ['\u2661', 'VARMULTICHAR', 'heart'], // '♡' - ['\u2662', 'VARMULTICHAR', 'diamond'], // '♢' - ['\u2663', 'VARMULTICHAR', 'club'], // '♣' - ['\u2605', 'VARMULTICHAR', 'bigstar'], // '★' - ['\u25EF', 'VARMULTICHAR', 'bigcirc'], // '◯' - ['\u25CA', 'VARMULTICHAR', 'lozenge'], // '◊' - ['\u25B3', 'VARMULTICHAR', 'bigtriangleup'], // '△' - ['\u25BD', 'VARMULTICHAR', 'bigtriangledown'], // '▽' - ['\u29EB', 'VARMULTICHAR', 'blacklozenge'], // '⧫' - ['\u25A0', 'VARMULTICHAR', 'blacksquare'], // '■' - ['\u25B2', 'VARMULTICHAR', 'blacktriangle'], // '▲' - ['\u25BC', 'VARMULTICHAR', 'blacktriangledown'], //'▼' - ['\u25C0', 'VARMULTICHAR', 'blacktriangleleft'], // '◀' - ['\u25B6', 'VARMULTICHAR', 'blacktriangleright'], // '▶' - ['\u25A1', 'VARMULTICHAR', 'Box'], // '□' - ['\u2218', 'VARMULTICHAR', 'circ'], // '∘' - ['\u22C6', 'VARMULTICHAR', 'star'], // '⋆' - - ['and\\b', 'AND'], - ['\\&\\&?', 'AND'], - ['\u2227', 'AND'], // '∧' - - ['or\\b', 'OR'], - ['\u2228', 'OR'], // '∨' - - ['not\\b', 'NOT'], - ['\u00ac', 'NOT'], // '¬' - - ['=', '='], - ['\u1400', '='], // '᐀' - ['\u30A0', '='], // '゠' - ['!=', 'NE'], - ['\u2260', 'NE'], // '≠' - ['<=', 'LE'], - ['\u2264', 'LE'], // '≤' - ['>=', 'GE'], - ['\u2265', 'GE'], // '≥' - ['<', '<'], - ['>', '>'], - - ['elementof\\b', 'IN'], - ['\u2208', 'IN'], // '∈' - - ['notelementof\\b', 'NOTIN'], - ['\u2209', 'NOTIN'], //'∉' - - ['containselement\\b', 'NI'], - ['\u220B', 'NI'], // '∋' - - ['notcontainselement\\b', 'NOTNI'], - ['\u220C', 'NOTNI'], // '∌' - - ['subset\\b', 'SUBSET'], - ['\u2282', 'SUBSET'], // '⊂' - - ['notsubset\\b', 'NOTSUBSET'], - ['\u2284', 'NOTSUBSET'], // '⊄' - - ['superset\\b', 'SUPERSET'], - ['\u2283', 'SUPERSET'], // '⊃' - - ['notsuperset\\b', 'NOTSUPERSET'], - ['\u2285', 'NOTSUPERSET'], //'⊅' - - ['union\\b', 'UNION'], - ['\u222A', 'UNION'], // '∪' - - ['intersect\\b', 'INTERSECT'], - ['\u2229', 'INTERSECT'], //'∩' - - ['!', '!'], - ['\'', '\''], - ['_', '_'], - ['\\.\\.\\.', 'LDOTS'], - ['[a-zA-Z∂][a-zA-Z∂0-9]*', 'VAR'], // include ∂ in VAR -]; - - -// defaults for parsers if not overridden by context - -// if true, allowed applied functions to omit parentheses around argument -// if false, omitting parentheses will lead to a Parse Error -const allowSimplifiedFunctionApplicationDefault = true; - -// if true, split multicharacter symbols into a product of letters -const splitSymbolsDefault = true; - -// symbols that won't be split into a product of letters if splitSymbols==true -const unsplitSymbolsDefault = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega']; - -// Applied functions must be given an argument so that -// they are applied to the argument -const appliedFunctionSymbolsDefault = ["abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg', 'conj']; - -// Functions could have an argument, in which case they are applied -// or, if they don't have an argument in parentheses, then they are treated -// like a variable, except that trailing ^ and ' have higher precedence -const functionSymbolsDefault = ['f', 'g']; - -// Parse Leibniz notation -const parseLeibnizNotationDefault = true; - - -class textToAst { - constructor({ - allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplicationDefault, - splitSymbols = splitSymbolsDefault, - unsplitSymbols = unsplitSymbolsDefault, - appliedFunctionSymbols = appliedFunctionSymbolsDefault, - functionSymbols = functionSymbolsDefault, - parseLeibnizNotation = parseLeibnizNotationDefault, - } = {}) { - this.allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplication; - this.splitSymbols = splitSymbols; - this.unsplitSymbols = unsplitSymbols; - this.appliedFunctionSymbols = appliedFunctionSymbols; - this.functionSymbols = functionSymbols; - this.parseLeibnizNotation = parseLeibnizNotation; + let input = operands[0]; - this.lexer = new lexer(text_rules); + if (typeof input === "number") { + let result = 0; + story.push( 'The derivative of a constant is zero so \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } else if ((typeof input === "string") && (input === x)) { + let result = ['*', + substitute( derivatives[operator], { "x": input } )]; + result = simplify$2(result); + story.push( 'It is the case that \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } else if ((typeof input === "string") && (input !== x)) { + let result = 0; + story.push( 'Since the derivative of a constant is zero, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } else { + let example_ast = [operator,'u']; + if(used_apply) + example_ast = ["apply"].concat(example_ast); + story.push( 'Recall \\(\\frac{d}{du}' + astToLatex$1.convert( example_ast ) + ' = ' + + astToLatex$1.convert( derivative$2( example_ast, 'u', [] ) ) + '\\).' ); + + story.push( 'By the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(substitute( derivatives[operator], { "x": input } )) + " \\cdot " + ddx + astToLatex$1.convert(input) + '\\).' ); + + let result = ['*', + substitute( derivatives[operator], { "x": input } ), + derivative$2( input, x, story )]; + result = simplify$2(result); + story.push( 'So by the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + return result; + } + } + return 0; } - advance(params) { - this.token = this.lexer.advance(params); - if (this.token.token_type === 'INVALID') { - throw new ParseError("Invalid symbol '" + this.token.original_text + "'", - this.lexer.location); - } - } + /****************************************************************/ + // + // The "story" that the differentiation code produces can be somewhat repetitive + // + // Here we fix this + // - return_state() { - return ({ - lexer_state: this.lexer.return_state(), - token: Object.assign({}, this.token) - }); + function lowercaseFirstLetter(string) + { + return string.charAt(0).toLowerCase() + string.slice(1); } - set_state(state) { - this.lexer.set_state(state.lexer_state); - this.token = Object.assign({}, state.token); + function simplify_story( story ) { + // remove neighboring duplicates + for (let i = story.length - 1; i >= 1; i--) { + if (story[i] === story[i-1]) + story.splice( i, 1 ); + } + + // Make it seem obvious that I know I am repeating myself + for (let i = 0; i < story.length; i++ ) { + for( let j = i + 1; j < story.length; j++ ) { + if (story[i] === story[j]) { + story[j] = 'Again, ' + lowercaseFirstLetter( story[j] ); + } + } + } + + return story; } - convert(input) { + function derivative_story(expr, x) { + var story = []; + derivative$2( expr, x, story ); + story = simplify_story( story ); + return story; + } + const derivativeStory = derivative_story; - this.lexer.set_input(input); - this.advance(); + var differentiation = /*#__PURE__*/Object.freeze({ + derivative: derivative$2, + derivative_story: derivative_story, + derivativeStory: derivativeStory + }); - var result = this.statement_list(); + /* + * convert syntax trees back to string representations + * + * Copyright 2014-2017 by + * Jim Fowler + * Duane Nykamp + * + * This file is part of a math-expressions library + * + * math-expressions is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or at your option any later version. + * + * math-expressions is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ + + + const unicode_operators = { + "+": function(operands) { return operands.join( ' ' ); }, + "-": function(operands) { return "- " + operands[0]; }, + "*": function(operands) { return operands.join( " " ); }, + "/": function(operands) { return operands[0] + "/" + operands[1]; }, + "_": function(operands) { return operands[0] + "_" + operands[1]; }, + "^": function(operands) { return operands[0] + "^" + operands[1]; }, + "prime": function(operands) { return operands[0] + "'"; }, + "tuple": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, + "array": function(operands) { return '[ ' + operands.join( ', ' ) + ' ]';}, + "list": function(operands) { return operands.join( ', ' );}, + "set": function(operands) { return '{ ' + operands.join( ', ' ) + ' }';}, + "vector": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, + "interval": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, + "matrix": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, + "and": function(operands) { return operands.join( ' and ' );}, + "or": function(operands) { return operands.join( ' or ' );}, + "not": function(operands) { return 'not ' + operands[0]; }, + "=": function(operands) { return operands.join( ' = ' );}, + "<": function(operands) { return operands.join( ' < ' );}, + ">": function(operands) { return operands.join( ' > ' );}, + "lts": function(operands) { return operands.join( ' < ' );}, + "gts": function(operands) { return operands.join( ' > ' );}, + + "le": function(operands) { return operands.join( ' ≤ ' );}, + "ge": function(operands) { return operands.join( ' ≥ ' );}, + "ne": function(operands) { return operands.join( ' ≠ ' );}, + "in": function(operands) { return operands[0] + " ∈ " + operands[1]; }, + "notin": function(operands) { return operands[0] + " ∉ " + operands[1]; }, + "ni": function(operands) { return operands[0] + " ∋ " + operands[1]; }, + "notni": function(operands) { return operands[0] + " ∌ " + operands[1]; }, + "subset": function(operands) { return operands[0] + " ⊂ " + operands[1]; }, + "notsubset": function(operands) { return operands[0] + " ⊄ " + operands[1]; }, + "superset": function(operands) { return operands[0] + " ⊃ " + operands[1]; }, + "notsuperset": function(operands) { return operands[0] + " ⊅ " + operands[1]; }, + "union": function (operands) { return operands.join(' ∪ '); }, + "intersect": function (operands) { return operands.join(' ∩ '); }, + "derivative_leibniz": function (operands) { return "d" + operands[0] + "/d" + operands[1]; }, + "partial_derivative_leibniz": function (operands) { return "∂" + operands[0] + "/∂" + operands[1]; }, + "|": function (operands) { return operands[0] + " | " + operands[1]; }, + ":": function (operands) { return operands[0] + " : " + operands[1]; }, + + }; + + const nonunicode_operators = { + "+": function(operands) { return operands.join( ' ' ); }, + "-": function(operands) { return "- " + operands[0]; }, + "*": function(operands) { return operands.join( " " ); }, + "/": function(operands) { return operands[0] + "/" + operands[1]; }, + "_": function(operands) { return operands[0] + "_" + operands[1]; }, + "^": function(operands) { return operands[0] + "^" + operands[1]; }, + "prime": function(operands) { return operands[0] + "'"; }, + "tuple": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, + "array": function(operands) { return '[ ' + operands.join( ', ' ) + ' ]';}, + "list": function(operands) { return operands.join( ', ' );}, + "set": function(operands) { return '{ ' + operands.join( ', ' ) + ' }';}, + "vector": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, + "interval": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, + "matrix": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, + "and": function(operands) { return operands.join( ' and ' );}, + "or": function(operands) { return operands.join( ' or ' );}, + "not": function(operands) { return 'not ' + operands[0]; }, + "=": function(operands) { return operands.join( ' = ' );}, + "<": function(operands) { return operands.join( ' < ' );}, + ">": function(operands) { return operands.join( ' > ' );}, + "lts": function(operands) { return operands.join( ' < ' );}, + "gts": function(operands) { return operands.join( ' > ' );}, + + "le": function(operands) { return operands.join( ' <= ' );}, + "ge": function(operands) { return operands.join( ' >= ' );}, + "ne": function(operands) { return operands.join( ' ne ' );}, + "in": function(operands) { return operands[0] + " elementof " + operands[1]; }, + "notin": function(operands) { return operands[0] + " notelementof " + operands[1]; }, + "ni": function(operands) { return operands[0] + " containselement " + operands[1]; }, + "notni": function(operands) { return operands[0] + " notcontainselement " + operands[1]; }, + "subset": function(operands) { return operands[0] + " subset " + operands[1]; }, + "notsubset": function(operands) { return operands[0] + " notsubset " + operands[1]; }, + "superset": function(operands) { return operands[0] + " superset " + operands[1]; }, + "notsuperset": function(operands) { return operands[0] + " notsuperset " + operands[1]; }, + "union": function (operands) { return operands.join(' union '); }, + "intersect": function (operands) { return operands.join(' intersect '); }, + "derivative_leibniz": function (operands) { return "d" + operands[0] + "/d" + operands[1]; }, + "partial_derivative_leibniz": function (operands) { return "∂" + operands[0] + "/∂" + operands[1]; }, + "|": function (operands) { return operands[0] + " | " + operands[1]; }, + ":": function (operands) { return operands[0] + " : " + operands[1]; }, + }; + + + const output_unicodeDefault = true; + + + class astToText { + constructor({ + output_unicode = output_unicodeDefault + } = {}) { + this.output_unicode = output_unicode; + this.operators = unicode_operators; + if(!output_unicode){ this.operators = nonunicode_operators;} + } - if (this.token.token_type !== 'EOF') { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); + convert(tree) { + return this.statement(tree); } - return flatten$18(result); + statement(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.single_statement(tree); + } + + let operator = tree[0]; + let operands = tree.slice(1); + + if(operator === 'ldots') + return '...'; + + if((!(operator in this.operators)) && operator!=="apply") + throw new Error("Badly formed ast: operator " + operator + " not recognized."); + if (operator === 'and' || operator === 'or') { + return this.operators[operator]( operands.map( function(v,i) { + let result = this.single_statement(v); + // for clarity, add parenthesis unless result is + // single quantity (with no spaces) or already has parens + if (result.toString().match(/ /) + && (!(result.toString().match(/^\(.*\)$/)))) + return '(' + result + ')'; + else + return result; + }.bind(this))); + } + return this.single_statement(tree); } + single_statement(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.expression(tree); + } - statement_list() { + let operator = tree[0]; + let operands = tree.slice(1); - var list = [this.statement()]; + if (operator === 'not') { + return this.operators[operator]( operands.map( function(v,i) { + let result = this.single_statement(v); + // for clarity, add parenthesis unless result is + // single quantity (with no spaces) or already has parens + if (result.toString().match(/ /) + && (!(result.toString().match(/^\(.*\)$/)))) + return '(' + result + ')'; + else + return result; + }.bind(this))); + } - while (this.token.token_type === ",") { - this.advance(); - list.push(this.statement()); - } + if((operator === '=') || (operator === 'ne') + || (operator === '<') || (operator === '>') + || (operator === 'le') || (operator === 'ge') + || (operator === 'in') || (operator === 'notin') + || (operator === 'ni') || (operator === 'notni') + || (operator === 'subset') || (operator === 'notsubset') + || (operator === 'superset') || (operator === 'notsuperset')) { + return this.operators[operator]( operands.map( function(v,i) { + return this.expression(v); + }.bind(this))); + } - if (list.length > 1) - list = ['list'].concat(list); - else - list = list[0]; + if(operator === 'lts' || operator === 'gts') { + let args = operands[0]; + let strict = operands[1]; + + if(args[0] !== 'tuple' || strict[0] !== 'tuple') + // something wrong if args or strict are not tuples + throw new Error("Badly formed ast"); + + let result = this.expression(args[1]); + for(let i=1; i< args.length-1; i++) { + if(strict[i]) { + if(operator === 'lts') + result += " < "; + else + result += " > "; + } + else { + if(operator === 'lts') { + if(this.output_unicode) + result += " ≤ "; + else + result += " <= "; + } + else { + if(this.output_unicode) + result += " ≥ "; + else + result += " >= "; + } + } + result += this.expression(args[i+1]); + } + return result; + } - return list; + return this.expression(tree); } - statement({ inside_absolute_value = 0 } = {}) { + expression(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.term(tree); + } - // three periods ... can be a statement by itself - if (this.token.token_type === 'LDOTS') { - this.advance(); - return ['ldots']; - } + let operator = tree[0]; + let operands = tree.slice(1); - var original_state; + if (operator === '+') { + return this.operators[operator]( operands.map( function(v,i) { + if(i>0) + return this.termWithPlusIfNotNegated(v); + else + return this.term(v); + }.bind(this) )); + } - try { + if ((operator === 'union') || (operator === 'intersect')) { + return this.operators[operator]( operands.map( function(v,i) { + return this.term(v); + }.bind(this))); + } + + return this.term(tree); + } - original_state = this.return_state(); + term(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.factor(tree); + } - let lhs = this.statement_a({ inside_absolute_value: inside_absolute_value }); + let operator = tree[0]; + let operands = tree.slice(1); - if (this.token.token_type !== ':') - return lhs; + if (operator === '-') { + return this.operators[operator]( operands.map( function(v,i) { + return this.term(v); + }.bind(this))); + } + if (operator === '*') { + return this.operators[operator]( operands.map( function(v,i) { + let result; + if(i > 0) { + result = this.factorWithParenthesesIfNegated(v); + if (result.toString().match( /^[0-9]/ )) + return '* ' + result; + else + return result + } + else + return this.factor(v); + }.bind(this))); + } - this.advance(); + if (operator === '/') { + return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); + } - let rhs = this.statement_a(); + return this.factor(tree); + } - return [':', lhs, rhs]; + symbolConvert(symbol) { + let symbolConversions= { + 'alpha': 'α', + 'beta': 'β', + 'Gamma': 'Γ', + 'gamma': 'γ', + 'Delta': 'Δ', + 'delta': 'δ', + 'epsilon': 'ε', + 'zeta': 'ζ', + 'eta': 'η', + 'Theta': 'ϴ', + 'theta': 'θ', + 'iota': 'ι', + 'kappa': 'κ', + 'Lambda': 'Λ', + 'lambda': 'λ', + 'mu': 'μ', + 'nu': 'ν', + 'Xi': 'Ξ', + 'xi': 'ξ', + 'Pi': 'Π', + 'pi': 'π', + 'rho': 'ρ', + 'Sigma': 'Σ', + 'sigma': 'σ', + 'tau': 'τ', + 'Upsilon': 'Υ', + 'upsilon': 'υ', + 'Phi': 'Φ', + 'phi': 'ϕ', + 'Psi': 'Ψ', + 'psi': 'ψ', + 'Omega': 'Ω', + 'omega': 'ω', + }; + if (this.output_unicode && (symbol in symbolConversions)) + return symbolConversions[symbol]; + else + return symbol + } - } - catch (e) { - try { + simple_factor_or_function_or_parens(tree) { + // return true if + // factor(tree) is a single character + // or tree is a non-negative number not in scientific notation + // or tree is a string + // or tree is a function call + // or factor(tree) is in parens - // if ran into problem parsing statement - // then try again with ignoring absolute value - // and then interpreting bar as a binary operator + let result = this.factor(tree); - // return state to what it was before attempting to parse statement - this.set_state(original_state); + if (result.toString().length === 1 + || (typeof tree === 'string') + || (tree[0] === 'apply') + || result.toString().match(/^\(.*\)$/) + ) { + return true; + } else if (typeof tree === 'number') { + if (tree >= 0 && !tree.toString().includes('e')) { + return true; + } else { + return false; + } + } else { + return false + } + } - let lhs = this.statement_a({ parse_absolute_value: false }); + factor(tree) { + if (typeof tree === 'string') { + return this.symbolConvert(tree); + } - if (this.token.token_type !== '|') { - throw (e); + if (typeof tree === 'number') { + if(tree === Infinity) { + if(this.output_unicode) { + return '∞'; + } + else { + return 'infinity'; + } + } + else if(tree === -Infinity) { + if(this.output_unicode) { + return '-∞'; + } + else { + return '-infinity'; + } + } + else { + let numberString = tree.toString(); + let eIndex = numberString.indexOf('e'); + if(eIndex === -1) { + return numberString; + } + let num = numberString.substring(0,eIndex); + let exponent = numberString.substring(eIndex+1); + if(exponent[0] === "+") { + return num + " * 10^" + exponent.substring(1); + } else { + return num + " * 10^(" + exponent + ")"; + } } + } - this.advance(); + let operator = tree[0]; + let operands = tree.slice(1); - let rhs = this.statement_a({ parse_absolute_value: false }); + if (operator === "^") { + let operand0 = this.factor(operands[0]); + + // so that f_(st)'^2(x) doesn't get extra parentheses + // (and no longer recognized as function call) + // check for simple factor after removing primes + let remove_primes = operands[0]; + while(remove_primes[0] === 'prime') { + remove_primes=remove_primes[1]; + } - return ['|', lhs, rhs]; + if(!(this.simple_factor_or_function_or_parens(remove_primes) || + (remove_primes[0] === '_' && (typeof remove_primes[1] === 'string')) + )) + operand0 = '(' + operand0.toString() + ')'; + let operand1 = this.factor(operands[1]); + if(!(this.simple_factor_or_function_or_parens(operands[1]))) + operand1 = '(' + operand1.toString() + ')'; + + return operand0 + '^' + operand1; } - catch (e2) { - throw (e); // throw original error + else if (operator === "_") { + return this.operators[operator]( operands.map( function(v,i) { + let result = this.factor(v); + if(this.simple_factor_or_function_or_parens(v)) + return result; + else + return '(' + result.toString() + ')'; + }.bind(this))); } - } - } - - statement_a({ inside_absolute_value = 0, parse_absolute_value = true } = {}) { + else if(operator === "prime") { + let op = operands[0]; - var lhs = this.statement_b({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value - }); + let n_primes=1; + while(op[0] === "prime") { + n_primes+=1; + op=op[1]; + } - while (this.token.token_type === 'OR') { + let result = this.factor(op); - let operation = this.token.token_type.toLowerCase(); + if (!(this.simple_factor_or_function_or_parens(op) || + (op[0] === '_' && (typeof op[1] === 'string')) + )) + result = '(' + result.toString() + ')'; + for(let i=0; i 1) + result = result + "^" + n_deriv; + result = result + this.symbolConvert(var1) + "/"; + let n_denom = 1; + if(Array.isArray(denom)) { + n_denom = denom.length-1; + } - relation(params) { + for(let i=1; i <= n_denom; i++) { + let denom_part = denom[i]; - if (this.token.token_type === 'NOT' || this.token.token_type === '!') { - this.advance(); - return ['not', this.relation(params)]; - } + let exponent = 1; + let var2 = ""; + if(Array.isArray(denom_part)) { + var2 = denom_part[1]; + exponent = denom_part[2]; + } + else + var2 = denom_part; - var lhs = this.expression(params); + result = result + deriv_symbol + this.symbolConvert(var2); - while ((this.token.token_type === '=') || (this.token.token_type === 'NE') || - (this.token.token_type === '<') || (this.token.token_type === '>') || - (this.token.token_type === 'LE') || (this.token.token_type === 'GE') || - (this.token.token_type === 'IN') || (this.token.token_type === 'NOTIN') || - (this.token.token_type === 'NI') || (this.token.token_type === 'NOTNI') || - (this.token.token_type === 'SUBSET') || (this.token.token_type === 'NOTSUBSET') || - (this.token.token_type === 'SUPERSET') || (this.token.token_type === 'NOTSUPERSET')) { + if(exponent > 1) + result = result + "^" + exponent; - let operation = this.token.token_type.toLowerCase(); + } + return result; - let inequality_sequence = 0; + } + else if(operator === 'apply'){ - if ((this.token.token_type === '<') || (this.token.token_type === 'LE')) { - inequality_sequence = -1; - } else if ((this.token.token_type === '>') || (this.token.token_type === 'GE')) { - inequality_sequence = 1; - } + if(operands[0] === 'abs') { + return '|' + this.statement(operands[1]) + '|'; + } - this.advance(); - let rhs = this.expression(params); - - if (inequality_sequence === -1) { - if ((this.token.token_type === '<') || this.token.token_type === 'LE') { - // sequence of multiple < or <= - let strict = ['tuple']; - if (operation === '<') - strict.push(true); - else - strict.push(false); + if (operands[0] === "factorial") { + let result = this.factor(operands[1]); + if(this.simple_factor_or_function_or_parens(operands[1]) || + (operands[1][0] === '_' && (typeof operands[1][1] === 'string')) + ) + return result + "!"; + else + return '(' + result.toString() + ')!'; - let args = ['tuple', lhs, rhs]; - while ((this.token.token_type === '<') || this.token.token_type === 'LE') { - if (this.token.token_type === '<') - strict.push(true); - else - strict.push(false); + } - this.advance(); - args.push(this.expression(params)); - } - lhs = ['lts', args, strict]; - } else { - lhs = [operation, lhs, rhs]; - } + let f = this.factor(operands[0]); + let f_args = this.statement(operands[1]); - } else if (inequality_sequence === 1) { - if ((this.token.token_type === '>') || this.token.token_type === 'GE') { - // sequence of multiple > or >= - let strict = ['tuple']; - if (operation === '>') - strict.push(true); - else - strict.push(false); + if(operands[1][0] !== 'tuple') + f_args = "(" + f_args + ")"; - let args = ['tuple', lhs, rhs]; - while ((this.token.token_type === '>') || this.token.token_type === 'GE') { - if (this.token.token_type === '>') - strict.push(true); - else - strict.push(false); + return f+f_args; + } + else { + return '(' + this.statement(tree) + ')'; + } + } - this.advance(); - args.push(this.expression(params)); - } - lhs = ['gts', args, strict]; - } else { - lhs = [operation, lhs, rhs]; - } + factorWithParenthesesIfNegated(tree){ + let result = this.factor(tree); - } else if (operation === '=') { - lhs = ['=', lhs, rhs]; + if (result.toString().match( /^-/ )) + return '(' + result.toString() + ')'; - // check for sequence of multiple = - while (this.token.token_type === '=') { - this.advance(); - lhs.push(this.expression(params)); - } - } else { + // else + return result; + } - lhs = [operation, lhs, rhs]; - } + termWithPlusIfNotNegated(tree){ + let result = this.term(tree); - } + if (!result.toString().match( /^-/ )) + return '+ ' + result.toString(); - return lhs; + // else + return result; } + } - expression(params) { - if (this.token.token_type === '+') - this.advance(); + var astToText$1 = new astToText(); - let negative_begin = false; - if (this.token.token_type === '-') { - negative_begin = true; - this.advance(); - } + function subscripts_to_strings(expr_or_tree, force=false) { + // convert ['_', a,b] to string + // if force is set, perform conversions for any values of a or b + // otherwise (the default), perform conversion only + // when both a and b are strings or numbers - var lhs = this.term(params); + var tree = get_tree(expr_or_tree); - if (negative_begin) { - lhs = ['-', lhs]; + if(!Array.isArray(tree)) { + return tree; } - - while ((this.token.token_type === '+') || (this.token.token_type === '-') - || (this.token.token_type === 'UNION') || - (this.token.token_type === 'INTERSECT')) { - - let operation = this.token.token_type.toLowerCase(); - let negative = false; - - if (this.token.token_type === '-') { - operation = '+'; - negative = true; - this.advance(); - } else { - this.advance(); - if (operation === '+' && this.token.token_type === '-') { - negative = true; - this.advance(); - } - } - let rhs = this.term(params); - if (negative) { - rhs = ['-', rhs]; + + let operator = tree[0]; + let operands = tree.slice(1); + + if(operator === '_') { + if(force || operands.every(x => ['number', 'string'].includes(typeof x))) { + return astToText$1.convert(tree); } - - lhs = [operation, lhs, rhs]; } - return lhs; + return [operator].concat(operands.map(x => subscripts_to_strings(x,force))); } - term(params) { - var lhs = this.factor(params); - var keepGoing = false; + function strings_to_subscripts(expr_or_tree) { + // convert string 'a_b' to ['_', 'a','b'] and string 'a_1' to ['_', 'a', 1] - do { - keepGoing = false; + var tree = get_tree(expr_or_tree); - if (this.token.token_type === '*') { - this.advance(); - lhs = ['*', lhs, this.factor(params)]; - keepGoing = true; - } else if (this.token.token_type === '/') { - this.advance(); - lhs = ['/', lhs, this.factor(params)]; - keepGoing = true; - } else { - // this is the one case where a | could indicate a closing absolute value - let params2 = Object.assign({}, params); - params2.allow_absolute_value_closing = true; - let rhs = this.nonMinusFactor(params2); - if (rhs !== false) { - lhs = ['*', lhs, rhs]; - keepGoing = true; + if(typeof tree === "string") { + let res = tree.match(/^([0-9a-zA-Z]+)_([a-zA-Z]+|[0-9]+)$/); + if(res) { + let base = Number(res[1]); + if(isNaN(base)) { + base = res[1]; + } + let sub = Number(res[2]); + if(isNaN(sub)) { + sub = res[2]; } + return ['_', base, sub] + }else { + return tree; } - } while (keepGoing); + } - return lhs; + if(!Array.isArray(tree)) { + return tree; + } + + let operator = tree[0]; + let operands = tree.slice(1); + + return [operator].concat(operands.map(strings_to_subscripts)); } - factor(params) { - if (this.token.token_type === '-') { - this.advance(); - return ['-', this.factor(params)]; - } - - var result = this.nonMinusFactor(params); + var normalization = /*#__PURE__*/Object.freeze({ + normalize_function_names: normalize_function_names, + normalize_applied_functions: normalize_applied_functions, + substitute_abs: substitute_abs, + default_order: default_order, + constants_to_floats: constants_to_floats, + tuples_to_vectors: tuples_to_vectors, + to_intervals: to_intervals, + subscripts_to_strings: subscripts_to_strings, + strings_to_subscripts: strings_to_subscripts + }); - if (result === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", this.lexer.location); - } else { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } - } else { - return result; - } + // check for equality by randomly sampling + function generate_random_integer(minvalue, maxvalue, rng) { + minvalue = math$19.ceil(minvalue); + maxvalue = math$19.floor(maxvalue); + return math$19.floor(rng() * (maxvalue - minvalue + 1)) + minvalue; } - nonMinusFactor(params) { - - var result = this.baseFactor(params); - // allow arbitrary sequence of factorials - if (this.token.token_type === '!' || this.token.token_type === "'") { - if (result === false) - throw new ParseError("Invalid location of " + this.token.token_type, - this.lexer.location); - while (this.token.token_type === '!' || this.token.token_type === "'") { - if (this.token.token_type === '!') - result = ['apply', 'factorial', result]; - else - result = ['prime', result]; - this.advance(); - } - } - if (this.token.token_type === '^') { - if (result === false) { - throw new ParseError("Invalid location of ^", this.lexer.location); - } - this.advance(); + const equals = function ({ expr, other, randomBindings, + expr_context, other_context, + relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, + allowed_error_in_numbers = 0, + include_error_in_number_exponents = false, + allowed_error_is_absolute = false, + rng, + }) { - // do not allow absolute value closing here - let params2 = Object.assign({}, params); - delete params2.allow_absolute_value_closing; - delete params2.inside_absolute_value; + if (Array.isArray(expr.tree) && Array.isArray(other.tree)) { - return ['^', result, this.factor(params2)]; - } + let expr_operator = expr.tree[0]; + let expr_operands = expr.tree.slice(1); + let other_operator = other.tree[0]; + let other_operands = other.tree.slice(1); - return result; - } + if (expr_operator === 'tuple' || expr_operator === 'vector' + || expr_operator === 'list' || expr_operator === 'array' + || expr_operator === 'matrix' || expr_operator === 'interval' + ) { + if (other_operator !== expr_operator) + return false; - baseFactor({ inside_absolute_value = 0, - parse_absolute_value = true, - allow_absolute_value_closing = false - } = {}) { + if (other_operands.length !== expr_operands.length) + return false; - var result = false; + for (let i = 0; i < expr_operands.length; i++) { + if (!equals({ + expr: expr_context.fromAst(expr_operands[i]), + other: other_context.fromAst(other_operands[i]), + randomBindings: randomBindings, + expr_context: expr_context, + other_context: other_context, + relative_tolerance, absolute_tolerance, tolerance_for_zero, + allowed_error_in_numbers: allowed_error_in_numbers, + include_error_in_number_exponents: include_error_in_number_exponents, + allowed_error_is_absolute: allowed_error_is_absolute, + rng, + })) + return false; + } - if (this.token.token_type === 'NUMBER') { - result = parseFloat(this.token.token_text); - this.advance(); - } else if (this.token.token_type === 'INFINITY') { - result = Infinity; - this.advance(); - } else if (this.token.token_type === 'VAR' || this.token.token_type === 'VARMULTICHAR') { - result = this.token.token_text; + return true; // each component is equal + } - if (this.appliedFunctionSymbols.includes(result) || - this.functionSymbols.includes(result)) { - let must_apply = false; - if (this.appliedFunctionSymbols.includes(result)) - must_apply = true; + // check if a relation with two operands + if (expr_operands.length === 2 && ["=", '>', '<', 'ge', 'le'].includes(expr_operator)) { + if (other_operands.length !== 2) { + return false; + } + //normalize operator + if (expr_operator === ">") { + expr_operator = "<"; + expr_operands = [expr_operands[1], expr_operands[0]]; + } else if (expr_operator === "ge") { + expr_operator = "le"; + expr_operands = [expr_operands[1], expr_operands[0]]; + } + if (other_operator === ">") { + other_operator = "<"; + other_operands = [other_operands[1], other_operands[0]]; + } else if (other_operator === "ge") { + other_operator = "le"; + other_operands = [other_operands[1], other_operands[0]]; + } - this.advance(); + if (expr_operator !== other_operator) { + return false; + } - if (this.token.token_type === '_') { - this.advance(); - let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); + // put in standard form + let expr_rhs = ['+', expr_operands[0], ['-', expr_operands[1]]]; + let other_rhs = ['+', other_operands[0], ['-', other_operands[1]]]; + let require_positive_proportion = (expr_operator !== "="); - // since baseFactor could return false, must check - if (subresult === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", - this.lexer.location); - } else { - throw new ParseError("Invalid location of '" + this.token.original_text + - "'", this.lexer.location); - } - } - result = ['_', result, subresult]; - } + return component_equals({ + expr: expr_context.fromAst(expr_rhs), + other: other_context.fromAst(other_rhs), + randomBindings: randomBindings, + expr_context: expr_context, + other_context: other_context, + allow_proportional: true, + require_positive_proportion: require_positive_proportion, + relative_tolerance, absolute_tolerance, tolerance_for_zero, + allowed_error_in_numbers: allowed_error_in_numbers, + include_error_in_number_exponents: include_error_in_number_exponents, + allowed_error_is_absolute: allowed_error_is_absolute, + rng, + }); - while (this.token.token_type === "'") { - result = ['prime', result]; - this.advance(); - } + } - if (this.token.token_type === '^') { - this.advance(); - result = ['^', result, this.factor({ parse_absolute_value: parse_absolute_value })]; - } + } - if (this.token.token_type === '(') { - this.advance(); - let parameters = this.statement_list(); + // if not special case, use standard numerical equality + return component_equals({ + expr: expr, + other: other, + randomBindings: randomBindings, + expr_context: expr_context, + other_context: other_context, + relative_tolerance, absolute_tolerance, tolerance_for_zero, + allowed_error_in_numbers: allowed_error_in_numbers, + include_error_in_number_exponents: include_error_in_number_exponents, + allowed_error_is_absolute: allowed_error_is_absolute, + rng, + }); - if (this.token.token_type !== ')') { - throw new ParseError('Expecting )', this.lexer.location); - } - this.advance(); + }; - if (parameters[0] === 'list') { - // rename from list to tuple - parameters[0] = 'tuple'; - } - result = ['apply', result, parameters]; - } else { - // if was an applied function symbol, - // cannot omit argument - if (must_apply) { - if (!this.allowSimplifiedFunctionApplication) - throw new ParseError("Expecting ( after function", - this.lexer.location); + const component_equals = function ({ expr, other, randomBindings, + expr_context, other_context, + allow_proportional = false, require_positive_proportion = false, + relative_tolerance, absolute_tolerance, tolerance_for_zero, + allowed_error_in_numbers, include_error_in_number_exponents, + allowed_error_is_absolute, + rng + }) { - // if allow simplied function application - // let the argument be the next factor - result = ['apply', result, this.factor({ parse_absolute_value: parse_absolute_value })]; - } - } - } else { + var max_value = Number.MAX_VALUE * 1E-20; + var min_nonzero_value = 0;//1E-100; //Number.MIN_VALUE & 1E20; - // determine if may be a derivative in Leibniz notation - if (this.parseLeibnizNotation) { + var minimum_matches = 10; + var number_tries = 100; + // if (allowed_error_in_numbers > 0) { + // minimum_matches = 400; + // number_tries = 4000; + // } - let original_state = this.return_state(); + // normalize function names, so in particular, e^x becomes exp(x) + expr = expr.normalize_function_names(); + other = other.normalize_function_names(); + + // convert subscripts to strings so that variables like x_t are considered single variable + expr = expr.subscripts_to_strings(); + other = other.subscripts_to_strings(); + + // Get set of variables mentioned in at least one of the two expressions + var variables = [expr.variables(), other.variables()]; + variables = variables.reduce(function (a, b) { return a.concat(b); }); + variables = variables.reduce(function (p, c) { + if (p.indexOf(c) < 0) p.push(c); + return p; + }, []); + + // pi, e, and i shouldn't be treated as a variable + // for the purposes of equality if they are defined as having values + if (math$19.define_pi) { + variables = variables.filter(function (a) { + return (a !== "pi"); + }); + } + if (math$19.define_i) { + variables = variables.filter(function (a) { + return (a !== "i"); + }); + } + if (math$19.define_e) { + variables = variables.filter(function (a) { + return (a !== "e"); + }); + } - let r = this.leibniz_notation(); + // determine if any of the variables are integers + // consider integer if is integer in either expressions' assumptions + var integer_variables = []; + for (let i = 0; i < variables.length; i++) + if (is_integer_ast(variables[i], expr_context.assumptions) + || is_integer_ast(variables[i], other_context.assumptions)) + integer_variables.push(variables[i]); + + // determine if any of the variables are functions + var functions = [expr.functions(), other.functions()]; + functions = functions.reduce(function (a, b) { return a.concat(b); }); + functions = functions.reduce(function (p, c) { + if (p.indexOf(c) < 0) p.push(c); + return p; + }, []); + functions = functions.filter(function (a) { + return a.length == 1; + }); - if (r) { - // successfully parsed derivative in Leibniz notation, so return - return r; - } - else { - // didn't find a properly format Leibniz notation - // so reset state and continue - this.set_state(original_state); - } - } + try { + var expr_f = expr.f(); + var other_f = other.f(); + } + catch (e) { + // Can't convert to mathjs to create function + // just check if equal via syntax + return expr.equalsViaSyntax(other) + } - // determine if should split text into single letter factors - let split = this.splitSymbols; + let expr_with_params, parameters_for_numbers; + let tolerance_function; - if (split) { - if (this.token.token_type === 'VARMULTICHAR' || - this.unsplitSymbols.includes(result) || - result.length === 1) { - split = false; - } else if (result.match(/[\d]/g)) { - // don't split if has a number in it - split = false; + if (allowed_error_in_numbers > 0) { + let result = replace_numbers_with_parameters({ + expr: expr, + variables: variables, + include_exponents: include_error_in_number_exponents, + }); + expr_with_params = expr_context.fromAst(result.expr_with_params); + parameters_for_numbers = result.parameters; + + let parameter_list = Object.keys(parameters_for_numbers); + if (parameter_list.length > 0) { + let derivative_sum = expr_with_params.derivative(parameter_list[0]); + if (!allowed_error_is_absolute) { + derivative_sum = derivative_sum + .multiply(parameters_for_numbers[parameter_list[0]]); + } + if (parameter_list.length > 1) { + for (let par of parameter_list.slice(1)) { + let term = expr_with_params.derivative(par); + if (!allowed_error_is_absolute) { + term = term.multiply(parameters_for_numbers[par]); + } + derivative_sum = derivative_sum.add(term); } } - if (split) { - // so that each character gets processed separately - // put all characters back on the input - // but with spaces - // then process again + let tolerance_expression = derivative_sum.multiply(allowed_error_in_numbers); - for (let i = result.length - 1; i >= 0; i--) { - this.lexer.unput(" "); - this.lexer.unput(result[i]); - } - this.advance(); + try { + tolerance_function = tolerance_expression.f(); + } catch (e) { + // can't create function out of derivative + // so can't compute tolerance that would correspond + // to the allowed error in numbers + + // Leave tolerance_function undefined - return this.baseFactor({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value, - allow_absolute_value_closing: allow_absolute_value_closing - }); - } else { - this.advance(); } - } - } else if (this.token.token_type === '(' || this.token.token_type === '[' || - this.token.token_type === '{') { - let token_left = this.token.token_type; - let expected_right, other_right; - if (this.token.token_type === '(') { - expected_right = ')'; - other_right = ']'; - } else if (this.token.token_type === '[') { - expected_right = ']'; - other_right = ')'; - } else { - expected_right = '}'; - other_right = null; + } - this.advance(); - result = this.statement_list(); + } - let n_elements = 1; - if (result[0] === "list") { - n_elements = result.length - 1; - } - if (this.token.token_type !== expected_right) { - if (n_elements !== 2 || other_right === null) { - throw new ParseError('Expecting ' + expected_right, - this.lexer.location); - } else if (this.token.token_type !== other_right) { - throw new ParseError('Expecting ) or ]', this.lexer.location); - } - // half-open interval - result[0] = 'tuple'; - result = ['interval', result]; - let closed; - if (token_left === '(') - closed = ['tuple', false, true]; - else - closed = ['tuple', true, false]; - result.push(closed); + var noninteger_binding_scale = 1; - } else if (n_elements >= 2) { - if (token_left === '(') { - result[0] = 'tuple'; - } else if (token_left === '[') { - result[0] = 'array'; - } else { - result[0] = 'set'; - } - } else if (token_left === '{') { - if (result[0] === '|' || result[0] === ':') { - result = ['set', result]; // set builder notation - } - else { - result = ['set', result]; // singleton set - } - } + var binding_scales = [10, 1, 100, 0.1, 1000, 0.01]; + var scale_num = 0; - this.advance(); + // Numerical test of equality + // If can find a region of the complex plane where the functions are equal + // at minimum_matches points, consider the functions equal + // unless the functions were always zero, in which case + // test at multiple scales to check for underflow - } else if (this.token.token_type === '|' && parse_absolute_value && - (inside_absolute_value === 0 || !allow_absolute_value_closing)) { + // In order to account for possible branch cuts, + // finding points where the functions are not equal does not lead to the + // conclusion that expression are unequal. Instead, to be consider unequal + // the functions must be unequal around many different points. - // allow the opening of an absolute value here if either - // - we aren't already inside an absolute value (inside_absolute_value==0), or - // - we don't allows an absolute value closing - // otherwise, skip this token so that will drop out the factor (and entire statement) - // to where the absolute value will close + let num_at_this_scale = 0; - inside_absolute_value += 1; + let always_zero = true; - this.advance(); + let num_finite_unequal = 0; - result = this.statement({ inside_absolute_value: inside_absolute_value }); - result = ['apply', 'abs', result]; + for (let i = 0; i < 10 * number_tries; i++) { + + // Look for a location where the magnitudes of both expressions + // are below max_value; + try { + var result = find_equality_region(binding_scales[scale_num], rng); + } + catch (e) { + continue; + } - if (this.token.token_type !== '|') { - throw new ParseError('Expecting |', this.lexer.location); + if (result.always_zero === false) { + always_zero = false; } - this.advance(); - } - if (this.token.token_type === '_') { - if (result === false) { - throw new ParseError("Invalid location of _", this.lexer.location); + if (!result.equal && !result.out_of_bounds && !result.always_zero && + result.sufficient_finite_values !== false + ) { + num_finite_unequal++; + if (num_finite_unequal > number_tries) { + return false; + } } - this.advance(); - let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); - if (subresult === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", this.lexer.location); - } else { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); + if (result.equal) { + if (result.always_zero) { + if (!always_zero) { + // if found always zero this time, but wasn't zero at a different point + // don't count as equal + continue; + } + // functions equal but zero + // repeat to make sure (changing if continuing to be zero) + num_at_this_scale += 1; + if (num_at_this_scale > 5) { + scale_num += 1; + num_at_this_scale = 0; + } + if (scale_num >= binding_scales.length) { + return true; // were equal and zero at all scales + } else + continue + } + else { + return true; } } - return ['_', result, subresult]; } + return false; - return result; - } - leibniz_notation() { - // attempt to find and return a derivative in Leibniz notation - // if unsuccessful, return false + function find_equality_region(noninteger_scale, rng) { - var result = this.token.token_text; + // Check if expr and other are equal in a region as follows + // 1. Randomly select bindings (use noninteger scale for non-integer variables) + // and evaluate expr and other at that point + // 2. If either value is too large, return { out_of_bounds: true } + // 3. If values are not equal (within tolerance), return { equal_at_start: false } + // 4. If functions are equal, then + // randomly select binding in neighborhood of that point + // (use non_integer scale/100 for non-integer variables) + // 5. If find a point where the functions are not equal, + // then return { equal_in_middle: false } + // 6. If find that functions are equal at minimum_matches points + // then return { equality: true, always_zero: always_zero } + // where always_zero is true if both functions were always zero + // and is false otherwise + // 7. If were unable to find sufficent points where both functions are finite + // return { sufficient_finite_values: false } + // If allow_proportional is true, then instead of return non-equal + // in step 3, use the ratio of value of these first evaluations to set + // the proportion, and base equality on remaining values having the + // same proportion - if (!(this.token.token_type === 'VAR' && (result[0] === "d" || result[0] === "∂") - && (result.length === 1 || (result.length === 2 && /[a-zA-Z]/.exec(result[1]))))) { - return false; - } - // found one of these two possibilities for start of derivative are - // - dx or ∂x (no space, x is a single letter) - // - d or ∂ - let deriv_symbol = result[0]; + var bindings = randomBindings(rng, variables, noninteger_scale); - let n_deriv = 1; + // replace any integer variables with integer + for (let i = 0; i < integer_variables.length; i++) { + bindings[integer_variables[i]] = generate_random_integer(-10, 10, rng); + } - let var1 = ""; - let var2s = []; - let var2_exponents = []; + // replace any function variables with a function + for (let i = 0; i < functions.length; i++) { + var a = generate_random_integer(-10, 10, rng); + var b = generate_random_integer(-10, 10, rng); + var c = generate_random_integer(-10, 10, rng); + bindings[functions[i]] = function (x) { + return math$19.add(math$19.multiply(math$19.add(math$19.multiply(a, x), b), x), c); + }; + } - if (result.length === 2) - var1 = result[1]; - else { // result is length 1 - // since have just a d or ∂ - // must be followed by a ^ or a VARMULTICHAR/VAR with no ∂ - this.advance(); - if (this.token.token_type === 'VARMULTICHAR' || - (this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) - ) { - var1 = this.token.token_text; + var bindingsIncludingParameters; + if (tolerance_function) { + bindingsIncludingParameters = Object.assign({}, bindings, parameters_for_numbers); } - else { - // since not VARMULTICHAR, must be a ^ next - if (this.token.token_type !== '^') { - return false; - } + var expr_evaluated = expr_f(bindings); + var other_evaluated = other_f(bindings); - // so far have d or ∂ followed by ^ - // must be followed by an integer - this.advance(); + var expr_abs = math$19.abs(expr_evaluated); + var other_abs = math$19.abs(other_evaluated); - if (this.token.token_type !== 'NUMBER') { - return false; - } + if (!(expr_abs < max_value && other_abs < max_value)) + return { out_of_bounds: true, always_zero: false }; - n_deriv = parseFloat(this.token.token_text); - if (!Number.isInteger(n_deriv)) { - return false; + if (!((expr_abs === 0 || expr_abs > min_nonzero_value) && + (other_abs === 0 || other_abs > min_nonzero_value))) + return { out_of_bounds: true, always_zero: false }; + + // now that found a finite point, + // check to see if expressions are nearly equal. + + var min_mag = Math.min(expr_abs, other_abs); + var max_mag = Math.max(expr_abs, other_abs); + var proportion = 1; + + let tol = 0; + if (tolerance_function) { + try { + tol = math$19.abs(tolerance_function(bindingsIncludingParameters)); + } catch (e) { + return { equal_at_start: false, always_zero: false }; + } + if (!Number.isFinite(tol)) { + return { equal_at_start: false, always_zero: false }; } + } - // see if next character is single character - this.advance(); + tol += min_mag * relative_tolerance; - // either a VAR with no ∂ - // or a VARMULTICHAR - if ((this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) - || this.token.token_type === 'VARMULTICHAR') { - var1 = this.token.token_text; + // never allow tol to get over 10% the min_mag + tol = Math.min(tol, 0.1 * min_mag); + + + // don't use min_mag to check for zero as mag will be zero + // for very small complex numbers + if (tol === 0 && (expr_evaluated === 0 || other_evaluated === 0)) { + tol += tolerance_for_zero; + } else { + tol += absolute_tolerance; + } + + if (!( + max_mag === 0 || + math$19.abs(math$19.subtract(expr_evaluated, other_evaluated)) < tol + )) { + if (!allow_proportional) { + return { equal_at_start: false, always_zero: false }; } - else { - return false; + // at this point, know both are not zero + if (expr_abs === 0 || other_abs === 0) { + return { equal_at_start: false, always_zero: false }; + } + + proportion = math$19.divide(expr_evaluated, other_evaluated); + if (require_positive_proportion && !(proportion > 0)) { + return { equal_at_start: false, always_zero: false }; } } - } - // next character must be a / - this.advance(); // allow a space this time + var always_zero = (max_mag === 0); - if (this.token.token_type !== '/') - return false; + // Look for a region around point + var finite_tries = 0; + for (let j = 0; j < 100; j++) { + var bindings2 = randomBindings( + rng, variables, noninteger_binding_scale / 100, bindings); - // find sequence of - // derivative symbol followed by a single character or VARMULTICHAR (with no space) - // optionally followed by a ^ and an integer (with no spaces) - // (with spaces allowed between elements of sequence) - // End when sum of exponents meets or exceeds n_deriv + // replace any integer variables with integer + for (let k = 0; k < integer_variables.length; k++) { + bindings2[integer_variables[k]] + = generate_random_integer(-10, 10, rng); + } - let exponent_sum = 0; + // replace any function variables with a function + for (let i = 0; i < functions.length; i++) { + var a = generate_random_integer(-10, 10, rng); + var b = generate_random_integer(-10, 10, rng); + var c = generate_random_integer(-10, 10, rng); + bindings2[functions[i]] = function (x) { + return math$19.add(math$19.multiply(math$19.add(math$19.multiply(a, x), b), x), c); + }; + } - this.advance(); // allow space just after the / + var bindings2IncludingParameters; + if (tolerance_function) { + bindings2IncludingParameters = Object.assign({}, bindings2, parameters_for_numbers); + } - while (true) { + try { + expr_evaluated = expr_f(bindings2); + other_evaluated = math$19.multiply(other_f(bindings2), proportion); + } + catch (e) { + continue; + } + expr_abs = math$19.abs(expr_evaluated); + other_abs = math$19.abs(other_evaluated); - // next must either be - // - a VAR whose first character matches derivative symbol - // and whose second character is a letter, or - // - a single character VAR that matches derivative symbol - // which must be followed by a VARMULTICHAR/VAR with no ∂ + if (expr_abs < max_value && other_abs < max_value) { + min_mag = Math.min(expr_abs, other_abs); + max_mag = Math.max(expr_abs, other_abs); - if (this.token.token_type !== 'VAR' || this.token.token_text[0] !== deriv_symbol) { - return false; - } + finite_tries++; - if (this.token.token_text.length > 2) { - // Put extra characters back on lexer - this.lexer.unput(this.token.token_text.slice(2)); + let tol = 0; + if (tolerance_function) { + try { + tol = math$19.abs(tolerance_function(bindings2IncludingParameters)); + } catch (e) { + continue; + } + if (!Number.isFinite(tol)) { + continue; + } + } + tol += min_mag * relative_tolerance; - // keep just two character token - this.token.token_text = this.token.token_text.slice(0, 2); + // never allow tol to get over 10% the min_mag + tol = Math.min(tol, 0.1 * min_mag); - } + // don't use min_mag to check for zero as mag will be zero + // for very small complex numbers + if (tol === 0 && (expr_evaluated === 0 || other_evaluated === 0)) { + tol += tolerance_for_zero; + } else { + tol += absolute_tolerance; + } - let token_text = this.token.token_text; + if (!( + max_mag === 0 || + math$19.abs(math$19.subtract(expr_evaluated, other_evaluated)) < tol + )) { + return { equality_in_middle: false, always_zero: false }; + } - // derivative symbol and variable together - if (token_text.length === 2) { - if (/[a-zA-Z]/.exec(token_text[1])) - var2s.push(token_text[1]); - else { - return false; - } - } - else { // token text was just the derivative symbol - this.advance(); + always_zero = always_zero && (max_mag === 0); - if (!((this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) - || this.token.token_type === 'VARMULTICHAR')) { - return false; + if (finite_tries >= minimum_matches) { + return { equal: true, always_zero: always_zero } + } } - var2s.push(this.token.token_text); } + return { sufficient_finite_values: false, always_zero: always_zero }; + } - // have derivative and variable, now check for optional ^ followed by number + }; - let this_exponent = 1; + function replace_numbers_with_parameters({ expr, variables, include_exponents = false }) { - let lastWasSpace = false; + // find all numbers, including pi and e, if defined as numerical + let parameters = {}; + let lastParNum = 0; - this.advance({ remove_initial_space: false }); - // if last token was a space advance to next non-space token - if (this.token.token_type === "SPACE") { - lastWasSpace = true; - this.advance(); + function get_new_parameter_name() { + lastParNum++; + let parName = "par" + lastParNum; + while (variables.includes(parName)) { + lastParNum++; + parName = "par" + lastParNum; } - if (this.token.token_type === '^') { - - this.advance(); + // found a new parameter name that isn't a variable + return parName; - if (this.token.token_type !== 'NUMBER') { - return false; - } + } - this_exponent = parseFloat(this.token.token_text); - if (!Number.isInteger(this_exponent)) { - return false; + function replace_number_sub(tree) { + if (typeof tree === 'number') { + if (tree === 0) { + // since will compute bounds for relative error in numbers + // can't include zero + return tree; + } else { + let par = get_new_parameter_name(); + parameters[par] = tree; + return par; } + } - lastWasSpace = false; - - this.advance({ remove_initial_space: false }); - // if last token was a space advance to next non-space token - if (this.token.token_type === "SPACE") { - lastWasSpace = true; - this.advance(); + if (typeof tree === "string") { + if (tree === "pi") { + if (math$19.define_pi) { + let par = get_new_parameter_name(); + parameters[par] = math$19.PI; + return par; + } + } else if (tree === "e") { + if (math$19.define_e) { + let par = get_new_parameter_name(); + parameters[par] = math$19.e; + return par; + } } + return tree; + } + if (!Array.isArray(tree)) { + return tree; } - var2_exponents.push(this_exponent); - exponent_sum += this_exponent; - if (exponent_sum > n_deriv) { - return false; + let operator = tree[0]; + let operands = tree.slice(1); + if (operator === "^" && !include_exponents) { + return [operator, replace_number_sub(operands[0]), operands[1]] + } else { + return [operator, ...operands.map(replace_number_sub)]; } - // possibly found derivative - if (exponent_sum === n_deriv) { + } - // check to make sure next token isn't another VAR or VARMULTICHAR - // in this case, the derivative isn't separated from what follows - if (!lastWasSpace && (this.token.token_type === "VAR" || this.token.token_type === "VARMULTICHAR")) { - return false; - } + // first evaluate numbers to combine then + // and turn any numerical constants to floating points + expr = expr.evaluate_numbers({ max_digits: Infinity }); + return { + expr_with_params: replace_number_sub(expr.tree), + parameters: parameters + } - // found derivative! + } - // if last token was a space advance to next non-space token - if (this.token.token_type === "SPACE") - this.advance(); + var alea = createCommonjsModule(function (module) { + // A port of an algorithm by Johannes Baagøe , 2010 + // http://baagoe.com/en/RandomMusings/javascript/ + // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror + // Original work is under MIT license - - let result_name = "derivative_leibniz"; - if (deriv_symbol === "∂") - result_name = "partial_" + result_name; + // Copyright (C) 2010 by Johannes Baagøe + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in + // all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + // THE SOFTWARE. - result = [result_name]; - if (n_deriv === 1) - result.push(var1); - else - result.push(["tuple", var1, n_deriv]); - let r2 = []; - for (let i = 0; i < var2s.length; i += 1) { - if (var2_exponents[i] === 1) - r2.push(var2s[i]); - else - r2.push(["tuple", var2s[i], var2_exponents[i]]); - } - r2 = ["tuple"].concat(r2); + (function(global, module, define) { - result.push(r2); + function Alea(seed) { + var me = this, mash = Mash(); - return result; - } - } - } -} + me.next = function() { + var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32 + me.s0 = me.s1; + me.s1 = me.s2; + return me.s2 = t - (me.c = t | 0); + }; -var textToAst$1 = new textToAst(); + // Apply the seeding algorithm from Baagoe. + me.c = 1; + me.s0 = mash(' '); + me.s1 = mash(' '); + me.s2 = mash(' '); + me.s0 -= mash(seed); + if (me.s0 < 0) { me.s0 += 1; } + me.s1 -= mash(seed); + if (me.s1 < 0) { me.s1 += 1; } + me.s2 -= mash(seed); + if (me.s2 < 0) { me.s2 += 1; } + mash = null; + } + + function copy(f, t) { + t.c = f.c; + t.s0 = f.s0; + t.s1 = f.s1; + t.s2 = f.s2; + return t; + } + function impl(seed, opts) { + var xg = new Alea(seed), + state = opts && opts.state, + prng = xg.next; + prng.int32 = function() { return (xg.next() * 0x100000000) | 0; }; + prng.double = function() { + return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 + }; + prng.quick = prng; + if (state) { + if (typeof(state) == 'object') copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; + } + + function Mash() { + var n = 0xefc8249d; + + var mash = function(data) { + data = String(data); + for (var i = 0; i < data.length; i++) { + n += data.charCodeAt(i); + var h = 0.02519603282416938 * n; + n = h >>> 0; + h -= n; + h *= n; + n = h >>> 0; + h -= n; + n += h * 0x100000000; // 2^32 + } + return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 + }; -function expand(expr_or_tree, no_division) { - // Initial implementation of expand - // Expands polynomials only up to degree 4 + return mash; + } - var tree = get_tree(expr_or_tree); - var transformations = []; - transformations.push([textToAst$1.convert("a*(b+c)"), textToAst$1.convert("a*b+a*c")]); - transformations.push([textToAst$1.convert("(a+b)*c"), textToAst$1.convert("a*c+b*c")]); - if(!no_division) - transformations.push([textToAst$1.convert("(a+b)/c"), textToAst$1.convert("a/c+b/c")]); - transformations.push([textToAst$1.convert("-(a+b)"), textToAst$1.convert("-a-b")]); - transformations.push([textToAst$1.convert("a(-b)"), textToAst$1.convert("-ab")]); - transformations.push([textToAst$1.convert("(a+b)^2"), textToAst$1.convert("a^2+2ab+b^2")]); - transformations.push([textToAst$1.convert("(a+b)^3"), textToAst$1.convert("a^3+3a^2b+3ab^2+b^3")]); - transformations.push([textToAst$1.convert("(a+b)^4"), textToAst$1.convert("a^4+4a^3b+6a^2b^2+4ab^3+b^4")]); - transformations.push([textToAst$1.convert("(-a)^2"), textToAst$1.convert("a^2")]); - transformations.push([textToAst$1.convert("(-a)^3"), textToAst$1.convert("-a^3")]); - transformations.push([textToAst$1.convert("(-a)^4"), textToAst$1.convert("a^4")]); + if (module && module.exports) { + module.exports = impl; + } else if (define && define.amd) { + define(function() { return impl; }); + } else { + this.alea = impl; + } - tree = applyAllTransformations(tree, transformations, 20); + })( + commonjsGlobal, + ('object') == 'object' && module, // present in node.js + (typeof undefined) == 'function' && undefined // present with an AMD loader + ); + }); - tree = flatten(tree); + var xor128 = createCommonjsModule(function (module) { + // A Javascript implementaion of the "xor128" prng algorithm by + // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper - tree = evaluate_numbers(tree); + (function(global, module, define) { - tree = collect_like_terms_factors(tree); + function XorGen(seed) { + var me = this, strseed = ''; - tree = normalize_negatives(tree); + me.x = 0; + me.y = 0; + me.z = 0; + me.w = 0; - return tree; -} + // Set up generator function. + me.next = function() { + var t = me.x ^ (me.x << 11); + me.x = me.y; + me.y = me.z; + me.z = me.w; + return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8); + }; -function expand_relations(expr_or_tree) { - var tree = get_tree(expr_or_tree); - return transform$2(tree, expand_relations_transform); -} + if (seed === (seed | 0)) { + // Integer seed. + me.x = seed; + } else { + // String seed. + strseed += seed; + } -function expand_relations_transform (ast) { - if(!Array.isArray(ast)) { - return ast; + // Mix in string seed, then discard an initial batch of 64 values. + for (var k = 0; k < strseed.length + 64; k++) { + me.x ^= strseed.charCodeAt(k) | 0; + me.next(); + } } - var operator = ast[0]; - var operands = ast.slice(1); - // since transforms in bottom up fashion, - // operands have already been expanded + function copy(f, t) { + t.x = f.x; + t.y = f.y; + t.z = f.z; + t.w = f.w; + return t; + } - if(operator === '=') { - if(operands.length <= 2) - return ast; - let result = ['and']; - for(let i=0; i < operands.length-1; i++) { - result.push(['=', operands[i], operands[i+1]]); + function impl(seed, opts) { + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (typeof(state) == 'object') copy(state, xg); + prng.state = function() { return copy(xg, {}); }; } - return result; + return prng; } - if(operator === 'gts' || operator === 'lts') { - let args = operands[0]; - let strict = operands[1]; - if(args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); + if (module && module.exports) { + module.exports = impl; + } else if (define && define.amd) { + define(function() { return impl; }); + } else { + this.xor128 = impl; + } + + })( + commonjsGlobal, + ('object') == 'object' && module, // present in node.js + (typeof undefined) == 'function' && undefined // present with an AMD loader + ); + }); + var xorwow = createCommonjsModule(function (module) { + // A Javascript implementaion of the "xorwow" prng algorithm by + // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper - let comparisons = []; - for(let i=1; i< args.length-1; i++) { - let new_operator; - if(strict[i]) { - if(operator === 'lts') - new_operator = '<'; - else - new_operator = '>'; - } - else { - if(operator === 'lts') - new_operator = 'le'; - else - new_operator = 'ge'; - } - comparisons.push([new_operator, args[i], args[i+1]]); - } + (function(global, module, define) { - let result = ['and', comparisons[0], comparisons[1]]; - for(let i=2; i>> 2)); + me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v; + return (me.d = (me.d + 362437 | 0)) + + (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0; + }; - let negate=false; - if(operator === 'notin' || operator === 'notni') - negate=true; + me.x = 0; + me.y = 0; + me.z = 0; + me.w = 0; + me.v = 0; - let x, interval; - if(operator === 'in' || operator === 'notin') { - x = operands[0]; - interval = operands[1]; + if (seed === (seed | 0)) { + // Integer seed. + me.x = seed; + } else { + // String seed. + strseed += seed; } - else { - x = operands[1]; - interval = operands[0]; + + // Mix in string seed, then discard an initial batch of 64 values. + for (var k = 0; k < strseed.length + 64; k++) { + me.x ^= strseed.charCodeAt(k) | 0; + if (k == strseed.length) { + me.d = me.x << 10 ^ me.x >>> 4; + } + me.next(); } + } + + function copy(f, t) { + t.x = f.x; + t.y = f.y; + t.z = f.z; + t.w = f.w; + t.v = f.v; + t.d = f.d; + return t; + } - // convert any tuples/arrays of length two to intervals - interval = to_intervals(interval); + function impl(seed, opts) { + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (typeof(state) == 'object') copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; + } - // if not interval, don't transform - if(interval[0] !== 'interval') - return ast; + if (module && module.exports) { + module.exports = impl; + } else if (define && define.amd) { + define(function() { return impl; }); + } else { + this.xorwow = impl; + } - let args = interval[1]; - let closed = interval[2]; - if(args[0] !== 'tuple' || closed[0] !== 'tuple') - throw new Error("Badly formed ast"); + })( + commonjsGlobal, + ('object') == 'object' && module, // present in node.js + (typeof undefined) == 'function' && undefined // present with an AMD loader + ); + }); - let a = args[1]; - let b = args[2]; + var xorshift7 = createCommonjsModule(function (module) { + // A Javascript implementaion of the "xorshift7" algorithm by + // François Panneton and Pierre L'ecuyer: + // "On the Xorgshift Random Number Generators" + // http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf - let comparisons = []; - if(closed[1]) { - if(negate) - comparisons.push(['<', x, a]); - else - comparisons.push(['ge', x, a]); - } - else { - if(negate) - comparisons.push(['le', x, a]); - else - comparisons.push(['>', x, a]); - } - if(closed[2]) { - if(negate) - comparisons.push(['>', x, b]); - else - comparisons.push(['le', x, b]); - } - else { - if(negate) - comparisons.push(['ge', x, b]); - else - comparisons.push(['<', x, b]); - } + (function(global, module, define) { - let result; - if(negate) - result = ['or'].concat(comparisons); - else - result = ['and'].concat(comparisons); + function XorGen(seed) { + var me = this; - return result; - } + // Set up generator function. + me.next = function() { + // Update xor generator. + var X = me.x, i = me.i, t, v; + t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24); + t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10); + t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3); + t = X[(i + 4) & 7]; v ^= t ^ (t << 7); + t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9); + X[i] = v; + me.i = (i + 1) & 7; + return v; + }; - // convert interval containment to inequalities - if(operator === 'subset' || operator === 'notsubset' || - operator === 'superset' || operator === 'notsuperset') { + function init(me, seed) { + var j, w, X = []; - let negate=false; - if(operator === 'notsubset' || operator === 'notsuperset') - negate=true; + if (seed === (seed | 0)) { + // Seed state array using a 32-bit integer. + w = X[0] = seed; + } else { + // Seed state using a string. + seed = '' + seed; + for (j = 0; j < seed.length; ++j) { + X[j & 7] = (X[j & 7] << 15) ^ + (seed.charCodeAt(j) + X[(j + 1) & 7] << 13); + } + } + // Enforce an array length of 8, not all zeroes. + while (X.length < 8) X.push(0); + for (j = 0; j < 8 && X[j] === 0; ++j); + if (j == 8) w = X[7] = -1; else w = X[j]; - let small, big; - if(operator === 'subset' || operator === 'notsubset') { - small = operands[0]; - big = operands[1]; - } - else { - small = operands[1]; - big = operands[0]; + me.x = X; + me.i = 0; + + // Discard an initial 256 values. + for (j = 256; j > 0; --j) { + me.next(); + } } - // convert any tuples/arrays of length two to intervals - small = to_intervals(small); - big = to_intervals(big); + init(me, seed); + } - // if not interval, don't transform - if(small[0] !== 'interval' || big[0] !== 'interval') - return ast; + function copy(f, t) { + t.x = f.x.slice(); + t.i = f.i; + return t; + } - let small_args = small[1]; - let small_closed = small[2]; - let big_args = big[1]; - let big_closed = big[2]; - if(small_args[0] !== 'tuple' || small_closed[0] !== 'tuple' || - big_args[0] !== 'tuple' || big_closed[0] !== 'tuple') - throw new Error("Badly formed ast"); - - let small_a = small_args[1]; - let small_b = small_args[2]; - let big_a = big_args[1]; - let big_b = big_args[2]; - - let comparisons = []; - if(small_closed[1] && !big_closed[1]) { - if(negate) - comparisons.push(['le', small_a,big_a]); - else - comparisons.push(['>', small_a,big_a]); - } - else { - if(negate) - comparisons.push(['<', small_a,big_a]); - else - comparisons.push(['ge', small_a,big_a]); - } - if(small_closed[2] && !big_closed[2]) { - if(negate) - comparisons.push(['ge', small_b,big_b]); - else - comparisons.push(['<', small_b,big_b]); - } - else { - if(negate) - comparisons.push(['>',small_b,big_b]); - else - comparisons.push(['le',small_b,big_b]); + function impl(seed, opts) { + if (seed == null) seed = +(new Date); + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (state.x) copy(state, xg); + prng.state = function() { return copy(xg, {}); }; } - let result; - if(negate) - result = ['or'].concat(comparisons); - else - result = ['and'].concat(comparisons); - - return result; - + return prng; } - return ast; -} + if (module && module.exports) { + module.exports = impl; + } else if (define && define.amd) { + define(function() { return impl; }); + } else { + this.xorshift7 = impl; + } -function substitute$1(pattern, bindings) { - var pattern_tree = get_tree(pattern); + })( + commonjsGlobal, + ('object') == 'object' && module, // present in node.js + (typeof undefined) == 'function' && undefined // present with an AMD loader + ); + }); - var bindings_tree = {}; - for(let b in bindings) { - bindings_tree[b] = get_tree(bindings[b]); - } + var xor4096 = createCommonjsModule(function (module) { + // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm. + // + // This fast non-cryptographic random number generator is designed for + // use in Monte-Carlo algorithms. It combines a long-period xorshift + // generator with a Weyl generator, and it passes all common batteries + // of stasticial tests for randomness while consuming only a few nanoseconds + // for each prng generated. For background on the generator, see Brent's + // paper: "Some long-period random number generators using shifts and xors." + // http://arxiv.org/pdf/1004.3115v1.pdf + // + // Usage: + // + // var xor4096 = require('xor4096'); + // random = xor4096(1); // Seed with int32 or string. + // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits. + // assert.equal(random.int32(), 1806534897); // signed int32, 32 bits. + // + // For nonzero numeric keys, this impelementation provides a sequence + // identical to that by Brent's xorgens 3 implementaion in C. This + // implementation also provides for initalizing the generator with + // string seeds, or for saving and restoring the state of the generator. + // + // On Chrome, this prng benchmarks about 2.1 times slower than + // Javascript's built-in Math.random(). - return substitute(pattern_tree, bindings_tree); + (function(global, module, define) { -} + function XorGen(seed) { + var me = this; -function substitute_component(pattern, component, value) { - let pattern_tree = get_tree(pattern); - let value_tree = get_tree(value); + // Set up generator function. + me.next = function() { + var w = me.w, + X = me.X, i = me.i, t, v; + // Update Weyl generator. + me.w = w = (w + 0x61c88647) | 0; + // Update xor generator. + v = X[(i + 34) & 127]; + t = X[i = ((i + 1) & 127)]; + v ^= v << 13; + t ^= t << 17; + v ^= v >>> 15; + t ^= t >>> 12; + // Update Xor generator array state. + v = X[i] = v ^ t; + me.i = i; + // Result is the combination. + return (v + (w ^ (w >>> 16))) | 0; + }; - if(typeof component === "number") { - component = [component]; + function init(me, seed) { + var t, v, i, j, w, X = [], limit = 128; + if (seed === (seed | 0)) { + // Numeric seeds initialize v, which is used to generates X. + v = seed; + seed = null; + } else { + // String seeds are mixed into v and X one character at a time. + seed = seed + '\0'; + v = 0; + limit = Math.max(limit, seed.length); + } + // Initialize circular array and weyl value. + for (i = 0, j = -32; j < limit; ++j) { + // Put the unicode characters into the array, and shuffle them. + if (seed) v ^= seed.charCodeAt((j + 32) % seed.length); + // After 32 shuffles, take v as the starting w value. + if (j === 0) w = v; + v ^= v << 10; + v ^= v >>> 15; + v ^= v << 4; + v ^= v >>> 13; + if (j >= 0) { + w = (w + 0x61c88647) | 0; // Weyl. + t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array. + i = (0 == t) ? i + 1 : 0; // Count zeroes. + } + } + // We have detected all zeroes; make the key nonzero. + if (i >= 128) { + X[(seed && seed.length || 0) & 127] = -1; + } + // Run the generator 512 times to further mix the state before using it. + // Factoring this as a function slows the main generator, so it is just + // unrolled here. The weyl generator is not advanced while warming up. + i = 127; + for (j = 4 * 128; j > 0; --j) { + v = X[(i + 34) & 127]; + t = X[i = ((i + 1) & 127)]; + v ^= v << 13; + t ^= t << 17; + v ^= v >>> 15; + t ^= t >>> 12; + X[i] = v ^ t; + } + // Storing state as object members is faster than using closure variables. + me.w = w; + me.X = X; + me.i = i; + } + + init(me, seed); + } + + function copy(f, t) { + t.i = f.i; + t.w = f.w; + t.X = f.X.slice(); + return t; } - else if(!Array.isArray(component)) { - throw Error("Invalid substitute_component: " + component); + function impl(seed, opts) { + if (seed == null) seed = +(new Date); + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (state.X) copy(state, xg); + prng.state = function() { return copy(xg, {}); }; + } + return prng; } + if (module && module.exports) { + module.exports = impl; + } else if (define && define.amd) { + define(function() { return impl; }); + } else { + this.xor4096 = impl; + } - let container_operators = ["list", "tuple", "vector", "array"]; + })( + commonjsGlobal, // window object or global + ('object') == 'object' && module, // present in node.js + (typeof undefined) == 'function' && undefined // present with an AMD loader + ); + }); - return substitute_component_sub(pattern_tree, component, value_tree); + var tychei = createCommonjsModule(function (module) { + // A Javascript implementaion of the "Tyche-i" prng algorithm by + // Samuel Neves and Filipe Araujo. + // See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf + + (function(global, module, define) { + + function XorGen(seed) { + var me = this, strseed = ''; + + // Set up generator function. + me.next = function() { + var b = me.b, c = me.c, d = me.d, a = me.a; + b = (b << 25) ^ (b >>> 7) ^ c; + c = (c - d) | 0; + d = (d << 24) ^ (d >>> 8) ^ a; + a = (a - b) | 0; + me.b = b = (b << 20) ^ (b >>> 12) ^ c; + me.c = c = (c - d) | 0; + me.d = (d << 16) ^ (c >>> 16) ^ a; + return me.a = (a - b) | 0; + }; + /* The following is non-inverted tyche, which has better internal + * bit diffusion, but which is about 25% slower than tyche-i in JS. + me.next = function() { + var a = me.a, b = me.b, c = me.c, d = me.d; + a = (me.a + me.b | 0) >>> 0; + d = me.d ^ a; d = d << 16 ^ d >>> 16; + c = me.c + d | 0; + b = me.b ^ c; b = b << 12 ^ d >>> 20; + me.a = a = a + b | 0; + d = d ^ a; me.d = d = d << 8 ^ d >>> 24; + me.c = c = c + d | 0; + b = b ^ c; + return me.b = (b << 7 ^ b >>> 25); + } + */ - function substitute_component_sub(tree, component, value_tree) { + me.a = 0; + me.b = 0; + me.c = 2654435769 | 0; + me.d = 1367130551; - if(component.length === 0) { - return value; - } - if(!Array.isArray(tree)) { - throw Error("Invalid substitute_component: expected list, tuple, vector, or array"); + if (seed === Math.floor(seed)) { + // Integer seed. + me.a = (seed / 0x100000000) | 0; + me.b = seed | 0; + } else { + // String seed. + strseed += seed; } - let operator = tree[0]; - let operands = tree.slice(1); - - if(!container_operators.includes(operator)) { - throw Error("Invalid substitute_component: expected list, tuple, vector, or array"); + // Mix in string seed, then discard an initial batch of 64 values. + for (var k = 0; k < strseed.length + 20; k++) { + me.b ^= strseed.charCodeAt(k) | 0; + me.next(); } + } - let ind = component[0]; - if(ind < 0 || ind > operands.length-1) { - throw Error("Invalid substitute_component: component out of range"); + function copy(f, t) { + t.a = f.a; + t.b = f.b; + t.c = f.c; + t.d = f.d; + return t; + } + function impl(seed, opts) { + var xg = new XorGen(seed), + state = opts && opts.state, + prng = function() { return (xg.next() >>> 0) / 0x100000000; }; + prng.double = function() { + do { + var top = xg.next() >>> 11, + bot = (xg.next() >>> 0) / 0x100000000, + result = (top + bot) / (1 << 21); + } while (result === 0); + return result; + }; + prng.int32 = xg.next; + prng.quick = prng; + if (state) { + if (typeof(state) == 'object') copy(state, xg); + prng.state = function() { return copy(xg, {}); }; } - let new_components = component.slice(1); - let result = substitute_component_sub(operands[ind], new_components, value_tree); + return prng; + } - return [operator, ...operands.slice(0,ind), result, ...operands.slice(ind+1)]; + if (module && module.exports) { + module.exports = impl; + } else if (define && define.amd) { + define(function() { return impl; }); + } else { + this.tychei = impl; } -} + })( + commonjsGlobal, + ('object') == 'object' && module, // present in node.js + (typeof undefined) == 'function' && undefined // present with an AMD loader + ); + }); -function get_component(pattern, component) { - let pattern_tree = get_tree(pattern); + var require$$2 = {}; - if(typeof component === "number") { - component = [component]; - } - else if(!Array.isArray(component)) { - throw Error("Invalid get_component: " + component); - } + var seedrandom$1 = createCommonjsModule(function (module) { + /* + Copyright 2019 David Bau. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - let container_operators = ["list", "tuple", "vector", "array"]; + */ - return get_component_sub(pattern_tree, component); + (function (global, pool, math) { + // + // The following constants are related to IEEE 754 limits. + // + var width = 256, // each RC4 output is 0 <= x < 256 + chunks = 6, // at least six RC4 outputs for each double + digits = 52, // there are 52 significant digits in a double + rngname = 'random', // rngname: name for Math.random and Math.seedrandom + startdenom = math.pow(width, chunks), + significance = math.pow(2, digits), + overflow = significance * 2, + mask = width - 1, + nodecrypto; // node.js crypto module, initialized at the bottom. - function get_component_sub(tree, component) { + // + // seedrandom() + // This is the seedrandom function described above. + // + function seedrandom(seed, options, callback) { + var key = []; + options = (options == true) ? { entropy: true } : (options || {}); + + // Flatten the seed string or build one from local entropy if needed. + var shortseed = mixkey(flatten( + options.entropy ? [seed, tostring(pool)] : + (seed == null) ? autoseed() : seed, 3), key); + + // Use the seed to initialize an ARC4 generator. + var arc4 = new ARC4(key); + + // This function returns a random double in [0, 1) that contains + // randomness in every bit of the mantissa of the IEEE 754 value. + var prng = function() { + var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 + d = startdenom, // and denominator d = 2 ^ 48. + x = 0; // and no 'extra last byte'. + while (n < significance) { // Fill up all significant digits by + n = (n + x) * width; // shifting numerator and + d *= width; // denominator and generating a + x = arc4.g(1); // new least-significant-byte. + } + while (n >= overflow) { // To avoid rounding up, before adding + n /= 2; // last byte, shift everything + d /= 2; // right using integer math until + x >>>= 1; // we have exactly the desired bits. + } + return (n + x) / d; // Form the number within [0, 1). + }; - if(component.length === 0) { - return tree; - } + prng.int32 = function() { return arc4.g(4) | 0; }; + prng.quick = function() { return arc4.g(4) / 0x100000000; }; + prng.double = prng; + + // Mix the randomness into accumulated entropy. + mixkey(tostring(arc4.S), pool); + + // Calling convention: what to return as a function of prng, seed, is_math. + return (options.pass || callback || + function(prng, seed, is_math_call, state) { + if (state) { + // Load the arc4 state from the given state if it has an S array. + if (state.S) { copy(state, arc4); } + // Only provide the .state method if requested via options.state. + prng.state = function() { return copy(arc4, {}); }; + } - if(!Array.isArray(tree)) { - throw Error("Invalid get_component: expected list, tuple, vector, or array"); - } + // If called as a method of Math (Math.seedrandom()), mutate + // Math.random because that is how seedrandom.js has worked since v1.0. + if (is_math_call) { math[rngname] = prng; return seed; } - let operator = tree[0]; - let operands = tree.slice(1); + // Otherwise, it is a newer calling convention, so return the + // prng directly. + else return prng; + })( + prng, + shortseed, + 'global' in options ? options.global : (this == math), + options.state); + } + + // + // ARC4 + // + // An ARC4 implementation. The constructor takes a key in the form of + // an array of at most (width) integers that should be 0 <= x < (width). + // + // The g(count) method returns a pseudorandom integer that concatenates + // the next (count) outputs from ARC4. Its return value is a number x + // that is in the range 0 <= x < (width ^ count). + // + function ARC4(key) { + var t, keylen = key.length, + me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; - if(!container_operators.includes(operator)) { - throw Error("Invalid get_component: expected list, tuple, vector, or array"); + // The empty key [] is treated as [0]. + if (!keylen) { key = [keylen++]; } + + // Set up S using the standard key scheduling algorithm. + while (i < width) { + s[i] = i++; + } + for (i = 0; i < width; i++) { + s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; + s[j] = t; } - let ind = component[0]; - if(ind < 0 || ind > operands.length-1) { - throw Error("Invalid get_component: component out of range"); + // The "g" method returns the next (count) outputs as one number. + (me.g = function(count) { + // Using instance members instead of closure state nearly doubles speed. + var t, r = 0, + i = me.i, j = me.j, s = me.S; + while (count--) { + t = s[i = mask & (i + 1)]; + r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; + } + me.i = i; me.j = j; + return r; + // For robust unpredictability, the function call below automatically + // discards an initial batch of values. This is called RC4-drop[256]. + // See http://google.com/search?q=rsa+fluhrer+response&btnI + })(width); + } + + // + // copy() + // Copies internal state of ARC4 to or from a plain object. + // + function copy(f, t) { + t.i = f.i; + t.j = f.j; + t.S = f.S.slice(); + return t; + } + // + // flatten() + // Converts an object tree to nested arrays of strings. + // + function flatten(obj, depth) { + var result = [], typ = (typeof obj), prop; + if (depth && typ == 'object') { + for (prop in obj) { + try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} + } } - let new_components = component.slice(1); - return get_component_sub(operands[ind], new_components); + return (result.length ? result : typ == 'string' ? obj : obj + '\0'); + } + // + // mixkey() + // Mixes a string seed into a key that is an array of integers, and + // returns a shortened string seed that is equivalent to the result key. + // + function mixkey(seed, key) { + var stringseed = seed + '', smear, j = 0; + while (j < stringseed.length) { + key[mask & j] = + mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); + } + return tostring(key); } -} + // + // autoseed() + // Returns an object for autoseeding, using window.crypto and Node crypto + // module if available. + // + function autoseed() { + try { + var out; + if (nodecrypto && (out = nodecrypto.randomBytes)) { + // The use of 'out' to remember randomBytes makes tight minified code. + out = out(width); + } else { + out = new Uint8Array(width); + (global.crypto || global.msCrypto).getRandomValues(out); + } + return tostring(out); + } catch (e) { + var browser = global.navigator, + plugins = browser && browser.plugins; + return [+new Date, global, plugins, global.screen, tostring(pool)]; + } + } -var transformation = /*#__PURE__*/Object.freeze({ - expand: expand, - expand_relations: expand_relations, - substitute: substitute$1, - substitute_component: substitute_component, - get_component: get_component -}); + // + // tostring() + // Converts an array of charcodes to a string + // + function tostring(a) { + return String.fromCharCode.apply(0, a); + } -function solve_linear(expr_or_tree, variable, assumptions) { - // assume expr is linear in variable + // + // When seedrandom.js is loaded, we immediately mix a few bits + // from the built-in RNG into the entropy pool. Because we do + // not want to interfere with deterministic PRNG state later, + // seedrandom will not call math.random on its own again after + // initialization. + // + mixkey(math.random(), pool); + // + // Nodejs and AMD support: export the implementation as a module using + // either convention. + // + if (('object') == 'object' && module.exports) { + module.exports = seedrandom; + // When in node.js, try using crypto package for autoseeding. + try { + nodecrypto = require$$2; + } catch (ex) {} + } else if ((typeof undefined) == 'function' && undefined.amd) { + undefined(function() { return seedrandom; }); + } else { + // When included as a plain script, set up Math.seedrandom global. + math['seed' + rngname] = seedrandom; + } - if(!(typeof variable === 'string')) - return undefined; - if(assumptions===undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); + // End anonymous scope, and pass initial values. + })( + // global: `self` in browsers (including strict mode and web workers), + // otherwise `this` in Node and other environments + (typeof self !== 'undefined') ? self : commonjsGlobal, + [], // pool: entropy pool starts empty + Math // math: package containing random, pow, and seedrandom + ); + }); - var tree = simplify$2(get_tree(expr_or_tree), assumptions); - //var tree = get_tree(expr_or_tree); + // A library of seedable RNGs implemented in Javascript. + // + // Usage: + // + // var seedrandom = require('seedrandom'); + // var random = seedrandom(1); // or any seed. + // var x = random(); // 0 <= x < 1. Every bit is random. + // var x = random.quick(); // 0 <= x < 1. 32 bits of randomness. - if(!Array.isArray(tree)) - return undefined; + // alea, a 53-bit multiply-with-carry generator by Johannes Baagøe. + // Period: ~2^116 + // Reported to pass all BigCrush tests. - var operator = tree[0]; - var operands = tree.slice(1); - if(!(operator === '=' || operator === 'ne' - || operator === '<' || operator === 'le' - || operator === '>' || operator === 'ge')) - return undefined; + // xor128, a pure xor-shift generator by George Marsaglia. + // Period: 2^128-1. + // Reported to fail: MatrixRank and LinearComp. - // set equal to zero, as lhs = 0 - var lhs = simplify$2(['+', operands[0], ['-', operands[1]]], - assumptions); + // xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl. + // Period: 2^192-2^32 + // Reported to fail: CollisionOver, SimpPoker, and LinearComp. - var no_var = tree => !variables(tree).includes(variable); - // factor out variable - var transformation = [ - ['+', ['*', '_a', variable], ['*', '_b', variable]], - ['*', ['+', '_a', '_b'], variable], - {variables: {_a: no_var, _b: no_var}, - allow_permutations: true, - allow_extended_match: true, - allow_implicit_identities: ['_a', '_b'], - evaluate_numbers: true, + // xorshift7, by François Panneton and Pierre L'ecuyer, takes + // a different approach: it adds robustness by allowing more shifts + // than Marsaglia's original three. It is a 7-shift generator + // with 256 bits, that passes BigCrush with no systmatic failures. + // Period 2^256-1. + // No systematic BigCrush failures reported. - }]; - lhs = simplify$2( - applyAllTransformations(lhs, [transformation], 20)); + // xor4096, by Richard Brent, is a 4096-bit xor-shift with a + // very long period that also adds a Weyl generator. It also passes + // BigCrush with no systematic failures. Its long period may + // be useful if you have many generators and need to avoid + // collisions. + // Period: 2^4128-2^32. + // No systematic BigCrush failures reported. - if(!variables(lhs).includes(variable)) - return undefined; - var pattern = ['+', ['*', '_a', variable], '_b']; + // Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random + // number generator derived from ChaCha, a modern stream cipher. + // https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf + // Period: ~2^127 + // No systematic BigCrush failures reported. - var params = { - variables: { _a: no_var, _b: no_var}, - allow_permutations: true, - allow_implicit_identities: ['_a', '_b'], - }; - var match$$1 = match(lhs, pattern, params); + // The original ARC4-based prng included in this library. + // Period: ~2^1600 - if(!match$$1) - return undefined; // not linear in variable - var a = simplify$2(match$$1['_a']); - var b = simplify$2(match$$1['_b']); + seedrandom$1.alea = alea; + seedrandom$1.xor128 = xor128; + seedrandom$1.xorwow = xorwow; + seedrandom$1.xorshift7 = xorshift7; + seedrandom$1.xor4096 = xor4096; + seedrandom$1.tychei = tychei; - if(!is_nonzero_ast(a, assumptions)) - return undefined; // can't confirm that there is a variable + var seedrandom$2 = seedrandom$1; - // equality or inequality with positive coefficient - if(operator === '=' || operator === 'ne' || is_positive_ast(a, assumptions)) { - let result = simplify$2(['/', ['-', b], a]); - return [operator, variable, result]; - } + //import { substitute_abs } from '../normalization/standard_form'; - if(!is_negative_ast(a, assumptions)) - return undefined; // couldn't determined sign and have inequality + function randomComplexBindings(rng, variables, radius, centers) { + var result = {}; - // have inequality with negative coefficient - var result = simplify$2(['/', ['-', b], a]); - if(operator === '<') - operator = '>'; - else if(operator === 'le') - operator = 'ge'; - else if(operator === '>') - operator = '<'; - else - operator = 'le'; + if (centers === undefined) { + variables.forEach(function (v) { + result[v] = math$19.complex(rng() * 2 * radius - radius, + rng() * 2 * radius - radius); + }); + } + else { + variables.forEach(function (v) { + result[v] = math$19.complex( + centers[v].re + rng() * 2 * radius - radius, + centers[v].im + rng() * 2 * radius - radius); + }); + } - return [operator, variable, result]; -} + return result; + } -var solve = /*#__PURE__*/Object.freeze({ - solve_linear: solve_linear -}); + const equals$1 = function (expr, other, + { relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, + allowed_error_in_numbers = 0, + include_error_in_number_exponents = false, + allowed_error_is_absolute = false, + } = {}) { -function clean_assumptions(tree, known) { - // normalize order and operators of assumptions in tree, - // remove any duplicates or those in known - // return ast or undefined if no assumptions found + let rng = seedrandom$2('complex_seed'); - if(!Array.isArray(tree) || tree.length === 0) - return tree; + //expr = expr.substitute_abs(); + //other = other.substitute_abs(); - tree= flatten( - default_order( - simplify_logical( - expand_relations(tree) - ) - ) - ); + // don't use complex equality if not analytic expression + // except abs is OK + if ((!expr.isAnalytic({ allow_abs: true, allow_relation: true })) || + (!other.isAnalytic({ allow_abs: true, allow_relation: true }))) + return false; - // check for duplicates (within tree or already in known) - var operator=tree[0]; - var operands=tree.slice(1); + return equals({ + expr: expr, + other: other, + randomBindings: randomComplexBindings, + expr_context: expr.context, + other_context: other.context, + relative_tolerance, absolute_tolerance, tolerance_for_zero, + allowed_error_in_numbers, + include_error_in_number_exponents, + allowed_error_is_absolute, + rng + }); + }; - if(operator === 'and' || operator === 'or') { - // remove duplicates, using trees.equal - operands = operands.reduce(function (a,b) { - if(a.every(function(v) { return !equal$2(v,b)})) - a.push(b); - return a; - },[]); + function randomRealBindings(rng, variables, radius, centers) { + var result = {}; - // if known exists, filter out those - if(operator === 'and' && known && Array.isArray(known)) { - let known_operands; - if(known[0] === 'and') - known_operands = known.slice(1); - else - known_operands = [known]; + if (centers === undefined) { + variables.forEach(function (v) { + result[v] = rng() * 2 * radius - radius; + }); + } + else { + variables.forEach(function (v) { + result[v] = centers[v] + rng() * 2 * radius - radius; + }); + } - operands = operands.filter( - v => known_operands.every(u => !equal$2(u, v)) - ); + return result; + } - } + const equals$2 = function (expr, other, + { relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, + allowed_error_in_numbers = 0, + include_error_in_number_exponents = false, + allowed_error_is_absolute = false, + } = {}) { - if(operands.length === 1) - tree = operands[0]; - else - tree = [operator].concat(operands); - } + // don't use real equality if not analytic expression + if ((!expr.isAnalytic()) || (!other.isAnalytic())) + return false; - // check if whole thing is known - if(operator !== 'and' && known && Array.isArray(known)) { - let known_operands; - if(known[0] === 'and') - known_operands = known.slice(1); - else - known_operands = [known]; + let rng = seedrandom('real_seed'); - if(!known_operands.every(u => !equal$2(u, tree))) - return undefined; - } + return equals({ + expr: expr, + other: other, + randomBindings: randomRealBindings, + expr_context: expr.context, + other_content: other.context, + relative_tolerance, absolute_tolerance, tolerance_for_zero, + allowed_error_in_numbers, + include_error_in_number_exponents, + allowed_error_is_absolute, + rng + }); + }; - return tree; -} + const equals$3 = function (expr, other, { + allowed_error_in_numbers = 0, + include_error_in_number_exponents = false, + allowed_error_is_absolute = false, + } = {}) { + return equal$2(expr.tree, other.tree, { + allowed_error_in_numbers: allowed_error_in_numbers, + include_error_in_number_exponents: include_error_in_number_exponents, + allowed_error_is_absolute: allowed_error_is_absolute, + }); + }; + const equals$$1 = function(expr, other, { min_elements_match=3, match_partial = false } = {} ) { -function calculate_derived_assumptions(assumptions, tree) { - // Calculate all assumptions on variables within tree that - // can be derived from the assumptions within tree, - // eliminating any assumptions that are already recorded - // in byvar or generic of assumptions - // - // if tree is undefined, calculate assumptions that can be - // derived from all given assumptions + // expr must be a discrete infinite set + if(!is_discrete_infinite_set(expr)) + return false; + // other must be a discrete infinite set or a list + if(is_discrete_infinite_set(other)) { + var assumptions = []; + let a = expr.context.get_assumptions(expr); + if(a !== undefined) + assumptions.push(a); + a = other.context.get_assumptions(other); + if(a !== undefined) + assumptions.push(a); + if(assumptions.length === 0) + assumptions = undefined; + else if(assumptions.length === 1) + assumptions=assumptions[0]; + else + assumptions = clean_assumptions(['and'].concat(assumptions)); - if(tree === undefined) { - tree = []; - for(let v in assumptions.byvar) { - let a = assumptions.byvar[v]; - if(a.length > 0) - tree.push(a); - } - if(tree.length === 0) - return {}; + if(match_partial) { + let match1 = contained_in(expr.tree, other.tree, assumptions, match_partial); + if(match1 === false) { + return 0; + } + let match2 = contained_in(other.tree, expr.tree, assumptions, match_partial); + if(match2 === false) { + return 0; + } - if(tree.length === 1) - tree = tree[0]; - else - tree = ['and'].concat(tree); + if(match1 === true) { + if(match2 === true) { + return 1; + } else { + return match2; + } + } else if(match2 === true) { + return match1; + } else { + return Math.min(match1, match2); + } - tree = clean_assumptions(tree); + } else { + return contained_in(expr.tree, other.tree, assumptions, match_partial) && + contained_in(other.tree, expr.tree, assumptions, match_partial); + } } + else { + // check if other is a list than ends in 'ldots' + let other_tree = other.tree; - if(!Array.isArray(tree) || tree.length === 0) - return {}; + if(other_tree[0] !== 'list') + return false; - var operator = tree[0]; - var operands = tree.slice(1); + let n_in_list = other_tree.length-2; - if(operator === 'and' || operator === 'or') { - let results = operands.map(function (v) { - return calculate_derived_assumptions(assumptions, v); - }); - - // array of all vars found in at least one result - let allvars = [...new Set(results.reduce( - (a,b) => [...a, ...Object.keys(b)], []))]; - - let derived = {}; - - for(let v of allvars) { - let res = results.reduce(function (a,b) { - if(b[v] !== undefined) - a.push(b[v]); - return a; - },[]); - - - // for OR, add only if obtain result for each operand - if(operator === 'and' || res.length === results.length) { - let new_derived = derived[v]; - if(new_derived === undefined) { - if(res.length > 1) - new_derived = [operator].concat(res); - else - new_derived = res[0]; - } - else { - if(res.length > 1) - new_derived = ['and', new_derived, - [operator].concat(res)]; - else - new_derived = ['and', new_derived, res[0]]; - } - - derived[v] = clean_assumptions( - new_derived, - get_assumptions(assumptions, v, {omit_derived: true})); - } - } - - return derived; - } - // Shouldn't get a NOT of (in)equality after simplifying logical - // if(operator === 'not') { - // let results = calculate_derived_assumptions(assumptions, operands[0]); - // for(let v of Object.keys(results)) { - // derived[v] = ['not', results[v]]; - // } - // return derived; - // } + if(other_tree[n_in_list+1][0] !== 'ldots') + return false; - let derived = {}; + if(n_in_list < min_elements_match) + return false; - if(operator === '=' || operator === 'ne' || - operator === '<' || operator === 'le' || - operator === 'in' || operator === 'subset' || - operator === 'notin' || operator === 'notsubset' - ) { + let the_list = other_tree.slice(0,n_in_list+1); - var addressed_assumption = false; - - // calculate derived if one side is equal to a variable - for(let ind = 0; ind < 2; ind++) { - let v = operands[ind]; - let other = operands[1-ind]; - let other_var = variables(other); - if((typeof v !== 'string') || other_var.length === 0 - || other_var.includes(v)) - continue; - - addressed_assumption = true; - - // look for any assumptions that from other that - // do not contain a v - var adjusted_op = operator; - if(ind === 1) { - if(operator === '<') - adjusted_op = '>'; - else if(operator === 'le') - adjusted_op = 'ge'; - else if(operator === 'in') - adjusted_op = 'ni'; - else if(operator === 'subset') - adjusted_op = 'superset'; - else if(operator === 'notin') - adjusted_op = 'notni'; - else if(operator === 'notsubset') - adjusted_op = 'notsuperset'; - } - let result = get_assumptions_for_expr( - assumptions, other, [v]); - - // combine with results for expr, if compatible - result = combine_assumptions(v, adjusted_op, other, result); - - if(result !== undefined) { - let new_derived = derived[v]; - - if(new_derived === undefined) { - new_derived = result; - } - else { - new_derived = ['and', new_derived, result]; - } - - derived[v] = clean_assumptions( - new_derived, get_assumptions( - assumptions, v, {omit_derived: true})); - - } - - } - if(addressed_assumption) - return derived; - } - - // if wasn't able to combine expressions, just add any assumptions - // on the operands - let results = []; + // get list of same size from + let generated_list = sequence_from_discrete_infinite(expr, n_in_list); - for(let op of operands) { - let res = get_assumptions_for_expr(assumptions, op, []); - if(res !== undefined) - results.push(res); - } + if(!generated_list) + return false; - if(results.length === 0) - return {}; + generated_list = ['list'].concat(generated_list); - if(results.length === 1) - results = results[0]; - else - results = ['and'].concat(results); + return equals$5(expr.context.from(generated_list), other.context.from(the_list)); - for(let v of variables(tree)) { - derived[v] = clean_assumptions( - results, get_assumptions( - assumptions, v, {omit_derived: true})); } - return derived; - -} + }; -function get_assumptions_for_expr(assumptions, expr, exclude_variables) { - // return any assumptions that can be calculated for expression expr - // that don't include exclude_variables - // - // The assumptions will be given directly in terms of expr when possible. + function is_discrete_infinite_set(expr) { - let variables$$1 = variables(expr); + var tree = expr.tree; + if(!Array.isArray(tree)) + return false; + if(tree[0] !== 'discrete_infinite_set') + return false; + var operands = tree.slice(1); - // filter out any of the excluded variables - variables$$1 = variables$$1.filter(v => !exclude_variables.includes(v)); + for(var v of operands) { + if(!Array.isArray(v)) + return false; + if(v[0] !== 'tuple') + return false; + if(v.length !== 5) + return false; + } - if(variables$$1.length === 0) - return undefined; + return true; + } - function isNumber(s) { - if (typeof s === 'number') - return true; - if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) - return true; - return false; - } - - // will proccess assumptions in case where variables are linear in expr - var pattern = ['_b']; - var implicit_identities = ['_b']; - var match_vars = {_b: isNumber}; - var coeff_mapping = {}; - for(let i=0; i < variables$$1.length; i++) { - let a = '_a' + i; - coeff_mapping[variables$$1[i]] = a; - pattern.push(['*', a, variables$$1[i]]); - implicit_identities.push(a); - match_vars[a] = isNumber; - } - - pattern = ['+'].concat(pattern); - - var m = match(expr, pattern, - {variables: match_vars, - allow_permutations: true, - allow_extended_match: false, - allow_implicit_identities: implicit_identities, - max_group: 1}); - - if(!m) { - // if not linear, get assumptions for each variable of expr - let results = []; - for(let v of variables(expr)) { - let res = get_assumptions_for_expr( - assumptions, v, exclude_variables); - if(res !== undefined) - results.push(res); - } - if(results.length === 0) - return undefined; - if(results.length === 1) - return results[0]; - return ['and'].concat(results); - } - - for(let v of variables$$1) - coeff_mapping[v] = m[coeff_mapping[v]]; - - let identity = false; - if(m["_b"] === 0 && m["_a0"] === 1 && variables$$1.length === 1) - identity = true; - - // find all assumptions involving variables but excluding exclude_variables - var new_assumptions; - new_assumptions = get_assumptions( - assumptions, [variables$$1], {exclude_variables: exclude_variables}); - - if(new_assumptions === undefined) - return undefined; - - return clean_assumptions(process_additional_assumptions(new_assumptions)); - - - function process_additional_assumptions(new_as) { - - if(!Array.isArray(new_as)) - return undefined; - - var operator = new_as[0]; - var operands = new_as.slice(1); - - if(operator === 'and' || operator === 'or') { - let results = operands - .map(process_additional_assumptions) - .filter(v => v !== undefined); - - if(results.length === 0) - return undefined; - if(operator === 'or') { - if(results.length === operands.length) - return ['or'].concat(results); - else - return undefined; - } - if(results.length === 1) - return results[0]; - else - return ['and'].concat(results); - } - - // can ignore NOTs, as simplify_logical should remove - // any before (in)equalities or containments - - if(!(['=', 'ne', '<', 'le'].includes(operator) || - (['in', 'notin', 'subset', 'notsubset'].includes(operator) - && identity))) { - - let new_exclude = exclude_variables.concat(variables(expr)); - let results = []; - for(let v of variables(new_as)) { - if(new_exclude.includes(v)) - continue; - let res = get_assumptions_for_expr(assumptions, v, new_exclude); - if(res !== undefined) - results.push(res); - } - if(results.length === 0) - return new_as; - if(results.length === 1) - return ['and', new_as, results[0]]; - return ['and', new_as].concat(results); - } - - let results = []; - - for(let ind=0; ind <= 1; ind++) { - let next_var = operands[ind]; - let next_rhs = operands[1-ind]; - - if((typeof next_var === 'string') && variables$$1.includes(next_var)) { - - var bindings = {}; - bindings[next_var] = next_rhs; - var new_expr = simplify$2(substitute(expr, bindings)); - - // may need to flip operator if it is an inequality - // Two factors could induce flipping - // - coefficient from expr is negative - // - switched sides in next inequality (ind === 1) - // The factors could cancel each other out - var flip = false; - var operator_eff = operator; - if((ind === 1 && coeff_mapping[next_var] > 0) || - (ind === 0 && coeff_mapping[next_var] < 0)) { - if(operator === '<') { - flip = true; - operator_eff = '>'; - } - else if(operator === 'le') { - flip = true; - operator_eff = 'ge'; - } - else if(operator === 'in') { - flip = true; - operator_eff = 'ni'; - } - else if(operator === 'subset') { - flip = true; - operator_eff = 'superset'; - } - else if(operator === 'notin') { - flip = true; - operator_eff = 'notni'; - } - else if(operator === 'notsubset') { - flip = true; - operator_eff = 'notsuperset'; - } - } - - if(flip) - results.push([operator, new_expr, expr]); - else - results.push([operator, expr, new_expr]); - - // look for more assumptions - let new_exclude = exclude_variables.concat([next_var]); - let res = get_assumptions_for_expr( - assumptions, new_expr, new_exclude); - // combine with results for expr, if compatible - res = combine_assumptions(expr, operator_eff, new_expr, res); - - if(res !== undefined) - results.push(res); - - } - } - - if(results.length === 1) - return results[0]; - else if(results.length > 1) - return ['and'].concat(results); - - // didn't address assumption - let new_exclude = exclude_variables.concat(variables(expr)); - results = []; - for(let v of variables(new_as)) { - if(new_exclude.includes(v)) - continue; - let res = get_assumptions_for_expr(assumptions, v, new_exclude); - if(res !== undefined) - results.push(res); - } - if(results.length === 0) - return new_as; - if(results.length === 1) - return ['and', new_as, results[0]]; - return ['and', new_as].concat(results); - } -} - - -function combine_assumptions(expr1, op1, expr2, new_as) { - // given the assumption "expr1 op1 expr2" and assumptions from new_as - // - return new assumptions involving expr1, if possible - // - return undefined if new_as appears to not affect expr1 - // - return new_as if new_as appear to affect expr1 but cannot - // be distilled to assumptions on expr1 - - if(!['=', 'ne', '<', 'le', '>', 'ge', 'in', 'notin', 'ni', 'notni', - 'subset', 'notsubset', 'superset', 'notsuperset'].includes(op1)) - return new_as; - - if(!Array.isArray(new_as)) - return undefined; - - var op2 = new_as[0]; - var operands2 = new_as.slice(1); - - if(op2 === 'and' || op2 === 'or') { - let results = operands2.map( - v => combine_assumptions(expr1, op1, expr2, v)) - .filter(v => v !== undefined); - - if(results.length === 0) - return undefined; - if(op2 === 'or') { - if(results.length === operands2.length) - return [['or'].concat(results)]; - else - return undefined; - } - if(results.length === 1) - return results[0]; - else - return ['and'].concat(results); - } - - if(!['=', 'ne', '<', 'le', 'in', 'notin', 'subset', 'notsubset'] - .includes(op2)) - return new_as; - - var op2_eff = op2; - var rhs; - if(equal$2(operands2[0], expr2)) { - rhs = operands2[1]; - } - else if(equal$2(operands2[1], expr2)) { - rhs = operands2[0]; - if(op2 === '<') - op2_eff = '>'; - else if(op2 === 'le') - op2_eff = 'ge'; - else if(op2 === 'in') - op2_eff = 'ni'; - else if(op2 === 'notin') - op2_eff = 'notni'; - else if(op2 === 'subset') - op2_eff = 'superset'; - else if(op2 === 'notsubset') - op2_eff = 'notsuperset'; - } - else { - return new_as; - } - - - // determined operator of combined expression - var combined_op; - if(op1 === '=') - combined_op = op2_eff; - else if(op2_eff === '=') - combined_op = op1; - else if(op1 === '<') { - if(op2_eff === '<' || op2_eff === 'le') - combined_op = '<'; - else if(op2_eff === 'in' || op2_eff === 'notin') - return new_as; - else - return undefined; // incompatible operators - } - else if(op1 === 'le') { - if(op2_eff === '<') - combined_op = '<'; - else if(op2_eff === 'le') - combined_op = 'le'; - else if(op2_eff === 'in' || op2_eff === 'notin') - return new_as; - else - return undefined; // incompatible operators - } - else if(op1 === '>') { - if(op2_eff === '>' || op2_eff === 'ge') - combined_op = '>'; - else if(op2_eff === 'in' || op2_eff === 'notin') - return new_as; - else - return undefined; // incompatible operators - } - else if(op1 === 'ge') { - if(op2_eff === '>') - combined_op = '>'; - else if(op2_eff === 'ge') - combined_op = 'ge'; - else if(op2_eff === 'in' || op2_eff === 'notin') - return new_as; - else - return undefined; // incompatible operators - } - else if(op1 === 'in') { - if(op2_eff === 'subset') - combined_op = 'in'; - else - return undefined; // incompatible operators - } - else if(op1 === 'notin') { - if(op2_eff === 'superset') - combined_op = 'notin'; - else - return undefined; // incompatible operators - } - else if(op1 === 'ni') { - if(op2_eff === 'notin') - combined_op = 'notsubset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'notni') { - if(op2_eff === 'in') - combined_op = 'notsuperset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'subset') { - if(op2_eff === 'subset') - combined_op = 'subset'; - else if(op2_eff === 'notni') - combined_op = 'notni'; - else if(op2_eff === 'notsuperset') - combined_op = 'notsuperset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'notsubset') { - if(op2_eff === 'superset') - combined_op = 'notsubset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'superset') { - if(op2_eff === 'superset') - combined_op = 'superset'; - else if(op2_eff === 'ni') - combined_op = 'ni'; - else if(op2_eff === 'notsubset') - combined_op = 'notsubset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'notsuperset') { - if(op2_eff === 'subset') - combined_op = 'notsuperset'; - else - return undefined; // incompatible operators - } - else - return undefined; - - - if(combined_op === '>') - return ['<', rhs, expr1]; - else if(combined_op === 'ge') - return ['le', rhs, expr1]; - else if(combined_op === 'ni') - return ['in', rhs, expr1]; - else if(combined_op === 'notni') - return ['notin', rhs, expr1]; - else if(combined_op === 'superset') - return ['subset', rhs, expr1]; - else if(combined_op === 'notsuperset') - return ['notsubset', rhs, expr1]; - else - return [combined_op, expr1, rhs]; -} + function contained_in(tree, i_set, assumptions, match_partial) { + // true if tree is contained in the discrete infinite set i_set + // tree is either a discrete infinite set + // or a tuple of form [offset, period, min_index, max_index] + if(tree[0] === 'discrete_infinite_set') { + if(match_partial) { + let num_matches = 0; + for(let piece of tree.slice(1)){ + let match = contained_in(piece, i_set, assumptions, match_partial); + if(match === true) { + num_matches++; + } else if(match !== false) { + num_matches += match; + } + } -function filter_assumptions_from_tree(tree, exclude_variables) { - // return an ast if found in tree assumptions without exclude_variables - // otherwise return undefined + let num_pieces = tree.length - 1; - if(!Array.isArray(tree) || tree.length === 0) { - return undefined; + if(num_matches === num_pieces) { + return true; + }else if(num_matches === 0) { + return false; + }else { + return num_matches/num_pieces; + } + } else { + return tree.slice(1).every(v => contained_in(v, i_set, assumptions)); + } } - if(!Array.isArray(exclude_variables)) - exclude_variables = [exclude_variables]; + // tree is a tuple of the form [offset, period, min_index, max_index] - var operator = tree[0]; - var operands = tree.slice(1); + var offset0 = tree[1]; + var period0 = tree[2]; + var min_index = tree[3]; + var max_index = tree[4]; + + // implemented only if min_index === -infinity and max_index === infinity + if(!Array.isArray(min_index) || min_index[0] !== '-' || min_index[1] !== Infinity + || max_index !== Infinity) + return false; - if(operator === 'and') { + // normalize to period 1 + offset0 = simplify$2( + ['/', offset0, period0], assumptions, Infinity); - var a= operands.map(function (v) { - return filter_assumptions_from_tree(v, exclude_variables); - }); + // if(!(typeof offset0 === 'number')) + // return false; - a=a.filter(v => v !== undefined); + var tuples = i_set.slice(1); - if(a.length === 0) - return undefined; - else if(a.length === 1) - return a[0]; - else - return ['and'].concat(a); - } + // data will be array of form [p, q, offset, period] + // where offset and period are normalized by period0 + // and p/q is fraction form of period - // if no intersection between exclude variables and variables in tree - // return tree - var tree_variables = variables(tree); - var contains_excluded = exclude_variables.filter( - (v) => tree_variables.includes(v)).length > 0; + var data = []; + for(let i=0; i 0) { - // only get assumptions that don't contain - // exclude variables - var byvar = filter_assumptions_from_tree( - assumptions.byvar[v], exclude_variables); - if(byvar !== undefined) - a.push(byvar); - } - if(assumptions.derived[v] && assumptions.derived[v].length > 0 - && !omit_derived) { - // only get derived assumptions that don't contain - // exclude variables - var da = filter_assumptions_from_tree( - assumptions.derived[v], exclude_variables); - if(da !== undefined) - a.push(da); - } - } - // if byvar and derived are undefined, - // then get assumptions from generic - else if(assumptions['generic'].length > 0) { - // if generic contains any variables other than x - // don't substitute those back into generic - if(v === 'x' || - !variables(assumptions['generic']).includes(v)) - a.push(substitute(assumptions['generic'], {x: v})); - } - }); - if(a.length === 1) - a=a[0]; - else if(a.length > 1) - a=['and'].concat(a); + let offset = simplify$2( + ['/', tuples[i][1], period0], assumptions, Infinity); + let period = simplify$2( + ['/', tuples[i][2], period0], assumptions, Infinity); - if(a.length > 0) - return clean_assumptions(a); - else - return undefined + if(typeof period !== 'number') + return false; + + let frac = math$19.fraction(period); + let p = frac.n; + let q = frac.d; + data.push([p,q,offset,period]); + } -} + // sort by p + data.sort(); -function get_assumptions(assumptions, variables_or_expr, params) { - // return an ast if found assumptions - // otherwise return undefined - // - // variables_or_expr - // - if a string or an array of an array, find assumptions on - // each of the variables represented by those strings - // directly from byvar and derived or from generic - // - if an ast, then - // - calculate assumptions of the expression itself, if possible, or - // - calculate assumptions on the variables of the expression. + // check any with period for which original period is a multiple + while(true) { + let p = data[0][0]; + if(p !== 1) + break; - // include any additional assumptions - // involving new variables found in assumptions + let offset = data[0][2]; + let period = data[0][3]; - if(params === undefined) - params = {}; - - var exclude_variables = params.exclude_variables; - if(exclude_variables === undefined) - exclude_variables = []; - else if(!Array.isArray(exclude_variables)) - exclude_variables = [exclude_variables]; - - var variables$$1; - var tree = get_tree(variables_or_expr); - - // if string, have a variable - if(typeof tree === "string") - variables$$1 = [tree]; - else if(!Array.isArray(tree)) - return undefined; - else if(Array.isArray(tree[0])) - // if array containing array, is list of variables - variables$$1 = tree[0]; - - - if(variables$$1) - return get_assumptions_sub(assumptions, variables$$1, - exclude_variables, params.omit_derived); - else - return get_assumptions_for_expr(assumptions, tree, exclude_variables) + // offsets match, then we've covered all of tree + let offset_diff = simplify$2( + expand( + ['+', offset, ['-', offset0]]), + assumptions, Infinity); -} + if(Number.isFinite(offset_diff) && Number.isFinite(period)) { + // use math.mod rather than % so it always non-negative + offset_diff = math$19.mod(offset_diff, period); + + if(math$19.min(offset_diff, period-offset_diff) < 1E-10*period) + return true; + } + data.splice(0,1); // remove first entry from data + if(data.length === 0) + return false; + } -function add_assumption(assumptions, expr_or_tree, exclude_generic) { - // add assumption in tree to assumptions - // if !exclude_generic, then add any generic assumptions to - // variables if they don't have previous assumptions - // return 1 if added assumption or 0 otherwise + var all_ps = [...new Set(data.map(v => v[0]))]; - var tree = get_tree(expr_or_tree); + let max_fraction_covered = 0; - if(!Array.isArray(tree)) - return 0; + for(let base_p of all_ps) { + // find all ps where base_p is a multiple + let options = data.map(function (v,i) { + let m = base_p/v[0]; + if(Number.isInteger(m)) + return [v[0], m, i]; + else + return undefined; + }).filter(v=>v); - tree = clean_assumptions(simplify$2(tree,assumptions)); + let covered = []; - var added = add_assumption_sub(assumptions, tree, exclude_generic); + for(let opt of options) { + let p = opt[0]; + let m = opt[1]; + let i = opt[2]; + let offset = data[i][2]; + let period = data[i][3]; - if(added) - assumptions.derived = calculate_derived_assumptions(assumptions); - return added; -} + for(let j=0; j < p; j++) { + let offset_diff = simplify$2( + expand( + ['+', offset, ['-', ['+', offset0, j]]]), + assumptions, Infinity); -function add_assumption_sub(assumptions, tree, exclude_generic) { - // add assumption in tree to assumptions - // if !exclude_generic, then add any generic assumptions to - // variables if they don't have previous assumptions - // return number of assumptions added + // use math.mod rather than % so it always non-negative + if(Number.isFinite(offset_diff) && Number.isFinite(period)) { + offset_diff = math$19.mod(offset_diff, period); - // if tree is an 'and', call once for each operand - // so that assumptions can be separated by variable - if(tree[0] === 'and') { - var results = tree.slice(1).map( - v => add_assumption_sub(assumptions, v, exclude_generic)); - return results.reduce(function (a,b) { return a + b;}); - } + if(math$19.min(offset_diff, period-offset_diff) < 1E-10*period) { - var variables$$1 = variables(tree); + for(let k=0; k 0) { - // check to see if any assumptions already for each variable - // if not, start by assigning generic assumptions - variables$$1.forEach(function (v) { - if(assumptions.byvar[v] === undefined) { + break; + } + } + } + } - // no previous assumptions, so - // include add assumption for v corresponding to generic - // unless non-x v is explicitly in generic - if(v === 'x' || - !variables(assumptions['generic']).includes(v)) { - add_assumption_sub( - assumptions, - substitute(assumptions['generic'], {x: v}), - true); - n_added += 1; - } + if(match_partial) { + let fraction_covered = 0; + for(let ind=0; ind < base_p; ind++) { + if(covered[ind]) { + fraction_covered++; + } + } + fraction_covered /= base_p; - } - }); + if(fraction_covered > max_fraction_covered) { + max_fraction_covered = fraction_covered; + } + } + } + if(match_partial && max_fraction_covered > 0) { + return max_fraction_covered; } + return false; - // attempt to solve for each variable - for(let variable of variables$$1) { + } - // solve using current state of assumptions - let solved = solve_linear(tree, variable, assumptions); - let new_a = tree; - if(solved) - new_a = solved; + function sequence_from_discrete_infinite(expr, n_elements) { - let current_a = assumptions['byvar'][variable]; + // assuming without checking that expr is discrete infinite set - if(current_a !== undefined && current_a.length !== 0) - new_a = ['and', current_a, new_a]; + var tree = expr.tree; + var operands = tree.slice(1); - new_a = clean_assumptions(new_a); + // implemented only if have just one tuple defining set + if(operands.length > 1) + return; - if(!equal$2(new_a, current_a)) { - assumptions['byvar'][variable] = new_a; - n_added +=1; - } - } + let offset = operands[0][1]; + let period = operands[0][2]; + let min_index = evaluate_numbers(operands[0][3]); + let max_index = operands[0][4]; - return n_added; + // implemented only if min_index is defined and an integer and max_index is infinity + if(!Number.isInteger(min_index) || max_index !== Infinity) + return; -} + let result = []; + for(let i=0; i < n_elements; i++) { + result.push(evaluate_numbers(['+', ['*', period, min_index+i], offset])); + } -function add_generic_assumption(assumptions, expr_or_tree) { - // add assumption in expr_or_tree to generic assumptions + return result; + } - // tree must contain the variable x - // the variable x represents any variable for which - // assumptions aren't specifically assigned + //exports.equalsViaFiniteField = equalsViaFiniteField; - // return 1 if added assumption or 0 otherwise + const equals$5 = function (expr, other, { + relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, + allowed_error_in_numbers = 0, + include_error_in_number_exponents = false, + allowed_error_is_absolute = false, + } = {}) { + if (expr.variables().includes('\uFF3F') || other.variables().includes('\uFF3F')) { + return false; + } - var tree = get_tree(expr_or_tree); + // first check with symbolic equality + // converting all numbers and numerical quantities to floating point + // and normalizing form of each expression + let exprNormalized = expr.evaluate_numbers({ max_digits: Infinity }) + .normalize_function_names() + .normalize_applied_functions() + .simplify(); + let otherNormalized = other.evaluate_numbers({ max_digits: Infinity }) + .normalize_function_names() + .normalize_applied_functions() + .simplify(); + + if (exprNormalized.equalsViaSyntax(otherNormalized, { + allowed_error_in_numbers, + include_error_in_number_exponents, + allowed_error_is_absolute, + }) + ) { + return true; + } else if (expr.equalsViaComplex(other, { + relative_tolerance, absolute_tolerance, tolerance_for_zero, + allowed_error_in_numbers, + include_error_in_number_exponents, + allowed_error_is_absolute, + })) { + return true; + // } else if (expr.equalsViaReal(other)) { + // return true; + } else if (equals$$1(expr, other)) { + return true; + } else { + return false; + } + }; - if(!Array.isArray(tree)) - return 0; + var equality = /*#__PURE__*/Object.freeze({ + equals: equals$5, + equalsViaComplex: equals$1, + equalsViaReal: equals$2, + equalsViaSyntax: equals$3, + equalsDiscreteInfinite: equals$$1 + }); - tree = clean_assumptions(simplify$2(tree,assumptions)); + const equalWithSignErrors = function (expr, other, + { equalityFunction = equals$5, max_sign_errors = 1 } = {} + ) { - var added = add_generic_assumption_sub(assumptions, tree); + if (equalityFunction(expr, other)) { + return { matched: true, n_sign_errors: 0 }; + } - if(added) - assumptions.derived = calculate_derived_assumptions(assumptions); + for (let i = 1; i <= max_sign_errors; i++) { + if (equalSpecifiedSignErrors(expr, other, { equalityFunction, n_sign_errors: i })) { + return { matched: true, n_sign_errors: i }; + } + } - return added; -} + return { matched: false }; + }; -function add_generic_assumption_sub(assumptions, tree) { + const equalSpecifiedSignErrors = function (expr, other, + { equalityFunction = equals$5, n_sign_errors = 1 } = {} + ) { - // if tree is an 'and', call once for each operand - // so that assumptions involving one variable can be separated - if(tree[0] === 'and') { - var results = tree.slice(1).map( - v => add_generic_assumption_sub(assumptions, v)); - return results.reduce(function (a,b) { return a + b;}); + if (n_sign_errors === 0) { + return equalityFunction(expr, other); + } else if (!(Number.isInteger(n_sign_errors) && n_sign_errors > 0)) { + throw Error(`Have not implemented equality check with ${n_sign_errors} sign errors.`) } - var variables$$1 = variables(tree); + if (n_sign_errors > 1) { + let oldEqualityFunction = equalityFunction; + equalityFunction = function (expr, other) { + return equalSpecifiedSignErrors(expr, other, { equalityFunction: oldEqualityFunction, n_sign_errors: n_sign_errors - 1}); + }; + } - if(!variables$$1.includes('x')) - return 0; + var root = expr.tree; + var stack = [[root]]; + var pointer = 0; + var tree; + var i; - // attempt to solve for x - // solve using current state of assumptions - let solved = solve_linear(tree, 'x', assumptions); + /* Unfortunately the root is handled separately */ + expr.tree = ['-', root]; + var equals$$2 = equalityFunction(expr, other); + expr.tree = root; - let new_a = tree; - if(solved) - new_a = solved; + if (equals$$2) return true; - let current_a = assumptions['generic']; + while (tree = stack[pointer++]) { + tree = tree[0]; - if(current_a.length !== 0) - new_a = ['and', current_a, new_a]; + if (!Array.isArray(tree)) { + continue; + } - new_a = clean_assumptions(new_a); + for (i = 1; i < tree.length; i++) { + stack.push([tree[i]]); + tree[i] = ['-', tree[i]]; + equals$$2 = equalityFunction(expr, other); + tree[i] = tree[i][1]; - if(equal$2(new_a, current_a)) { - return 0; + if (equals$$2) return true; + } } - assumptions['generic'] = new_a; + return false; + }; + + var sign_error = /*#__PURE__*/Object.freeze({ + equalSpecifiedSignErrors: equalSpecifiedSignErrors, + equalWithSignErrors: equalWithSignErrors + }); - return 1; -} + function add$2(expr_or_tree1, expr_or_tree2) { + var result = ['+', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; + return clean(result); + } + function subtract$2(expr_or_tree1, expr_or_tree2) { + var result = ['+', get_tree(expr_or_tree1), ['-', get_tree(expr_or_tree2)]]; + return clean(result); + } -function remove_assumption(assumptions, expr_or_tree) { + function multiply$2(expr_or_tree1, expr_or_tree2) { + var result = ['*', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; + return clean(result); + } - var tree=get_tree(expr_or_tree); + function divide$2(expr_or_tree1, expr_or_tree2) { + var result = ['/', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; + return clean(result); + } - if(!Array.isArray(tree)) - return 0; + function pow$2(expr_or_tree1, expr_or_tree2) { + var result = ['^', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; + return clean(result); + } - tree = clean_assumptions(simplify$2(tree,assumptions)); + function mod$2(expr_or_tree1, expr_or_tree2) { + var result = ['apply', 'mod', ['tuple', get_tree(expr_or_tree1), + get_tree(expr_or_tree2)]]; + return clean(result); + } - var removed = remove_assumption_sub(assumptions, tree); + function copy(expr_or_tree) { + return get_tree(expr_or_tree); + } - if(removed) - assumptions.derived = calculate_derived_assumptions(assumptions); + var arithmetic$1 = /*#__PURE__*/Object.freeze({ + add: add$2, + subtract: subtract$2, + multiply: multiply$2, + divide: divide$2, + pow: pow$2, + mod: mod$2, + copy: copy + }); - return removed; + var analytic_operators = ['+', '-', '*', '/', '^', 'tuple', 'vector', 'list', 'array', 'matrix', 'interval']; + var analytic_functions = ["exp", "log", "log10", "sqrt", "factorial", "gamma", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec']; + var relation_operators = ['=', 'le', 'ge', '<', '>']; -} + function isAnalytic(expr_or_tree, { allow_abs = false, allow_relation = false } = {}) { + var tree = normalize_applied_functions( + normalize_function_names(expr_or_tree)); -function remove_assumption_sub(assumptions, tree) { + tree = subscripts_to_strings(tree); + var operators_found = operators$1(tree); + for (let i = 0; i < operators_found.length; i++) { + let oper = operators_found[i]; + if (analytic_operators.indexOf(oper) === -1) { + if (allow_relation) { + if (relation_operators.indexOf(oper) === -1) { + return false; + } + } else { + return false; + } + } + } - // if tree is an 'and', call once for each operand - // so that assumptions can be separated by variable - if(tree[0] === 'and') { - var results = tree.slice(1).map(v => remove_assumption_sub( - assumptions, v)); - return results.reduce(function (a,b) { return a+b;}); + var functions_found = functions(tree); + for (let i = 0; i < functions_found.length; i++) { + let fun = functions_found[i]; + if (analytic_functions.indexOf(fun) === -1) { + if ((!allow_abs) || fun !== "abs") + return false; + } } - var variables$$1 = variables(tree); + return true; + } + + var analytic = /*#__PURE__*/Object.freeze({ + isAnalytic: isAnalytic + }); - if(variables$$1.length === 0) - return 0; + function create_discrete_infinite_set({ + offsets, + periods, + min_index = ['-', Infinity], + max_index = Infinity, + } = {}) { - var n_removed = 0; + offsets = get_tree(offsets); + periods = get_tree(periods); + min_index = get_tree(min_index); + max_index = get_tree(max_index); - // attempt to solve for each variable - for(let variable of variables$$1) { - // solve using current state of assumptions - let solved = solve_linear(tree, variable, assumptions); - let current = assumptions['byvar'][variable]; + if(offsets === undefined || periods === undefined) + return undefined; - // didn't find any assumptions to remove - if(!current || current.length === 0) { - continue; - } + let results = []; + if(offsets[0] === 'list') { + if(periods[0] === 'list') { + if(offsets.length !== periods.length || offsets.length === 1) + return undefined; + for(let i=1; i !(equal$2(v, tree) || equal$2(v,solved))); + function matrix$4(entries){ //entries is an array of arrays of math expressions + var expression=[]; + expression.push('matrix'); + var r = entries.length; + var c = entries[0].length; + for (let i = 1; i < r; i++){ + if (entries[i].length !== c){ //check if columns are equal size + throw new Error("Matrix dimensions mismatch"); + } + } + expression.push(tuple([r,c])); + let theMatrix = []; + for (let j = 0; j < r; j++){ + theMatrix.push(tuple(entries[j].map(function(v) {return v.tree;}))); + } + expression.push(tuple(theMatrix)); + return expression; + } - if(operands.length === 0) { - result = []; - } - else if(operands.length === 1) { - result = operands[0]; - } - else if(operands.length < n_op) { - result = [operator].concat(operands); - } - else { - // didn't find anything to remove - continue - } - } - else { - if(equal$2(current, tree) || equal$2(current, solved)) { - result = []; - } - else { - // didn't find anything to remove - continue; - } - } + function vector_add(v1, v2){ + v1 = get_tree(v1); + v2 = get_tree(v2); + + if(v1.length !== v2.length || (v1[0] !== 'tuple' && v1[0] !== 'vector') || (v2[0] !== 'tuple' && v2[0] !== 'vector')) { + throw new Error("Can't add. Those aren't vectors, or the dimensions don't match"); + } + var v_sum = ['vector']; + var len = v1.length; + for (let i = 1; i < len; i = i+1){ + v_sum.push(['+', v1[i], v2[i]]); + } + return simplify$2(v_sum); + } - n_removed += 1; - assumptions['byvar'][variable] = result; + function scalar_mul(k, v){ + v = get_tree(v); + + if(v[0] !== 'tuple' && v[0] !== 'vector'){ + throw new Error("Can't scalar multiply. Isn't a vector"); + } + var v_prod = ['vector']; + var len = v.length; + for (let i = 1; i < len; i = i+1){ + v_prod.push(['*', v[i], k]); + } + return simplify$2(v_prod); + } - } + function vector_sub(v1, v2){ + return vector_add(v1, scalar_mul(-1, v2)); + } - return n_removed; + function dot_prod(v1, v2){ + v1 = get_tree(v1); + v2 = get_tree(v2); + + if(v1.length !== v2.length || (v1[0] !== 'tuple' && v1[0] !== 'vector') || (v2[0] !== 'tuple' && v2[0] !== 'vector')) { + throw new Error("Can't take dot product. Those aren't vectors, or the dimensions don't match"); + } + var sum = 0; + var term = 0; + var len = v1.length; + for (let i = 1; i < len; i = i+1){ + term = ['*', v1[i], v2[i]]; + sum = ['+', sum, term]; + } + return simplify$2(sum); + } -} + function cross_prod(v1, v2){ + v1 = get_tree(v1); + v2 = get_tree(v2); + + if((v1[0] !== 'tuple' && v1[0] !== 'vector') || (v2[0] !== 'tuple' && v2[0] !== 'vector')){ + throw new Error("Can't take cross product. Those aren't vectors"); + } + + if (v1.length === 3 && v2.length === 3){ + return simplify$2(['+', ['*', v1[1], v2[2]], ['-', ['*', v1[2], v2[1]]]]); + } + + if (v1.length === 4 && v2.length === 4){ + var x_coord = ['+', ['*', v1[2], v2[3]], ['-',['*', v1[3], v2[2]]]]; + var y_coord = ['+', ['*', v1[3], v2[1]], ['-',['*', v1[1], v2[3]]]]; + var z_coord = ['+', ['*', v1[1], v2[2]], ['-',['*', v1[2], v2[1]]]]; + return simplify$2(['vector', x_coord, y_coord, z_coord]); + } + + throw new Error("Can't take cross product. The dimensions aren't both 2 or 3."); + } -function remove_generic_assumption(assumptions, expr_or_tree) { - // remove assumption in expr_or_tree from generic assumptions + var matrix$5 = /*#__PURE__*/Object.freeze({ + matrix: matrix$4, + vector_add: vector_add, + scalar_mul: scalar_mul, + vector_sub: vector_sub, + dot_prod: dot_prod, + cross_prod: cross_prod + }); - // return 1 if removed assumption or 0 otherwise + /* + * convert syntax trees to Guppy XML representations + * + * Copyright 2017 by Jim Fowler + * + * This file is part of a math-this.expressions library + * + * math-this.expressions is free software: you can redistribute + * it and/or modify it under the this.terms of the GNU General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or at your option any later version. + * + * math-this.expressions is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ + + + + + class astToGuppy{ + constructor(){ + this.operators = { + "+": function(operands) { return operands.join( '+' ); }, + "-": function(operands) { return "-" + operands.join( '-' ) + ""; }, + "*": function(operands) { return operands.join( '\\cdot*' ); }, + "/": function(operands) { return astToGuppy.dfrac(operands[0], operands[1]); }, + "^": function(operands) { return astToGuppy.power(operands[0],operands[1]); }, + "sin": function(operands) { return astToGuppy.trig("sin",operands[0]); }, + "cos": function(operands) { return astToGuppy.trig("cos",operands[0]); }, + "tan": function(operands) { return astToGuppy.trig("tan",operands[0]); }, + "arcsin": function(operands) { return astToGuppy.trig("arcsin",operands[0]); }, + "arccos": function(operands) { return astToGuppy.trig("arccos",operands[0]); }, + "arctan": function(operands) { return astToGuppy.trig("arctan",operands[0]); }, + "arccsc": function(operands) { return astToGuppy.trig("arccsc",operands[0]); }, + "arcsec": function(operands) { return astToGuppy.trig("arcsec",operands[0]); }, + "arccot": function(operands) { return astToGuppy.trig("arccot",operands[0]); }, + "csc": function(operands) { return astToGuppy.trig("csc",operands[0]); }, + "sec": function(operands) { return astToGuppy.trig("sec",operands[0]); }, + "cot": function(operands) { return astToGuppy.trig("cot",operands[0]); }, + "log": function(operands) { return astToGuppy.trig("log",operands[0]); }, + "exp": function(operands) { return astToGuppy.trig("exp",operands[0]); }, + "ln": function(operands) { return astToGuppy.trig("ln",operands[0]); }, + "sqrt": function(operands) { return astToGuppy.sqrt(operands[0]); }, + "abs": function(operands) { return astToGuppy.abs(operands[0]); }, + //"factorial": function(operands) { return operands[0] + "!"; }, + }; - var tree=get_tree(expr_or_tree); + } - if(!Array.isArray(tree)) - return 0; + static dfrac(a,b) { + return '\\dfrac{}{}\\frac{}{}()/()' + a + '' + b + ''; + } - tree = clean_assumptions(simplify$2(tree,assumptions)); + static trig(name, parameter ) { + return '\\' + name + '\\left(\\right) ' + name + '()' + parameter + ''; + } - var removed = remove_generic_assumption_sub(assumptions, tree); + static sqrt(x) { + return '\\sqrt{}sqrt()' + x + ''; + } - if(removed) - assumptions.derived = calculate_derived_assumptions(assumptions); + static power(x,y) { + return '{}^{}()^()' + x + '' + y + ''; + } - return removed; -} + static abs(x) { + return '\\left|\\right|abs()' + x + ''; + } + static paren(x) { + return '\\left(\\right)()' + x + ''; + } -function remove_generic_assumption_sub(assumptions, tree) { + static isFunctionSymbol( symbol ){ + var functionSymbols = ['sin', 'cos', 'tan', 'csc', 'sec', 'cot', 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'log', 'ln', 'exp', 'sqrt', 'abs', 'this.factorial']; + return (functionSymbols.indexOf(symbol) !== -1); + } - // if tree is an 'and', call once for each operand - // so that assumptions involving one variable can be separated - if(tree[0] === 'and') { - var results = tree.slice(1).map(v => remove_generic_assumption_sub( - assumptions, v)); - return results.reduce(function (a,b) { return a+b;}); + static isGreekLetterSymbol( symbol ){ + var greekSymbols = ['pi', 'theta', 'theta', 'Theta', 'alpha', 'nu', 'beta', 'xi', 'Xi', 'gamma', 'Gamma', 'delta', 'Delta', 'pi', 'Pi', 'epsilon', 'epsilon', 'rho', 'rho', 'zeta', 'sigma', 'Sigma', 'eta', 'tau', 'upsilon', 'Upsilon', 'iota', 'phi', 'phi', 'Phi', 'kappa', 'chi', 'lambda', 'Lambda', 'psi', 'Psi', 'omega', 'Omega']; + return (greekSymbols.indexOf(symbol) !== -1); } - var variables$$1 = variables(tree); + factorWithParenthesesIfNegated(tree){ + var result = this.factor(tree); - if(!variables$$1.includes('x')) - return 0; + if (result.toString().match( /^-/ )) + return astToGuppy.paren( result.toString() ); - var current = assumptions['generic']; + // else + return result; + } - if(current.length === 0) - return 0; - // solve using current state of assumptions - let solved = solve_linear(tree, 'x', assumptions); - // remove any occurence of tree from current - var operator=current[0]; - var operands=current.slice(1); - var n_op = operands.length; - var result; + /* + this.factor = + '(' this.expression ')' | + number | + variable | + function this.factor | + this.factor '^' this.factor + '-' this.factor | + nonMinusthis.factor + */ - if(operator === 'and') { - // remove any match, using trees.equal - operands = operands.filter( - v => !(equal$2(v, tree) || equal$2(v,solved))); - - if(operands.length === 0) { - result = []; - } - else if(operands.length === 1) { - result = operands[0]; - } - else if(operands.length < n_op) { - result = [operator].concat(operands); - } - else { - // didn't find anything to remove - return 0; - } - } - else { - if(equal$2(current, tree) || equal$2(current, solved)) { - result = []; - } - else { - // didn't find anything to remove - return 0; - } - } - - assumptions['generic'] = result; - - return 1; -} - - -function initialize_assumptions() { - var assumptions = {}; - assumptions['byvar'] = {}; - assumptions['derived'] = {}; - assumptions['generic'] = []; - assumptions['not_commutative'] = []; - assumptions['get_assumptions'] = function(v, params) { - return get_assumptions(assumptions, v, params); - }; - assumptions['add_assumption'] = function(v, exclude_generic) { - return add_assumption(assumptions, v, exclude_generic); - }; - assumptions['add_generic_assumption'] = function(v) { - return add_generic_assumption(assumptions, v); - }; - assumptions['remove_assumption'] = function(v) { - return remove_assumption(assumptions, v); - }; - assumptions['remove_generic_assumption'] = function(v) { - return remove_generic_assumption(assumptions, v); - }; - - return assumptions; -} - -/* - * convert syntax trees back to LaTeX code - * - * Copyright 2014-2017 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - -const operators$3 = { - "+": function(operands) { - return operands.join(' '); - }, - "-": function(operands) { - return "- " + operands[0]; - }, - "*": function(operands) { - return operands.join(" "); - }, - "/": function(operands) { - return "\\frac{" + operands[0] + "}{" + operands[1] + "}"; - }, - "_": function(operands) { - return operands[0] + "_{" + operands[1] + "}"; - }, - "^": function(operands) { - return operands[0] + "^{" + operands[1] + "}"; - }, - "prime": function(operands) { - return operands[0] + "'"; - }, - "tuple": function(operands) { - return '\\left( ' + operands.join(', ') + ' \\right)'; - }, - "array": function(operands) { - return '\\left[ ' + operands.join(', ') + ' \\right]'; - }, - "list": function(operands) { - return operands.join(', '); - }, - "set": function(operands) { - return '\\left\\{ ' + operands.join(', ') + ' \\right\\}'; - }, - "vector": function(operands) { - return '\\left( ' + operands.join(', ') + ' \\right)'; - }, - "interval": function(operands) { - return '\\left( ' + operands.join(', ') + ' \\right)'; - }, - "matrix": function(operands) { - return '\\left( ' + operands.join(', ') + ' \\right)'; - }, - "and": function(operands) { - return operands.join(' \\land '); - }, - "or": function(operands) { - return operands.join(' \\lor '); - }, - "not": function(operands) { - return '\\lnot ' + operands[0]; - }, - "=": function(operands) { - return operands.join(' = '); - }, - "<": function(operands) { - return operands.join(' < '); - }, - ">": function(operands) { - return operands.join(' > '); - }, - "lts": function(operands) { - return operands.join(' < '); - }, - "gts": function(operands) { - return operands.join(' > '); - }, - "le": function(operands) { - return operands.join(' \\le '); - }, - "ge": function(operands) { - return operands.join(' \\ge '); - }, - "ne": function(operands) { - return operands.join(' \\ne '); - }, - "in": function(operands) { - return operands[0] + " \\in " + operands[1]; - }, - "notin": function(operands) { - return operands[0] + " \\notin " + operands[1]; - }, - "ni": function(operands) { - return operands[0] + " \\ni " + operands[1]; - }, - "notni": function(operands) { - return operands[0] + " \\not\\ni " + operands[1]; - }, - "subset": function(operands) { - return operands[0] + " \\subset " + operands[1]; - }, - "notsubset": function(operands) { - return operands[0] + " \\not\\subset " + operands[1]; - }, - "superset": function(operands) { - return operands[0] + " \\supset " + operands[1]; - }, - "notsuperset": function(operands) { - return operands[0] + " \\not\\supset " + operands[1]; - }, - "union": function(operands) { - return operands.join(' \\cup '); - }, - "intersect": function(operands) { - return operands.join(' \\cap '); - }, - "derivative_leibniz": function (operands) { - return "\\frac{d" + operands[0] + "}{d" + operands[1] + "}"; - }, - "partial_derivative_leibniz": function (operands) { - return "\\frac{d" + operands[0] + "}{d" + operands[1] + "}"; - }, - "|": function (operands) { - return operands[0] + " \\mid " + operands[1]; - }, - ":": function (operands) { - return operands[0] + " : " + operands[1]; - }, -}; - -// defaults for parsers if not overridden by context - - -// allowed multicharacter latex symbols -// in addition to the below applied function symbols -const allowedLatexSymbolsDefault = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'partial', "abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg']; - -const matrixEnvironmentDefault = 'bmatrix'; - -class astToLatex { - - constructor({ - allowedLatexSymbols=allowedLatexSymbolsDefault, - matrixEnvironment=matrixEnvironmentDefault, - } = {}){ - this.allowedLatexSymbols = allowedLatexSymbols; - this.matrixEnvironment = matrixEnvironment; - } - - convert(tree) { - return this.statement(tree); - } - - statement(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.single_statement(tree); - } + factor(tree) { + if (typeof tree === 'string') { + if (astToGuppy.isGreekLetterSymbol(tree)) { + return '\\' + tree + ' $' + tree + ''; + } - var operator = tree[0]; - var operands = tree.slice(1); + return '' + tree + ''; + } - if(operator === 'ldots') - return '\\ldots'; + if (typeof tree === 'number') { + return '' + tree + ''; + } - if ((!(operator in operators$3)) && operator !== "apply") - throw new Error("Badly formed ast: operator " + operator + " not recognized."); + var operator = tree[0]; + var operands = tree.slice(1); - if (operator === 'and' || operator === 'or') { - return operators$3[operator](operands.map(function(v, i) { - let result = this.single_statement(v); - // for clarity, add parenthesis unless result is - // single quantity (with no spaces) or already has parens - if (result.toString().match(/ /) && - (!(result.toString().match(/^\\left\(.*\\right\)$/)))) - return '\\left(' + result + '\\right)'; - else - return result; - }.bind(this))); - } - return this.single_statement(tree); - } + if(operator === "apply") { + operator = tree[1]; + operands = tree.slice(2); + } - single_statement(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.expression(tree); - } + // Absolute value doesn't need any special parentheses handling, but its operand is really an this.expression + if (operator === "abs") { + return this.operators[operator]( operands.map( function(v,i) { return this.expression(v); }.bind(this) )); + } else if (astToGuppy.isFunctionSymbol(operator)) { + if ((operator === 'this.factorial') && ((operands[0].toString().length === 1) || (operands[0].toString().match( /^[0-9]*$/ )))) + return this.operators[operator]( operands ); - var operator = tree[0]; - var operands = tree.slice(1); + return this.operators[operator]( operands.map( function(v,i) { + var result = this.factor(v); + return result; + }.bind(this))); + } - if (operator === 'not') { - return operators$3[operator](operands.map(function(v, i) { - let result = this.single_statement(v); - // for clarity, add parenthesis unless result is - // single quantity (with no spaces) or already has parens - if (result.toString().match(/ /) && - (!(result.toString().match(/^\\left\(.*\\right\)$/)))) - return '\\left(' + result + '\\right)'; - else - return result; - }.bind(this))); - } + if (operator === "^") { + return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); + } + + if (operator === '~') { + return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); + } - if ((operator === '=') || (operator === 'ne') || - (operator === '<') || (operator === '>') || - (operator === 'le') || (operator === 'ge') || - (operator === 'in') || (operator === 'notin') || - (operator === 'ni') || (operator === 'notni') || - (operator === 'subset') || (operator === 'notsubset') || - (operator === 'superset') || (operator === 'notsuperset')) { - return operators$3[operator](operands.map(function(v, i) { - return this.expression(v); - }.bind(this))); + return astToGuppy.paren( this.expression(tree) ); } - if (operator === 'lts' || operator === 'gts') { - let args = operands[0]; - let strict = operands[1]; - if (args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); + /* + this.term = + this.term '*' this.factor | + this.term nonMinusthis.factor | + this.term '/' this.factor | + this.factor + */ - let result = this.expression(args[1]); - for (let i = 1; i < args.length - 1; i++) { - if (strict[i]) { - if (operator === 'lts') - result += " < "; - else - result += " > "; - } - else { - if (operator === 'lts') { - result += " \\le "; - } - else { - result += " \\ge "; - } + term(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.factor(tree); } - result += this.expression(args[i + 1]); - } - return result; - } - return this.expression(tree); - } + var operator = tree[0]; + var operands = tree.slice(1); - expression(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.term(tree); - } + if (operator === '*') { + return this.operators[operator]( operands.map( function(v,i) { + var result = this.factorWithParenthesesIfNegated(v); - var operator = tree[0]; - var operands = tree.slice(1); + if (result.toString().match( /^[0-9]/ ) && (i > 0)) + return ' * ' + result; + else + return result; + }.bind(this))); + } - if (operator === '+') { - return operators$3[operator](operands.map(function(v, i) { - if (i > 0) - return this.termWithPlusIfNotNegated(v); - else - return this.term(v); - }.bind(this))); - } + if (operator === '/') { + return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); + } - if ((operator === 'union') || (operator === 'intersect')) { - return operators$3[operator](operands.map(function(v, i) { - return this.term(v); - }.bind(this))); + return this.factor(tree); } - return this.term(tree); - } + /* + this.expression = + this.expression '+' this.term | + this.expression '-' this.term | + this.term + */ - term(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.factor(tree); - } + expression(tree) { + if ((typeof tree === 'string') || (typeof tree === 'number')) { + return this.term(tree); + } - var operator = tree[0]; - var operands = tree.slice(1); + var operator = tree[0]; + var operands = tree.slice(1); - if (operator === '-') { - return operators$3[operator](operands.map(function(v, i) { - return this.term(v); - }.bind(this))); - } - if (operator === '*') { - return operators$3[operator](operands.map(function(v, i) { - let result; - if (i > 0) { - result = this.factorWithParenthesesIfNegated(v); - if (result.toString().match(/^[0-9]/)) - return '\\cdot ' + result; - else - return '\\, ' + result + if ((operator === '+') || (operator === '-')) { + return this.operators[operator]( operands.map( function(v,i) { return this.factorWithParenthesesIfNegated(v); }.bind(this) )); } - else - return this.factor(v); - }.bind(this))); + + return this.term(tree); } - if (operator === '/') { - return operators$3[operator](operands.map(function(v, i) { - return this.expression(v); - }.bind(this))); + + convert(tree){ + return ('' + this.expression(tree) + '').replace(/<\/e>/g,''); } - return this.factor(tree); } - simple_factor_or_function_or_parens(tree) { - // return true if - // factor(tree) is a single character - // or tree is a non-negative number not in scientific notation - // or tree is a string - // or tree is a function call other than sqrt - // or factor(tree) is in parens + /* + * convert syntax trees to GLSL representations + * + * Copyright 2014-2018 by + * Jim Fowler + * Duane Nykamp + * + * This file is part of a math-expressions library + * + * math-expressions is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or at your option any later version. + * + * math-expressions is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ - var result = this.factor(tree); - if (result.toString().length === 1 || - (typeof tree === 'string') || - (tree[0] === 'apply' && tree[1] !== "sqrt") || - result.toString().match(/^\\left\(.*\\right\)$/) - ) { - return true; - } else if (typeof tree === "number") { - if(tree >= 0 && !tree.toString().includes('e')) { - return true; - } else { - return false; - } - } else { - return false - } - } + const glslOperators = { + "+": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = result + "+" + rhs; }); return result; }, + "-": function(operands) { var result = "-" + operands[0]; operands.slice(1).forEach(function(rhs) { result = result + "-" + rhs; }); return result; }, + "~": function(operands) { var result = "vec2(0.0,0.0)"; operands.forEach(function(rhs) { result = result + "-" + rhs; }); return result; }, + "*": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = "cmul(" + result + "," + rhs + ")"; }); return result; }, + "/": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = "cdiv(" + result + "," + rhs + ")"; }); return result; }, - stringConvert(string) { - if (string.length > 1) { - if(this.allowedLatexSymbols.includes(string)) - return "\\" + string; - else - return "\\var{" + string + '}'; - } - return string; - } + "sin": function(operands) { return "csin(" + operands[0] + ")"; }, + "cos": function(operands) { return "ccos(" + operands[0] + ")"; }, + "tan": function(operands) { return "ctan(" + operands[0] + ")"; }, - factor(tree) { - if (typeof tree === 'string') { - return this.stringConvert(tree); - } + "sinh": function(operands) { return "csinh(" + operands[0] + ")"; }, + "cosh": function(operands) { return "ccosh(" + operands[0] + ")"; }, + + "arcsin": function(operands) { return "carcsin(" + operands[0] + ")"; }, + "arccos": function(operands) { return "carccos(" + operands[0] + ")"; }, + "arctan": function(operands) { return "carctan(" + operands[0] + ")"; }, - if (typeof tree === 'number') { - if(tree === Infinity) - return "\\infty"; - else if(tree === -Infinity) - return "-\\infty"; - else { - let numberString = tree.toString(); - let eIndex = numberString.indexOf('e'); - if(eIndex === -1) { - return numberString; - } - let num = numberString.substring(0,eIndex); - let exponent = numberString.substring(eIndex+1); + "arccsc": function(operands) { return "carcsin(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, + "arcsec": function(operands) { return "carccos(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, + "arccot": function(operands) { return "carctan(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, - return num + " \\cdot 10^{" + exponent + "}"; - } - } + "csc": function(operands) { return "ccsc(" + operands[0] + ")"; }, + "sec": function(operands) { return "csec(" + operands[0] + ")"; }, + "cot": function(operands) { return "ccot(" + operands[0] + ")"; }, - var operator = tree[0]; - var operands = tree.slice(1); + "exp": function(operands) { return "cexp(" + operands[0] + ")"; }, + "conj": function(operands) { return "conjugate(" + operands[0] + ")"; }, + + "sqrt": function(operands) { return "cpower(" + operands[0] + ",vec2(0.5,0.0))"; }, + "log": function(operands) { return "clog(" + operands[0] + ")"; }, + "ln": function(operands) { return "clog(" + operands[0] + ")"; }, + "^": function(operands) { return "cpower(" + operands[0] + "," + operands[1] + ")"; }, + + "abs": function(operands) { return "cabs(" + operands[0] + ")"; }, + "apply": function(operands) { return "vec2(NaN,NaN)"; }, + }; - if (operator === "^") { - let operand0 = this.factor(operands[0]); + class astToGLSL { + constructor() { + } + + convert(tree) { + if (typeof tree === 'boolean') + throw Error("no support for boolean"); - // so that f_(st)'^2(x) doesn't get extra parentheses - // (and no longer recognized as function call) - // check for simple factor after removing primes - let remove_primes = operands[0]; - while (remove_primes[0] === 'prime') { - remove_primes = remove_primes[1]; + + if (typeof tree === 'string') { + if (tree === "e") + return "vec2(2.71828182845905,0.0)"; + + if (tree === "pi") + return "vec2(3.14159265358979,0.0)"; + + if (tree === "i") + return "vec2(0.0,1.0)"; + + return String(tree); + } + + if (typeof tree === 'number') { + return "vec2(" + String(tree) + ",0.0)"; } + + if (("real" in tree) && ("imaginary" in tree)) + return tree; - if (!(this.simple_factor_or_function_or_parens(remove_primes) || - (remove_primes[0] === '_' && (typeof remove_primes[1] === 'string')) - )) - operand0 = '\\left(' + operand0.toString() + '\\right)'; + if (!Array.isArray(tree)) { + throw Error("Invalid ast"); + } - return operand0 + '^{' + this.statement(operands[1]) + '}'; - } - else if (operator === "_") { - let operand0 = this.factor(operands[0]); - if (!(this.simple_factor_or_function_or_parens(operands[0]))) - operand0 = '\\left(' + operand0.toString() + '\\right)'; + + var operator = tree[0]; + var operands = tree.slice(1); - return operand0 + '_{' + this.statement(operands[1]) + '}'; - } - else if (operator === "prime") { - let op = operands[0]; + if(operator === "apply") { + if(typeof operands[0] !== 'string') + throw Error("Non string functions not implemented for conversion to GLSL"); - let n_primes = 1; - while (op[0] === "prime") { - n_primes += 1; - op = op[1]; + var operator = operands[0]; + var operands = operands.slice(1); + + return glslOperators[operator]( operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); } - - let result = this.factor(op); - - if (!(this.simple_factor_or_function_or_parens(op) || - (op[0] === '_' && (typeof op[1] === 'string')) - )) - result = '\\left(' + result.toString() + '\\right)'; - for (let i = 0; i < n_primes; i++) { - result += "'"; + + if (operator in glslOperators) { + return glslOperators[operator]( operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); } - return result; - } - else if (operator === "-") { - return operators$3[operator](operands.map(function(v, i) { - return this.factor(v); - }.bind(this))); - } - else if (operator === 'tuple' || operator === 'array' || - operator === 'list' || - operator === 'set' || operator === 'vector' || - operator === '|' || operator === ':') { - return operators$3[operator](operands.map(function(v, i) { - return this.statement(v); - }.bind(this))); + + throw Error("Operator " + operator + " not implemented for conversion to mathjs"); + } + } - } - else if (operator === 'interval') { + var astToLatex$2 = new astToLatex(); + var astToText$2 = new astToText(); + var astToGuppy$1 = new astToGuppy(); + var astToGLSL$1 = new astToGLSL(); - let args = operands[0]; - let closed = operands[1]; - if (args[0] !== 'tuple' || closed[0] !== 'tuple') - throw new Error("Badly formed ast"); + const tex = function(expr) { + return astToLatex$2.convert( expr.tree ); + }; - let result = this.statement(args[1]) + ", " + - this.statement(args[2]); + const toLatex = tex; - if (closed[1]) - result = '\\left[ ' + result; - else - result = '\\left( ' + result; + const toString = function(expr) { + return astToText$2.convert( expr.tree ); + }; - if (closed[2]) - result = result + ' \\right]'; - else - result = result + ' \\right)'; + const toGLSL = function(expr) { + return astToGLSL$1.convert( expr.tree ); + }; - return result; + const toXML = function(expr) { + return astToGuppy$1.convert( expr.tree ); + }; - } - else if (operator === 'matrix') { - let size = operands[0]; - let args = operands[1]; + var printing = /*#__PURE__*/Object.freeze({ + tex: tex, + toLatex: toLatex, + toString: toString, + toXML: toXML, + toGLSL: toGLSL + }); - let result = '\\begin{' + this.matrixEnvironment + '} '; + const integrateNumerically = function(expr, x,a,b) { + var intervals = 100; + var total = 0.0; + var bindings = {}; - for(let row = 0; row < size[1]; row += 1) { - for(let col = 0; col < size[2]; col += 1) { - result = result + this.statement(args[row+1][col+1]); - if(col < size[2]-1) - result = result + ' & '; - } - if(row < size[1]-1) - result = result + ' \\\\ '; + for( var i=0; i < intervals; i++ ) { + var sample_point = a + ((b - a) * (i + 0.5) / intervals); + bindings[x] = sample_point; + total = total + expr.evaluate( bindings ); } - result = result + ' \\end{' + this.matrixEnvironment + '}'; - return result; + return total * (b - a) / intervals; + }; - } - else if(operator === 'derivative_leibniz' || operator === 'partial_derivative_leibniz') { - let deriv_symbol = "d"; - if(operator === 'partial_derivative_leibniz') - deriv_symbol = "\\partial "; + var integration = /*#__PURE__*/Object.freeze({ + integrateNumerically: integrateNumerically + }); - let num = operands[0]; - let denom = operands[1]; + function expression_to_polynomial(expr_or_tree) { - let n_deriv = 1; - let var1 = ""; - if(Array.isArray(num)) { - var1 = num[1]; - n_deriv = num[2]; - } - else - var1 = num; + var tree = get_tree(expr_or_tree); - let result = deriv_symbol; - if(n_deriv > 1) - result = result.trimRight() + "^{" + n_deriv + "}" + this.stringConvert(var1); - else { - result = result + this.stringConvert(var1); + if(typeof tree === 'string') { + if((tree === 'pi' && math$19.define_pi) + || (tree === 'i' && math$19.define_i) + || (tree === 'e' && math$19.define_e)) + return tree; // treat as number + else + return ['polynomial', tree, [[1, 1]]]; // treat a polynomial variable } - result = "\\frac{ " + result + " }{ "; + if(typeof tree === 'number') + return tree; - let n_denom = 1; - if(Array.isArray(denom)) { - n_denom = denom.length-1; + let c = evaluate_to_constant(tree); + if(c !== null && Number.isFinite(c)) { + return simplify$2(tree); } - for(let i=1; i <= n_denom; i++) { - let denom_part = denom[i]; + if(!Array.isArray(tree)) + return false; - let exponent = 1; - let var2 = ""; - if(Array.isArray(denom_part)) { - var2 = denom_part[1]; - exponent = denom_part[2]; - } - else - var2 = denom_part; + // if contains invalid operators, it's not a polynomial + if(!operators$1(tree).every( + v => ['+', '-', '*', '^', '/', '_', 'prime'].includes(v))) + return false; - result = result + deriv_symbol + this.stringConvert(var2); + var operator = tree[0]; + var operands = tree.slice(1); - if(exponent > 1) - result = result + "^{" + exponent + "}"; + if(operator === '+') { + let result = operands.map(expression_to_polynomial); - result = result + " "; + // return false if any operand returned false + if(!result.every(v => v !== false)) + return false; + return result.reduce((u,v) => polynomial_add(u,v)); } - result = result + "}"; - return result; + else if(operator === '-') { + let result = expression_to_polynomial(operands[0]); - } - else if (operator === 'apply') { + if(!result) + return false; - if (operands[0] === 'abs') { - return '\\left|' + this.statement(operands[1]) + '\\right|'; + return polynomial_neg(result); } + else if(operator === '*') { + let result = operands.map(expression_to_polynomial); - if (operands[0] === "factorial") { - let result = this.factor(operands[1]); - if (this.simple_factor_or_function_or_parens(operands[1]) || - (operands[1][0] === '_' && (typeof operands[1][1] === 'string')) - ) - return result + "!"; - else - return '\\left(' + result.toString() + '\\right)!'; - } + // return false if any operand returned false + if(!result.every(v => v !== false )) + return false; - if (operands[0] === 'sqrt') { - return '\\sqrt{' + this.statement(operands[1]) + '}'; + return result.reduce((u,v) => polynomial_mul(u,v)); } + else if(operator === '^') { - let f = this.factor(operands[0]); - let f_args = this.statement(operands[1]); - - if (operands[1][0] !== 'tuple') - f_args = "\\left(" + f_args + "\\right)"; + let base = operands[0]; + let subresult = expression_to_polynomial(base); - return f + f_args; - } - else { - return '\\left(' + this.statement(tree) + '\\right)'; - } - } + // if subresult itself is false, then don't have a polynomial + if(subresult === false) + return false; - factorWithParenthesesIfNegated(tree) { - var result = this.factor(tree); + let pow = simplify$2(operands[1]); - if (result.toString().match(/^-/)) - return '\\left(' + result.toString() + '\\right)'; + // if pow isn't a literal nonnegative integer + if((typeof pow !== 'number') || pow < 0 || !Number.isInteger(pow)) { - // else - return result; - } + let pow_num = evaluate_to_constant(pow); - termWithPlusIfNotNegated(tree) { - var result = this.term(tree); + // check if pow is a rational number with a small base + if(pow_num !== null || Number.isFinite(pow_num)) { + let pow_fraction = math$19.fraction(pow_num); + if(pow_fraction.d <= 100) { + if(pow_fraction.s < 0) + base = ['^', base, ['/', -1, pow_fraction.d]]; + else + base = ['^', base, ['/', 1, pow_fraction.d]]; - if (!result.toString().match(/^-/)) - return '+ ' + result.toString(); + var results = ['polynomial', simplify$2(base), []]; - // else - return result; - } + results[2].push([pow_fraction.n, 1]); -} - -const textToAst$2 = new textToAst(); -const astToLatex$1 = new astToLatex(); - -var derivatives = { - "sin": textToAst$2.convert('cos x'), - "cos": textToAst$2.convert('-(sin x)'), - "tan": textToAst$2.convert('(sec x)^2'), - "cot": textToAst$2.convert('-((csc x)^2)'), - "sec": textToAst$2.convert('(sec x)*(tan x)'), - "csc": textToAst$2.convert('-(csc x)*(cot x)'), - "sqrt": textToAst$2.convert('1/(2*sqrt(x))'), - "log": textToAst$2.convert('1/x'), - "ln": textToAst$2.convert('1/x'), - "exp": textToAst$2.convert('exp(x)'), - "arcsin": textToAst$2.convert('1/sqrt(1 - x^2)'), - "arccos": textToAst$2.convert('-1/sqrt(1 - x^2)'), - "arctan": textToAst$2.convert('1/(1 + x^2)'), - "arccsc": textToAst$2.convert('-1/(sqrt(-1/x^2 + 1)*x^2)'), - "arcsec": textToAst$2.convert('1/(sqrt(-1/x^2 + 1)*x^2)'), - "arccot": textToAst$2.convert('-1/(1 + x^2)'), - "abs": textToAst$2.convert('abs(x)/x'), -}; - - -function derivative$2(expr_or_tree,x,story = []) { - var tree = get_tree(expr_or_tree); + return results; - var ddx = '\\frac{d}{d' + x + '} '; + } + } - // Derivative of a constant - if (typeof tree === 'number') { - story.push( 'The derivative of a constant is zero, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); - return 0; - } + // just return entire tree as a polynomial variable + return ["polynomial", tree, [[1,1]]]; + } - // Derivative of a more complicated constant - if ((variables(tree)).indexOf(x) < 0) { - story.push( 'The derivative of a constant is zero, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); - return 0; - } + if(pow===0) { + return 1; + } + if(pow===1) { + return subresult; + } - // Derivative of a variable - if (typeof tree === 'string') { - if (x === tree) { - story.push( 'We know the derivative of the identity function is one, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 1\\).' ); - return 1; - } + return polynomial_pow(subresult, pow); - // should never get to this line - // as would have been considered a constant - story.push( 'As far as \\(' + astToLatex$1.convert(x) + '\\) is concerned, \\(' + astToLatex$1.convert(tree) + '\\) is constant, so ' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); - return 0; - } + } + else if(operator === '/') { + var denom = operands[1]; - var operator = tree[0]; - var operands = tree.slice(1); + var denom_num = evaluate_to_constant(denom); - // derivative of sum is sum of derivatives - if ((operator === '+') || (operator === '-') || (operator === '~')) { - story.push( 'Using the sum rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (operands.map( function(v,i) { return ddx + astToLatex$1.convert(v); } )).join( ' + ' ) + '\\).' ); - let result = [operator].concat( operands.map( function(v,i) { return derivative$2(v,x,story); } ) ); - result = simplify$2(result); - story.push( 'So using the sum rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } + if(denom_num === null || !Number.isFinite(denom_num)) { + // return entire tree as polynomial variable + return ['polynomial', tree, [[1, 1]]]; + } - // product rule - if (operator === '*') { - let non_numeric_operands = []; - let numeric_operands = []; - - for( let i=0; i 0) { - if (non_numeric_operands.length === 0) { - story.push( 'Since the derivative of a constant is zero, \\(' + ddx + astToLatex$1.convert( tree ) + ' = 0.\\)' ); - let result = 0; - return result; - } - - let remaining = ['*'].concat( non_numeric_operands ); - if (non_numeric_operands.length === 1) - remaining = non_numeric_operands[0]; - - - - if (remaining === x) { - story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (numeric_operands.map( function(v,i) { return astToLatex$1.convert(v); } )).join( ' \\cdot ' ) + '\\).' ); - let result = ['*'].concat( numeric_operands ); - result = simplify$2(result); - return result; - } - - story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (numeric_operands.map( function(v,i) { return astToLatex$1.convert(v); } )).join( ' \\cdot ' ) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(remaining) + '\\right)\\).' ); - - let d = derivative$2(remaining,x,story); - let result = ['*'].concat( numeric_operands.concat( [d] ) ); - result = simplify$2(result); - story.push( 'And so \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - story.push( 'Using the product rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + - (operands.map( function(v,i) { - return (operands.map( function(w,j) { - if (i === j) - return ddx + '\\left(' + astToLatex$1.convert(v) + '\\right)'; - else - return astToLatex$1.convert(w); - })).join( ' \\cdot ' ) })).join( ' + ' ) + '\\).' ); - - let inner_operands = operands.slice(); - - let result = ['+'].concat( operands.map( function(v,i) { - return ['*'].concat( inner_operands.map( function(w,j) { - if (i === j) { - let d = derivative$2(w,x,story); - // remove terms that have derivative 1 - if (d === 1) - return null; - - return d; - } else { - return w; - } - } ).filter( function(t) { return t != null; } ) ); - } ) ); - result = simplify$2(result); - story.push( 'So using the product rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - - return result; - } - - // quotient rule - if (operator === '/') { - let f = operands[0]; - let g = operands[1]; + var numer_result = expression_to_polynomial(operands[0]); - if ((variables(g)).indexOf(x) < 0) { - story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(['/', 1, g]) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(f) + '\\right)\\).' ); + return polynomial_mul(numer_result, ['/', 1, denom_num]); + } - let df = derivative$2(f,x,story); - let quotient_rule = textToAst$2.convert('(1/g)*d'); - let result = substitute( quotient_rule, { "d": df, "g": g } ); - result = simplify$2(result); - story.push( 'So \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } + else { + // return entire tree as polynomial variable + return ['polynomial', tree, [[1, 1]]]; + } - if ((variables(f)).indexOf(x) < 0) { - if (f !== 1) { - story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(f) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(['/',1,g]) + '\\right)\\).' ); - } - story.push( 'Since \\(\\frac{d}{du} \\frac{1}{u}\\) is \\(\\frac{-1}{u^2}\\), the chain rule gives \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(f) + '\\cdot \\frac{-1}{ ' + astToLatex$1.convert(g) + '^2} \\cdot ' + ddx + astToLatex$1.convert( g ) + "\\)." ); + } - let a = derivative$2(g,x,story); - let quotient_rule = textToAst$2.convert('f * (-a/(g^2))'); - let result = substitute( quotient_rule, { "f": f, "a": a, "g": g } ); - result = simplify$2(result); - story.push( 'So since \\(\\frac{d}{du} \\frac{1}{u}\\) is \\(\\frac{-1}{u^2}\\), the chain rule gives \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + function polynomials_in_same_leading_variable(p,q) { + // If both polynomials have same leading variable, return unchanged. + // Else, rewrite the polymomial whose leading variable comes later + // as a polynomial that is constant in leading variable of other - return result; - } + if(p[1] !== q[1]) { + if(compare_function(p[1], q[1]) < 0) { + // variable p[1] is earlier in default order + // so write q as a polynomial constant in p[1] + q = ["polynomial", p[1], [[0, q]]]; + } + else { + // variable q[1] is earlier in default order + // so write p as a polynomial constant in q[1] + p = ["polynomial", q[1], [[0, p]]]; + } + } - story.push( 'Using the quotient rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = \\frac{' + ddx + '\\left(' + astToLatex$1.convert(f) + '\\right) \\cdot ' + astToLatex$1.convert(g) + ' - ' + astToLatex$1.convert(f) + '\\cdot ' + ddx + '\\left(' + astToLatex$1.convert(g) + '\\right)}{ \\left( ' + astToLatex$1.convert(g) + ' \\right)^2} \\).' ); + return [p, q]; + } - let a = derivative$2(f,x,story); - let b = derivative$2(g,x,story); - let quotient_rule = textToAst$2.convert('(a * g - f * b)/(g^2)'); + function polynomial_add(p,q) { //being called on empty polynomials - let result = substitute( quotient_rule, { "a": a, "b": b, "f": f, "g": g } ); - result = simplify$2(result); - story.push( 'So using the quotient rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); + if(p[0] !== "polynomial") { + if(q[0] !== "polynomial") + return simplify$2(['+', p, q]); + else { + // write p as a constant polynomial in q's first variable + p = ["polynomial", q[1], [[0, p]]]; + } + } + else { + if (q[0] !== "polynomial") { + // write q as a constant polynomial in p's first variable + q = ["polynomial", p[1], [[0, q]]]; + } + else { + // if needed, rewrite polynomials so have same first variable + let tmp = polynomials_in_same_leading_variable(p,q); + p = tmp[0]; + q = tmp[1]; + } + } - return result; - } + // at this point, both q and p are polynomials with same first variable - // power rule - if (operator === '^') { - let base = operands[0]; - let exponent = operands[1]; - - if ((variables(exponent)).indexOf(x) < 0) { - if ((typeof base === 'string') && (base === 'x')) { - if (typeof exponent === 'number') { - let power_rule = textToAst$2.convert('n * (f^m)'); - let result = substitute( power_rule, { "n": exponent, "m": exponent - 1, "f": base } ); - result = simplify$2(result); - story.push( 'By the power rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '}\\).' ); - return result; - } - - let power_rule = textToAst$2.convert('n * (f^(n-1))'); - let result = substitute( power_rule, { "n": exponent, "f": base } ); - result = simplify$2(result); - story.push( 'By the power rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '}\\).' ); - - return result; - } - - if (exponent !== 1) { - story.push( 'By the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '} \\cdot ' + ddx + astToLatex$1.convert( base ) + '\\).' ); - } - - let a = derivative$2(base,x,story); - - if (exponent === 1) - return a; - - if (typeof exponent === 'number') { - let power_rule = textToAst$2.convert('n * (f^m) * a'); - let result = substitute( power_rule, { "n": exponent, "m": exponent - 1, "f": base, "a" : a } ); - result = simplify$2(result); - story.push( 'So by the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - let power_rule = textToAst$2.convert('n * (f^(n-1)) * a'); - let result = substitute( power_rule, { "n": exponent, "f": base, "a" : a } ); - result = simplify$2(result); - story.push( 'So by the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - if (base === 'e' && math$19.define_e) { - if ((typeof exponent === 'string') && (exponent === x)) { - let power_rule = textToAst$2.convert('e^(f)'); - let result = substitute( power_rule, { "f": exponent } ); - result = simplify$2(result); - story.push( 'The derivative of \\(e^' + astToLatex$1.convert( x ) + '\\) is itself, that is, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( tree ) + '\\).' ); - - return result; - } - - story.push( 'Using the rule for \\(e^x\\) and the chain rule, we know \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( tree ) + ' \\cdot ' + ddx + astToLatex$1.convert( exponent ) + '\\).' ); - - let power_rule = textToAst$2.convert('e^(f)*d'); - - let d = derivative$2(exponent,x,story); - let result = substitute( power_rule, { "f": exponent, "d": d } ); - result = simplify$2(result); - story.push( 'So using the rule for \\(e^x\\) and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - if (typeof base === 'number') { - if ((typeof exponent === 'string') && (exponent === x)) { - let power_rule = textToAst$2.convert('a^(f) * log(a)'); - let result = substitute( power_rule, { "a": base, "f": exponent } ); - result = simplify$2(result); - story.push( 'The derivative of \\(a^' + astToLatex$1.convert( x ) + '\\) is \\(a^{' + astToLatex$1.convert( x ) + '} \\, \\log a\\), that is, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( result ) + '\\).' ); - - return result; - } - - let exp_rule = textToAst$2.convert('a^(f) * log(a)'); - let partial_result = substitute( exp_rule, { "a": base, "f": exponent } ); - - story.push( 'Using the rule for \\(a^x\\) and the chain rule, we know \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( partial_result ) + ' \\cdot ' + ddx + astToLatex$1.convert( exponent ) + '\\).' ); - - let power_rule = textToAst$2.convert('a^(b)*log(a)*d'); - let d = derivative$2(exponent,x,story); - let result = substitute( power_rule, { "a": base, "b": exponent, "d": d } ); - result = simplify$2(result); - story.push( 'So using the rule for \\(a^x\\) and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - // general case of a function raised to a function - let f = base; - let g = exponent; - - story.push( "Recall the general rule for exponents, namely that \\(\\frac{d}{dx} u(x)^{v(x)} = u(x)^{v(x)} \\cdot \\left( v'(x) \\cdot \\log u(x) + \\frac{v(x) \\cdot u'(x)}{u(x)} \\right)\\). In this case, \\(u(x) = " + astToLatex$1.convert( f ) + "\\) and \\(v(x) = " + astToLatex$1.convert( g ) + "\\)." ); - - let a = derivative$2(f,x,story); - let b = derivative$2(g,x,story); - - let power_rule = textToAst$2.convert('(f^g)*(b * log(f) + (g * a)/f)'); - let result = substitute( power_rule, { "a": a, "b": b, "f": f, "g": g } ); - result = simplify$2(result); - story.push( 'So by the general rule for exponents, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - if (operator === "apply" && !(operands[0] in derivatives)) { - // derivative of function whose derivative is not given - - let input = operands[1]; - - story.push( 'By the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(substitute( ["apply",operands[0] + "'","x"], { "x": input } )) + " \\cdot " + ddx + astToLatex$1.convert(input) + '\\).' ); - - let result = ['*', - substitute( ["apply",operands[0] + "'","x"], { "x": input } ), - derivative$2( input, x, story )]; - result = simplify$2(result); - story.push( 'So by the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - // chain rule - if ((operator === "apply" && operands[0] in derivatives) || - operator in derivatives) { - - let used_apply = false; - if(operator === "apply") { - operator = operands[0]; - operands = operands.slice(1); - used_apply = true; - } - - let input = operands[0]; - - if (typeof input === "number") { - let result = 0; - story.push( 'The derivative of a constant is zero so \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } else if ((typeof input === "string") && (input === x)) { - let result = ['*', - substitute( derivatives[operator], { "x": input } )]; - result = simplify$2(result); - story.push( 'It is the case that \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } else if ((typeof input === "string") && (input !== x)) { - let result = 0; - story.push( 'Since the derivative of a constant is zero, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } else { - let example_ast = [operator,'u']; - if(used_apply) - example_ast = ["apply"].concat(example_ast); - story.push( 'Recall \\(\\frac{d}{du}' + astToLatex$1.convert( example_ast ) + ' = ' + - astToLatex$1.convert( derivative$2( example_ast, 'u', [] ) ) + '\\).' ); - - story.push( 'By the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(substitute( derivatives[operator], { "x": input } )) + " \\cdot " + ddx + astToLatex$1.convert(input) + '\\).' ); - - let result = ['*', - substitute( derivatives[operator], { "x": input } ), - derivative$2( input, x, story )]; - result = simplify$2(result); - story.push( 'So by the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - } + let sum = ["polynomial", p[1], []]; - return 0; -} - -/****************************************************************/ -// -// The "story" that the differentiation code produces can be somewhat repetitive -// -// Here we fix this -// - -function lowercaseFirstLetter(string) -{ - return string.charAt(0).toLowerCase() + string.slice(1); -} - -function simplify_story( story ) { - // remove neighboring duplicates - for (let i = story.length - 1; i >= 1; i--) { - if (story[i] === story[i-1]) - story.splice( i, 1 ); - } - - // Make it seem obvious that I know I am repeating myself - for (let i = 0; i < story.length; i++ ) { - for( let j = i + 1; j < story.length; j++ ) { - if (story[i] === story[j]) { - story[j] = 'Again, ' + lowercaseFirstLetter( story[j] ); - } - } - } - - return story; -} - - -function derivative_story(expr, x) { - var story = []; - derivative$2( expr, x, story ); - story = simplify_story( story ); - return story; -} -const derivativeStory = derivative_story; - -var differentiation = /*#__PURE__*/Object.freeze({ - derivative: derivative$2, - derivative_story: derivative_story, - derivativeStory: derivativeStory -}); - -/* - * convert syntax trees back to string representations - * - * Copyright 2014-2017 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - -const unicode_operators = { - "+": function(operands) { return operands.join( ' ' ); }, - "-": function(operands) { return "- " + operands[0]; }, - "*": function(operands) { return operands.join( " " ); }, - "/": function(operands) { return operands[0] + "/" + operands[1]; }, - "_": function(operands) { return operands[0] + "_" + operands[1]; }, - "^": function(operands) { return operands[0] + "^" + operands[1]; }, - "prime": function(operands) { return operands[0] + "'"; }, - "tuple": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "array": function(operands) { return '[ ' + operands.join( ', ' ) + ' ]';}, - "list": function(operands) { return operands.join( ', ' );}, - "set": function(operands) { return '{ ' + operands.join( ', ' ) + ' }';}, - "vector": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "interval": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "matrix": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "and": function(operands) { return operands.join( ' and ' );}, - "or": function(operands) { return operands.join( ' or ' );}, - "not": function(operands) { return 'not ' + operands[0]; }, - "=": function(operands) { return operands.join( ' = ' );}, - "<": function(operands) { return operands.join( ' < ' );}, - ">": function(operands) { return operands.join( ' > ' );}, - "lts": function(operands) { return operands.join( ' < ' );}, - "gts": function(operands) { return operands.join( ' > ' );}, - - "le": function(operands) { return operands.join( ' ≤ ' );}, - "ge": function(operands) { return operands.join( ' ≥ ' );}, - "ne": function(operands) { return operands.join( ' ≠ ' );}, - "in": function(operands) { return operands[0] + " ∈ " + operands[1]; }, - "notin": function(operands) { return operands[0] + " ∉ " + operands[1]; }, - "ni": function(operands) { return operands[0] + " ∋ " + operands[1]; }, - "notni": function(operands) { return operands[0] + " ∌ " + operands[1]; }, - "subset": function(operands) { return operands[0] + " ⊂ " + operands[1]; }, - "notsubset": function(operands) { return operands[0] + " ⊄ " + operands[1]; }, - "superset": function(operands) { return operands[0] + " ⊃ " + operands[1]; }, - "notsuperset": function(operands) { return operands[0] + " ⊅ " + operands[1]; }, - "union": function (operands) { return operands.join(' ∪ '); }, - "intersect": function (operands) { return operands.join(' ∩ '); }, - "derivative_leibniz": function (operands) { return "d" + operands[0] + "/d" + operands[1]; }, - "partial_derivative_leibniz": function (operands) { return "∂" + operands[0] + "/∂" + operands[1]; }, - "|": function (operands) { return operands[0] + " | " + operands[1]; }, - ":": function (operands) { return operands[0] + " : " + operands[1]; }, - -}; - -const nonunicode_operators = { - "+": function(operands) { return operands.join( ' ' ); }, - "-": function(operands) { return "- " + operands[0]; }, - "*": function(operands) { return operands.join( " " ); }, - "/": function(operands) { return operands[0] + "/" + operands[1]; }, - "_": function(operands) { return operands[0] + "_" + operands[1]; }, - "^": function(operands) { return operands[0] + "^" + operands[1]; }, - "prime": function(operands) { return operands[0] + "'"; }, - "tuple": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "array": function(operands) { return '[ ' + operands.join( ', ' ) + ' ]';}, - "list": function(operands) { return operands.join( ', ' );}, - "set": function(operands) { return '{ ' + operands.join( ', ' ) + ' }';}, - "vector": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "interval": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "matrix": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "and": function(operands) { return operands.join( ' and ' );}, - "or": function(operands) { return operands.join( ' or ' );}, - "not": function(operands) { return 'not ' + operands[0]; }, - "=": function(operands) { return operands.join( ' = ' );}, - "<": function(operands) { return operands.join( ' < ' );}, - ">": function(operands) { return operands.join( ' > ' );}, - "lts": function(operands) { return operands.join( ' < ' );}, - "gts": function(operands) { return operands.join( ' > ' );}, - - "le": function(operands) { return operands.join( ' <= ' );}, - "ge": function(operands) { return operands.join( ' >= ' );}, - "ne": function(operands) { return operands.join( ' ne ' );}, - "in": function(operands) { return operands[0] + " elementof " + operands[1]; }, - "notin": function(operands) { return operands[0] + " notelementof " + operands[1]; }, - "ni": function(operands) { return operands[0] + " containselement " + operands[1]; }, - "notni": function(operands) { return operands[0] + " notcontainselement " + operands[1]; }, - "subset": function(operands) { return operands[0] + " subset " + operands[1]; }, - "notsubset": function(operands) { return operands[0] + " notsubset " + operands[1]; }, - "superset": function(operands) { return operands[0] + " superset " + operands[1]; }, - "notsuperset": function(operands) { return operands[0] + " notsuperset " + operands[1]; }, - "union": function (operands) { return operands.join(' union '); }, - "intersect": function (operands) { return operands.join(' intersect '); }, - "derivative_leibniz": function (operands) { return "d" + operands[0] + "/d" + operands[1]; }, - "partial_derivative_leibniz": function (operands) { return "∂" + operands[0] + "/∂" + operands[1]; }, - "|": function (operands) { return operands[0] + " | " + operands[1]; }, - ":": function (operands) { return operands[0] + " : " + operands[1]; }, -}; - - -const output_unicodeDefault = true; - - -class astToText { - constructor({ - output_unicode = output_unicodeDefault - } = {}) { - this.output_unicode = output_unicode; - this.operators = unicode_operators; - if(!output_unicode){ this.operators = nonunicode_operators;} - } + let p_terms = p[2]; + let q_terms = q[2]; + let sum_terms = sum[2]; - convert(tree) { - return this.statement(tree); - } + let len_p = p_terms.length; + let len_q = q_terms.length; + let i = 0; + let j = 0; - statement(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.single_statement(tree); - } + while (i < len_p || j < len_q){ + if (i === len_p){ + if (q_terms[j][1]) + sum_terms.push(q_terms[j]); + j = j+1; + } + else if (j === len_q){ + if (p_terms[i][1]) + sum_terms.push(p_terms[i]); + i = i+1; + } + else if (p_terms[i][0] === q_terms[j][0]){ + let temp = polynomial_add(p_terms[i][1], q_terms[j][1]); + if(temp) + sum_terms.push([p_terms[i][0], temp]); + i = i+1; + j = j+1; + } + else if (p_terms[i][0] < q_terms[j][0]){ + if (p_terms[i][1]) + sum_terms.push(p_terms[i]); + i = i+1; + } + else{ + if (q_terms[j][1]) + sum_terms.push(q_terms[j]); + j = j+1; + } + } - let operator = tree[0]; - let operands = tree.slice(1); + // all terms canceled + if(sum_terms.length === 0) + return 0; - if(operator === 'ldots') - return '...'; + // only a term that is constant in leading variable is left + if(sum_terms.length === 1 && (sum_terms[0][0] === 0)) + return sum_terms[0][1]; - if((!(operator in this.operators)) && operator!=="apply") - throw new Error("Badly formed ast: operator " + operator + " not recognized."); + return sum; - if (operator === 'and' || operator === 'or') { - return this.operators[operator]( operands.map( function(v,i) { - let result = this.single_statement(v); - // for clarity, add parenthesis unless result is - // single quantity (with no spaces) or already has parens - if (result.toString().match(/ /) - && (!(result.toString().match(/^\(.*\)$/)))) - return '(' + result + ')'; - else - return result; - }.bind(this))); - } - return this.single_statement(tree); -} + } - single_statement(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.expression(tree); - } - let operator = tree[0]; - let operands = tree.slice(1); + function polynomial_neg(p) { - if (operator === 'not') { - return this.operators[operator]( operands.map( function(v,i) { - let result = this.single_statement(v); - // for clarity, add parenthesis unless result is - // single quantity (with no spaces) or already has parens - if (result.toString().match(/ /) - && (!(result.toString().match(/^\(.*\)$/)))) - return '(' + result + ')'; - else - return result; - }.bind(this))); - } - - if((operator === '=') || (operator === 'ne') - || (operator === '<') || (operator === '>') - || (operator === 'le') || (operator === 'ge') - || (operator === 'in') || (operator === 'notin') - || (operator === 'ni') || (operator === 'notni') - || (operator === 'subset') || (operator === 'notsubset') - || (operator === 'superset') || (operator === 'notsuperset')) { - return this.operators[operator]( operands.map( function(v,i) { - return this.expression(v); - }.bind(this))); - } - - if(operator === 'lts' || operator === 'gts') { - let args = operands[0]; - let strict = operands[1]; - - if(args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); - - let result = this.expression(args[1]); - for(let i=1; i< args.length-1; i++) { - if(strict[i]) { - if(operator === 'lts') - result += " < "; - else - result += " > "; - } - else { - if(operator === 'lts') { - if(this.output_unicode) - result += " ≤ "; - else - result += " <= "; - } - else { - if(this.output_unicode) - result += " ≥ "; - else - result += " >= "; - } - } - result += this.expression(args[i+1]); - } - return result; - } - - return this.expression(tree); -} - - expression(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.term(tree); - } + if(p[0] !== "polynomial") { + return simplify$2(['-', p ]); + } - let operator = tree[0]; - let operands = tree.slice(1); + let result = ["polynomial", p[1], []]; + let p_terms = p[2]; + let result_terms = result[2]; - if (operator === '+') { - return this.operators[operator]( operands.map( function(v,i) { - if(i>0) - return this.termWithPlusIfNotNegated(v); - else - return this.term(v); - }.bind(this) )); - } + let len = p_terms.length; - if ((operator === 'union') || (operator === 'intersect')) { - return this.operators[operator]( operands.map( function(v,i) { - return this.term(v); - }.bind(this))); - } + for (var i = 0; i < len; i = i + 1){ + result_terms.push([p_terms[i][0], polynomial_neg(p_terms[i][1])]); + } - return this.term(tree); -} + return result; + } - term(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.factor(tree); - } - let operator = tree[0]; - let operands = tree.slice(1); + function polynomial_sub(p,q) { - if (operator === '-') { - return this.operators[operator]( operands.map( function(v,i) { - return this.term(v); - }.bind(this))); - } - if (operator === '*') { - return this.operators[operator]( operands.map( function(v,i) { - let result; - if(i > 0) { - result = this.factorWithParenthesesIfNegated(v); - if (result.toString().match( /^[0-9]/ )) - return '* ' + result; - else - return result - } - else - return this.factor(v); - }.bind(this))); - } + return polynomial_add(p, polynomial_neg(q)); - if (operator === '/') { - return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); - } - - return this.factor(tree); -} - - symbolConvert(symbol) { - let symbolConversions= { - 'alpha': 'α', - 'beta': 'β', - 'Gamma': 'Γ', - 'gamma': 'γ', - 'Delta': 'Δ', - 'delta': 'δ', - 'epsilon': 'ε', - 'zeta': 'ζ', - 'eta': 'η', - 'Theta': 'ϴ', - 'theta': 'θ', - 'iota': 'ι', - 'kappa': 'κ', - 'Lambda': 'Λ', - 'lambda': 'λ', - 'mu': 'μ', - 'nu': 'ν', - 'Xi': 'Ξ', - 'xi': 'ξ', - 'Pi': 'Π', - 'pi': 'π', - 'rho': 'ρ', - 'Sigma': 'Σ', - 'sigma': 'σ', - 'tau': 'τ', - 'Upsilon': 'Υ', - 'upsilon': 'υ', - 'Phi': 'Φ', - 'phi': 'ϕ', - 'Psi': 'Ψ', - 'psi': 'ψ', - 'Omega': 'Ω', - 'omega': 'ω', - }; - if (this.output_unicode && (symbol in symbolConversions)) - return symbolConversions[symbol]; - else - return symbol -} - - simple_factor_or_function_or_parens(tree) { - // return true if - // factor(tree) is a single character - // or tree is a non-negative number not in scientific notation - // or tree is a string - // or tree is a function call - // or factor(tree) is in parens - - let result = this.factor(tree); - - if (result.toString().length === 1 - || (typeof tree === 'string') - || (tree[0] === 'apply') - || result.toString().match(/^\(.*\)$/) - ) { - return true; - } else if (typeof tree === 'number') { - if (tree >= 0 && !tree.toString().includes('e')) { - return true; - } else { - return false; - } - } else { - return false - } } - factor(tree) { - if (typeof tree === 'string') { - return this.symbolConvert(tree); - } - if (typeof tree === 'number') { - if(tree === Infinity) { - if(this.output_unicode) { - return '∞'; - } - else { - return 'infinity'; - } - } - else if(tree === -Infinity) { - if(this.output_unicode) { - return '-∞'; - } - else { - return '-infinity'; - } + function polynomial_mul(p,q) { + + if(p[0] !== "polynomial") { + if(q[0] !== "polynomial") { + return simplify$2(['*', p, q]); + } + else if(p) { + let prod = ["polynomial", q[1], []]; + let q_terms = q[2]; + let prod_terms = prod[2]; + for(let term of q_terms) { + if(term[1]) + prod_terms.push([term[0], polynomial_mul(p, term[1])]); + } + return prod; + } } else { - let numberString = tree.toString(); - let eIndex = numberString.indexOf('e'); - if(eIndex === -1) { - return numberString; - } - let num = numberString.substring(0,eIndex); - let exponent = numberString.substring(eIndex+1); - if(exponent[0] === "+") { - return num + " * 10^" + exponent.substring(1); - } else { - return num + " * 10^(" + exponent + ")"; - } + if (q && q[0] !== "polynomial") { + let prod = ["polynomial", p[1], []]; + let p_terms = p[2]; + let prod_terms = prod[2]; + for(let term of p_terms) { + if(term[1]) + prod_terms.push([term[0], polynomial_mul(term[1], q)]); + } + return prod; + } } - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if (operator === "^") { - let operand0 = this.factor(operands[0]); - - // so that f_(st)'^2(x) doesn't get extra parentheses - // (and no longer recognized as function call) - // check for simple factor after removing primes - let remove_primes = operands[0]; - while(remove_primes[0] === 'prime') { - remove_primes=remove_primes[1]; - } - - if(!(this.simple_factor_or_function_or_parens(remove_primes) || - (remove_primes[0] === '_' && (typeof remove_primes[1] === 'string')) - )) - operand0 = '(' + operand0.toString() + ')'; - - let operand1 = this.factor(operands[1]); - if(!(this.simple_factor_or_function_or_parens(operands[1]))) - operand1 = '(' + operand1.toString() + ')'; - - return operand0 + '^' + operand1; - } - else if (operator === "_") { - return this.operators[operator]( operands.map( function(v,i) { - let result = this.factor(v); - if(this.simple_factor_or_function_or_parens(v)) - return result; - else - return '(' + result.toString() + ')'; - }.bind(this))); - } - else if(operator === "prime") { - let op = operands[0]; - - let n_primes=1; - while(op[0] === "prime") { - n_primes+=1; - op=op[1]; - } - - let result = this.factor(op); - - if (!(this.simple_factor_or_function_or_parens(op) || - (op[0] === '_' && (typeof op[1] === 'string')) - )) - result = '(' + result.toString() + ')'; - for(let i=0; i 1) - result = result + "^" + n_deriv; - result = result + this.symbolConvert(var1) + "/"; - - let n_denom = 1; - if(Array.isArray(denom)) { - n_denom = denom.length-1; - } - for(let i=1; i <= n_denom; i++) { - let denom_part = denom[i]; + // two non-constant polynomials + // if needed, rewrite polynomials so have same first variable + let tmp = polynomials_in_same_leading_variable(p,q); + p = tmp[0]; + q = tmp[1]; + + let p_terms = p[2]; + let q_terms = q[2]; + + let prod = ["polynomial", p[1], []]; + let prod_terms = prod[2]; + let p_len = p_terms.length; + let q_len = q_terms.length; + + //find the degrees that will occur in the product + let degrees = []; + for (let term_p of p_terms){ + for (let term_q of q_terms){ + let found = false; + let current_deg = term_p[0] + term_q[0]; + for (let deg of degrees){ + if (current_deg === deg){ + found = true; + break; + } + } + if (!found) + degrees.push(current_deg); + } + } - let exponent = 1; - let var2 = ""; - if(Array.isArray(denom_part)) { - var2 = denom_part[1]; - exponent = denom_part[2]; - } - else - var2 = denom_part; + degrees.sort(function(a, b){return a - b}); - result = result + deriv_symbol + this.symbolConvert(var2); + //this is where the product is computed + for(let deg of degrees){ + let sum = 0; + let i = 0; + while (i < p_len && p_terms[i][0] <= deg){ + let j = 0; + while (j < q_len && q_terms[j][0] <= deg){ + if ((p_terms[i][0] + q_terms[j][0]) === deg){ + sum = polynomial_add(sum, polynomial_mul(p_terms[i][1], q_terms[j][1])); + break; + } + j = j+1; + } + i = i+1; + } + if(sum) + prod_terms.push([deg, sum]); + } - if(exponent > 1) - result = result + "^" + exponent; + return prod; + } - } - return result; - } - else if(operator === 'apply'){ + function polynomial_pow(p, e) { - if(operands[0] === 'abs') { - return '|' + this.statement(operands[1]) + '|'; - } + if(isNaN(e) || e < 0 || !Number.isInteger(e)) + return undefined; - if (operands[0] === "factorial") { - let result = this.factor(operands[1]); - if(this.simple_factor_or_function_or_parens(operands[1]) || - (operands[1][0] === '_' && (typeof operands[1][1] === 'string')) - ) - return result + "!"; - else - return '(' + result.toString() + ')!'; + let res = 1; - } + while(e > 0) { - let f = this.factor(operands[0]); - let f_args = this.statement(operands[1]); + if(e & 1) { + // odd exponent + res = polynomial_mul(res, p); + } - if(operands[1][0] !== 'tuple') - f_args = "(" + f_args + ")"; + p = polynomial_mul(p, p); - return f+f_args; - } - else { - return '(' + this.statement(tree) + ')'; - } -} + e >>= 1; // divide by 2 and truncate - factorWithParenthesesIfNegated(tree){ - let result = this.factor(tree); + } - if (result.toString().match( /^-/ )) - return '(' + result.toString() + ')'; + return res; + } - // else - return result; -} - termWithPlusIfNotNegated(tree){ - let result = this.term(tree); + function polynomial_to_expression(p) { - if (!result.toString().match( /^-/ )) - return '+ ' + result.toString(); + if(!Array.isArray(p) || p[0] !== "polynomial") + return p; - // else - return result; -} + let x = p[1]; + let terms = p[2]; -} + let result = []; -var astToText$1 = new astToText(); + let len_terms = terms.length; + for(var i = 0; i < len_terms; i = i+1) { + if(terms[i][1]) { + if(terms[i][0]===0) + result.push(polynomial_to_expression(terms[i][1])); + else if(terms[i][0]===1) + result.push(['*', polynomial_to_expression(terms[i][1]), x]); + else + result.push(['*', polynomial_to_expression(terms[i][1]), + ['^', x, terms[i][0]]]); -function subscripts_to_strings(expr_or_tree, force=false) { - // convert ['_', a,b] to string - // if force is set, perform conversions for any values of a or b - // otherwise (the default), perform conversion only - // when both a and b are strings or numbers + } + } - var tree = get_tree(expr_or_tree); + if(result.length === 0) + return 0; + else if(result.length === 1) + result = result[0]; + else + result.unshift('+'); - if(!Array.isArray(tree)) { - return tree; - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '_') { - if(force || operands.every(x => ['number', 'string'].includes(typeof x))) { - return astToText$1.convert(tree); - } + return simplify$2(result); } - return [operator].concat(operands.map(x => subscripts_to_strings(x,force))); -} - + function initial_term(p) { + //takes a polynomial ["polynomial", "var"...] and returns the initial term according to lexicographic order, in form ["monomial", coefficient, [[variable1, power1], ...]] -function strings_to_subscripts(expr_or_tree) { - // convert string 'a_b' to ['_', 'a','b'] and string 'a_1' to ['_', 'a', 1] + if (!Array.isArray(p) || p[0] !== "polynomial") + return p; - var tree = get_tree(expr_or_tree); + let var_powers = []; - if(typeof tree === "string") { - let res = tree.match(/^([0-9a-zA-Z]+)_([a-zA-Z]+|[0-9]+)$/); - if(res) { - let base = Number(res[1]); - if(isNaN(base)) { - base = res[1]; + while( Array.isArray(p) && p[0] === "polynomial"){ + let x = p[1]; + let terms = p[2]; + let exp = (terms[terms.length-1])[0]; + p = (terms[terms.length-1])[1]; + var_powers.push([x,exp]); } - let sub = Number(res[2]); - if(isNaN(sub)) { - sub = res[2]; - } - return ['_', base, sub] - }else { - return tree; - } - } - if(!Array.isArray(tree)) { - return tree; + return ["monomial", p, var_powers]; } - - let operator = tree[0]; - let operands = tree.slice(1); - - return [operator].concat(operands.map(strings_to_subscripts)); -} + function mono_less_than(left,right) { + //takes two monomials ["monomial", coeff, terms array] and returns true if left is less than right in lexicographic order. + //stringify vars before calling this + if (!Array.isArray(right) || right[0] !== "monomial") + return false; //if right is constant, always false -var normalization = /*#__PURE__*/Object.freeze({ - normalize_function_names: normalize_function_names, - normalize_applied_functions: normalize_applied_functions, - substitute_abs: substitute_abs, - default_order: default_order, - constants_to_floats: constants_to_floats, - tuples_to_vectors: tuples_to_vectors, - to_intervals: to_intervals, - subscripts_to_strings: subscripts_to_strings, - strings_to_subscripts: strings_to_subscripts -}); + if (!Array.isArray(left) || left[0] !== "monomial") + return true; //if left is constant and right is not, always true -// check for equality by randomly sampling + let left_vars = left[2]; + let right_vars = right[2]; + let left_length = left_vars.length; + let right_length = right_vars.length; + var shorter; + if (left_length < right_length) + shorter = left_length; + else + shorter = right_length; -function generate_random_integer(minvalue, maxvalue, rng) { - minvalue = math$19.ceil(minvalue); - maxvalue = math$19.floor(maxvalue); - return math$19.floor(rng() * (maxvalue - minvalue + 1)) + minvalue; -} + for ( var i = 0; i < shorter; i++ ){ + if(left_vars[i][0] !== right_vars[i][0]) { + if(compare_function(left_vars[i][0], right_vars[i][0]) < 0) { + // left variable is earlier in default order + return false; + } + else { + // right variable is earlier in default order + return true; + } + } + if(left_vars[i][1] < right_vars[i][1]) { + // left power is lower + return true; + } + if(left_vars[i][1] > right_vars[i][1]) { + // right power is lower + return false; + } + } + if ( left_length === right_length || shorter === right_length ){ + // same monomial, except possibly coefficient, or same until left is longer + return false; + } + else { + // same until right is longer + return true; + } + } + function mono_gcd(left, right) { + //takes two monomials ["monomial", coeff, terms array] and returns their greatest common divisor as a monomial + //stringify vars before calling this -const equals = function ({ expr, other, randomBindings, - expr_context, other_context, - relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - rng, -}) { + if (!Array.isArray(left) || !Array.isArray(right) || left[0] !== "monomial" || right[0] !== "monomial") + return 1; //if either is constant, gcd is 1 - if (Array.isArray(expr.tree) && Array.isArray(other.tree)) { + let left_vars = left[2]; + let right_vars = right[2]; + let gcd_vars = []; + let left_length = left_vars.length; + let right_length = right_vars.length; - let expr_operator = expr.tree[0]; - let expr_operands = expr.tree.slice(1); - let other_operator = other.tree[0]; - let other_operands = other.tree.slice(1); + let i = 0; + let j = 0; + while (i < left_length && j < right_length){ + if (left_vars[i][0] === right_vars[j][0]){ + if (left_vars[i][1] < right_vars[j][1]){ + gcd_vars.push(left_vars[i]); + } + else{ + gcd_vars.push(right_vars[j]); + } + i = i + 1; + j = j + 1; + } + else if (compare_function(left_vars[i][0], right_vars[j][0]) < 0){ + i = i + 1; + } + else if (compare_function(right_vars[j][0], left_vars[i][0]) < 0){ + j = j + 1; + } + } - if (expr_operator === 'tuple' || expr_operator === 'vector' - || expr_operator === 'list' || expr_operator === 'array' - || expr_operator === 'matrix' || expr_operator === 'interval' - ) { + if (gcd_vars.length === 0) + return 1; //if they have no common variables, gcd is 1 - if (other_operator !== expr_operator) - return false; + return ["monomial", 1, gcd_vars]; + } - if (other_operands.length !== expr_operands.length) - return false; + function mono_div(top, bottom) { + //!!This function should only be called if bottom has coefficient 1 and divides the top (e.g., bottom was computed using mono_gcd)!! + //takes two monomials ["monomial", coeff, terms array] and returns their quotient as a monomial + //stringify vars before calling this - for (let i = 0; i < expr_operands.length; i++) { - if (!equals({ - expr: expr_context.fromAst(expr_operands[i]), - other: other_context.fromAst(other_operands[i]), - randomBindings: randomBindings, - expr_context: expr_context, - other_context: other_context, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - rng, - })) - return false; + if ( !Array.isArray(bottom) || bottom[0] !== "monomial"){ + //if bottom is constant + if (bottom === 1) + return top; + if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant + return evaluate_numbers(['/', top, bottom]); + else + return [top[0], evaluate_numbers(['/', top[1], bottom]), top[2]]; //shouldn't be passing constants other than 1 } - return true; // each component is equal - } + if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant and bottom is not + return undefined; - // check if a relation with two operands - if (expr_operands.length === 2 && ["=", '>', '<', 'ge', 'le'].includes(expr_operator)) { - if (other_operands.length !== 2) { - return false; - } - //normalize operator - if (expr_operator === ">") { - expr_operator = "<"; - expr_operands = [expr_operands[1], expr_operands[0]]; - } else if (expr_operator === "ge") { - expr_operator = "le"; - expr_operands = [expr_operands[1], expr_operands[0]]; - } - if (other_operator === ">") { - other_operator = "<"; - other_operands = [other_operands[1], other_operands[0]]; - } else if (other_operator === "ge") { - other_operator = "le"; - other_operands = [other_operands[1], other_operands[0]]; - } + let top_vars = top[2]; + let bottom_vars = bottom[2]; + let div_vars = []; + let top_length = top_vars.length; + let bottom_length = bottom_vars.length; - if (expr_operator !== other_operator) { - return false; + let i = 0; + let j = 0; + while (i < top_length && j < bottom_length){ + if (top_vars[i][0] === bottom_vars[j][0]){ + if (top_vars[i][1] < bottom_vars[j][1]){ + return undefined; //does not divide + } + else{ + let diff = top_vars[i][1] - bottom_vars[j][1]; + if (diff !== 0) + div_vars.push( [ top_vars[i][0] , diff ] ); + } + i = i + 1; + j = j + 1; + } + else if (compare_function(top_vars[i][0], bottom_vars[j][0]) < 0){ + div_vars.push( top_vars[i] ); + i = i + 1; + } + else if (compare_function(bottom_vars[j][0], top_vars[i][0]) < 0){ + return undefined; //does not divide + } } - // put in standard form - let expr_rhs = ['+', expr_operands[0], ['-', expr_operands[1]]]; - let other_rhs = ['+', other_operands[0], ['-', other_operands[1]]]; - let require_positive_proportion = (expr_operator !== "="); - - return component_equals({ - expr: expr_context.fromAst(expr_rhs), - other: other_context.fromAst(other_rhs), - randomBindings: randomBindings, - expr_context: expr_context, - other_context: other_context, - allow_proportional: true, - require_positive_proportion: require_positive_proportion, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - rng, - }); - - } - - } - - // if not special case, use standard numerical equality - return component_equals({ - expr: expr, - other: other, - randomBindings: randomBindings, - expr_context: expr_context, - other_context: other_context, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - rng, - }); + if (j < bottom_length) + return undefined; -}; - - -const component_equals = function ({ expr, other, randomBindings, - expr_context, other_context, - allow_proportional = false, require_positive_proportion = false, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers, include_error_in_number_exponents, - allowed_error_is_absolute, - rng -}) { - - var max_value = Number.MAX_VALUE * 1E-20; - var min_nonzero_value = 0;//1E-100; //Number.MIN_VALUE & 1E20; - - var minimum_matches = 10; - var number_tries = 100; - // if (allowed_error_in_numbers > 0) { - // minimum_matches = 400; - // number_tries = 4000; - // } - - // normalize function names, so in particular, e^x becomes exp(x) - expr = expr.normalize_function_names(); - other = other.normalize_function_names(); - - // convert subscripts to strings so that variables like x_t are considered single variable - expr = expr.subscripts_to_strings(); - other = other.subscripts_to_strings(); - - // Get set of variables mentioned in at least one of the two expressions - var variables = [expr.variables(), other.variables()]; - variables = variables.reduce(function (a, b) { return a.concat(b); }); - variables = variables.reduce(function (p, c) { - if (p.indexOf(c) < 0) p.push(c); - return p; - }, []); - - // pi, e, and i shouldn't be treated as a variable - // for the purposes of equality if they are defined as having values - if (math$19.define_pi) { - variables = variables.filter(function (a) { - return (a !== "pi"); - }); - } - if (math$19.define_i) { - variables = variables.filter(function (a) { - return (a !== "i"); - }); - } - if (math$19.define_e) { - variables = variables.filter(function (a) { - return (a !== "e"); - }); - } + while (i < top_length){ + div_vars.push( top_vars[i]); + i=i+1; + } - // determine if any of the variables are integers - // consider integer if is integer in either expressions' assumptions - var integer_variables = []; - for (let i = 0; i < variables.length; i++) - if (is_integer_ast(variables[i], expr_context.assumptions) - || is_integer_ast(variables[i], other_context.assumptions)) - integer_variables.push(variables[i]); - - // determine if any of the variables are functions - var functions = [expr.functions(), other.functions()]; - functions = functions.reduce(function (a, b) { return a.concat(b); }); - functions = functions.reduce(function (p, c) { - if (p.indexOf(c) < 0) p.push(c); - return p; - }, []); - functions = functions.filter(function (a) { - return a.length == 1; - }); + if (div_vars.length === 0){ + if (bottom[1] === 1) + return top[1]; //everything canceled, return coefficient of the top + else + return evaluate_numbers(['/', top[1], bottom[1]]); + } - try { - var expr_f = expr.f(); - var other_f = other.f(); - } - catch (e) { - // Can't convert to mathjs to create function - // just check if equal via syntax - return expr.equalsViaSyntax(other) + if (bottom[1] === 1) + return ["monomial", top[1], div_vars]; + else + return ["monomial", evaluate_numbers(['/', top[1], bottom[1]]), div_vars]; } - let expr_with_params, parameters_for_numbers; - let tolerance_function; + function mono_is_div(top, bottom) { + //takes two monomials ["monomial", coeff, terms array] and returns true if bottom divides top, otherwise returns false + //stringify vars before calling this - if (allowed_error_in_numbers > 0) { - let result = replace_numbers_with_parameters({ - expr: expr, - variables: variables, - include_exponents: include_error_in_number_exponents, - }); - expr_with_params = expr_context.fromAst(result.expr_with_params); - parameters_for_numbers = result.parameters; + if (bottom === 0) + return false; - let parameter_list = Object.keys(parameters_for_numbers); - if (parameter_list.length > 0) { - let derivative_sum = expr_with_params.derivative(parameter_list[0]); - if (!allowed_error_is_absolute) { - derivative_sum = derivative_sum - .multiply(parameters_for_numbers[parameter_list[0]]); + if ( !Array.isArray(bottom) || bottom[0] !== "monomial"){ //if bottom is nonzero constant + return true; } - if (parameter_list.length > 1) { - for (let par of parameter_list.slice(1)) { - let term = expr_with_params.derivative(par); - if (!allowed_error_is_absolute) { - term = term.multiply(parameters_for_numbers[par]); + + if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant and bottom is not + return false; + + let top_vars = top[2]; + let bottom_vars = bottom[2]; + let div_vars = []; + let top_length = top_vars.length; + let bottom_length = bottom_vars.length; + + let i = 0; + let j = 0; + while (i < top_length && j < bottom_length){ + if (top_vars[i][0] === bottom_vars[j][0]){ + if (top_vars[i][1] < bottom_vars[j][1]){ + return false; //does not divide + } + else{ + let diff = top_vars[i][1] - bottom_vars[j][1]; + if (diff !== 0) + div_vars.push( [ top_vars[i][0] , diff ] ); + } + i = i + 1; + j = j + 1; + } + else if (compare_function(top_vars[i][0], bottom_vars[j][0]) < 0){ + div_vars.push( top_vars[i] ); + i = i + 1; + } + else if (compare_function(bottom_vars[j][0], top_vars[i][0]) < 0){ + return false; //does not divide } - derivative_sum = derivative_sum.add(term); - } } - let tolerance_expression = derivative_sum.multiply(allowed_error_in_numbers); + if (j < bottom_length) + return false; - try { - tolerance_function = tolerance_expression.f(); - } catch (e) { - // can't create function out of derivative - // so can't compute tolerance that would correspond - // to the allowed error in numbers + return true; + } - // Leave tolerance_function undefined + function mono_to_poly(mono){ + //takes a monomial ["monomial", coeff, terms array] and returns the corresponding polynomial ["polynomial", var1, ...] - } + if ( !Array.isArray(mono) || mono[0] !== "monomial") + return mono; //if constant, just return itself - } + let num_vars = mono[2].length; + let i = num_vars-1; + let result = mono[1]; + + while ( i >= 0){ + var coeffs = []; + coeffs.push([mono[2][i][1],result]); + result = ["polynomial", mono[2][i][0], coeffs]; + i=i-1; + } + return result; } + function max_div_init(f$$1, monos){ + //f is a polynomial ["polynomial", ...], monos is array of monomials ["monomial", ...]. returns the largest term (a monomial) of f divisible by something + //in monos, and the index of the divisor. + //stringify vars before calling this + if ( f$$1 === 0){ + return 0; + } + let focus = f$$1; + let var_powers = []; - var noninteger_binding_scale = 1; + while( Array.isArray(focus) && focus[0] === "polynomial"){ + let x = focus[1]; + let terms = focus[2]; + let exp = terms[terms.length-1][0]; + focus = terms[terms.length-1][1]; + var_powers.push([x,exp]); + } - var binding_scales = [10, 1, 100, 0.1, 1000, 0.01]; - var scale_num = 0; + let current_term = ["monomial", focus, var_powers]; - // Numerical test of equality - // If can find a region of the complex plane where the functions are equal - // at minimum_matches points, consider the functions equal - // unless the functions were always zero, in which case - // test at multiple scales to check for underflow + let monos_size = monos.length; + for ( var i = 0; i < monos_size; i = i+1 ){ + if (mono_is_div(current_term, monos[i])){ + return [current_term, i]; + } + } - // In order to account for possible branch cuts, - // finding points where the functions are not equal does not lead to the - // conclusion that expression are unequal. Instead, to be consider unequal - // the functions must be unequal around many different points. + return max_div_init(polynomial_sub( f$$1, mono_to_poly(current_term)), monos); + } - let num_at_this_scale = 0; + function poly_div(f$$1, divs){ + //takes a polynomial f and an array of polynomials div = [g1,g2,...], and returns a standard expression (according to mult. division) of the form [[[s1,m1],[s2,m2],....], f'] where f=m1g_{s1}+m2g_{s2}+...+f' + //stringify vars before calling this - let always_zero = true; + let inits = []; + let su_mu = []; + let sp = []; + let mp = []; + let f_prime = f$$1; - let num_finite_unequal = 0; + for (var g of divs){ + inits.push(initial_term(g)); + } - for (let i = 0; i < 10 * number_tries; i++) { + let m = max_div_init(f_prime, inits); - // Look for a location where the magnitudes of both expressions - // are below max_value; - try { - var result = find_equality_region(binding_scales[scale_num], rng); - } - catch (e) { - continue; - } + while (m !== 0){ + sp = m[1]; + mp = mono_div(m[0], inits[sp]); + su_mu.push([sp, mp]); + f_prime = polynomial_sub(f_prime, polynomial_mul(mono_to_poly(mp), divs[sp])); + m = max_div_init(f_prime, inits); + } - if (result.always_zero === false) { - always_zero = false; - } + return [su_mu, f_prime]; + } + function prereduce(polys){ + //takes an array of polys, and does some simply reductions: gets rid of 0 polynomials, if there's a constant: just return [1], if there are no nonzero polys: return [0]. - if (!result.equal && !result.out_of_bounds && !result.always_zero && - result.sufficient_finite_values !== false - ) { - num_finite_unequal++; - if (num_finite_unequal > number_tries) { - return false; - } - } + let len = polys.length; + let new_polys = []; - if (result.equal) { - if (result.always_zero) { - if (!always_zero) { - // if found always zero this time, but wasn't zero at a different point - // don't count as equal - continue; - } - // functions equal but zero - // repeat to make sure (changing if continuing to be zero) - num_at_this_scale += 1; - if (num_at_this_scale > 5) { - scale_num += 1; - num_at_this_scale = 0; - } - if (scale_num >= binding_scales.length) { - return true; // were equal and zero at all scales - } else - continue - } - else { - return true; + //check for 0's, constants + for (var j = 0; j < len; j++ ){ + if (polys[j] !== 0 && (!Array.isArray(polys[j]) || polys[j][0] !== "polynomial")){ + return [1]; //if there's a nonzero constant, return [1] + } + if (polys[j] !== 0){ + new_polys.push(polys[j]); + } } - } + + if (new_polys.length === 0) + return [0]; + + return new_polys; } - return false; + function reduce_ith(i, polys){ + //takes an index i and an array polys of polynomials, and reduces the ith polynomial wrt the rest (i.e., finds a std expression and replaces with f'). Returns the reduced polynomial. + //stringify vars before calling this + let inits = []; + let sp = []; + let mp = []; + let f_prime = polys[i]; + let len = polys.length; - function find_equality_region(noninteger_scale, rng) { + for (var j = 0; j < len; j = j+1){ + if (j === i) //don't want to cancel out with itself, so put 0 for this initial term instead to avoid it being used + inits.push(0); + else + inits.push(initial_term(polys[j])); + } - // Check if expr and other are equal in a region as follows - // 1. Randomly select bindings (use noninteger scale for non-integer variables) - // and evaluate expr and other at that point - // 2. If either value is too large, return { out_of_bounds: true } - // 3. If values are not equal (within tolerance), return { equal_at_start: false } - // 4. If functions are equal, then - // randomly select binding in neighborhood of that point - // (use non_integer scale/100 for non-integer variables) - // 5. If find a point where the functions are not equal, - // then return { equal_in_middle: false } - // 6. If find that functions are equal at minimum_matches points - // then return { equality: true, always_zero: always_zero } - // where always_zero is true if both functions were always zero - // and is false otherwise - // 7. If were unable to find sufficent points where both functions are finite - // return { sufficient_finite_values: false } - // If allow_proportional is true, then instead of return non-equal - // in step 3, use the ratio of value of these first evaluations to set - // the proportion, and base equality on remaining values having the - // same proportion + let m = max_div_init(f_prime, inits); + while (m !== 0){ + sp = m[1]; + mp = mono_div(m[0], inits[sp]); + f_prime = polynomial_sub(f_prime, polynomial_mul(mono_to_poly(mp), polys[sp])); + m = max_div_init(f_prime, inits); + } + return f_prime; - var bindings = randomBindings(rng, variables, noninteger_scale); + /* OLD CODE: - // replace any integer variables with integer - for (let i = 0; i < integer_variables.length; i++) { - bindings[integer_variables[i]] = generate_random_integer(-10, 10, rng); - } + if (!Array.isArray(polys) || i >= polys.length){ + return undefined; + } - // replace any function variables with a function - for (let i = 0; i < functions.length; i++) { - var a = generate_random_integer(-10, 10, rng); - var b = generate_random_integer(-10, 10, rng); - var c = generate_random_integer(-10, 10, rng); - bindings[functions[i]] = function (x) { - return math$19.add(math$19.multiply(math$19.add(math$19.multiply(a, x), b), x), c); - }; - } + let len = polys.length; + let new_polys = []; + //check for 0's, constants + for (var j = 0; j < len; j++ ){ + if (polys[j] !== 0 && (!Array.isArray(polys[j]) || polys[j][0] !== "polynomial")){ + return 1; //if there's a nonzero constant, return [1] + } + if (polys[j] !== 0){ + new_polys.push(polys[j]); + } + } - var bindingsIncludingParameters; - if (tolerance_function) { - bindingsIncludingParameters = Object.assign({}, bindings, parameters_for_numbers); - } + len = new_polys.length; - var expr_evaluated = expr_f(bindings); - var other_evaluated = other_f(bindings); + if (len === 0) + return 0; //if there were no nonzero polys, return [0] - var expr_abs = math$19.abs(expr_evaluated); - var other_abs = math$19.abs(other_evaluated); + if (len === 1) + return new_polys[0]; //if there's only one poly, don't need to reduce - if (!(expr_abs < max_value && other_abs < max_value)) - return { out_of_bounds: true, always_zero: false }; + let others = []; + for ( var j = 0; j < len; j++ ){ + if (j !== i) + others.push(new_polys[j]); + } - if (!((expr_abs === 0 || expr_abs > min_nonzero_value) && - (other_abs === 0 || other_abs > min_nonzero_value))) - return { out_of_bounds: true, always_zero: false }; + return poly_div(new_polys[i], others)[1];*/ + } - // now that found a finite point, - // check to see if expressions are nearly equal. + function reduce$1(polys){ + //takes an array of polynomials, and reduces them with respect to each other until they can't be reduced anymore. Returns array of reduced polynomials. + //this could be made more efficient with better bookkeeping if necessary - currently copying sub-arrays a lot, whenever call reduce_ith. Would need to track changes in sub-arrays. + //stringify vars before calling this - var min_mag = Math.min(expr_abs, other_abs); - var max_mag = Math.max(expr_abs, other_abs); - var proportion = 1; + let i = 0; + let h=[]; + let new_polys = prereduce(polys); + let len = new_polys.length; - let tol = 0; - if (tolerance_function) { - try { - tol = math$19.abs(tolerance_function(bindingsIncludingParameters)); - } catch (e) { - return { equal_at_start: false, always_zero: false }; + if (len === 1) + return new_polys; //if there's only one poly, don't need to reduce + /*prereduce more frequently: + while (i < len){ + h = reduce_ith(i, new_polys); + if ( _.isEqual( h, new_polys[i] )){ //from underscore lib to compare arrays with objects + i=i+1; + } + else{ + new_polys[i] = h; + i = 0; + new_polys = prereduce(new_polys); + len = new_polys.length; + } + }*/ + + /* This code prereduces less frequently, maybe slightly faster?*/ + let trigger = true; + while (trigger){ + trigger = false; + new_polys = prereduce(new_polys); + len = new_polys.length; + i = 0; + while (i < len){ + h = reduce_ith(i, new_polys); + if ( !underscore.isEqual( h, new_polys[i] )){ //from underscore lib to compare arrays with objects + new_polys[i]=h; + trigger = true; + } + i = i+1; + } } - if (!Number.isFinite(tol)) { - return { equal_at_start: false, always_zero: false }; + + i = 0; + let init = []; + let coeff = 0; + while (i < len){ //leading coeffs should be 1 + init = initial_term(new_polys[i]); + if (!Array.isArray(init) || init[0] !== "monomial") + new_polys[i] = 1; + else{ + coeff = init[1]; + if (coeff !== 1) + new_polys[i] = polynomial_mul(new_polys[i], ['/', 1, coeff]); + } + i = i + 1; } - } - tol += min_mag * relative_tolerance; + return new_polys; + } - // never allow tol to get over 10% the min_mag - tol = Math.min(tol, 0.1 * min_mag); + function hij(i, j, polys){ + //takes indices i,j and an array of polynomials. Returns the polynomial hij computed from the ith and jth polys in polynomials, for Buchberger's criterion. + //stringify vars before calling this + let init_gi = initial_term(polys[i]); + let init_gj = initial_term(polys[j]); + let gcd = mono_gcd(init_gi, init_gj); + let mij = mono_to_poly(mono_div(init_gi, gcd)); + let mji = mono_to_poly(mono_div(init_gj, gcd)); + let std_exp = poly_div(polynomial_sub(polynomial_mul(mji, polys[i]), polynomial_mul(mij, polys[j])), polys); + return std_exp[1]; + } - // don't use min_mag to check for zero as mag will be zero - // for very small complex numbers - if (tol === 0 && (expr_evaluated === 0 || other_evaluated === 0)) { - tol += tolerance_for_zero; - } else { - tol += absolute_tolerance; - } + function build_hij_table(table, polys){ + //takes an empty table and an array of polynomials, and fills in table where table[[i,j]]=h_ij for i < j < polys.length. (Look up h_ij based on the index in polys) returns first choice for h + //stringify vars before calling this - if (!( - max_mag === 0 || - math$19.abs(math$19.subtract(expr_evaluated, other_evaluated)) < tol - )) { - if (!allow_proportional) { - return { equal_at_start: false, always_zero: false }; - } - // at this point, know both are not zero - if (expr_abs === 0 || other_abs === 0) { - return { equal_at_start: false, always_zero: false }; - } + let len = polys.length; + let i = 0; + let j = 1; + + let candidates = []; - proportion = math$19.divide(expr_evaluated, other_evaluated); - if (require_positive_proportion && !(proportion > 0)) { - return { equal_at_start: false, always_zero: false }; + while (j < len){ + while (i < j){ + table[[i,j]] = hij(i,j,polys); + if (table[[i,j]] !== 0) + candidates.push(table[[i,j]]); + i = i + 1; + } + i = 0; + j = j + 1; } - } + if (candidates.length > 0) + return choice_lowest_degree(candidates); //call different choice functions here. Could avoid iterating through again if check as go. - var always_zero = (max_mag === 0); + return 0; + } - // Look for a region around point - var finite_tries = 0; - for (let j = 0; j < 100; j++) { - var bindings2 = randomBindings( - rng, variables, noninteger_binding_scale / 100, bindings); + function update_hij_table(table, polys, h){ + //takes an hij table, array of polynomials that the table was built for, and a poynomial h. Updates the hij values for the addition of the polynomial h, h is added with the highest index. return next choice of h. - // replace any integer variables with integer - for (let k = 0; k < integer_variables.length; k++) { - bindings2[integer_variables[k]] - = generate_random_integer(-10, 10, rng); - } + let len = polys.length; + polys.push(h); + let i = 0; + let j = 1; - // replace any function variables with a function - for (let i = 0; i < functions.length; i++) { - var a = generate_random_integer(-10, 10, rng); - var b = generate_random_integer(-10, 10, rng); - var c = generate_random_integer(-10, 10, rng); - bindings2[functions[i]] = function (x) { - return math$19.add(math$19.multiply(math$19.add(math$19.multiply(a, x), b), x), c); - }; + let candidates = []; + while (j < len){ //this loop updates old hij values. + while (i < j){ + if (table[[i,j]] !== 0){ + table[[i,j]] = hij(i,j,polys); + if (table[[i,j]] !== 0) + candidates.push(table[[i,j]]); + } + i = i + 1; + } + i = 0; + j = j+1; } - var bindings2IncludingParameters; - if (tolerance_function) { - bindings2IncludingParameters = Object.assign({}, bindings2, parameters_for_numbers); + while (i < len){ //this loop adds values with h + table [[i,len]] = hij(i,len,polys); + if (table[[i,len]] !== 0) + candidates.push(table[[i,len]]); + i = i + 1; } - try { - expr_evaluated = expr_f(bindings2); - other_evaluated = math$19.multiply(other_f(bindings2), proportion); - } - catch (e) { - continue; - } - expr_abs = math$19.abs(expr_evaluated); - other_abs = math$19.abs(other_evaluated); + if (candidates.length > 0) + return choice_lowest_degree(candidates); //call different choice functions here. Could avoid iterating through again if check as go. - if (expr_abs < max_value && other_abs < max_value) { - min_mag = Math.min(expr_abs, other_abs); - max_mag = Math.max(expr_abs, other_abs); + return 0; + } - finite_tries++; + function choice_lowest_degree(polys){ + //takes an array of polynomials, returns the polynomial of lowest degree. - let tol = 0; - if (tolerance_function) { - try { - tol = math$19.abs(tolerance_function(bindings2IncludingParameters)); - } catch (e) { - continue; - } - if (!Number.isFinite(tol)) { - continue; - } - } - tol += min_mag * relative_tolerance; + let inits = []; + let len = polys.length; - // never allow tol to get over 10% the min_mag - tol = Math.min(tol, 0.1 * min_mag); + for (i = 0; i < len; i = i+1){ + inits.push(initial_term(polys[i])); + } - // don't use min_mag to check for zero as mag will be zero - // for very small complex numbers - if (tol === 0 && (expr_evaluated === 0 || other_evaluated === 0)) { - tol += tolerance_for_zero; - } else { - tol += absolute_tolerance; - } + let min_index = 0; + for (var i = 1; i < len; i = i+1){ + if (inits[i] === 1) + return 1; + if (mono_less_than(inits[i], inits[min_index])) + min_index = i; + } - if (!( - max_mag === 0 || - math$19.abs(math$19.subtract(expr_evaluated, other_evaluated)) < tol - )) { - return { equality_in_middle: false, always_zero: false }; - } + return polys[min_index]; + } - always_zero = always_zero && (max_mag === 0); + function reduced_grobner(polys){ + //takes an array of polynomials, returns reduced grobner basis of the ideal they generate. + //stringify vars before calling this - if (finite_tries >= minimum_matches) { - return { equal: true, always_zero: always_zero } - } + let new_polys = reduce$1(polys); + + let table = {}; + let h = build_hij_table(table, new_polys); + while (h !== 0){ + h = update_hij_table(table, new_polys, h); } - } - return { sufficient_finite_values: false, always_zero: always_zero }; - } -}; + new_polys = reduce$1(new_polys); -function replace_numbers_with_parameters({ expr, variables, include_exponents = false }) { + return new_polys; + } - // find all numbers, including pi and e, if defined as numerical - let parameters = {}; - let lastParNum = 0; + function poly_lcm(f$$1,g){ + //takes two polynomials f and g, and returns their least common multiple. + //stringify vars before calling this - function get_new_parameter_name() { - lastParNum++; - let parName = "par" + lastParNum; - while (variables.includes(parName)) { - lastParNum++; - parName = "par" + lastParNum; - } + let t = ["polynomial", "_t", [[1,1]]]; + let one_minus_t = ["polynomial", "_t", [[0,1], [1,-1]]]; + let grob = reduced_grobner([polynomial_mul(t, f$$1), polynomial_mul(one_minus_t, g)]); - // found a new parameter name that isn't a variable - return parName; + //find term without _t + let len = grob.length; + for (var i = 0; i < len; i = i + 1){ + if (!Array.isArray(grob[i]) || grob[i][0] !== "polynomial"){ + return 1; //if there is a constant in the grobner basis, return 1 (shouldn't have constants other than 1, so could probably just check for 1) + } + if (grob[i][1] !== "_t") + return grob[i]; + } + return undefined; //this should never be reached, unless something bad happens? } - function replace_number_sub(tree) { - if (typeof tree === 'number') { - if (tree === 0) { - // since will compute bounds for relative error in numbers - // can't include zero - return tree; - } else { - let par = get_new_parameter_name(); - parameters[par] = tree; - return par; + function poly_gcd(f$$1,g){ + //takes two polynomials f and g, and returns their greatest common divisor. + //stringify vars before calling this + + let lcm = poly_lcm(f$$1,g); + let fg = polynomial_mul(f$$1,g); + let std_exp = poly_div(fg, [lcm]); + + let sum = 0; + let len = std_exp[0].length; + for (var i = 0; i < len; i = i+1){ + sum = polynomial_add(sum, mono_to_poly(std_exp[0][i][1])); } - } - if (typeof tree === "string") { - if (tree === "pi") { - if (math$19.define_pi) { - let par = get_new_parameter_name(); - parameters[par] = math$19.PI; - return par; - } - } else if (tree === "e") { - if (math$19.define_e) { - let par = get_new_parameter_name(); - parameters[par] = math$19.e; - return par; - } + //divide by leading coeff, so leading coeff of gcd is 1 + let init = initial_term(sum); + if (!Array.isArray(init) || init[0] !== "monomial") + sum = 1; + else{ + let coeff = init[1]; + if (coeff !== 1) + sum = polynomial_mul(sum, ['/', 1, coeff]); } - return tree; - } - if (!Array.isArray(tree)) { - return tree; - } + return sum; + } - let operator = tree[0]; - let operands = tree.slice(1); - if (operator === "^" && !include_exponents) { - return [operator, replace_number_sub(operands[0]), operands[1]] - } else { - return [operator, ...operands.map(replace_number_sub)]; - } - - } - - // first evaluate numbers to combine then - // and turn any numerical constants to floating points - expr = expr.evaluate_numbers({ max_digits: Infinity }); - return { - expr_with_params: replace_number_sub(expr.tree), - parameters: parameters - } - -} - -var alea = createCommonjsModule(function (module) { -// A port of an algorithm by Johannes Baagøe , 2010 -// http://baagoe.com/en/RandomMusings/javascript/ -// https://github.com/nquinlan/better-random-numbers-for-javascript-mirror -// Original work is under MIT license - - -// Copyright (C) 2010 by Johannes Baagøe -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - - - -(function(global, module, define) { - -function Alea(seed) { - var me = this, mash = Mash(); - - me.next = function() { - var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32 - me.s0 = me.s1; - me.s1 = me.s2; - return me.s2 = t - (me.c = t | 0); - }; - - // Apply the seeding algorithm from Baagoe. - me.c = 1; - me.s0 = mash(' '); - me.s1 = mash(' '); - me.s2 = mash(' '); - me.s0 -= mash(seed); - if (me.s0 < 0) { me.s0 += 1; } - me.s1 -= mash(seed); - if (me.s1 < 0) { me.s1 += 1; } - me.s2 -= mash(seed); - if (me.s2 < 0) { me.s2 += 1; } - mash = null; -} - -function copy(f, t) { - t.c = f.c; - t.s0 = f.s0; - t.s1 = f.s1; - t.s2 = f.s2; - return t; -} - -function impl(seed, opts) { - var xg = new Alea(seed), - state = opts && opts.state, - prng = xg.next; - prng.int32 = function() { return (xg.next() * 0x100000000) | 0; }; - prng.double = function() { - return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 - }; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; -} - -function Mash() { - var n = 0xefc8249d; - - var mash = function(data) { - data = String(data); - for (var i = 0; i < data.length; i++) { - n += data.charCodeAt(i); - var h = 0.02519603282416938 * n; - n = h >>> 0; - h -= n; - h *= n; - n = h >>> 0; - h -= n; - n += h * 0x100000000; // 2^32 - } - return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 - }; - - return mash; -} - - -if (module && module.exports) { - module.exports = impl; -} else if (define && define.amd) { - define(function() { return impl; }); -} else { - this.alea = impl; -} - -})( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader -); -}); - -var xor128 = createCommonjsModule(function (module) { -// A Javascript implementaion of the "xor128" prng algorithm by -// George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper - -(function(global, module, define) { - -function XorGen(seed) { - var me = this, strseed = ''; - - me.x = 0; - me.y = 0; - me.z = 0; - me.w = 0; - - // Set up generator function. - me.next = function() { - var t = me.x ^ (me.x << 11); - me.x = me.y; - me.y = me.z; - me.z = me.w; - return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8); - }; - - if (seed === (seed | 0)) { - // Integer seed. - me.x = seed; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 64; k++) { - me.x ^= strseed.charCodeAt(k) | 0; - me.next(); - } -} - -function copy(f, t) { - t.x = f.x; - t.y = f.y; - t.z = f.z; - t.w = f.w; - return t; -} - -function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; -} - -if (module && module.exports) { - module.exports = impl; -} else if (define && define.amd) { - define(function() { return impl; }); -} else { - this.xor128 = impl; -} - -})( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader -); -}); - -var xorwow = createCommonjsModule(function (module) { -// A Javascript implementaion of the "xorwow" prng algorithm by -// George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper - -(function(global, module, define) { - -function XorGen(seed) { - var me = this, strseed = ''; - - // Set up generator function. - me.next = function() { - var t = (me.x ^ (me.x >>> 2)); - me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v; - return (me.d = (me.d + 362437 | 0)) + - (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0; - }; - - me.x = 0; - me.y = 0; - me.z = 0; - me.w = 0; - me.v = 0; - - if (seed === (seed | 0)) { - // Integer seed. - me.x = seed; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 64; k++) { - me.x ^= strseed.charCodeAt(k) | 0; - if (k == strseed.length) { - me.d = me.x << 10 ^ me.x >>> 4; - } - me.next(); - } -} - -function copy(f, t) { - t.x = f.x; - t.y = f.y; - t.z = f.z; - t.w = f.w; - t.v = f.v; - t.d = f.d; - return t; -} - -function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; -} - -if (module && module.exports) { - module.exports = impl; -} else if (define && define.amd) { - define(function() { return impl; }); -} else { - this.xorwow = impl; -} - -})( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader -); -}); - -var xorshift7 = createCommonjsModule(function (module) { -// A Javascript implementaion of the "xorshift7" algorithm by -// François Panneton and Pierre L'ecuyer: -// "On the Xorgshift Random Number Generators" -// http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf - -(function(global, module, define) { - -function XorGen(seed) { - var me = this; - - // Set up generator function. - me.next = function() { - // Update xor generator. - var X = me.x, i = me.i, t, v; - t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24); - t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10); - t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3); - t = X[(i + 4) & 7]; v ^= t ^ (t << 7); - t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9); - X[i] = v; - me.i = (i + 1) & 7; - return v; - }; - - function init(me, seed) { - var j, w, X = []; + function poly_by_divisor(f$$1, d){ + //takes two polynomials f and d (where d is a divisor of f), and returns f divided by d. + //!!Only call if d evenly divides f!! + //stringify vars before calling this - if (seed === (seed | 0)) { - // Seed state array using a 32-bit integer. - w = X[0] = seed; - } else { - // Seed state using a string. - seed = '' + seed; - for (j = 0; j < seed.length; ++j) { - X[j & 7] = (X[j & 7] << 15) ^ - (seed.charCodeAt(j) + X[(j + 1) & 7] << 13); + let std_exp = poly_div(f$$1, [d]); + let sum = 0; + let len = std_exp[0].length; + for (var i = 0; i < len; i = i+1){ + sum = polynomial_add(sum, mono_to_poly(std_exp[0][i][1])); } - } - // Enforce an array length of 8, not all zeroes. - while (X.length < 8) X.push(0); - for (j = 0; j < 8 && X[j] === 0; ++j); - if (j == 8) w = X[7] = -1; else w = X[j]; - - me.x = X; - me.i = 0; - - // Discard an initial 256 values. - for (j = 256; j > 0; --j) { - me.next(); - } + return sum; } - init(me, seed); -} + function reduce_rational_expression(top, bottom){ + //input: top and bottom of a rational expression. top and bottom should be polynomials, ["polynomial", ...]. returns an array with two entries: new_top and new_bottom, which are reduced (gcd of new_top and new_bottom is 1). new_bottom will always have leading coefficient 1 (according to lexicographic order) -function copy(f, t) { - t.x = f.x.slice(); - t.i = f.i; - return t; -} + let stringy_top = stringify_vars(top); + let stringy_bottom = stringify_vars(bottom); + top = stringy_top[0]; + bottom = stringy_bottom[0]; -function impl(seed, opts) { - if (seed == null) seed = +(new Date); - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (state.x) copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; -} - -if (module && module.exports) { - module.exports = impl; -} else if (define && define.amd) { - define(function() { return impl; }); -} else { - this.xorshift7 = impl; -} - -})( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader -); -}); - -var xor4096 = createCommonjsModule(function (module) { -// A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm. -// -// This fast non-cryptographic random number generator is designed for -// use in Monte-Carlo algorithms. It combines a long-period xorshift -// generator with a Weyl generator, and it passes all common batteries -// of stasticial tests for randomness while consuming only a few nanoseconds -// for each prng generated. For background on the generator, see Brent's -// paper: "Some long-period random number generators using shifts and xors." -// http://arxiv.org/pdf/1004.3115v1.pdf -// -// Usage: -// -// var xor4096 = require('xor4096'); -// random = xor4096(1); // Seed with int32 or string. -// assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits. -// assert.equal(random.int32(), 1806534897); // signed int32, 32 bits. -// -// For nonzero numeric keys, this impelementation provides a sequence -// identical to that by Brent's xorgens 3 implementaion in C. This -// implementation also provides for initalizing the generator with -// string seeds, or for saving and restoring the state of the generator. -// -// On Chrome, this prng benchmarks about 2.1 times slower than -// Javascript's built-in Math.random(). - -(function(global, module, define) { - -function XorGen(seed) { - var me = this; - - // Set up generator function. - me.next = function() { - var w = me.w, - X = me.X, i = me.i, t, v; - // Update Weyl generator. - me.w = w = (w + 0x61c88647) | 0; - // Update xor generator. - v = X[(i + 34) & 127]; - t = X[i = ((i + 1) & 127)]; - v ^= v << 13; - t ^= t << 17; - v ^= v >>> 15; - t ^= t >>> 12; - // Update Xor generator array state. - v = X[i] = v ^ t; - me.i = i; - // Result is the combination. - return (v + (w ^ (w >>> 16))) | 0; - }; - - function init(me, seed) { - var t, v, i, j, w, X = [], limit = 128; - if (seed === (seed | 0)) { - // Numeric seeds initialize v, which is used to generates X. - v = seed; - seed = null; - } else { - // String seeds are mixed into v and X one character at a time. - seed = seed + '\0'; - v = 0; - limit = Math.max(limit, seed.length); - } - // Initialize circular array and weyl value. - for (i = 0, j = -32; j < limit; ++j) { - // Put the unicode characters into the array, and shuffle them. - if (seed) v ^= seed.charCodeAt((j + 32) % seed.length); - // After 32 shuffles, take v as the starting w value. - if (j === 0) w = v; - v ^= v << 10; - v ^= v >>> 15; - v ^= v << 4; - v ^= v >>> 13; - if (j >= 0) { - w = (w + 0x61c88647) | 0; // Weyl. - t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array. - i = (0 == t) ? i + 1 : 0; // Count zeroes. - } - } - // We have detected all zeroes; make the key nonzero. - if (i >= 128) { - X[(seed && seed.length || 0) & 127] = -1; - } - // Run the generator 512 times to further mix the state before using it. - // Factoring this as a function slows the main generator, so it is just - // unrolled here. The weyl generator is not advanced while warming up. - i = 127; - for (j = 4 * 128; j > 0; --j) { - v = X[(i + 34) & 127]; - t = X[i = ((i + 1) & 127)]; - v ^= v << 13; - t ^= t << 17; - v ^= v >>> 15; - t ^= t >>> 12; - X[i] = v ^ t; - } - // Storing state as object members is faster than using closure variables. - me.w = w; - me.X = X; - me.i = i; - } - - init(me, seed); -} - -function copy(f, t) { - t.i = f.i; - t.w = f.w; - t.X = f.X.slice(); - return t; -} -function impl(seed, opts) { - if (seed == null) seed = +(new Date); - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (state.X) copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; -} - -if (module && module.exports) { - module.exports = impl; -} else if (define && define.amd) { - define(function() { return impl; }); -} else { - this.xor4096 = impl; -} - -})( - commonjsGlobal, // window object or global - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader -); -}); - -var tychei = createCommonjsModule(function (module) { -// A Javascript implementaion of the "Tyche-i" prng algorithm by -// Samuel Neves and Filipe Araujo. -// See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf - -(function(global, module, define) { - -function XorGen(seed) { - var me = this, strseed = ''; - - // Set up generator function. - me.next = function() { - var b = me.b, c = me.c, d = me.d, a = me.a; - b = (b << 25) ^ (b >>> 7) ^ c; - c = (c - d) | 0; - d = (d << 24) ^ (d >>> 8) ^ a; - a = (a - b) | 0; - me.b = b = (b << 20) ^ (b >>> 12) ^ c; - me.c = c = (c - d) | 0; - me.d = (d << 16) ^ (c >>> 16) ^ a; - return me.a = (a - b) | 0; - }; - - /* The following is non-inverted tyche, which has better internal - * bit diffusion, but which is about 25% slower than tyche-i in JS. - me.next = function() { - var a = me.a, b = me.b, c = me.c, d = me.d; - a = (me.a + me.b | 0) >>> 0; - d = me.d ^ a; d = d << 16 ^ d >>> 16; - c = me.c + d | 0; - b = me.b ^ c; b = b << 12 ^ d >>> 20; - me.a = a = a + b | 0; - d = d ^ a; me.d = d = d << 8 ^ d >>> 24; - me.c = c = c + d | 0; - b = b ^ c; - return me.b = (b << 7 ^ b >>> 25); + let gcd = poly_gcd(top, bottom); + let denom_coeff = (initial_term(bottom))[1]; + let div = polynomial_mul(gcd,denom_coeff); + let new_top = poly_by_divisor(top, div); + let new_bottom = poly_by_divisor(bottom, div); + return [destringify_vars(destringify_vars(new_top, stringy_top[1]), stringy_bottom[1]), destringify_vars(destringify_vars(new_bottom, stringy_top[1]), stringy_bottom[1])]; } - */ - me.a = 0; - me.b = 0; - me.c = 2654435769 | 0; - me.d = 1367130551; + function stringify_vars(f$$1){ + //takes a polynomial f and converts all variables to strings. Returns the new, stringy polynomial, and a dictionary to convert back to the original degrees. - if (seed === Math.floor(seed)) { - // Integer seed. - me.a = (seed / 0x100000000) | 0; - me.b = seed | 0; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 20; k++) { - me.b ^= strseed.charCodeAt(k) | 0; - me.next(); - } -} - -function copy(f, t) { - t.a = f.a; - t.b = f.b; - t.c = f.c; - t.d = f.d; - return t; -} -function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; -} - -if (module && module.exports) { - module.exports = impl; -} else if (define && define.amd) { - define(function() { return impl; }); -} else { - this.tychei = impl; -} - -})( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader -); -}); - -var require$$2 = {}; - -var seedrandom$1 = createCommonjsModule(function (module) { -/* -Copyright 2019 David Bau. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -(function (global, pool, math) { -// -// The following constants are related to IEEE 754 limits. -// - -var width = 256, // each RC4 output is 0 <= x < 256 - chunks = 6, // at least six RC4 outputs for each double - digits = 52, // there are 52 significant digits in a double - rngname = 'random', // rngname: name for Math.random and Math.seedrandom - startdenom = math.pow(width, chunks), - significance = math.pow(2, digits), - overflow = significance * 2, - mask = width - 1, - nodecrypto; // node.js crypto module, initialized at the bottom. - -// -// seedrandom() -// This is the seedrandom function described above. -// -function seedrandom(seed, options, callback) { - var key = []; - options = (options == true) ? { entropy: true } : (options || {}); - - // Flatten the seed string or build one from local entropy if needed. - var shortseed = mixkey(flatten( - options.entropy ? [seed, tostring(pool)] : - (seed == null) ? autoseed() : seed, 3), key); - - // Use the seed to initialize an ARC4 generator. - var arc4 = new ARC4(key); - - // This function returns a random double in [0, 1) that contains - // randomness in every bit of the mantissa of the IEEE 754 value. - var prng = function() { - var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 - d = startdenom, // and denominator d = 2 ^ 48. - x = 0; // and no 'extra last byte'. - while (n < significance) { // Fill up all significant digits by - n = (n + x) * width; // shifting numerator and - d *= width; // denominator and generating a - x = arc4.g(1); // new least-significant-byte. - } - while (n >= overflow) { // To avoid rounding up, before adding - n /= 2; // last byte, shift everything - d /= 2; // right using integer math until - x >>>= 1; // we have exactly the desired bits. - } - return (n + x) / d; // Form the number within [0, 1). - }; - - prng.int32 = function() { return arc4.g(4) | 0; }; - prng.quick = function() { return arc4.g(4) / 0x100000000; }; - prng.double = prng; - - // Mix the randomness into accumulated entropy. - mixkey(tostring(arc4.S), pool); - - // Calling convention: what to return as a function of prng, seed, is_math. - return (options.pass || callback || - function(prng, seed, is_math_call, state) { - if (state) { - // Load the arc4 state from the given state if it has an S array. - if (state.S) { copy(state, arc4); } - // Only provide the .state method if requested via options.state. - prng.state = function() { return copy(arc4, {}); }; - } - - // If called as a method of Math (Math.seedrandom()), mutate - // Math.random because that is how seedrandom.js has worked since v1.0. - if (is_math_call) { math[rngname] = prng; return seed; } - - // Otherwise, it is a newer calling convention, so return the - // prng directly. - else return prng; - })( - prng, - shortseed, - 'global' in options ? options.global : (this == math), - options.state); -} - -// -// ARC4 -// -// An ARC4 implementation. The constructor takes a key in the form of -// an array of at most (width) integers that should be 0 <= x < (width). -// -// The g(count) method returns a pseudorandom integer that concatenates -// the next (count) outputs from ARC4. Its return value is a number x -// that is in the range 0 <= x < (width ^ count). -// -function ARC4(key) { - var t, keylen = key.length, - me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; - - // The empty key [] is treated as [0]. - if (!keylen) { key = [keylen++]; } - - // Set up S using the standard key scheduling algorithm. - while (i < width) { - s[i] = i++; - } - for (i = 0; i < width; i++) { - s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; - s[j] = t; - } - - // The "g" method returns the next (count) outputs as one number. - (me.g = function(count) { - // Using instance members instead of closure state nearly doubles speed. - var t, r = 0, - i = me.i, j = me.j, s = me.S; - while (count--) { - t = s[i = mask & (i + 1)]; - r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; - } - me.i = i; me.j = j; - return r; - // For robust unpredictability, the function call below automatically - // discards an initial batch of values. This is called RC4-drop[256]. - // See http://google.com/search?q=rsa+fluhrer+response&btnI - })(width); -} - -// -// copy() -// Copies internal state of ARC4 to or from a plain object. -// -function copy(f, t) { - t.i = f.i; - t.j = f.j; - t.S = f.S.slice(); - return t; -} -// -// flatten() -// Converts an object tree to nested arrays of strings. -// -function flatten(obj, depth) { - var result = [], typ = (typeof obj), prop; - if (depth && typ == 'object') { - for (prop in obj) { - try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} - } - } - return (result.length ? result : typ == 'string' ? obj : obj + '\0'); -} - -// -// mixkey() -// Mixes a string seed into a key that is an array of integers, and -// returns a shortened string seed that is equivalent to the result key. -// -function mixkey(seed, key) { - var stringseed = seed + '', smear, j = 0; - while (j < stringseed.length) { - key[mask & j] = - mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); - } - return tostring(key); -} - -// -// autoseed() -// Returns an object for autoseeding, using window.crypto and Node crypto -// module if available. -// -function autoseed() { - try { - var out; - if (nodecrypto && (out = nodecrypto.randomBytes)) { - // The use of 'out' to remember randomBytes makes tight minified code. - out = out(width); - } else { - out = new Uint8Array(width); - (global.crypto || global.msCrypto).getRandomValues(out); - } - return tostring(out); - } catch (e) { - var browser = global.navigator, - plugins = browser && browser.plugins; - return [+new Date, global, plugins, global.screen, tostring(pool)]; - } -} - -// -// tostring() -// Converts an array of charcodes to a string -// -function tostring(a) { - return String.fromCharCode.apply(0, a); -} - -// -// When seedrandom.js is loaded, we immediately mix a few bits -// from the built-in RNG into the entropy pool. Because we do -// not want to interfere with deterministic PRNG state later, -// seedrandom will not call math.random on its own again after -// initialization. -// -mixkey(math.random(), pool); - -// -// Nodejs and AMD support: export the implementation as a module using -// either convention. -// -if (('object') == 'object' && module.exports) { - module.exports = seedrandom; - // When in node.js, try using crypto package for autoseeding. - try { - nodecrypto = require$$2; - } catch (ex) {} -} else if ((typeof undefined) == 'function' && undefined.amd) { - undefined(function() { return seedrandom; }); -} else { - // When included as a plain script, set up Math.seedrandom global. - math['seed' + rngname] = seedrandom; -} - - -// End anonymous scope, and pass initial values. -})( - // global: `self` in browsers (including strict mode and web workers), - // otherwise `this` in Node and other environments - (typeof self !== 'undefined') ? self : commonjsGlobal, - [], // pool: entropy pool starts empty - Math // math: package containing random, pow, and seedrandom -); -}); - -// A library of seedable RNGs implemented in Javascript. -// -// Usage: -// -// var seedrandom = require('seedrandom'); -// var random = seedrandom(1); // or any seed. -// var x = random(); // 0 <= x < 1. Every bit is random. -// var x = random.quick(); // 0 <= x < 1. 32 bits of randomness. - -// alea, a 53-bit multiply-with-carry generator by Johannes Baagøe. -// Period: ~2^116 -// Reported to pass all BigCrush tests. - - -// xor128, a pure xor-shift generator by George Marsaglia. -// Period: 2^128-1. -// Reported to fail: MatrixRank and LinearComp. - - -// xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl. -// Period: 2^192-2^32 -// Reported to fail: CollisionOver, SimpPoker, and LinearComp. - - -// xorshift7, by François Panneton and Pierre L'ecuyer, takes -// a different approach: it adds robustness by allowing more shifts -// than Marsaglia's original three. It is a 7-shift generator -// with 256 bits, that passes BigCrush with no systmatic failures. -// Period 2^256-1. -// No systematic BigCrush failures reported. - - -// xor4096, by Richard Brent, is a 4096-bit xor-shift with a -// very long period that also adds a Weyl generator. It also passes -// BigCrush with no systematic failures. Its long period may -// be useful if you have many generators and need to avoid -// collisions. -// Period: 2^4128-2^32. -// No systematic BigCrush failures reported. - - -// Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random -// number generator derived from ChaCha, a modern stream cipher. -// https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf -// Period: ~2^127 -// No systematic BigCrush failures reported. - - -// The original ARC4-based prng included in this library. -// Period: ~2^1600 - - -seedrandom$1.alea = alea; -seedrandom$1.xor128 = xor128; -seedrandom$1.xorwow = xorwow; -seedrandom$1.xorshift7 = xorshift7; -seedrandom$1.xor4096 = xor4096; -seedrandom$1.tychei = tychei; - -var seedrandom$2 = seedrandom$1; - -//import { substitute_abs } from '../normalization/standard_form'; - -function randomComplexBindings(rng, variables, radius, centers) { - var result = {}; - - if (centers === undefined) { - variables.forEach(function (v) { - result[v] = math$19.complex(rng() * 2 * radius - radius, - rng() * 2 * radius - radius); - }); - } - else { - variables.forEach(function (v) { - result[v] = math$19.complex( - centers[v].re + rng() * 2 * radius - radius, - centers[v].im + rng() * 2 * radius - radius); - }); - } + if (!Array.isArray(f$$1) || f$$1[0] !== "polynomial") + return [f$$1, {}]; //if it's not a polynomial, don't need to change anything. - return result; -} + let table = {}; + let var_string = "z" + JSON.stringify(f$$1[1]); + table[var_string] = f$$1[1]; + f$$1[1] = var_string; -const equals$1 = function (expr, other, - { relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - } = {}) { + let terms = f$$1[2]; + let current = []; + for (let f_term of terms){ + current = stringify_vars(f_term[1]); + f_term[1] = current[0]; + for (let key in current[1]){ + table[key] = current[1][key]; + } + } - let rng = seedrandom$2('complex_seed'); + return [f$$1, table]; + } - //expr = expr.substitute_abs(); - //other = other.substitute_abs(); + function destringify_vars(f$$1, table){ + //takes a stringy polynomial and a dictionary {string:actual_variable,...} and returns the polynomial with strings replaced with the actual variable they represent. - // don't use complex equality if not analytic expression - // except abs is OK - if ((!expr.isAnalytic({ allow_abs: true, allow_relation: true })) || - (!other.isAnalytic({ allow_abs: true, allow_relation: true }))) - return false; + if (!Array.isArray(f$$1) || f$$1[0] !== "polynomial") + return f$$1; //it it's not a polynomial, don't need to change anything. - return equals({ - expr: expr, - other: other, - randomBindings: randomComplexBindings, - expr_context: expr.context, - other_context: other.context, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers, - include_error_in_number_exponents, - allowed_error_is_absolute, - rng - }); -}; + if (table[f$$1[1]]) + f$$1[1] = table[f$$1[1]]; -function randomRealBindings(rng, variables, radius, centers) { - var result = {}; + let terms = f$$1[2]; + for (let f_term of terms){ + f_term[1] = destringify_vars(f_term[1], table); + } - if (centers === undefined) { - variables.forEach(function (v) { - result[v] = rng() * 2 * radius - radius; - }); - } - else { - variables.forEach(function (v) { - result[v] = centers[v] + rng() * 2 * radius - radius; - }); + return f$$1; } - return result; -} - -const equals$2 = function (expr, other, - { relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - } = {}) { + var textToAst$3 = new textToAst(); - // don't use real equality if not analytic expression - if ((!expr.isAnalytic()) || (!other.isAnalytic())) - return false; + function common_denominator(tree, assumptions) { - let rng = seedrandom('real_seed'); + tree = simplify$2(tree, assumptions); - return equals({ - expr: expr, - other: other, - randomBindings: randomRealBindings, - expr_context: expr.context, - other_content: other.context, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers, - include_error_in_number_exponents, - allowed_error_is_absolute, - rng - }); -}; - -const equals$3 = function (expr, other, { - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, -} = {}) { - return equal$2(expr.tree, other.tree, { - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - }); -}; + var transformations = []; + transformations.push( + [textToAst$3.convert("a/c+b/c"), textToAst$3.convert("(a+b)/c"), + {evaluate_numbers: true, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [textToAst$3.convert("a/c-b/c"), textToAst$3.convert("(a-b)/c"), + {evaluate_numbers: true, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [textToAst$3.convert("a+b/c"), textToAst$3.convert("(ac+b)/c"), + {evaluate_numbers: true, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [textToAst$3.convert("a-b/c"), textToAst$3.convert("(ac-b)/c"), + {evaluate_numbers: true, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [textToAst$3.convert("a/d+b/c"), textToAst$3.convert("(ac+bd)/(cd)"), + {evaluate_numbers: true, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push( + [textToAst$3.convert("a/d-b/c"), textToAst$3.convert("(ac-bd)/(cd)"), + {evaluate_numbers: true, + allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }] + ); + transformations.push([textToAst$3.convert("x*(y/z)"), textToAst$3.convert("(x*y)/z"), + {allow_extended_match: true, + allow_permutations: true, + max_group: 1, + }]); + transformations.push([textToAst$3.convert("(x/y)/z"), textToAst$3.convert("x/(y*z)"), + {allow_extended_match: true, + allow_permutations: true, + }]); + transformations.push([textToAst$3.convert("x/(y/z)"), textToAst$3.convert("xz/y"), + {allow_extended_match: true, + allow_permutations: true, + }]); + + tree = applyAllTransformations(tree, transformations, 40); + + tree = expand(tree, true); -const equals$$1 = function(expr, other, { min_elements_match=3, match_partial = false } = {} ) { + return tree; + } - // expr must be a discrete infinite set - if(!is_discrete_infinite_set(expr)) - return false; - // other must be a discrete infinite set or a list - if(is_discrete_infinite_set(other)) { - var assumptions = []; - let a = expr.context.get_assumptions(expr); - if(a !== undefined) - assumptions.push(a); - a = other.context.get_assumptions(other); - if(a !== undefined) - assumptions.push(a); - if(assumptions.length === 0) - assumptions = undefined; - else if(assumptions.length === 1) - assumptions=assumptions[0]; - else - assumptions = clean_assumptions(['and'].concat(assumptions)); + function as_num_denom(expr_or_tree) { + // Return tuple containing numerator and denominator + // after attempting to place over common denominator - if(match_partial) { - let match1 = contained_in(expr.tree, other.tree, assumptions, match_partial); - if(match1 === false) { - return 0; - } - let match2 = contained_in(other.tree, expr.tree, assumptions, match_partial); - if(match2 === false) { - return 0; - } + var tree = get_tree(expr_or_tree); - if(match1 === true) { - if(match2 === true) { - return 1; - } else { - return match2; - } - } else if(match2 === true) { - return match1; - } else { - return Math.min(match1, match2); - } + tree = common_denominator(tree); - } else { - return contained_in(expr.tree, other.tree, assumptions, match_partial) && - contained_in(other.tree, expr.tree, assumptions, match_partial); - } + if(tree[0] === '/') + return [tree[1], tree[2]]; + else + return [tree, 1]; } - else { - // check if other is a list than ends in 'ldots' - let other_tree = other.tree; - if(other_tree[0] !== 'list') - return false; + function reduce_rational(expr_or_tree) { + var tree = get_tree(expr_or_tree); - let n_in_list = other_tree.length-2; + var num_denom = as_num_denom(tree); - if(other_tree[n_in_list+1][0] !== 'ldots') - return false; + if(num_denom[1] === 1) + return tree; - if(n_in_list < min_elements_match) - return false; + var poly_num = expression_to_polynomial(num_denom[0]); + var poly_denom = expression_to_polynomial(num_denom[1]); - let the_list = other_tree.slice(0,n_in_list+1); + var reduced_polys = reduce_rational_expression(poly_num, poly_denom); - // get list of same size from - let generated_list = sequence_from_discrete_infinite(expr, n_in_list); + var num_new = polynomial_to_expression(reduced_polys[0]); + var denom_new = polynomial_to_expression(reduced_polys[1]); - if(!generated_list) - return false; + if(denom_new === 1) + return num_new; + else + return ['/', num_new, denom_new]; - generated_list = ['list'].concat(generated_list); + } - return equals$5(expr.context.from(generated_list), other.context.from(the_list)); + const common_demoninator = common_denominator; - } + var rational = /*#__PURE__*/Object.freeze({ + reduce_rational: reduce_rational, + common_demoninator: common_demoninator + }); -}; + function round_numbers_to_precision(expr_or_tree, digits=14) { + // round any decimals to specified number of significant digits + var tree = get_tree(expr_or_tree); -function is_discrete_infinite_set(expr) { + if(digits < 1) { + throw Error("For round_numbers_to_precision, digits must be positive"); + } - var tree = expr.tree; - if(!Array.isArray(tree)) - return false; - if(tree[0] !== 'discrete_infinite_set') - return false; - var operands = tree.slice(1); + if(!Number.isFinite(digits)) { + throw Error("For round_numbers_to_precision, digits must be a number"); + } - for(var v of operands) { - if(!Array.isArray(v)) - return false; - if(v[0] !== 'tuple') - return false; - if(v.length !== 5) - return false; - } + if(digits > 15) { + return tree; + } + + digits = Math.round(digits); - return true; -} + return round_numbers_to_precision_sub(tree,digits); + } + const round_numbers_to_precision_sub = function(tree, digits=14) { -function contained_in(tree, i_set, assumptions, match_partial) { - // true if tree is contained in the discrete infinite set i_set - // tree is either a discrete infinite set - // or a tuple of form [offset, period, min_index, max_index] + if(typeof tree === "number") { - if(tree[0] === 'discrete_infinite_set') { - if(match_partial) { - let num_matches = 0; - for(let piece of tree.slice(1)){ - let match = contained_in(piece, i_set, assumptions, match_partial); - if(match === true) { - num_matches++; - } else if(match !== false) { - num_matches += match; + if(Number.isFinite(tree) && tree !== 0) { + const scaleFactor = math$19.floor(math$19.log10(math$19.abs(tree))); + const n = digits - scaleFactor - 1; + if(n < 0) { + // mathjs toFixed truncates zeros when n is negative + // so add back on when creating float + return parseFloat(number_7(tree, n)+'0'.repeat(math$19.abs(n))); + } else { + return parseFloat(number_7(tree, n)) } } + } + if(!Array.isArray(tree)) { + return tree; + } + let operator = tree[0]; + let operands = tree.slice(1); + return [operator, ...operands.map(x => round_numbers_to_precision_sub(x,digits))] + }; - let num_pieces = tree.length - 1; - if(num_matches === num_pieces) { - return true; - }else if(num_matches === 0) { - return false; - }else { - return num_matches/num_pieces; - } - } else { - return tree.slice(1).every(v => contained_in(v, i_set, assumptions)); + function round_numbers_to_decimals(expr_or_tree, ndecimals=14) { + // round any numbers to specified number of decimals + + var tree = get_tree(expr_or_tree); + + + if(!Number.isFinite(ndecimals)) { + throw Error("For round_numbers_to_decimals, ndecimals must be a number"); } - } - // tree is a tuple of the form [offset, period, min_index, max_index] + ndecimals = Math.round(ndecimals); - var offset0 = tree[1]; - var period0 = tree[2]; - var min_index = tree[3]; - var max_index = tree[4]; + // no need to go much beyond limits of double precision + ndecimals = Math.max(-330, Math.min(330, ndecimals)); - // implemented only if min_index === -infinity and max_index === infinity - if(!Array.isArray(min_index) || min_index[0] !== '-' || min_index[1] !== Infinity - || max_index !== Infinity) - return false; + return round_numbers_to_decimals_sub(tree,ndecimals); + } + + const round_numbers_to_decimals_sub = function(tree, ndecimals=0) { - // normalize to period 1 - offset0 = simplify$2( - ['/', offset0, period0], assumptions, Infinity); + if(typeof tree === "number") { + if(ndecimals < 0) { + // mathjs toFixed truncates zeros when n is negative + // so add back on when creating float + return parseFloat(number_7(tree, ndecimals)+'0'.repeat(math$19.abs(ndecimals))); + } else { + return parseFloat(number_7(tree, ndecimals)) + } + } + if(!Array.isArray(tree)) { + return tree; + } + let operator = tree[0]; + let operands = tree.slice(1); + return [operator, ...operands.map(x => round_numbers_to_decimals_sub(x,ndecimals))] + }; - // if(!(typeof offset0 === 'number')) - // return false; + var round$2 = /*#__PURE__*/Object.freeze({ + round_numbers_to_precision: round_numbers_to_precision, + round_numbers_to_decimals: round_numbers_to_decimals + }); - var tuples = i_set.slice(1); + const expression_to_tree = [ + simplify$3, + differentiation, + normalization, + arithmetic$1, + transformation, + solve, + sets, + matrix$5, + rational, + round$2, + ]; - // data will be array of form [p, q, offset, period] - // where offset and period are normalized by period0 - // and p/q is fraction form of period + const expression_to_other = [ + variables$1, + printing, + equality, + integration, + evaluation, + analytic, + sign_error, + ]; - var data = []; - for(let i=0; i + * Duane Nykamp + * + * This file is part of a math-expressions library + * + * math-expressions is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or at your option any later version. + * + * math-expressions is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ + + // UPDATETHIS: Is this grammar still correct? + + /* Grammar: + + statement_list = + statement_list ',' statement | + statement + + statement = + '\\dots' | + statement_a '|' statement_a | + statement_a 'MID' statement_a | + statement_a ':' statement_a + **** statement_a '|' statement_a + used with turning off '|' statement '|' in baseFactor + tried only after parse error encountered + + statement_a = + statement_a 'OR' statement_b | + statement_b + + statement_b = + statement_b 'AND' relation | + relation + + relation = + 'NOT' relation | + relation '=' expression | + relation 'NE' expression | + relation '<' expression | + relation '>' expression | + relation 'LE' expression | + relation 'GE' expression | + relation 'IN' expression | + relation 'NOTIN' expression | + relation 'NI' expression | + relation 'NOTNI' expression | + relation 'SUBSET' expression | + relation 'NOTSUBSET' expression | + relation 'SUPERSET' expression | + relation 'NOTSUPERSET' expression | + expression + + expression = + expression '+' term | + expression '-' term | + expression 'UNION' term | + expression 'INTERSECT' term | + '+' term | + term + + term = + term '*' factor | + term nonMinusFactor | + term '/' factor | + factor + + baseFactor = + '(' statement_list ')' | + '[' statement_list ']' | + '{' statement_list '}' | + 'LBRACE' statement_list 'RBRACE' | + '(' statement ',' statement ']' | + '[' statement ',' statement ')' | + '|' statement '|' | + \frac{statement}{statement} | + number | + variable | + modified_function '(' statement_list ')' | + modified_applied_function '(' statement_list ')' | + modified_function '{' statement_list '}' | + modified_applied_function '{' statement_list '}' | + modified_function | + modified_applied_function factor | + sqrt '[' statement ']' '{' statement '}' | + baseFactor '_' baseFactor | + *** modified_applied_function factor + allowed only if allowSimplifiedFunctionApplication==true + *** '|' statement '|' + allowed only at beginning of factor or if not currently in absolute value + + modified_function = + function | + function '_' baseFactor | + function '_' baseFactor '^' factor | + function '^' factor + function "'" + function '_' baseFactor "'" + function '_' baseFactor "'" '^' factor + function "'" '^' factor + *** where the "'" after the functions can be repeated + + modified_applied_function = + applied_function | + applied_function '_' baseFactor | + applied_function '_' baseFactor '^' factor | + applied_function '^' factor + applied_function "'" + applied_function '_' baseFactor "'" + applied_function '_' baseFactor "'" '^' factor + applied_function "'" '^' factor + *** where the "'" after the applied_functions can be repeated + + nonMinusFactor = + baseFactor | + baseFactor '^' factor | + baseFactor '!' and/or "'" | + baseFactor '!' and/or "'" '^' factor| + *** where '!' and/or "'" indicates arbitrary sequence of "!" and/or "'" + + factor = + '-' factor | + nonMinusFactor - if(typeof period !== 'number') - return false; + */ - let frac = math$19.fraction(period); - let p = frac.n; - let q = frac.d; - data.push([p,q,offset,period]); - } - // sort by p - data.sort(); + // Some of the latex commands that lead to spacing + const whitespace_rule = '\\s|\\\\,|\\\\!|\\\\ |\\\\>|\\\\;|\\\\:|\\\\quad\\b|\\\\qquad\\b'; - // check any with period for which original period is a multiple - while(true) { - let p = data[0][0]; - if(p !== 1) - break; + // in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, + // it must be at the end or followed a comma, &, |, \|, ), }, \}, ], \\, or \end + const sci_notat_exp_regex$1 = '(E[+\\-]?[0-9]+\\s*($|(?=\\,|&|\\||\\\\\\||\\)|\\}|\\\\}|\\]|\\\\\\\\|\\\\end)))?'; + + const latex_rules = [ + ['[0-9]+(\\.[0-9]*)?'+sci_notat_exp_regex$1 , 'NUMBER'], + ['\\.[0-9]+'+sci_notat_exp_regex$1, 'NUMBER'], + ['\\*', '*'], + ['\\/', '/'], + ['-', '-'], + ['\\+', '+'], + ['\\^', '^'], + ['\\(', '('], + ['\\\\left\\s*\\(', '('], + ['\\\\bigl\\s*\\(', '('], + ['\\\\Bigl\\s*\\(', '('], + ['\\\\biggl\\s*\\(', '('], + ['\\\\Biggl\\s*\\(', '('], + ['\\)', ')'], + ['\\\\right\\s*\\)', ')'], + ['\\\\bigr\\s*\\)', ')'], + ['\\\\Bigr\\s*\\)', ')'], + ['\\\\biggr\\s*\\)', ')'], + ['\\\\Biggr\\s*\\)', ')'], + ['\\[', '['], + ['\\\\left\\s*\\[', '['], + ['\\\\bigl\\s*\\[', '['], + ['\\\\Bigl\\s*\\[', '['], + ['\\\\biggl\\s*\\[', '['], + ['\\\\Biggl\\s*\\[', '['], + ['\\]', ']'], + ['\\\\right\\s*\\]', ']'], + ['\\\\bigr\\s*\\]', ']'], + ['\\\\Bigr\\s*\\]', ']'], + ['\\\\biggr\\s*\\]', ']'], + ['\\\\Biggr\\s*\\]', ']'], + ['\\|', '|'], + ['\\\\left\\s*\\|', '|L'], + ['\\\\bigl\\s*\\|', '|L'], + ['\\\\Bigl\\s*\\|', '|L'], + ['\\\\biggl\\s*\\|', '|L'], + ['\\\\Biggl\\s*\\|', '|L'], + ['\\\\right\\s*\\|', '|'], + ['\\\\bigr\\s*\\|', '|'], + ['\\\\Bigr\\s*\\|', '|'], + ['\\\\biggr\\s*\\|', '|'], + ['\\\\Biggr\\s*\\|', '|'], + ['\\\\big\\s*\\|', '|'], + ['\\\\Big\\s*\\|', '|'], + ['\\\\bigg\\s*\\|', '|'], + ['\\\\Bigg\\s*\\|', '|'], + ['{', '{'], + ['}', '}'], + ['\\\\{', 'LBRACE'], + ['\\\\left\\s*\\\\{', 'LBRACE'], + ['\\\\bigl\\s*\\\\{', 'LBRACE'], + ['\\\\Bigl\\s*\\\\{', 'LBRACE'], + ['\\\\biggl\\s*\\\\{', 'LBRACE'], + ['\\\\Biggl\\s*\\\\{', 'LBRACE'], + ['\\\\}', 'RBRACE'], + ['\\\\right\\s*\\\\}', 'RBRACE'], + ['\\\\bigr\\s*\\\\}', 'RBRACE'], + ['\\\\Bigr\\s*\\\\}', 'RBRACE'], + ['\\\\biggr\\s*\\\\}', 'RBRACE'], + ['\\\\Biggr\\s*\\\\}', 'RBRACE'], + ['\\\\cdot(?![a-zA-Z])', '*'], + ['\\\\div(?![a-zA-Z])', '/'], + ['\\\\times(?![a-zA-Z])', '*'], + ['\\\\frac(?![a-zA-Z])', 'FRAC'], + [',', ','], + [':', ':'], + ['\\\\mid', 'MID'], + + ['\\\\vartheta(?![a-zA-Z])', 'LATEXCOMMAND', '\\theta'], + ['\\\\varepsilon(?![a-zA-Z])', 'LATEXCOMMAND', '\\epsilon'], + ['\\\\varrho(?![a-zA-Z])', 'LATEXCOMMAND', '\\rho'], + ['\\\\varphi(?![a-zA-Z])', 'LATEXCOMMAND', '\\phi'], + + ['\\\\infty(?![a-zA-Z])', 'INFINITY'], + + ['\\\\asin(?![a-zA-Z])', 'LATEXCOMMAND', '\\arcsin'], + ['\\\\acos(?![a-zA-Z])', 'LATEXCOMMAND', '\\arccos'], + ['\\\\atan(?![a-zA-Z])', 'LATEXCOMMAND', '\\arctan'], + ['\\\\sqrt(?![a-zA-Z])', 'SQRT'], + + ['\\\\land(?![a-zA-Z])', 'AND'], + ['\\\\wedge(?![a-zA-Z])', 'AND'], + + ['\\\\lor(?![a-zA-Z])', 'OR'], + ['\\\\vee(?![a-zA-Z])', 'OR'], + + ['\\\\lnot(?![a-zA-Z])', 'NOT'], + + ['=', '='], + ['\\\\neq(?![a-zA-Z])', 'NE'], + ['\\\\ne(?![a-zA-Z])', 'NE'], + ['\\\\not\\s*=', 'NE'], + ['\\\\leq(?![a-zA-Z])', 'LE'], + ['\\\\le(?![a-zA-Z])', 'LE'], + ['\\\\geq(?![a-zA-Z])', 'GE'], + ['\\\\ge(?![a-zA-Z])', 'GE'], + ['<', '<'], + ['\\\\lt(?![a-zA-Z])', '<'], + ['>', '>'], + ['\\\\gt(?![a-zA-Z])', '>'], + + ['\\\\in(?![a-zA-Z])', 'IN'], + + ['\\\\notin(?![a-zA-Z])', 'NOTIN'], + ['\\\\not\\s*\\\\in(?![a-zA-Z])', 'NOTIN'], + + ['\\\\ni(?![a-zA-Z])', 'NI'], + + ['\\\\not\\s*\\\\ni(?![a-zA-Z])', 'NOTNI'], + + ['\\\\subset(?![a-zA-Z])', 'SUBSET'], + + ['\\\\not\\s*\\\\subset(?![a-zA-Z])', 'NOTSUBSET'], + + ['\\\\supset(?![a-zA-Z])', 'SUPERSET'], + + ['\\\\not\\s*\\\\supset(?![a-zA-Z])', 'NOTSUPERSET'], + + ['\\\\cup(?![a-zA-Z])', 'UNION'], + + ['\\\\cap(?![a-zA-Z])', 'INTERSECT'], + + ['!', '!'], + ['\'', '\''], + ['_', '_'], + ['&', '&'], + ['\\\\ldots', 'LDOTS'], + + ['\\\\\\\\', 'LINEBREAK'], + + ['\\\\begin\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'BEGINENVIRONMENT'], + + ['\\\\end\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'ENDENVIRONMENT'], + + ['\\\\var\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'VARMULTICHAR'], + + ['\\\\[a-zA-Z]+(?![a-zA-Z])', 'LATEXCOMMAND'], + ['[a-zA-Z]', 'VAR'] + ]; - let offset = data[0][2]; - let period = data[0][3]; - // offsets match, then we've covered all of tree - let offset_diff = simplify$2( - expand( - ['+', offset, ['-', offset0]]), - assumptions, Infinity); + // defaults for parsers if not overridden by context - if(Number.isFinite(offset_diff) && Number.isFinite(period)) { - // use math.mod rather than % so it always non-negative - offset_diff = math$19.mod(offset_diff, period); + // if true, allowed applied functions to omit parentheses around argument + // if false, omitting parentheses will lead to a Parse Error + const allowSimplifiedFunctionApplicationDefault$1 = true; - if(math$19.min(offset_diff, period-offset_diff) < 1E-10*period) - return true; - } - data.splice(0,1); // remove first entry from data - if(data.length === 0) - return false; - } + // allowed multicharacter latex symbols + // in addition to the below applied function symbols + const allowedLatexSymbolsDefault$1 = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'partial']; - var all_ps = [...new Set(data.map(v => v[0]))]; + // Applied functions must be given an argument so that + // they are applied to the argument + const appliedFunctionSymbolsDefault$1 = ["abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg']; - let max_fraction_covered = 0; + // Functions could have an argument, in which case they are applied + // or, if they don't have an argument in parentheses, then they are treated + // like a variable, except that trailing ^ and ' have higher precedence + const functionSymbolsDefault$1 = ['f', 'g']; - for(let base_p of all_ps) { - // find all ps where base_p is a multiple - let options = data.map(function (v,i) { - let m = base_p/v[0]; - if(Number.isInteger(m)) - return [v[0], m, i]; - else - return undefined; - }).filter(v=>v); + // Parse Leibniz notation + const parseLeibnizNotationDefault$1 = true; - let covered = []; - for(let opt of options) { - let p = opt[0]; - let m = opt[1]; - let i = opt[2]; - let offset = data[i][2]; - let period = data[i][3]; + class latexToAst { + constructor({ + allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplicationDefault$1, + allowedLatexSymbols = allowedLatexSymbolsDefault$1, + appliedFunctionSymbols = appliedFunctionSymbolsDefault$1, + functionSymbols = functionSymbolsDefault$1, + parseLeibnizNotation = parseLeibnizNotationDefault$1, + } = {}) { + this.allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplication; + this.allowedLatexSymbols = allowedLatexSymbols; + this.appliedFunctionSymbols = appliedFunctionSymbols; + this.functionSymbols = functionSymbols; + this.parseLeibnizNotation = parseLeibnizNotation; + this.lexer = new lexer(latex_rules, whitespace_rule); - for(let j=0; j < p; j++) { + } + + advance(params) { + this.token = this.lexer.advance(params); + if (this.token.token_type === 'INVALID') { + throw new ParseError("Invalid symbol '" + this.token.original_text + "'", + this.lexer.location); + } + } - let offset_diff = simplify$2( - expand( - ['+', offset, ['-', ['+', offset0, j]]]), - assumptions, Infinity); + return_state() { + return ({ + lexer_state: this.lexer.return_state(), + token: Object.assign({}, this.token) + }); + } - // use math.mod rather than % so it always non-negative - if(Number.isFinite(offset_diff) && Number.isFinite(period)) { - offset_diff = math$19.mod(offset_diff, period); + set_state(state) { + this.lexer.set_state(state.lexer_state); + this.token = Object.assign({}, state.token); + } - if(math$19.min(offset_diff, period-offset_diff) < 1E-10*period) { - for(let k=0; k max_fraction_covered) { - max_fraction_covered = fraction_covered; + var list = [this.statement()]; + + while (this.token.token_type === ",") { + this.advance(); + list.push(this.statement()); } + + if (list.length > 1) + list = ['list'].concat(list); + else + list = list[0]; + + return list; } - } - if(match_partial && max_fraction_covered > 0) { - return max_fraction_covered; - } + statement({ inside_absolute_value = 0 } = {}) { + + // \ldots can be a statement by itself + if (this.token.token_type === 'LDOTS') { + this.advance(); + return ['ldots']; + } - return false; + var original_state; -} + try { + original_state = this.return_state(); -function sequence_from_discrete_infinite(expr, n_elements) { + let lhs = this.statement_a({ inside_absolute_value: inside_absolute_value }); - // assuming without checking that expr is discrete infinite set + if (this.token.token_type !== ':' && this.token.token_type !== 'MID') + return lhs; - var tree = expr.tree; - var operands = tree.slice(1); + let operator = this.token.token_type === ':' ? ':' : '|'; - // implemented only if have just one tuple defining set - if(operands.length > 1) - return; + this.advance(); - let offset = operands[0][1]; - let period = operands[0][2]; - let min_index = evaluate_numbers(operands[0][3]); - let max_index = operands[0][4]; + let rhs = this.statement_a(); - // implemented only if min_index is defined and an integer and max_index is infinity - if(!Number.isInteger(min_index) || max_index !== Infinity) - return; + return [operator, lhs, rhs]; - let result = []; + } + catch (e) { + try { - for(let i=0; i < n_elements; i++) { - result.push(evaluate_numbers(['+', ['*', period, min_index+i], offset])); - } + // if ran into problem parsing statement + // then try again with ignoring absolute value + // and then interpreting bar as a binary operator - return result; -} + // return state to what it was before attempting to parse statement + this.set_state(original_state); -//exports.equalsViaFiniteField = equalsViaFiniteField; + let lhs = this.statement_a({ parse_absolute_value: false }); -const equals$5 = function (expr, other, { - relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, -} = {}) { - if (expr.variables().includes('\uFF3F') || other.variables().includes('\uFF3F')) { - return false; - } + if (this.token.token_type[0] !== '|') { + throw (e); + } - // first check with symbolic equality - // converting all numbers and numerical quantities to floating point - // and normalizing form of each expression - let exprNormalized = expr.evaluate_numbers({ max_digits: Infinity }) - .normalize_function_names() - .normalize_applied_functions() - .simplify(); - let otherNormalized = other.evaluate_numbers({ max_digits: Infinity }) - .normalize_function_names() - .normalize_applied_functions() - .simplify(); - - if (exprNormalized.equalsViaSyntax(otherNormalized, { - allowed_error_in_numbers, - include_error_in_number_exponents, - allowed_error_is_absolute, - }) - ) { - return true; - } else if (expr.equalsViaComplex(other, { - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers, - include_error_in_number_exponents, - allowed_error_is_absolute, - })) { - return true; - // } else if (expr.equalsViaReal(other)) { - // return true; - } else if (equals$$1(expr, other)) { - return true; - } else { - return false; - } -}; + this.advance(); -var equality = /*#__PURE__*/Object.freeze({ - equals: equals$5, - equalsViaComplex: equals$1, - equalsViaReal: equals$2, - equalsViaSyntax: equals$3, - equalsDiscreteInfinite: equals$$1 -}); + let rhs = this.statement_a({ parse_absolute_value: false }); -const equalWithSignErrors = function (expr, other, - { equalityFunction = equals$5, max_sign_errors = 1 } = {} -) { + return ['|', lhs, rhs]; - if (equalityFunction(expr, other)) { - return { matched: true, n_sign_errors: 0 }; - } + } + catch (e2) { + throw (e); // throw original error + } + } + } + + statement_a({ inside_absolute_value = 0, parse_absolute_value = true } = {}) { + + var lhs = this.statement_b({ + inside_absolute_value: inside_absolute_value, + parse_absolute_value: parse_absolute_value + }); + + while (this.token.token_type === 'OR') { + + let operation = this.token.token_type.toLowerCase(); + + this.advance(); + + let rhs = this.statement_b({ + inside_absolute_value: inside_absolute_value, + parse_absolute_value: parse_absolute_value + }); + + lhs = [operation, lhs, rhs]; + } - for (let i = 1; i <= max_sign_errors; i++) { - if (equalSpecifiedSignErrors(expr, other, { equalityFunction, n_sign_errors: i })) { - return { matched: true, n_sign_errors: i }; + return lhs; } - } - return { matched: false }; -}; -const equalSpecifiedSignErrors = function (expr, other, - { equalityFunction = equals$5, n_sign_errors = 1 } = {} -) { + statement_b(params) { + // split AND into second statement to give higher precedence than OR - if (n_sign_errors === 0) { - return equalityFunction(expr, other); - } else if (!(Number.isInteger(n_sign_errors) && n_sign_errors > 0)) { - throw Error(`Have not implemented equality check with ${n_sign_errors} sign errors.`) - } + var lhs = this.relation(params); - if (n_sign_errors > 1) { - let oldEqualityFunction = equalityFunction; - equalityFunction = function (expr, other) { - return equalSpecifiedSignErrors(expr, other, { equalityFunction: oldEqualityFunction, n_sign_errors: n_sign_errors - 1}); - }; - } + while (this.token.token_type === 'AND') { - var root = expr.tree; - var stack = [[root]]; - var pointer = 0; - var tree; - var i; + let operation = this.token.token_type.toLowerCase(); - /* Unfortunately the root is handled separately */ - expr.tree = ['-', root]; - var equals$$2 = equalityFunction(expr, other); - expr.tree = root; + this.advance(); - if (equals$$2) return true; + let rhs = this.relation(params); - while (tree = stack[pointer++]) { - tree = tree[0]; + lhs = [operation, lhs, rhs]; + } - if (!Array.isArray(tree)) { - continue; + return lhs; } - for (i = 1; i < tree.length; i++) { - stack.push([tree[i]]); - tree[i] = ['-', tree[i]]; - equals$$2 = equalityFunction(expr, other); - tree[i] = tree[i][1]; - if (equals$$2) return true; - } - } + relation(params) { - return false; -}; + if (this.token.token_type === 'NOT' || this.token.token_type === '!') { + this.advance(); + return ['not', this.relation(params)]; + } -var sign_error = /*#__PURE__*/Object.freeze({ - equalSpecifiedSignErrors: equalSpecifiedSignErrors, - equalWithSignErrors: equalWithSignErrors -}); + var lhs = this.expression(params); -function add$2(expr_or_tree1, expr_or_tree2) { - var result = ['+', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; - return clean(result); -} + while ((this.token.token_type === '=') || (this.token.token_type === 'NE') + || (this.token.token_type === '<') || (this.token.token_type === '>') + || (this.token.token_type === 'LE') || (this.token.token_type === 'GE') + || (this.token.token_type === 'IN') || (this.token.token_type === 'NOTIN') + || (this.token.token_type === 'NI') || (this.token.token_type === 'NOTNI') + || (this.token.token_type === 'SUBSET') || (this.token.token_type === 'NOTSUBSET') + || (this.token.token_type === 'SUPERSET') || (this.token.token_type === 'NOTSUPERSET')) { -function subtract$2(expr_or_tree1, expr_or_tree2) { - var result = ['+', get_tree(expr_or_tree1), ['-', get_tree(expr_or_tree2)]]; - return clean(result); -} + let operation = this.token.token_type.toLowerCase(); -function multiply$2(expr_or_tree1, expr_or_tree2) { - var result = ['*', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; - return clean(result); -} + let inequality_sequence = 0; + + if ((this.token.token_type === '<') || (this.token.token_type === 'LE')) { + inequality_sequence = -1; + } + else if ((this.token.token_type === '>') || (this.token.token_type === 'GE')) { + inequality_sequence = 1; + } -function divide$2(expr_or_tree1, expr_or_tree2) { - var result = ['/', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; - return clean(result); -} + this.advance(); + let rhs = this.expression(params); -function pow$2(expr_or_tree1, expr_or_tree2) { - var result = ['^', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; - return clean(result); -} + if (inequality_sequence === -1) { + if ((this.token.token_type === '<') || this.token.token_type === 'LE') { + // sequence of multiple < or <= + let strict = ['tuple']; + if (operation === '<') + strict.push(true); + else + strict.push(false); -function mod$2(expr_or_tree1, expr_or_tree2) { - var result = ['apply', 'mod', ['tuple', get_tree(expr_or_tree1), - get_tree(expr_or_tree2)]]; - return clean(result); -} + let args = ['tuple', lhs, rhs]; + while ((this.token.token_type === '<') || this.token.token_type === 'LE') { + if (this.token.token_type === '<') + strict.push(true); + else + strict.push(false); -function copy(expr_or_tree) { - return get_tree(expr_or_tree); -} + this.advance(); + args.push(this.expression(params)); + } + lhs = ['lts', args, strict]; + } + else { + lhs = [operation, lhs, rhs]; + } -var arithmetic$1 = /*#__PURE__*/Object.freeze({ - add: add$2, - subtract: subtract$2, - multiply: multiply$2, - divide: divide$2, - pow: pow$2, - mod: mod$2, - copy: copy -}); + } + else if (inequality_sequence === 1) { + if ((this.token.token_type === '>') || this.token.token_type === 'GE') { + // sequence of multiple > or >= + let strict = ['tuple']; + if (operation === '>') + strict.push(true); + else + strict.push(false); -var analytic_operators = ['+', '-', '*', '/', '^', 'tuple', 'vector', 'list', 'array', 'matrix', 'interval']; -var analytic_functions = ["exp", "log", "log10", "sqrt", "factorial", "gamma", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec']; -var relation_operators = ['=', 'le', 'ge', '<', '>']; + let args = ['tuple', lhs, rhs]; + while ((this.token.token_type === '>') || this.token.token_type === 'GE') { + if (this.token.token_type === '>') + strict.push(true); + else + strict.push(false); -function isAnalytic(expr_or_tree, { allow_abs = false, allow_relation = false } = {}) { + this.advance(); + args.push(this.expression(params)); + } + lhs = ['gts', args, strict]; + } + else { + lhs = [operation, lhs, rhs]; + } - var tree = normalize_applied_functions( - normalize_function_names(expr_or_tree)); + } + else if (operation === '=') { + lhs = ['=', lhs, rhs]; - tree = subscripts_to_strings(tree); + // check for sequence of multiple = + while (this.token.token_type === '=') { + this.advance(); + lhs.push(this.expression(params)); + } + } + else { - var operators_found = operators$1(tree); - for (let i = 0; i < operators_found.length; i++) { - let oper = operators_found[i]; - if (analytic_operators.indexOf(oper) === -1) { - if (allow_relation) { - if (relation_operators.indexOf(oper) === -1) { - return false; + lhs = [operation, lhs, rhs]; } - } else { - return false; + } - } - } - var functions_found = functions(tree); - for (let i = 0; i < functions_found.length; i++) { - let fun = functions_found[i]; - if (analytic_functions.indexOf(fun) === -1) { - if ((!allow_abs) || fun !== "abs") - return false; + return lhs; } - } - return true; -} -var analytic = /*#__PURE__*/Object.freeze({ - isAnalytic: isAnalytic -}); + expression(params) { + if (this.token.token_type === '+') + this.advance(); -function create_discrete_infinite_set({ - offsets, - periods, - min_index = ['-', Infinity], - max_index = Infinity, -} = {}) { + let negative_begin = false; + if (this.token.token_type === '-') { + negative_begin = true; + this.advance(); + } - offsets = get_tree(offsets); - periods = get_tree(periods); - min_index = get_tree(min_index); - max_index = get_tree(max_index); + var lhs = this.term(params); + if (negative_begin) { + lhs = ['-', lhs]; + } + while ((this.token.token_type === '+') || (this.token.token_type === '-') + || (this.token.token_type === 'UNION') + || (this.token.token_type === 'INTERSECT')) { - if(offsets === undefined || periods === undefined) - return undefined; + let operation = this.token.token_type.toLowerCase(); + let negative = false; - let results = []; - if(offsets[0] === 'list') { - if(periods[0] === 'list') { - if(offsets.length !== periods.length || offsets.length === 1) - return undefined; - for(let i=1; i - * - * This file is part of a math-this.expressions library - * - * math-this.expressions is free software: you can redistribute - * it and/or modify it under the this.terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-this.expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ + var result = this.baseFactor(params); + // allow arbitrary sequence of factorials + if (this.token.token_type === '!' || this.token.token_type === "'") { + if (result === false) + throw new ParseError("Invalid location of " + this.token.token_type, + this.lexer.location); + while (this.token.token_type === '!' || this.token.token_type === "'") { + if (this.token.token_type === '!') + result = ['apply', 'factorial', result]; + else + result = ['prime', result]; + this.advance(); + } + } + if (this.token.token_type === '^') { + if (result === false) { + throw new ParseError("Invalid location of ^", this.lexer.location); + } + this.advance(); + // do not allow absolute value closing here + let params2 = Object.assign({}, params); + delete params2.allow_absolute_value_closing; + delete params2.inside_absolute_value; -class astToGuppy{ - constructor(){ - this.operators = { - "+": function(operands) { return operands.join( '+' ); }, - "-": function(operands) { return "-" + operands.join( '-' ) + ""; }, - "*": function(operands) { return operands.join( '\\cdot*' ); }, - "/": function(operands) { return astToGuppy.dfrac(operands[0], operands[1]); }, - "^": function(operands) { return astToGuppy.power(operands[0],operands[1]); }, - "sin": function(operands) { return astToGuppy.trig("sin",operands[0]); }, - "cos": function(operands) { return astToGuppy.trig("cos",operands[0]); }, - "tan": function(operands) { return astToGuppy.trig("tan",operands[0]); }, - "arcsin": function(operands) { return astToGuppy.trig("arcsin",operands[0]); }, - "arccos": function(operands) { return astToGuppy.trig("arccos",operands[0]); }, - "arctan": function(operands) { return astToGuppy.trig("arctan",operands[0]); }, - "arccsc": function(operands) { return astToGuppy.trig("arccsc",operands[0]); }, - "arcsec": function(operands) { return astToGuppy.trig("arcsec",operands[0]); }, - "arccot": function(operands) { return astToGuppy.trig("arccot",operands[0]); }, - "csc": function(operands) { return astToGuppy.trig("csc",operands[0]); }, - "sec": function(operands) { return astToGuppy.trig("sec",operands[0]); }, - "cot": function(operands) { return astToGuppy.trig("cot",operands[0]); }, - "log": function(operands) { return astToGuppy.trig("log",operands[0]); }, - "exp": function(operands) { return astToGuppy.trig("exp",operands[0]); }, - "ln": function(operands) { return astToGuppy.trig("ln",operands[0]); }, - "sqrt": function(operands) { return astToGuppy.sqrt(operands[0]); }, - "abs": function(operands) { return astToGuppy.abs(operands[0]); }, - //"factorial": function(operands) { return operands[0] + "!"; }, - }; + return ['^', result, this.factor(params2)]; + } - } + return result; + } - static dfrac(a,b) { - return '\\dfrac{}{}\\frac{}{}()/()' + a + '' + b + ''; - } - static trig(name, parameter ) { - return '\\' + name + '\\left(\\right) ' + name + '()' + parameter + ''; - } + baseFactor({ inside_absolute_value = 0, + parse_absolute_value = true, + allow_absolute_value_closing = false + } = {}) { - static sqrt(x) { - return '\\sqrt{}sqrt()' + x + ''; - } + var result = false; - static power(x,y) { - return '{}^{}()^()' + x + '' + y + ''; - } + if (this.token.token_type === 'FRAC') { + this.advance(); - static abs(x) { - return '\\left|\\right|abs()' + x + ''; - } + if (this.token.token_type !== '{') { + throw new ParseError("Expecting {", this.lexer.location); + } + this.advance(); - static paren(x) { - return '\\left(\\right)()' + x + ''; - } + // determine if may be a derivative in Leibniz notation + if (this.parseLeibnizNotation) { - static isFunctionSymbol( symbol ){ - var functionSymbols = ['sin', 'cos', 'tan', 'csc', 'sec', 'cot', 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'log', 'ln', 'exp', 'sqrt', 'abs', 'this.factorial']; - return (functionSymbols.indexOf(symbol) !== -1); - } + let original_state = this.return_state(); - static isGreekLetterSymbol( symbol ){ - var greekSymbols = ['pi', 'theta', 'theta', 'Theta', 'alpha', 'nu', 'beta', 'xi', 'Xi', 'gamma', 'Gamma', 'delta', 'Delta', 'pi', 'Pi', 'epsilon', 'epsilon', 'rho', 'rho', 'zeta', 'sigma', 'Sigma', 'eta', 'tau', 'upsilon', 'Upsilon', 'iota', 'phi', 'phi', 'Phi', 'kappa', 'chi', 'lambda', 'Lambda', 'psi', 'Psi', 'omega', 'Omega']; - return (greekSymbols.indexOf(symbol) !== -1); - } + let r = this.leibniz_notation(); - factorWithParenthesesIfNegated(tree){ - var result = this.factor(tree); + if (r) { + // successfully parsed derivative in Leibniz notation, so return + return r; + } + else { + // didn't find a properly format Leibniz notation + // so reset state and continue + this.set_state(original_state); + } + } - if (result.toString().match( /^-/ )) - return astToGuppy.paren( result.toString() ); + let numerator = this.statement({ parse_absolute_value: parse_absolute_value }); - // else - return result; - } + if (this.token.token_type !== '}') { + throw new ParseError("Expecting }", this.lexer.location); + } + this.advance(); + if (this.token.token_type !== '{') { + throw new ParseError("Expecting {", this.lexer.location); + } + this.advance(); + let denominator = this.statement({ parse_absolute_value: parse_absolute_value }); + if (this.token.token_type !== '}') { + throw new ParseError("Expecting }", this.lexer.location); + } + this.advance(); + return ['/', numerator, denominator]; + } - /* - this.factor = - '(' this.expression ')' | - number | - variable | - function this.factor | - this.factor '^' this.factor - '-' this.factor | - nonMinusthis.factor - */ + if (this.token.token_type === 'BEGINENVIRONMENT') { + let environment = /\\begin\s*{\s*([a-zA-Z0-9]+)\s*}/.exec(this.token.token_text)[1]; -factor(tree) { - if (typeof tree === 'string') { - if (astToGuppy.isGreekLetterSymbol(tree)) { - return '\\' + tree + ' $' + tree + ''; - } + if (['matrix', 'pmatrix', 'bmatrix'].includes(environment)) { - return '' + tree + ''; - } + let n_rows = 0; + let n_cols = 0; - if (typeof tree === 'number') { - return '' + tree + ''; - } + let all_rows = []; + let row = []; + let n_this_row = 0; + let last_token = this.token.token_type; - var operator = tree[0]; - var operands = tree.slice(1); + this.advance(); - if(operator === "apply") { - operator = tree[1]; - operands = tree.slice(2); - } - // Absolute value doesn't need any special parentheses handling, but its operand is really an this.expression - if (operator === "abs") { - return this.operators[operator]( operands.map( function(v,i) { return this.expression(v); }.bind(this) )); - } else if (astToGuppy.isFunctionSymbol(operator)) { - if ((operator === 'this.factorial') && ((operands[0].toString().length === 1) || (operands[0].toString().match( /^[0-9]*$/ )))) - return this.operators[operator]( operands ); + while (this.token.token_type !== 'ENDENVIRONMENT') { + if (this.token.token_type === '&') { + if (last_token === '&' || last_token === 'LINEBREAK') { + // blank entry, let entry be zero + row.push(0); + n_this_row += 1; + } + last_token = this.token.token_type; + this.advance(); + } + else if (this.token.token_type === 'LINEBREAK') { + if (last_token === '&' || last_token === 'LINEBREAK') { + // blank entry, let entry be zero + row.push(0); + n_this_row += 1; + } + all_rows.push(row); + if (n_this_row > n_cols) + n_cols = n_this_row; + + n_rows += 1; + n_this_row = 0; + row = []; + last_token = this.token.token_type; + this.advance(); + } + else { + if (last_token === '&' || last_token === 'LINEBREAK' || 'BEGINENVIRONMENT') { + row.push(this.statement({ parse_absolute_value: parse_absolute_value })); + n_this_row += 1; + last_token = ' '; - return this.operators[operator]( operands.map( function(v,i) { - var result = this.factor(v); - return result; - }.bind(this))); - } + } + else { + throw new ParseError("Invalid location of " + this.token.original_text, this.lexer.location); + } + } + } - if (operator === "^") { - return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); - } + // token is ENDENVIRONMENT + let environment2 = /\\end\s*{\s*([a-zA-Z0-9]+)\s*}/.exec(this.token.token_text)[1]; + if (environment2 !== environment) { + throw new ParseError("Expecting \\end{" + environment + "}", this.lexer.location); + } - if (operator === '~') { - return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); - } + // add last row + if (last_token === '&') { + // blank entry, let entry be zero + row.push(0); + n_this_row += 1; + } + all_rows.push(row); + if (n_this_row > n_cols) + n_cols = n_this_row; + n_rows += 1; - return astToGuppy.paren( this.expression(tree) ); - } + this.advance(); - /* - this.term = - this.term '*' this.factor | - this.term nonMinusthis.factor | - this.term '/' this.factor | - this.factor - */ + // create matrix + result = ["matrix", ["tuple", n_rows, n_cols]]; + let body = ["tuple"]; + for (let r of all_rows) { + let new_row = ["tuple"].concat(r); + for (let i = r.length; i < n_cols; i += 1) + new_row.push(0); - term(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.factor(tree); - } + body.push(new_row); - var operator = tree[0]; - var operands = tree.slice(1); + } + result.push(body); - if (operator === '*') { - return this.operators[operator]( operands.map( function(v,i) { - var result = this.factorWithParenthesesIfNegated(v); + return result; + } + else { + throw new ParseError("Unrecognized environment " + environment, this.lexer.location); + } - if (result.toString().match( /^[0-9]/ ) && (i > 0)) - return ' * ' + result; - else - return result; - }.bind(this))); } - if (operator === '/') { - return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); - } + if (this.token.token_type === 'NUMBER') { + result = parseFloat(this.token.token_text); + this.advance(); + } else if (this.token.token_type === 'INFINITY') { + result = Infinity; + this.advance(); + } else if (this.token.token_type === 'SQRT') { + this.advance(); - return this.factor(tree); - } + let root = 2; + if (this.token.token_type === '[') { + this.advance(); + let parameter = this.statement({ parse_absolute_value: parse_absolute_value }); + if (this.token.token_type !== ']') { + throw new ParseError("Expecting ]", this.lexer.location); + } + this.advance(); - /* - this.expression = - this.expression '+' this.term | - this.expression '-' this.term | - this.term - */ + root = parameter; + } - expression(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.term(tree); - } + if (this.token.token_type !== '{') { + throw new ParseError("Expecting {", this.lexer.location); + } - var operator = tree[0]; - var operands = tree.slice(1); + this.advance(); + let parameter = this.statement({ parse_absolute_value: parse_absolute_value }); + if (this.token.token_type !== '}') { + throw new ParseError("Expecting }", this.lexer.location); + } + this.advance(); - if ((operator === '+') || (operator === '-')) { - return this.operators[operator]( operands.map( function(v,i) { return this.factorWithParenthesesIfNegated(v); }.bind(this) )); - } + if (root === 2) + result = ['apply', 'sqrt', parameter]; + else + result = ['^', parameter, ['/', 1, root]]; + } else if (this.token.token_type === 'VAR' || this.token.token_type === 'LATEXCOMMAND' + || this.token.token_type === 'VARMULTICHAR') { + result = this.token.token_text; + + if (this.token.token_type === 'LATEXCOMMAND') { + result = result.slice(1); + if (!(this.appliedFunctionSymbols.includes(result) + || this.functionSymbols.includes(result) + || this.allowedLatexSymbols.includes(result) + )) { + throw new ParseError("Unrecognized latex command " + this.token.original_text, + this.lexer.location); + } + } + else if (this.token.token_type === 'VARMULTICHAR') { + // strip out name of variable from \var command + result = /\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(result)[1]; + } - return this.term(tree); - } + if (this.appliedFunctionSymbols.includes(result) + || this.functionSymbols.includes(result)) { + let must_apply = false; + if (this.appliedFunctionSymbols.includes(result)) + must_apply = true; + this.advance(); - convert(tree){ - return ('' + this.expression(tree) + '').replace(/<\/e>/g,''); - } - -} - -/* - * convert syntax trees to GLSL representations - * - * Copyright 2014-2018 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - -const glslOperators = { - "+": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = result + "+" + rhs; }); return result; }, - "-": function(operands) { var result = "-" + operands[0]; operands.slice(1).forEach(function(rhs) { result = result + "-" + rhs; }); return result; }, - "~": function(operands) { var result = "vec2(0.0,0.0)"; operands.forEach(function(rhs) { result = result + "-" + rhs; }); return result; }, - "*": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = "cmul(" + result + "," + rhs + ")"; }); return result; }, - "/": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = "cdiv(" + result + "," + rhs + ")"; }); return result; }, - - "sin": function(operands) { return "csin(" + operands[0] + ")"; }, - "cos": function(operands) { return "ccos(" + operands[0] + ")"; }, - "tan": function(operands) { return "ctan(" + operands[0] + ")"; }, - - "sinh": function(operands) { return "csinh(" + operands[0] + ")"; }, - "cosh": function(operands) { return "ccosh(" + operands[0] + ")"; }, - - "arcsin": function(operands) { return "carcsin(" + operands[0] + ")"; }, - "arccos": function(operands) { return "carccos(" + operands[0] + ")"; }, - "arctan": function(operands) { return "carctan(" + operands[0] + ")"; }, - - "arccsc": function(operands) { return "carcsin(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, - "arcsec": function(operands) { return "carccos(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, - "arccot": function(operands) { return "carctan(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, - - "csc": function(operands) { return "ccsc(" + operands[0] + ")"; }, - "sec": function(operands) { return "csec(" + operands[0] + ")"; }, - "cot": function(operands) { return "ccot(" + operands[0] + ")"; }, - - "exp": function(operands) { return "cexp(" + operands[0] + ")"; }, - - "conj": function(operands) { return "conjugate(" + operands[0] + ")"; }, - - "sqrt": function(operands) { return "cpower(" + operands[0] + ",vec2(0.5,0.0))"; }, - "log": function(operands) { return "clog(" + operands[0] + ")"; }, - "ln": function(operands) { return "clog(" + operands[0] + ")"; }, - "^": function(operands) { return "cpower(" + operands[0] + "," + operands[1] + ")"; }, - - "abs": function(operands) { return "cabs(" + operands[0] + ")"; }, - "apply": function(operands) { return "vec2(NaN,NaN)"; }, -}; + if (this.token.token_type === '_') { + this.advance(); + let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); -class astToGLSL { - constructor() { - } - - convert(tree) { - if (typeof tree === 'boolean') - throw Error("no support for boolean"); + // since baseFactor could return false, must check + if (subresult === false) { + if (this.token.token_type === "EOF") { + throw new ParseError("Unexpected end of input", + this.lexer.location); + } + else { + throw new ParseError("Invalid location of '" + this.token.original_text + + "'", this.lexer.location); + } + } + result = ['_', result, subresult]; + } - - if (typeof tree === 'string') { - if (tree === "e") - return "vec2(2.71828182845905,0.0)"; - - if (tree === "pi") - return "vec2(3.14159265358979,0.0)"; - - if (tree === "i") - return "vec2(0.0,1.0)"; - - return String(tree); - } - - if (typeof tree === 'number') { - return "vec2(" + String(tree) + ",0.0)"; - } - - if (("real" in tree) && ("imaginary" in tree)) - return tree; + while (this.token.token_type === "'") { + result = ['prime', result]; + this.advance(); + } - if (!Array.isArray(tree)) { - throw Error("Invalid ast"); - } + if (this.token.token_type === '^') { + this.advance(); + result = ['^', result, this.factor({ parse_absolute_value: parse_absolute_value })]; + } - - var operator = tree[0]; - var operands = tree.slice(1); + if (this.token.token_type === '{' || this.token.token_type === '(') { + let expected_right; + if (this.token.token_type === '{') + expected_right = '}'; + else + expected_right = ')'; - if(operator === "apply") { - if(typeof operands[0] !== 'string') - throw Error("Non string functions not implemented for conversion to GLSL"); + this.advance(); + let parameters = this.statement_list(); - var operator = operands[0]; - var operands = operands.slice(1); - - return glslOperators[operator]( operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); - } - - if (operator in glslOperators) { - return glslOperators[operator]( operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); - } - - throw Error("Operator " + operator + " not implemented for conversion to mathjs"); - } -} + if (this.token.token_type !== expected_right) { + throw new ParseError('Expecting ' + expected_right, + this.lexer.location); + } + this.advance(); -var astToLatex$2 = new astToLatex(); -var astToText$2 = new astToText(); -var astToGuppy$1 = new astToGuppy(); -var astToGLSL$1 = new astToGLSL(); + if (parameters[0] === 'list') { + // rename from list to tuple + parameters[0] = 'tuple'; + } -const tex = function(expr) { - return astToLatex$2.convert( expr.tree ); -}; + result = ['apply', result, parameters]; -const toLatex = tex; + } + else { + // if was an applied function symbol, + // cannot omit argument + if (must_apply) { + if (!this.allowSimplifiedFunctionApplication) + throw new ParseError("Expecting ( after function", + this.lexer.location); + + // if allow simplied function application + // let the argument be the next factor + result = ['apply', result, this.factor({ parse_absolute_value: parse_absolute_value })]; + } + } + } + else { + this.advance(); + } + } else if (this.token.token_type === '(' || this.token.token_type === '[' + || this.token.token_type === '{' + || this.token.token_type === 'LBRACE') { + let token_left = this.token.token_type; + let expected_right, other_right; + if (this.token.token_type === '(') { + expected_right = ')'; + other_right = ']'; + } + else if (this.token.token_type === '[') { + expected_right = ']'; + other_right = ')'; + } + else if (this.token.token_type === '{') { + expected_right = '}'; + other_right = null; + } + else { + expected_right = 'RBRACE'; + other_right = null; + } -const toString = function(expr) { - return astToText$2.convert( expr.tree ); -}; + this.advance(); + result = this.statement_list(); -const toGLSL = function(expr) { - return astToGLSL$1.convert( expr.tree ); -}; + let n_elements = 1; + if (result[0] === "list") { + n_elements = result.length - 1; + } -const toXML = function(expr) { - return astToGuppy$1.convert( expr.tree ); -}; + if (this.token.token_type !== expected_right) { + if (n_elements !== 2 || other_right === null) { + throw new ParseError('Expecting ' + expected_right, + this.lexer.location); + } + else if (this.token.token_type !== other_right) { + throw new ParseError('Expecting ) or ]', this.lexer.location); + } -var printing = /*#__PURE__*/Object.freeze({ - tex: tex, - toLatex: toLatex, - toString: toString, - toXML: toXML, - toGLSL: toGLSL -}); + // half-open interval + result[0] = 'tuple'; + result = ['interval', result]; + let closed; + if (token_left === '(') + closed = ['tuple', false, true]; + else + closed = ['tuple', true, false]; + result.push(closed); -const integrateNumerically = function(expr, x,a,b) { - var intervals = 100; - var total = 0.0; - var bindings = {}; + } + else if (n_elements >= 2) { + if (token_left === '(' || token_left === '{') { + result[0] = 'tuple'; + } + else if (token_left === '[') { + result[0] = 'array'; + } + else { + result[0] = 'set'; + } + } + else if (token_left === 'LBRACE') { + if (result[0] === '|' || result[0] === ':') { + result = ['set', result]; // set builder notation + } + else { + result = ['set', result]; // singleton set + } + } - for( var i=0; i < intervals; i++ ) { - var sample_point = a + ((b - a) * (i + 0.5) / intervals); - bindings[x] = sample_point; - total = total + expr.evaluate( bindings ); - } + this.advance(); - return total * (b - a) / intervals; -}; + } else if (this.token.token_type[0] === '|' && parse_absolute_value && + (inside_absolute_value === 0 || !allow_absolute_value_closing || + this.token.token_type[1] === 'L')) { -var integration = /*#__PURE__*/Object.freeze({ - integrateNumerically: integrateNumerically -}); + // allow the opening of an absolute value here if either + // - we aren't already inside an absolute value (inside_absolute_value==0), + // - we don't allows an absolute value closing, or + // - the | was marked as a left + // otherwise, skip this token so that will drop out the factor (and entire statement) + // to where the absolute value will close -function expression_to_polynomial(expr_or_tree) { + inside_absolute_value += 1; - var tree = get_tree(expr_or_tree); + this.advance(); - if(typeof tree === 'string') { - if((tree === 'pi' && math$19.define_pi) - || (tree === 'i' && math$19.define_i) - || (tree === 'e' && math$19.define_e)) - return tree; // treat as number - else - return ['polynomial', tree, [[1, 1]]]; // treat a polynomial variable - } + result = this.statement({ inside_absolute_value: inside_absolute_value }); + result = ['apply', 'abs', result]; - if(typeof tree === 'number') - return tree; + if (this.token.token_type !== '|') { + throw new ParseError('Expecting |', this.lexer.location); + } - let c = evaluate_to_constant(tree); - if(c !== null && Number.isFinite(c)) { - return simplify$2(tree); - } + this.advance(); + } - if(!Array.isArray(tree)) - return false; + if (this.token.token_type === '_') { + if (result === false) { + throw new ParseError("Invalid location of _", this.lexer.location); + } + this.advance(); + let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); - // if contains invalid operators, it's not a polynomial - if(!operators$1(tree).every( - v => ['+', '-', '*', '^', '/', '_', 'prime'].includes(v))) - return false; + if (subresult === false) { + if (this.token.token_type === "EOF") { + throw new ParseError("Unexpected end of input", this.lexer.location); + } + else { + throw new ParseError("Invalid location of '" + this.token.original_text + "'", + this.lexer.location); + } + } + return ['_', result, subresult]; + } - var operator = tree[0]; - var operands = tree.slice(1); + return result; + } - if(operator === '+') { - let result = operands.map(expression_to_polynomial); - // return false if any operand returned false - if(!result.every(v => v !== false)) - return false; + leibniz_notation() { + // attempt to find and return a derivative in Leibniz notation + // if unsuccessful, return false - return result.reduce((u,v) => polynomial_add(u,v)); - } - else if(operator === '-') { - let result = expression_to_polynomial(operands[0]); + var result = this.token.token_text; - if(!result) - return false; + let deriv_symbol = ""; - return polynomial_neg(result); - } - else if(operator === '*') { - let result = operands.map(expression_to_polynomial); + let n_deriv = 1; - // return false if any operand returned false - if(!result.every(v => v !== false )) - return false; + let var1 = ""; + let var2s = []; + let var2_exponents = []; - return result.reduce((u,v) => polynomial_mul(u,v)); - } - else if(operator === '^') { + if (this.token.token_type === "LATEXCOMMAND" && result.slice(1) === "partial") + deriv_symbol = "∂"; + else if (this.token.token_type === "VAR" && result === "d") + deriv_symbol = "d"; + else + return false; - let base = operands[0]; - let subresult = expression_to_polynomial(base); + // since have just a d or ∂ + // one option is that have a ^ followed by an integer next possibly in {} - // if subresult itself is false, then don't have a polynomial - if(subresult === false) - return false; + this.advance(); - let pow = simplify$2(operands[1]); + if (this.token.token_type === '^') { + // so far have d or ∂ followed by ^ + // must be followed by an integer + this.advance(); - // if pow isn't a literal nonnegative integer - if((typeof pow !== 'number') || pow < 0 || !Number.isInteger(pow)) { + let in_braces = false; + if (this.token.token_type === '{') { + in_braces = true; - let pow_num = evaluate_to_constant(pow); + this.advance(); + } - // check if pow is a rational number with a small base - if(pow_num !== null || Number.isFinite(pow_num)) { - let pow_fraction = math$19.fraction(pow_num); - if(pow_fraction.d <= 100) { - if(pow_fraction.s < 0) - base = ['^', base, ['/', -1, pow_fraction.d]]; - else - base = ['^', base, ['/', 1, pow_fraction.d]]; + if (this.token.token_type !== 'NUMBER') { + return false; + } - var results = ['polynomial', simplify$2(base), []]; + n_deriv = parseFloat(this.token.token_text); + if (!Number.isInteger(n_deriv)) { + return false; + } - results[2].push([pow_fraction.n, 1]); + // found integer, - return results; + // if in braces, require } + if (in_braces) { + this.advance(); - } - } + if (this.token.token_type !== '}') { + return false; + } + } - // just return entire tree as a polynomial variable - return ["polynomial", tree, [[1,1]]]; - } + this.advance(); + } - if(pow===0) { - return 1; - } - if(pow===1) { - return subresult; - } - return polynomial_pow(subresult, pow); + // since have a d or ∂, optionally followed by ^ and integer + // next we must have: + // a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols - } - else if(operator === '/') { - var denom = operands[1]; + if (this.token.token_type === 'VAR') + var1 = this.token.token_text; + else if (this.token.token_type === 'VARMULTICHAR') { + // strip out name of variable from \var command + var1 = /\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(this.token.token_text)[1]; + } + else if (this.token.token_type === 'LATEXCOMMAND') { + result = this.token.token_text.slice(1); + if (this.allowedLatexSymbols.includes(result)) + var1 = result; + else + return false; + } - var denom_num = evaluate_to_constant(denom); + // Finished numerator. + // Next need a } and { - if(denom_num === null || !Number.isFinite(denom_num)) { - // return entire tree as polynomial variable - return ['polynomial', tree, [[1, 1]]]; - } + this.advance(); - var numer_result = expression_to_polynomial(operands[0]); + if (this.token.token_type !== '}') { + return false; + } - return polynomial_mul(numer_result, ['/', 1, denom_num]); - } + this.advance(); + if (this.token.token_type !== '{') { + return false; + } + else { + this.advance(); - else { - // return entire tree as polynomial variable - return ['polynomial', tree, [[1, 1]]]; - } + } + // In denominator now + // find sequence of + // derivative symbol followed by + // - a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols + // optionally followed by a ^ and an integer + // End when sum of exponents meets or exceeds n_deriv -} + let exponent_sum = 0; + while (true) { -function polynomials_in_same_leading_variable(p,q) { - // If both polynomials have same leading variable, return unchanged. - // Else, rewrite the polymomial whose leading variable comes later - // as a polynomial that is constant in leading variable of other + // next must be + // - a VAR equal to deriv_symbol="d" or \partial when deriv_symbol = "∂" - if(p[1] !== q[1]) { - if(compare_function(p[1], q[1]) < 0) { - // variable p[1] is earlier in default order - // so write q as a polynomial constant in p[1] - q = ["polynomial", p[1], [[0, q]]]; - } - else { - // variable q[1] is earlier in default order - // so write p as a polynomial constant in q[1] - p = ["polynomial", q[1], [[0, p]]]; - } - } - return [p, q]; -} + if (!((deriv_symbol === "d" && this.token.token_type === "VAR" && this.token.token_text === "d") + || (deriv_symbol === "∂" && this.token.token_type === "LATEXCOMMAND" + && this.token.token_text.slice(1) === "partial"))) { + return false; + } + // followed by + // - a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols -function polynomial_add(p,q) { //being called on empty polynomials + this.advance(); - if(p[0] !== "polynomial") { - if(q[0] !== "polynomial") - return simplify$2(['+', p, q]); - else { - // write p as a constant polynomial in q's first variable - p = ["polynomial", q[1], [[0, p]]]; - } - } - else { - if (q[0] !== "polynomial") { - // write q as a constant polynomial in p's first variable - q = ["polynomial", p[1], [[0, q]]]; - } - else { - // if needed, rewrite polynomials so have same first variable - let tmp = polynomials_in_same_leading_variable(p,q); - p = tmp[0]; - q = tmp[1]; - } - } - - // at this point, both q and p are polynomials with same first variable - - let sum = ["polynomial", p[1], []]; - - let p_terms = p[2]; - let q_terms = q[2]; - let sum_terms = sum[2]; - - let len_p = p_terms.length; - let len_q = q_terms.length; - let i = 0; - let j = 0; - - while (i < len_p || j < len_q){ - if (i === len_p){ - if (q_terms[j][1]) - sum_terms.push(q_terms[j]); - j = j+1; - } - else if (j === len_q){ - if (p_terms[i][1]) - sum_terms.push(p_terms[i]); - i = i+1; - } - else if (p_terms[i][0] === q_terms[j][0]){ - let temp = polynomial_add(p_terms[i][1], q_terms[j][1]); - if(temp) - sum_terms.push([p_terms[i][0], temp]); - i = i+1; - j = j+1; - } - else if (p_terms[i][0] < q_terms[j][0]){ - if (p_terms[i][1]) - sum_terms.push(p_terms[i]); - i = i+1; + if (this.token.token_type === 'VAR') + var2s.push(this.token.token_text); + else if (this.token.token_type === 'VARMULTICHAR') { + // strip out name of variable from \var command + var2s.push(/\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(this.token.token_text)[1]); } - else{ - if (q_terms[j][1]) - sum_terms.push(q_terms[j]); - j = j+1; + else if (this.token.token_type === 'LATEXCOMMAND') { + let r = this.token.token_text.slice(1); + if (this.allowedLatexSymbols.includes(r)) + var2s.push(r); + else { + return false; + } } - } - - // all terms canceled - if(sum_terms.length === 0) - return 0; - - // only a term that is constant in leading variable is left - if(sum_terms.length === 1 && (sum_terms[0][0] === 0)) - return sum_terms[0][1]; - - return sum; - -} - - -function polynomial_neg(p) { + else { + return false; + } + // have derivative and variable, now check for optional ^ followed by number - if(p[0] !== "polynomial") { - return simplify$2(['-', p ]); - } + let this_exponent = 1; - let result = ["polynomial", p[1], []]; - let p_terms = p[2]; - let result_terms = result[2]; + this.advance(); - let len = p_terms.length; + if (this.token.token_type === '^') { - for (var i = 0; i < len; i = i + 1){ - result_terms.push([p_terms[i][0], polynomial_neg(p_terms[i][1])]); - } + this.advance(); - return result; -} + let in_braces = false; + if (this.token.token_type === '{') { + in_braces = true; + this.advance(); + } -function polynomial_sub(p,q) { + if (this.token.token_type !== 'NUMBER') { + return false; + } - return polynomial_add(p, polynomial_neg(q)); + this_exponent = parseFloat(this.token.token_text); + if (!Number.isInteger(this_exponent)) { + return false; + } -} + // if in braces, require } + if (in_braces) { + this.advance(); + if (this.token.token_type !== '}') { + return false; + } + } -function polynomial_mul(p,q) { + this.advance(); - if(p[0] !== "polynomial") { - if(q[0] !== "polynomial") { - return simplify$2(['*', p, q]); - } - else if(p) { - let prod = ["polynomial", q[1], []]; - let q_terms = q[2]; - let prod_terms = prod[2]; - for(let term of q_terms) { - if(term[1]) - prod_terms.push([term[0], polynomial_mul(p, term[1])]); - } - return prod; - } - } - else { - if (q && q[0] !== "polynomial") { - let prod = ["polynomial", p[1], []]; - let p_terms = p[2]; - let prod_terms = prod[2]; - for(let term of p_terms) { - if(term[1]) - prod_terms.push([term[0], polynomial_mul(term[1], q)]); - } - return prod; - } - } - - // two non-constant polynomials - // if needed, rewrite polynomials so have same first variable - let tmp = polynomials_in_same_leading_variable(p,q); - p = tmp[0]; - q = tmp[1]; - - let p_terms = p[2]; - let q_terms = q[2]; - - let prod = ["polynomial", p[1], []]; - let prod_terms = prod[2]; - let p_len = p_terms.length; - let q_len = q_terms.length; - - //find the degrees that will occur in the product - let degrees = []; - for (let term_p of p_terms){ - for (let term_q of q_terms){ - let found = false; - let current_deg = term_p[0] + term_q[0]; - for (let deg of degrees){ - if (current_deg === deg){ - found = true; - break; - } - } - if (!found) - degrees.push(current_deg); } - } - degrees.sort(function(a, b){return a - b}); + var2_exponents.push(this_exponent); + exponent_sum += this_exponent; - //this is where the product is computed - for(let deg of degrees){ - let sum = 0; - let i = 0; - while (i < p_len && p_terms[i][0] <= deg){ - let j = 0; - while (j < q_len && q_terms[j][0] <= deg){ - if ((p_terms[i][0] + q_terms[j][0]) === deg){ - sum = polynomial_add(sum, polynomial_mul(p_terms[i][1], q_terms[j][1])); - break; - } - j = j+1; - } - i = i+1; + if (exponent_sum > n_deriv) { + return false; } - if(sum) - prod_terms.push([deg, sum]); - } - - return prod; -} + // possibly found derivative + if (exponent_sum === n_deriv) { -function polynomial_pow(p, e) { + // next token must be a } + if (this.token.token_type !== '}') { + return false; - if(isNaN(e) || e < 0 || !Number.isInteger(e)) - return undefined; + } - let res = 1; + // found derivative! - while(e > 0) { + this.advance(); - if(e & 1) { - // odd exponent - res = polynomial_mul(res, p); - } + let result_name = "derivative_leibniz"; + if (deriv_symbol === "∂") + result_name = "partial_" + result_name; - p = polynomial_mul(p, p); + result = [result_name]; - e >>= 1; // divide by 2 and truncate + if (n_deriv === 1) + result.push(var1); + else + result.push(["tuple", var1, n_deriv]); - } + let r2 = []; + for (let i = 0; i < var2s.length; i += 1) { + if (var2_exponents[i] === 1) + r2.push(var2s[i]); + else + r2.push(["tuple", var2s[i], var2_exponents[i]]); + } + r2 = ["tuple"].concat(r2); - return res; -} + result.push(r2); + return result; -function polynomial_to_expression(p) { + } + } + } + } - if(!Array.isArray(p) || p[0] !== "polynomial") - return p; + class latexToGuppy{ + constructor(){ + this.latexToAst = new latexToAst(); + this.astToGuppy = new astToGuppy(); + } - let x = p[1]; - let terms = p[2]; + convert(latex){ + return this.astToGuppy.convert(this.latexToAst.convert(latex)); + } + } - let result = []; + class latexToMathjs{ + constructor(){ + this.latexToAst = new latexToAst(); + this.astToMathjs = new astToMathjs(); + } - let len_terms = terms.length; - for(var i = 0; i < len_terms; i = i+1) { - if(terms[i][1]) { - if(terms[i][0]===0) - result.push(polynomial_to_expression(terms[i][1])); - else if(terms[i][0]===1) - result.push(['*', polynomial_to_expression(terms[i][1]), x]); - else - result.push(['*', polynomial_to_expression(terms[i][1]), - ['^', x, terms[i][0]]]); + convert(latex){ + return this.astToMathjs.convert(this.latexToAst.convert(latex)); + } + } - } + class latexToText{ + constructor(){ + this.latexToAst = new latexToAst(); + this.astToText = new astToText(); } - if(result.length === 0) - return 0; - else if(result.length === 1) - result = result[0]; - else - result.unshift('+'); + convert(latex){ + return this.astToText.convert(this.latexToAst.convert(latex)); + } + } - return simplify$2(result); -} + /* + * convert math.s tree to AST + * + * Copyright 2014-2017 by + * Jim Fowler + * Duane Nykamp + * + * This file is part of a math-expressions library + * + * math-expressions is free software: you can redistribute + * it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, either + * version 3 of the License, or at your option any later version. + * + * math-expressions is distributed in the hope that it + * will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + */ -function initial_term(p) { - //takes a polynomial ["polynomial", "var"...] and returns the initial term according to lexicographic order, in form ["monomial", coefficient, [[variable1, power1], ...]] - if (!Array.isArray(p) || p[0] !== "polynomial") - return p; + const operators$4 = { + "+,add": function(operands) { return ['+'].concat(operands); }, + "*,multiply": function(operands) { return ['*'].concat(operands); }, + "/,divide": function(operands) { return ['/', operands[0], operands[1]]; }, + "-,unaryMinus": function(operands) { return ['-', operands[0]]; }, + "-,subtract": function(operands) { return ['+', operands[0], ['-', operands[1]]]; }, + "^,pow": function(operands) { return ['^', operands[0], operands[1]]; }, + "and,and": function(operands) { return ['and'].concat(operands); }, + "or,or": function(operands) { return ['or'].concat(operands); }, + "not,not": function(operands) { return ['not', operands[0]]; }, + "==,equal": function(operands) { return ['='].concat(operands); }, + "<,smaller": function(operands) { return ['<', operands[0], operands[1]]; }, + ">,larger": function(operands) { return ['>', operands[0], operands[1]]; }, + "<=,smallerEq": function(operands) { return ['le', operands[0], operands[1]]; }, + ">=,largerEq": function(operands) { return ['ge', operands[0], operands[1]]; }, + "!=,unequal": function(operands) { return ['ne', operands[0], operands[1]]; }, + "!,factorial": function(operands) { return ['apply', 'factorial', operands[0]];}, + }; - let var_powers = []; + class mathjsToAst { - while( Array.isArray(p) && p[0] === "polynomial"){ - let x = p[1]; - let terms = p[2]; - let exp = (terms[terms.length-1])[0]; - p = (terms[terms.length-1])[1]; - var_powers.push([x,exp]); - } + convert(mathnode){ + if(mathnode.isConstantNode) + return mathnode.value; + if(mathnode.isSymbolNode) + return mathnode.name; - return ["monomial", p, var_powers]; -} + if(mathnode.isOperatorNode) { + var key = [mathnode.op, mathnode.fn].join(','); + if(key in operators$4) + return operators$4[key]( + mathnode.args.map( function(v,i) { return this.convert(v); }.bind(this) ) ); + else + throw Error("Unsupported operator: " + mathnode.op + + ", " + mathnode.fn); + } -function mono_less_than(left,right) { - //takes two monomials ["monomial", coeff, terms array] and returns true if left is less than right in lexicographic order. - //stringify vars before calling this + if(mathnode.isFunctionNode) { + var args = mathnode.args.map( + function(v,i) { return this.convert(v); }.bind(this) ); - if (!Array.isArray(right) || right[0] !== "monomial") - return false; //if right is constant, always false + if( args.length > 1) + args = ["tuple"].concat(args); + else + args = args[0]; - if (!Array.isArray(left) || left[0] !== "monomial") - return true; //if left is constant and right is not, always true + var result = ["apply", mathnode.name]; + result.push(args); + return result; - let left_vars = left[2]; - let right_vars = right[2]; - let left_length = left_vars.length; - let right_length = right_vars.length; - var shorter; - if (left_length < right_length) - shorter = left_length; - else - shorter = right_length; + } + + if(mathnode.isArrayNode) { + return ["vector"].concat(mathnode.args.map( + function(v,i) { return this.convert(v); }.bind(this) ) ); + } + + if(mathnode.isParenthesisNode) + return this.convert(mathnode.content); + + throw Error("Unsupported node type: " + mathnode.type); - for ( var i = 0; i < shorter; i++ ){ - if(left_vars[i][0] !== right_vars[i][0]) { - if(compare_function(left_vars[i][0], right_vars[i][0]) < 0) { - // left variable is earlier in default order - return false; - } - else { - // right variable is earlier in default order - return true; - } - } - if(left_vars[i][1] < right_vars[i][1]) { - // left power is lower - return true; - } - if(left_vars[i][1] > right_vars[i][1]) { - // right power is lower - return false; - } - } - if ( left_length === right_length || shorter === right_length ){ - // same monomial, except possibly coefficient, or same until left is longer - return false; - } - else { - // same until right is longer - return true; } -} - - -function mono_gcd(left, right) { - //takes two monomials ["monomial", coeff, terms array] and returns their greatest common divisor as a monomial - //stringify vars before calling this - - if (!Array.isArray(left) || !Array.isArray(right) || left[0] !== "monomial" || right[0] !== "monomial") - return 1; //if either is constant, gcd is 1 - - let left_vars = left[2]; - let right_vars = right[2]; - let gcd_vars = []; - let left_length = left_vars.length; - let right_length = right_vars.length; + + } - let i = 0; - let j = 0; - while (i < left_length && j < right_length){ - if (left_vars[i][0] === right_vars[j][0]){ - if (left_vars[i][1] < right_vars[j][1]){ - gcd_vars.push(left_vars[i]); - } - else{ - gcd_vars.push(right_vars[j]); - } - i = i + 1; - j = j + 1; - } - else if (compare_function(left_vars[i][0], right_vars[j][0]) < 0){ - i = i + 1; - } - else if (compare_function(right_vars[j][0], left_vars[i][0]) < 0){ - j = j + 1; - } + class mathjsToGuppy{ + constructor(){ + this.mathjsToAst = new mathjsToAst(); + this.astToGuppy = new astToGuppy(); } - if (gcd_vars.length === 0) - return 1; //if they have no common variables, gcd is 1 - - return ["monomial", 1, gcd_vars]; -} - -function mono_div(top, bottom) { - //!!This function should only be called if bottom has coefficient 1 and divides the top (e.g., bottom was computed using mono_gcd)!! - //takes two monomials ["monomial", coeff, terms array] and returns their quotient as a monomial - //stringify vars before calling this - - if ( !Array.isArray(bottom) || bottom[0] !== "monomial"){ - //if bottom is constant - if (bottom === 1) - return top; - if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant - return evaluate_numbers(['/', top, bottom]); - else - return [top[0], evaluate_numbers(['/', top[1], bottom]), top[2]]; //shouldn't be passing constants other than 1 + convert(mathjs){ + return this.astToGuppy.convert(this.mathjsToAst.convert(mathjs)); } + } - if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant and bottom is not - return undefined; - - let top_vars = top[2]; - let bottom_vars = bottom[2]; - let div_vars = []; - let top_length = top_vars.length; - let bottom_length = bottom_vars.length; - - let i = 0; - let j = 0; - while (i < top_length && j < bottom_length){ - if (top_vars[i][0] === bottom_vars[j][0]){ - if (top_vars[i][1] < bottom_vars[j][1]){ - return undefined; //does not divide - } - else{ - let diff = top_vars[i][1] - bottom_vars[j][1]; - if (diff !== 0) - div_vars.push( [ top_vars[i][0] , diff ] ); - } - i = i + 1; - j = j + 1; - } - else if (compare_function(top_vars[i][0], bottom_vars[j][0]) < 0){ - div_vars.push( top_vars[i] ); - i = i + 1; - } - else if (compare_function(bottom_vars[j][0], top_vars[i][0]) < 0){ - return undefined; //does not divide - } + class mathjsToLatex{ + constructor(){ + this.mathjsToAst = new mathjsToAst(); + this.astToLatex = new astToLatex(); } - if (j < bottom_length) - return undefined; + convert(mathjs){ + return this.astToLatex.convert(this.mathjsToAst.convert(mathjs)); + } + } - while (i < top_length){ - div_vars.push( top_vars[i]); - i=i+1; + class mathjsToText{ + constructor(){ + this.mathjsToAst = new mathjsToAst(); + this.astToText = new astToText(); } - if (div_vars.length === 0){ - if (bottom[1] === 1) - return top[1]; //everything canceled, return coefficient of the top - else - return evaluate_numbers(['/', top[1], bottom[1]]); + convert(mathjs){ + return this.astToText.convert(this.mathjsToAst.convert(mathjs)); } + } - if (bottom[1] === 1) - return ["monomial", top[1], div_vars]; - else - return ["monomial", evaluate_numbers(['/', top[1], bottom[1]]), div_vars]; -} + var global$1 = (typeof global !== "undefined" ? global : + typeof self !== "undefined" ? self : + typeof window !== "undefined" ? window : {}); -function mono_is_div(top, bottom) { - //takes two monomials ["monomial", coeff, terms array] and returns true if bottom divides top, otherwise returns false - //stringify vars before calling this + // shim for using process in browser + // based off https://github.com/defunctzombie/node-process/blob/master/browser.js - if (bottom === 0) - return false; + function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); + } + function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); + } + var cachedSetTimeout = defaultSetTimout; + var cachedClearTimeout = defaultClearTimeout; + if (typeof global$1.setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } + if (typeof global$1.clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } - if ( !Array.isArray(bottom) || bottom[0] !== "monomial"){ //if bottom is nonzero constant - return true; - } + function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } - if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant and bottom is not - return false; - let top_vars = top[2]; - let bottom_vars = bottom[2]; - let div_vars = []; - let top_length = top_vars.length; - let bottom_length = bottom_vars.length; - - let i = 0; - let j = 0; - while (i < top_length && j < bottom_length){ - if (top_vars[i][0] === bottom_vars[j][0]){ - if (top_vars[i][1] < bottom_vars[j][1]){ - return false; //does not divide - } - else{ - let diff = top_vars[i][1] - bottom_vars[j][1]; - if (diff !== 0) - div_vars.push( [ top_vars[i][0] , diff ] ); - } - i = i + 1; - j = j + 1; - } - else if (compare_function(top_vars[i][0], bottom_vars[j][0]) < 0){ - div_vars.push( top_vars[i] ); - i = i + 1; - } - else if (compare_function(bottom_vars[j][0], top_vars[i][0]) < 0){ - return false; //does not divide - } - } + } + function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } - if (j < bottom_length) - return false; - return true; -} -function mono_to_poly(mono){ - //takes a monomial ["monomial", coeff, terms array] and returns the corresponding polynomial ["polynomial", var1, ...] + } + var queue = []; + var draining = false; + var currentQueue; + var queueIndex = -1; - if ( !Array.isArray(mono) || mono[0] !== "monomial") - return mono; //if constant, just return itself + function cleanUpNextTick() { + if (!draining || !currentQueue) { + return; + } + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } + } - let num_vars = mono[2].length; - let i = num_vars-1; - let result = mono[1]; + function drainQueue() { + if (draining) { + return; + } + var timeout = runTimeout(cleanUpNextTick); + draining = true; - while ( i >= 0){ - var coeffs = []; - coeffs.push([mono[2][i][1],result]); - result = ["polynomial", mono[2][i][0], coeffs]; - i=i-1; - } + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + runClearTimeout(timeout); + } + function nextTick(fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); + } + } + // v8 likes predictible objects + function Item(fun, array) { + this.fun = fun; + this.array = array; + } + Item.prototype.run = function () { + this.fun.apply(null, this.array); + }; + var title = 'browser'; + var platform = 'browser'; + var browser = true; + var env = {}; + var argv = []; + var version$2 = ''; // empty string to avoid regexp issues + var versions = {}; + var release = {}; + var config$2 = {}; + + function noop() {} + + var on = noop; + var addListener = noop; + var once = noop; + var off = noop; + var removeListener = noop; + var removeAllListeners = noop; + var emit = noop; + + function binding(name) { + throw new Error('process.binding is not supported'); + } + + function cwd () { return '/' } + function chdir (dir) { + throw new Error('process.chdir is not supported'); + }function umask() { return 0; } + + // from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js + var performance = global$1.performance || {}; + var performanceNow = + performance.now || + performance.mozNow || + performance.msNow || + performance.oNow || + performance.webkitNow || + function(){ return (new Date()).getTime() }; + + // generate timestamp or delta + // see http://nodejs.org/api/process.html#process_process_hrtime + function hrtime(previousTimestamp){ + var clocktime = performanceNow.call(performance)*1e-3; + var seconds = Math.floor(clocktime); + var nanoseconds = Math.floor((clocktime%1)*1e9); + if (previousTimestamp) { + seconds = seconds - previousTimestamp[0]; + nanoseconds = nanoseconds - previousTimestamp[1]; + if (nanoseconds<0) { + seconds--; + nanoseconds += 1e9; + } + } + return [seconds,nanoseconds] + } + + var startTime = new Date(); + function uptime() { + var currentTime = new Date(); + var dif = currentTime - startTime; + return dif / 1000; + } + + var process = { + nextTick: nextTick, + title: title, + browser: browser, + env: env, + argv: argv, + version: version$2, + versions: versions, + on: on, + addListener: addListener, + once: once, + off: off, + removeListener: removeListener, + removeAllListeners: removeAllListeners, + emit: emit, + binding: binding, + cwd: cwd, + chdir: chdir, + umask: umask, + hrtime: hrtime, + platform: platform, + release: release, + config: config$2, + uptime: uptime + }; + + /** + * Helpers. + */ + + var s = 1000; + var m = s * 60; + var h = m * 60; + var d = h * 24; + var y = d * 365.25; + + /** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ - return result; -} + var ms = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse$2(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); + }; -function max_div_init(f$$1, monos){ - //f is a polynomial ["polynomial", ...], monos is array of monomials ["monomial", ...]. returns the largest term (a monomial) of f divisible by something - //in monos, and the index of the divisor. - //stringify vars before calling this + /** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ - if ( f$$1 === 0){ - return 0; + function parse$2(str) { + str = String(str); + if (str.length > 100) { + return; } - let focus = f$$1; - let var_powers = []; - - while( Array.isArray(focus) && focus[0] === "polynomial"){ - let x = focus[1]; - let terms = focus[2]; - let exp = terms[terms.length-1][0]; - focus = terms[terms.length-1][1]; - var_powers.push([x,exp]); + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; } - - let current_term = ["monomial", focus, var_powers]; - - let monos_size = monos.length; - for ( var i = 0; i < monos_size; i = i+1 ){ - if (mono_is_div(current_term, monos[i])){ - return [current_term, i]; - } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; } + } - return max_div_init(polynomial_sub( f$$1, mono_to_poly(current_term)), monos); -} - -function poly_div(f$$1, divs){ - //takes a polynomial f and an array of polynomials div = [g1,g2,...], and returns a standard expression (according to mult. division) of the form [[[s1,m1],[s2,m2],....], f'] where f=m1g_{s1}+m2g_{s2}+...+f' - //stringify vars before calling this - - let inits = []; - let su_mu = []; - let sp = []; - let mp = []; - let f_prime = f$$1; + /** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ - for (var g of divs){ - inits.push(initial_term(g)); + function fmtShort(ms) { + if (ms >= d) { + return Math.round(ms / d) + 'd'; } - - let m = max_div_init(f_prime, inits); - - while (m !== 0){ - sp = m[1]; - mp = mono_div(m[0], inits[sp]); - su_mu.push([sp, mp]); - f_prime = polynomial_sub(f_prime, polynomial_mul(mono_to_poly(mp), divs[sp])); - m = max_div_init(f_prime, inits); + if (ms >= h) { + return Math.round(ms / h) + 'h'; } - - return [su_mu, f_prime]; -} - -function prereduce(polys){ - //takes an array of polys, and does some simply reductions: gets rid of 0 polynomials, if there's a constant: just return [1], if there are no nonzero polys: return [0]. - - let len = polys.length; - let new_polys = []; - - //check for 0's, constants - for (var j = 0; j < len; j++ ){ - if (polys[j] !== 0 && (!Array.isArray(polys[j]) || polys[j][0] !== "polynomial")){ - return [1]; //if there's a nonzero constant, return [1] - } - if (polys[j] !== 0){ - new_polys.push(polys[j]); - } + if (ms >= m) { + return Math.round(ms / m) + 'm'; } + if (ms >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; + } - if (new_polys.length === 0) - return [0]; - - return new_polys; -} + /** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ -function reduce_ith(i, polys){ - //takes an index i and an array polys of polynomials, and reduces the ith polynomial wrt the rest (i.e., finds a std expression and replaces with f'). Returns the reduced polynomial. - //stringify vars before calling this + function fmtLong(ms) { + return plural(ms, d, 'day') || + plural(ms, h, 'hour') || + plural(ms, m, 'minute') || + plural(ms, s, 'second') || + ms + ' ms'; + } - let inits = []; - let sp = []; - let mp = []; - let f_prime = polys[i]; - let len = polys.length; + /** + * Pluralization helper. + */ - for (var j = 0; j < len; j = j+1){ - if (j === i) //don't want to cancel out with itself, so put 0 for this initial term instead to avoid it being used - inits.push(0); - else - inits.push(initial_term(polys[j])); + function plural(ms, n, name) { + if (ms < n) { + return; } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; + } + return Math.ceil(ms / n) + ' ' + name + 's'; + } - let m = max_div_init(f_prime, inits); + var debug = createCommonjsModule(function (module, exports) { + /** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ - while (m !== 0){ - sp = m[1]; - mp = mono_div(m[0], inits[sp]); - f_prime = polynomial_sub(f_prime, polynomial_mul(mono_to_poly(mp), polys[sp])); - m = max_div_init(f_prime, inits); - } + exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; + exports.coerce = coerce; + exports.disable = disable; + exports.enable = enable; + exports.enabled = enabled; + exports.humanize = ms; - return f_prime; + /** + * The currently active debug mode names, and names to skip. + */ - /* OLD CODE: + exports.names = []; + exports.skips = []; - if (!Array.isArray(polys) || i >= polys.length){ - return undefined; - } + /** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ - let len = polys.length; - let new_polys = []; + exports.formatters = {}; - //check for 0's, constants - for (var j = 0; j < len; j++ ){ - if (polys[j] !== 0 && (!Array.isArray(polys[j]) || polys[j][0] !== "polynomial")){ - return 1; //if there's a nonzero constant, return [1] - } - if (polys[j] !== 0){ - new_polys.push(polys[j]); - } - } + /** + * Previous log timestamp. + */ - len = new_polys.length; + var prevTime; - if (len === 0) - return 0; //if there were no nonzero polys, return [0] + /** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ - if (len === 1) - return new_polys[0]; //if there's only one poly, don't need to reduce + function selectColor(namespace) { + var hash = 0, i; - let others = []; - for ( var j = 0; j < len; j++ ){ - if (j !== i) - others.push(new_polys[j]); + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer } - return poly_div(new_polys[i], others)[1];*/ -} - -function reduce$1(polys){ - //takes an array of polynomials, and reduces them with respect to each other until they can't be reduced anymore. Returns array of reduced polynomials. - //this could be made more efficient with better bookkeeping if necessary - currently copying sub-arrays a lot, whenever call reduce_ith. Would need to track changes in sub-arrays. - //stringify vars before calling this + return exports.colors[Math.abs(hash) % exports.colors.length]; + } - let i = 0; - let h=[]; - let new_polys = prereduce(polys); - let len = new_polys.length; + /** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ - if (len === 1) - return new_polys; //if there's only one poly, don't need to reduce - /*prereduce more frequently: - while (i < len){ - h = reduce_ith(i, new_polys); - if ( _.isEqual( h, new_polys[i] )){ //from underscore lib to compare arrays with objects - i=i+1; - } - else{ - new_polys[i] = h; - i = 0; - new_polys = prereduce(new_polys); - len = new_polys.length; - } - }*/ - - /* This code prereduces less frequently, maybe slightly faster?*/ - let trigger = true; - while (trigger){ - trigger = false; - new_polys = prereduce(new_polys); - len = new_polys.length; - i = 0; - while (i < len){ - h = reduce_ith(i, new_polys); - if ( !underscore.isEqual( h, new_polys[i] )){ //from underscore lib to compare arrays with objects - new_polys[i]=h; - trigger = true; - } - i = i+1; - } - } + function createDebug(namespace) { - i = 0; - let init = []; - let coeff = 0; - while (i < len){ //leading coeffs should be 1 - init = initial_term(new_polys[i]); - if (!Array.isArray(init) || init[0] !== "monomial") - new_polys[i] = 1; - else{ - coeff = init[1]; - if (coeff !== 1) - new_polys[i] = polynomial_mul(new_polys[i], ['/', 1, coeff]); - } - i = i + 1; - } + function debug() { + // disabled? + if (!debug.enabled) return; - return new_polys; -} + var self = debug; -function hij(i, j, polys){ - //takes indices i,j and an array of polynomials. Returns the polynomial hij computed from the ith and jth polys in polynomials, for Buchberger's criterion. - //stringify vars before calling this + // set `diff` timestamp + var curr = +new Date(); + var ms$$1 = curr - (prevTime || curr); + self.diff = ms$$1; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; - let init_gi = initial_term(polys[i]); - let init_gj = initial_term(polys[j]); - let gcd = mono_gcd(init_gi, init_gj); - let mij = mono_to_poly(mono_div(init_gi, gcd)); - let mji = mono_to_poly(mono_div(init_gj, gcd)); - let std_exp = poly_div(polynomial_sub(polynomial_mul(mji, polys[i]), polynomial_mul(mij, polys[j])), polys); - return std_exp[1]; -} + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } -function build_hij_table(table, polys){ - //takes an empty table and an array of polynomials, and fills in table where table[[i,j]]=h_ij for i < j < polys.length. (Look up h_ij based on the index in polys) returns first choice for h - //stringify vars before calling this + args[0] = exports.coerce(args[0]); - let len = polys.length; - let i = 0; - let j = 1; + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); + } - let candidates = []; + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); - while (j < len){ - while (i < j){ - table[[i,j]] = hij(i,j,polys); - if (table[[i,j]] !== 0) - candidates.push(table[[i,j]]); - i = i + 1; + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; } - i = 0; - j = j + 1; - } + return match; + }); - if (candidates.length > 0) - return choice_lowest_degree(candidates); //call different choice functions here. Could avoid iterating through again if check as go. + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); - return 0; -} - -function update_hij_table(table, polys, h){ - //takes an hij table, array of polynomials that the table was built for, and a poynomial h. Updates the hij values for the addition of the polynomial h, h is added with the highest index. return next choice of h. - - let len = polys.length; - polys.push(h); - let i = 0; - let j = 1; - - let candidates = []; - while (j < len){ //this loop updates old hij values. - while (i < j){ - if (table[[i,j]] !== 0){ - table[[i,j]] = hij(i,j,polys); - if (table[[i,j]] !== 0) - candidates.push(table[[i,j]]); - } - i = i + 1; - } - i = 0; - j = j+1; + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); } - while (i < len){ //this loop adds values with h - table [[i,len]] = hij(i,len,polys); - if (table[[i,len]] !== 0) - candidates.push(table[[i,len]]); - i = i + 1; + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); + + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); } - if (candidates.length > 0) - return choice_lowest_degree(candidates); //call different choice functions here. Could avoid iterating through again if check as go. + return debug; + } - return 0; -} + /** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ -function choice_lowest_degree(polys){ - //takes an array of polynomials, returns the polynomial of lowest degree. + function enable(namespaces) { + exports.save(namespaces); - let inits = []; - let len = polys.length; + exports.names = []; + exports.skips = []; - for (i = 0; i < len; i = i+1){ - inits.push(initial_term(polys[i])); - } + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; - let min_index = 0; - for (var i = 1; i < len; i = i+1){ - if (inits[i] === 1) - return 1; - if (mono_less_than(inits[i], inits[min_index])) - min_index = i; + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } } + } - return polys[min_index]; -} + /** + * Disable debug output. + * + * @api public + */ -function reduced_grobner(polys){ - //takes an array of polynomials, returns reduced grobner basis of the ideal they generate. - //stringify vars before calling this + function disable() { + exports.enable(''); + } - let new_polys = reduce$1(polys); + /** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ - let table = {}; - let h = build_hij_table(table, new_polys); - while (h !== 0){ - h = update_hij_table(table, new_polys, h); + function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } } - - new_polys = reduce$1(new_polys); - - return new_polys; -} - -function poly_lcm(f$$1,g){ - //takes two polynomials f and g, and returns their least common multiple. - //stringify vars before calling this - - let t = ["polynomial", "_t", [[1,1]]]; - let one_minus_t = ["polynomial", "_t", [[0,1], [1,-1]]]; - let grob = reduced_grobner([polynomial_mul(t, f$$1), polynomial_mul(one_minus_t, g)]); - - //find term without _t - let len = grob.length; - for (var i = 0; i < len; i = i + 1){ - if (!Array.isArray(grob[i]) || grob[i][0] !== "polynomial"){ - return 1; //if there is a constant in the grobner basis, return 1 (shouldn't have constants other than 1, so could probably just check for 1) - } - if (grob[i][1] !== "_t") - return grob[i]; + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } } + return false; + } - return undefined; //this should never be reached, unless something bad happens? -} + /** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ -function poly_gcd(f$$1,g){ - //takes two polynomials f and g, and returns their greatest common divisor. - //stringify vars before calling this + function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; + } + }); + var debug_1 = debug.coerce; + var debug_2 = debug.disable; + var debug_3 = debug.enable; + var debug_4 = debug.enabled; + var debug_5 = debug.humanize; + var debug_6 = debug.names; + var debug_7 = debug.skips; + var debug_8 = debug.formatters; - let lcm = poly_lcm(f$$1,g); - let fg = polynomial_mul(f$$1,g); - let std_exp = poly_div(fg, [lcm]); + var browser$1 = createCommonjsModule(function (module, exports) { + /** + * This is the web browser implementation of `debug()`. + * + * Expose `debug()` as the module. + */ - let sum = 0; - let len = std_exp[0].length; - for (var i = 0; i < len; i = i+1){ - sum = polynomial_add(sum, mono_to_poly(std_exp[0][i][1])); - } + exports = module.exports = debug; + exports.log = log; + exports.formatArgs = formatArgs; + exports.save = save; + exports.load = load; + exports.useColors = useColors; + exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); - //divide by leading coeff, so leading coeff of gcd is 1 - let init = initial_term(sum); - if (!Array.isArray(init) || init[0] !== "monomial") - sum = 1; - else{ - let coeff = init[1]; - if (coeff !== 1) - sum = polynomial_mul(sum, ['/', 1, coeff]); - } + /** + * Colors. + */ - return sum; -} + exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' + ]; -function poly_by_divisor(f$$1, d){ - //takes two polynomials f and d (where d is a divisor of f), and returns f divided by d. - //!!Only call if d evenly divides f!! - //stringify vars before calling this + /** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ - let std_exp = poly_div(f$$1, [d]); - let sum = 0; - let len = std_exp[0].length; - for (var i = 0; i < len; i = i+1){ - sum = polynomial_add(sum, mono_to_poly(std_exp[0][i][1])); + function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; } - return sum; -} - -function reduce_rational_expression(top, bottom){ - //input: top and bottom of a rational expression. top and bottom should be polynomials, ["polynomial", ...]. returns an array with two entries: new_top and new_bottom, which are reduced (gcd of new_top and new_bottom is 1). new_bottom will always have leading coefficient 1 (according to lexicographic order) - let stringy_top = stringify_vars(top); - let stringy_bottom = stringify_vars(bottom); - top = stringy_top[0]; - bottom = stringy_bottom[0]; - - let gcd = poly_gcd(top, bottom); - let denom_coeff = (initial_term(bottom))[1]; - let div = polynomial_mul(gcd,denom_coeff); - let new_top = poly_by_divisor(top, div); - let new_bottom = poly_by_divisor(bottom, div); - return [destringify_vars(destringify_vars(new_top, stringy_top[1]), stringy_bottom[1]), destringify_vars(destringify_vars(new_bottom, stringy_top[1]), stringy_bottom[1])]; -} + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); + } -function stringify_vars(f$$1){ - //takes a polynomial f and converts all variables to strings. Returns the new, stringy polynomial, and a dictionary to convert back to the original degrees. + /** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ - if (!Array.isArray(f$$1) || f$$1[0] !== "polynomial") - return [f$$1, {}]; //if it's not a polynomial, don't need to change anything. + exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; + } + }; - let table = {}; - let var_string = "z" + JSON.stringify(f$$1[1]); - table[var_string] = f$$1[1]; - f$$1[1] = var_string; - let terms = f$$1[2]; - let current = []; - for (let f_term of terms){ - current = stringify_vars(f_term[1]); - f_term[1] = current[0]; - for (let key in current[1]){ - table[key] = current[1][key]; - } - } + /** + * Colorize log arguments if enabled. + * + * @api public + */ - return [f$$1, table]; -} + function formatArgs(args) { + var useColors = this.useColors; -function destringify_vars(f$$1, table){ - //takes a stringy polynomial and a dictionary {string:actual_variable,...} and returns the polynomial with strings replaced with the actual variable they represent. + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); - if (!Array.isArray(f$$1) || f$$1[0] !== "polynomial") - return f$$1; //it it's not a polynomial, don't need to change anything. + if (!useColors) return; - if (table[f$$1[1]]) - f$$1[1] = table[f$$1[1]]; + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit'); - let terms = f$$1[2]; - for (let f_term of terms){ - f_term[1] = destringify_vars(f_term[1], table); - } + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); - return f$$1; -} + args.splice(lastC, 0, c); + } -var textToAst$3 = new textToAst(); + /** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ -function common_denominator(tree, assumptions) { + function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); + } - tree = simplify$2(tree, assumptions); + /** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ - var transformations = []; - transformations.push( - [textToAst$3.convert("a/c+b/c"), textToAst$3.convert("(a+b)/c"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a/c-b/c"), textToAst$3.convert("(a-b)/c"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a+b/c"), textToAst$3.convert("(ac+b)/c"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a-b/c"), textToAst$3.convert("(ac-b)/c"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a/d+b/c"), textToAst$3.convert("(ac+bd)/(cd)"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a/d-b/c"), textToAst$3.convert("(ac-bd)/(cd)"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push([textToAst$3.convert("x*(y/z)"), textToAst$3.convert("(x*y)/z"), - {allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }]); - transformations.push([textToAst$3.convert("(x/y)/z"), textToAst$3.convert("x/(y*z)"), - {allow_extended_match: true, - allow_permutations: true, - }]); - transformations.push([textToAst$3.convert("x/(y/z)"), textToAst$3.convert("xz/y"), - {allow_extended_match: true, - allow_permutations: true, - }]); + function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} + } - tree = applyAllTransformations(tree, transformations, 40); + /** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ - tree = expand(tree, true); + function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} - return tree; -} + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; + } + return r; + } -function as_num_denom(expr_or_tree) { - // Return tuple containing numerator and denominator - // after attempting to place over common denominator + /** + * Enable namespaces listed in `localStorage.debug` initially. + */ - var tree = get_tree(expr_or_tree); + exports.enable(load()); - tree = common_denominator(tree); + /** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ - if(tree[0] === '/') - return [tree[1], tree[2]]; - else - return [tree, 1]; -} + function localstorage() { + try { + return window.localStorage; + } catch (e) {} + } + }); + var browser_1 = browser$1.log; + var browser_2 = browser$1.formatArgs; + var browser_3 = browser$1.save; + var browser_4 = browser$1.load; + var browser_5 = browser$1.useColors; + var browser_6 = browser$1.storage; + var browser_7 = browser$1.colors; + + // MIT lisence + // from https://github.com/substack/tty-browserify/blob/1ba769a6429d242f36226538835b4034bf6b7886/index.js + + function isatty() { + return false; + } -function reduce_rational(expr_or_tree) { - var tree = get_tree(expr_or_tree); + function ReadStream() { + throw new Error('tty.ReadStream is not implemented'); + } - var num_denom = as_num_denom(tree); + function WriteStream() { + throw new Error('tty.ReadStream is not implemented'); + } - if(num_denom[1] === 1) - return tree; + var tty = { + isatty: isatty, + ReadStream: ReadStream, + WriteStream: WriteStream + } - var poly_num = expression_to_polynomial(num_denom[0]); - var poly_denom = expression_to_polynomial(num_denom[1]); + var lookup = []; + var revLookup = []; + var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array; + var inited = false; + function init () { + inited = true; + var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i]; + revLookup[code.charCodeAt(i)] = i; + } - var reduced_polys = reduce_rational_expression(poly_num, poly_denom); + revLookup['-'.charCodeAt(0)] = 62; + revLookup['_'.charCodeAt(0)] = 63; + } - var num_new = polynomial_to_expression(reduced_polys[0]); - var denom_new = polynomial_to_expression(reduced_polys[1]); + function toByteArray (b64) { + if (!inited) { + init(); + } + var i, j, l, tmp, placeHolders, arr; + var len = b64.length; - if(denom_new === 1) - return num_new; - else - return ['/', num_new, denom_new]; + if (len % 4 > 0) { + throw new Error('Invalid string. Length must be a multiple of 4') + } -} + // the number of equal signs (place holders) + // if there are two placeholders, than the two characters before it + // represent one byte + // if there is only one, then the three characters before it represent 2 bytes + // this is just a cheap hack to not do indexOf twice + placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0; -const common_demoninator = common_denominator; + // base64 is 4/3 + up to two characters of the original data + arr = new Arr(len * 3 / 4 - placeHolders); -var rational = /*#__PURE__*/Object.freeze({ - reduce_rational: reduce_rational, - common_demoninator: common_demoninator -}); + // if there are placeholders, only get up to the last complete 4 chars + l = placeHolders > 0 ? len - 4 : len; -function round_numbers_to_precision(expr_or_tree, digits=14) { - // round any decimals to specified number of significant digits + var L = 0; - var tree = get_tree(expr_or_tree); + for (i = 0, j = 0; i < l; i += 4, j += 3) { + tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]; + arr[L++] = (tmp >> 16) & 0xFF; + arr[L++] = (tmp >> 8) & 0xFF; + arr[L++] = tmp & 0xFF; + } - if(digits < 1) { - throw Error("For round_numbers_to_precision, digits must be positive"); - } + if (placeHolders === 2) { + tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4); + arr[L++] = tmp & 0xFF; + } else if (placeHolders === 1) { + tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2); + arr[L++] = (tmp >> 8) & 0xFF; + arr[L++] = tmp & 0xFF; + } - if(!Number.isFinite(digits)) { - throw Error("For round_numbers_to_precision, digits must be a number"); + return arr } - if(digits > 15) { - return tree; + function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] } - digits = Math.round(digits); - - return round_numbers_to_precision_sub(tree,digits); -} - -const round_numbers_to_precision_sub = function(tree, digits=14) { - - if(typeof tree === "number") { - - if(Number.isFinite(tree) && tree !== 0) { - const scaleFactor = math$19.floor(math$19.log10(math$19.abs(tree))); - const n = digits - scaleFactor - 1; - if(n < 0) { - // mathjs toFixed truncates zeros when n is negative - // so add back on when creating float - return parseFloat(number_7(tree, n)+'0'.repeat(math$19.abs(n))); - } else { - return parseFloat(number_7(tree, n)) - } + function encodeChunk (uint8, start, end) { + var tmp; + var output = []; + for (var i = start; i < end; i += 3) { + tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]); + output.push(tripletToBase64(tmp)); } + return output.join('') } - if(!Array.isArray(tree)) { - return tree; - } - let operator = tree[0]; - let operands = tree.slice(1); - return [operator, ...operands.map(x => round_numbers_to_precision_sub(x,digits))] -}; + function fromByteArray (uint8) { + if (!inited) { + init(); + } + var tmp; + var len = uint8.length; + var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes + var output = ''; + var parts = []; + var maxChunkLength = 16383; // must be multiple of 3 -function round_numbers_to_decimals(expr_or_tree, ndecimals=14) { - // round any numbers to specified number of decimals + // go through the array every three bytes, we'll deal with trailing stuff later + for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { + parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))); + } - var tree = get_tree(expr_or_tree); + // pad the end with zeros, but make sure to not forget the extra bytes + if (extraBytes === 1) { + tmp = uint8[len - 1]; + output += lookup[tmp >> 2]; + output += lookup[(tmp << 4) & 0x3F]; + output += '=='; + } else if (extraBytes === 2) { + tmp = (uint8[len - 2] << 8) + (uint8[len - 1]); + output += lookup[tmp >> 10]; + output += lookup[(tmp >> 4) & 0x3F]; + output += lookup[(tmp << 2) & 0x3F]; + output += '='; + } + parts.push(output); - if(!Number.isFinite(ndecimals)) { - throw Error("For round_numbers_to_decimals, ndecimals must be a number"); + return parts.join('') } - ndecimals = Math.round(ndecimals); + function read (buffer, offset, isLE, mLen, nBytes) { + var e, m; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var nBits = -7; + var i = isLE ? (nBytes - 1) : 0; + var d = isLE ? -1 : 1; + var s = buffer[offset + i]; - // no need to go much beyond limits of double precision - ndecimals = Math.max(-330, Math.min(330, ndecimals)); + i += d; - return round_numbers_to_decimals_sub(tree,ndecimals); -} + e = s & ((1 << (-nBits)) - 1); + s >>= (-nBits); + nBits += eLen; + for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} -const round_numbers_to_decimals_sub = function(tree, ndecimals=0) { + m = e & ((1 << (-nBits)) - 1); + e >>= (-nBits); + nBits += mLen; + for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} - if(typeof tree === "number") { - if(ndecimals < 0) { - // mathjs toFixed truncates zeros when n is negative - // so add back on when creating float - return parseFloat(number_7(tree, ndecimals)+'0'.repeat(math$19.abs(ndecimals))); + if (e === 0) { + e = 1 - eBias; + } else if (e === eMax) { + return m ? NaN : ((s ? -1 : 1) * Infinity) } else { - return parseFloat(number_7(tree, ndecimals)) + m = m + Math.pow(2, mLen); + e = e - eBias; } + return (s ? -1 : 1) * m * Math.pow(2, e - mLen) } - if(!Array.isArray(tree)) { - return tree; - } - let operator = tree[0]; - let operands = tree.slice(1); - return [operator, ...operands.map(x => round_numbers_to_decimals_sub(x,ndecimals))] -}; - -var round$2 = /*#__PURE__*/Object.freeze({ - round_numbers_to_precision: round_numbers_to_precision, - round_numbers_to_decimals: round_numbers_to_decimals -}); - -const expression_to_tree = [ - simplify$3, - differentiation, - normalization, - arithmetic$1, - transformation, - solve, - sets, - matrix$5, - rational, - round$2, -]; - -const expression_to_other = [ - variables$1, - printing, - equality, - integration, - evaluation, - analytic, - sign_error, -]; - -// standard functions - -//"intersect", "cross", "det", "diag", "dot", "eye", " inv", " sort", " trace", " transpose", "max", "mean", "median", "min", "mode", "nthRoot" -// "ceil", "fix", "floor", "round" - -function abs$2(expr_or_tree) {return ['apply', 'abs', get_tree(expr_or_tree)];} -function exp$2(expr_or_tree) {return ['apply', 'exp', get_tree(expr_or_tree)];} -function log$2(expr_or_tree) {return ['apply', 'log', get_tree(expr_or_tree)];} -function log10$2(expr_or_tree) {return ['apply', 'log10', get_tree(expr_or_tree)];} -function sign$4(expr_or_tree) {return ['apply', 'sign', get_tree(expr_or_tree)];} -function sqrt$2(expr_or_tree) {return ['apply', 'sqrt', get_tree(expr_or_tree)];} -function conj$2(expr_or_tree) {return ['apply', 'conj', get_tree(expr_or_tree)];} -function im$2(expr_or_tree) {return ['apply', 'im', get_tree(expr_or_tree)];} -function re$2(expr_or_tree) {return ['apply', 're', get_tree(expr_or_tree)];} -function factorial$2(expr_or_tree) {return ['apply', 'factorial', get_tree(expr_or_tree)];} -function gamma$2(expr_or_tree) {return ['apply', 'gamma', get_tree(expr_or_tree)];} -function erf$2(expr_or_tree) {return ['apply', 'erf', get_tree(expr_or_tree)];} -function acos$2(expr_or_tree) {return ['apply', 'acos', get_tree(expr_or_tree)];} -function acosh$2(expr_or_tree) {return ['apply', 'acosh', get_tree(expr_or_tree)];} -function acot$2(expr_or_tree) {return ['apply', 'acot', get_tree(expr_or_tree)];} -function acoth$2(expr_or_tree) {return ['apply', 'acoth', get_tree(expr_or_tree)];} -function acsc$2(expr_or_tree) {return ['apply', 'acsc', get_tree(expr_or_tree)];} -function acsch$2(expr_or_tree) {return ['apply', 'acsch', get_tree(expr_or_tree)];} -function asec$2(expr_or_tree) {return ['apply', 'asec', get_tree(expr_or_tree)];} -function asech$2(expr_or_tree) {return ['apply', 'asech', get_tree(expr_or_tree)];} -function asin$2(expr_or_tree) {return ['apply', 'asin', get_tree(expr_or_tree)];} -function asinh$2(expr_or_tree) {return ['apply', 'asinh', get_tree(expr_or_tree)];} -function atan$2(expr_or_tree) {return ['apply', 'atan', get_tree(expr_or_tree)];} -function atanh$2(expr_or_tree) {return ['apply', 'atanh', get_tree(expr_or_tree)];} -function cos$2(expr_or_tree) {return ['apply', 'cos', get_tree(expr_or_tree)];} -function cosh$2(expr_or_tree) {return ['apply', 'cosh', get_tree(expr_or_tree)];} -function cot$2(expr_or_tree) {return ['apply', 'cot', get_tree(expr_or_tree)];} -function coth$2(expr_or_tree) {return ['apply', 'coth', get_tree(expr_or_tree)];} -function csc$2(expr_or_tree) {return ['apply', 'csc', get_tree(expr_or_tree)];} -function csch$2(expr_or_tree) {return ['apply', 'csch', get_tree(expr_or_tree)];} -function sec$2(expr_or_tree) {return ['apply', 'sec', get_tree(expr_or_tree)];} -function sech$2(expr_or_tree) {return ['apply', 'sech', get_tree(expr_or_tree)];} -function sin$2(expr_or_tree) {return ['apply', 'sin', get_tree(expr_or_tree)];} -function sinh$2(expr_or_tree) {return ['apply', 'sinh', get_tree(expr_or_tree)];} -function tan$2(expr_or_tree) {return ['apply', 'tan', get_tree(expr_or_tree)];} -function tanh$2(expr_or_tree) {return ['apply', 'tanh', get_tree(expr_or_tree)];} - -// function of two variables -function atan2$2(expr_or_tree1, expr_or_tree2) { - return ['apply', 'atan2', ['tuple', get_tree(expr_or_tree1), - get_tree(expr_or_tree2)]]; -} - -var standard = /*#__PURE__*/Object.freeze({ - abs: abs$2, - exp: exp$2, - log: log$2, - log10: log10$2, - sign: sign$4, - sqrt: sqrt$2, - conj: conj$2, - im: im$2, - re: re$2, - factorial: factorial$2, - gamma: gamma$2, - erf: erf$2, - acos: acos$2, - acosh: acosh$2, - acot: acot$2, - acoth: acoth$2, - acsc: acsc$2, - acsch: acsch$2, - asec: asec$2, - asech: asech$2, - asin: asin$2, - asinh: asinh$2, - atan: atan$2, - atanh: atanh$2, - cos: cos$2, - cosh: cosh$2, - cot: cot$2, - coth: coth$2, - csc: csc$2, - csch: csch$2, - sec: sec$2, - sech: sech$2, - sin: sin$2, - sinh: sinh$2, - tan: tan$2, - tanh: tanh$2, - atan2: atan2$2 -}); - -const expression_to_tree$1 = [ - standard, -]; - -// UPDATETHIS: Delete or change to new license & package name - -/* - * recursive descent parser for math expressions - * - * Copyright 2014-2017 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - -// UPDATETHIS: Is this grammar still correct? - -/* Grammar: - - statement_list = - statement_list ',' statement | - statement - - statement = - '\\dots' | - statement_a '|' statement_a | - statement_a 'MID' statement_a | - statement_a ':' statement_a - **** statement_a '|' statement_a - used with turning off '|' statement '|' in baseFactor - tried only after parse error encountered - - statement_a = - statement_a 'OR' statement_b | - statement_b - - statement_b = - statement_b 'AND' relation | - relation - - relation = - 'NOT' relation | - relation '=' expression | - relation 'NE' expression | - relation '<' expression | - relation '>' expression | - relation 'LE' expression | - relation 'GE' expression | - relation 'IN' expression | - relation 'NOTIN' expression | - relation 'NI' expression | - relation 'NOTNI' expression | - relation 'SUBSET' expression | - relation 'NOTSUBSET' expression | - relation 'SUPERSET' expression | - relation 'NOTSUPERSET' expression | - expression - - expression = - expression '+' term | - expression '-' term | - expression 'UNION' term | - expression 'INTERSECT' term | - '+' term | - term - - term = - term '*' factor | - term nonMinusFactor | - term '/' factor | - factor - - baseFactor = - '(' statement_list ')' | - '[' statement_list ']' | - '{' statement_list '}' | - 'LBRACE' statement_list 'RBRACE' | - '(' statement ',' statement ']' | - '[' statement ',' statement ')' | - '|' statement '|' | - \frac{statement}{statement} | - number | - variable | - modified_function '(' statement_list ')' | - modified_applied_function '(' statement_list ')' | - modified_function '{' statement_list '}' | - modified_applied_function '{' statement_list '}' | - modified_function | - modified_applied_function factor | - sqrt '[' statement ']' '{' statement '}' | - baseFactor '_' baseFactor | - *** modified_applied_function factor - allowed only if allowSimplifiedFunctionApplication==true - *** '|' statement '|' - allowed only at beginning of factor or if not currently in absolute value - - modified_function = - function | - function '_' baseFactor | - function '_' baseFactor '^' factor | - function '^' factor - function "'" - function '_' baseFactor "'" - function '_' baseFactor "'" '^' factor - function "'" '^' factor - *** where the "'" after the functions can be repeated - - modified_applied_function = - applied_function | - applied_function '_' baseFactor | - applied_function '_' baseFactor '^' factor | - applied_function '^' factor - applied_function "'" - applied_function '_' baseFactor "'" - applied_function '_' baseFactor "'" '^' factor - applied_function "'" '^' factor - *** where the "'" after the applied_functions can be repeated - - nonMinusFactor = - baseFactor | - baseFactor '^' factor | - baseFactor '!' and/or "'" | - baseFactor '!' and/or "'" '^' factor| - *** where '!' and/or "'" indicates arbitrary sequence of "!" and/or "'" - - factor = - '-' factor | - nonMinusFactor - -*/ - - -// Some of the latex commands that lead to spacing -const whitespace_rule = '\\s|\\\\,|\\\\!|\\\\ |\\\\>|\\\\;|\\\\:|\\\\quad\\b|\\\\qquad\\b'; - -// in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, -// it must be at the end or followed a comma, &, |, \|, ), }, \}, ], \\, or \end -const sci_notat_exp_regex$1 = '(E[+\\-]?[0-9]+\\s*($|(?=\\,|&|\\||\\\\\\||\\)|\\}|\\\\}|\\]|\\\\\\\\|\\\\end)))?'; - -const latex_rules = [ - ['[0-9]+(\\.[0-9]*)?'+sci_notat_exp_regex$1 , 'NUMBER'], - ['\\.[0-9]+'+sci_notat_exp_regex$1, 'NUMBER'], - ['\\*', '*'], - ['\\/', '/'], - ['-', '-'], - ['\\+', '+'], - ['\\^', '^'], - ['\\(', '('], - ['\\\\left\\s*\\(', '('], - ['\\\\bigl\\s*\\(', '('], - ['\\\\Bigl\\s*\\(', '('], - ['\\\\biggl\\s*\\(', '('], - ['\\\\Biggl\\s*\\(', '('], - ['\\)', ')'], - ['\\\\right\\s*\\)', ')'], - ['\\\\bigr\\s*\\)', ')'], - ['\\\\Bigr\\s*\\)', ')'], - ['\\\\biggr\\s*\\)', ')'], - ['\\\\Biggr\\s*\\)', ')'], - ['\\[', '['], - ['\\\\left\\s*\\[', '['], - ['\\\\bigl\\s*\\[', '['], - ['\\\\Bigl\\s*\\[', '['], - ['\\\\biggl\\s*\\[', '['], - ['\\\\Biggl\\s*\\[', '['], - ['\\]', ']'], - ['\\\\right\\s*\\]', ']'], - ['\\\\bigr\\s*\\]', ']'], - ['\\\\Bigr\\s*\\]', ']'], - ['\\\\biggr\\s*\\]', ']'], - ['\\\\Biggr\\s*\\]', ']'], - ['\\|', '|'], - ['\\\\left\\s*\\|', '|L'], - ['\\\\bigl\\s*\\|', '|L'], - ['\\\\Bigl\\s*\\|', '|L'], - ['\\\\biggl\\s*\\|', '|L'], - ['\\\\Biggl\\s*\\|', '|L'], - ['\\\\right\\s*\\|', '|'], - ['\\\\bigr\\s*\\|', '|'], - ['\\\\Bigr\\s*\\|', '|'], - ['\\\\biggr\\s*\\|', '|'], - ['\\\\Biggr\\s*\\|', '|'], - ['\\\\big\\s*\\|', '|'], - ['\\\\Big\\s*\\|', '|'], - ['\\\\bigg\\s*\\|', '|'], - ['\\\\Bigg\\s*\\|', '|'], - ['{', '{'], - ['}', '}'], - ['\\\\{', 'LBRACE'], - ['\\\\left\\s*\\\\{', 'LBRACE'], - ['\\\\bigl\\s*\\\\{', 'LBRACE'], - ['\\\\Bigl\\s*\\\\{', 'LBRACE'], - ['\\\\biggl\\s*\\\\{', 'LBRACE'], - ['\\\\Biggl\\s*\\\\{', 'LBRACE'], - ['\\\\}', 'RBRACE'], - ['\\\\right\\s*\\\\}', 'RBRACE'], - ['\\\\bigr\\s*\\\\}', 'RBRACE'], - ['\\\\Bigr\\s*\\\\}', 'RBRACE'], - ['\\\\biggr\\s*\\\\}', 'RBRACE'], - ['\\\\Biggr\\s*\\\\}', 'RBRACE'], - ['\\\\cdot(?![a-zA-Z])', '*'], - ['\\\\div(?![a-zA-Z])', '/'], - ['\\\\times(?![a-zA-Z])', '*'], - ['\\\\frac(?![a-zA-Z])', 'FRAC'], - [',', ','], - [':', ':'], - ['\\\\mid', 'MID'], - - ['\\\\vartheta(?![a-zA-Z])', 'LATEXCOMMAND', '\\theta'], - ['\\\\varepsilon(?![a-zA-Z])', 'LATEXCOMMAND', '\\epsilon'], - ['\\\\varrho(?![a-zA-Z])', 'LATEXCOMMAND', '\\rho'], - ['\\\\varphi(?![a-zA-Z])', 'LATEXCOMMAND', '\\phi'], - - ['\\\\infty(?![a-zA-Z])', 'INFINITY'], - - ['\\\\asin(?![a-zA-Z])', 'LATEXCOMMAND', '\\arcsin'], - ['\\\\acos(?![a-zA-Z])', 'LATEXCOMMAND', '\\arccos'], - ['\\\\atan(?![a-zA-Z])', 'LATEXCOMMAND', '\\arctan'], - ['\\\\sqrt(?![a-zA-Z])', 'SQRT'], - - ['\\\\land(?![a-zA-Z])', 'AND'], - ['\\\\wedge(?![a-zA-Z])', 'AND'], - - ['\\\\lor(?![a-zA-Z])', 'OR'], - ['\\\\vee(?![a-zA-Z])', 'OR'], - - ['\\\\lnot(?![a-zA-Z])', 'NOT'], - - ['=', '='], - ['\\\\neq(?![a-zA-Z])', 'NE'], - ['\\\\ne(?![a-zA-Z])', 'NE'], - ['\\\\not\\s*=', 'NE'], - ['\\\\leq(?![a-zA-Z])', 'LE'], - ['\\\\le(?![a-zA-Z])', 'LE'], - ['\\\\geq(?![a-zA-Z])', 'GE'], - ['\\\\ge(?![a-zA-Z])', 'GE'], - ['<', '<'], - ['\\\\lt(?![a-zA-Z])', '<'], - ['>', '>'], - ['\\\\gt(?![a-zA-Z])', '>'], - - ['\\\\in(?![a-zA-Z])', 'IN'], - - ['\\\\notin(?![a-zA-Z])', 'NOTIN'], - ['\\\\not\\s*\\\\in(?![a-zA-Z])', 'NOTIN'], - - ['\\\\ni(?![a-zA-Z])', 'NI'], - - ['\\\\not\\s*\\\\ni(?![a-zA-Z])', 'NOTNI'], - - ['\\\\subset(?![a-zA-Z])', 'SUBSET'], - - ['\\\\not\\s*\\\\subset(?![a-zA-Z])', 'NOTSUBSET'], - - ['\\\\supset(?![a-zA-Z])', 'SUPERSET'], - - ['\\\\not\\s*\\\\supset(?![a-zA-Z])', 'NOTSUPERSET'], - - ['\\\\cup(?![a-zA-Z])', 'UNION'], - - ['\\\\cap(?![a-zA-Z])', 'INTERSECT'], - - ['!', '!'], - ['\'', '\''], - ['_', '_'], - ['&', '&'], - ['\\\\ldots', 'LDOTS'], - - ['\\\\\\\\', 'LINEBREAK'], - - ['\\\\begin\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'BEGINENVIRONMENT'], - - ['\\\\end\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'ENDENVIRONMENT'], - - ['\\\\var\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'VARMULTICHAR'], - - ['\\\\[a-zA-Z]+(?![a-zA-Z])', 'LATEXCOMMAND'], - ['[a-zA-Z]', 'VAR'] -]; + function write (buffer, value, offset, isLE, mLen, nBytes) { + var e, m, c; + var eLen = nBytes * 8 - mLen - 1; + var eMax = (1 << eLen) - 1; + var eBias = eMax >> 1; + var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0); + var i = isLE ? 0 : (nBytes - 1); + var d = isLE ? 1 : -1; + var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; -// defaults for parsers if not overridden by context + value = Math.abs(value); -// if true, allowed applied functions to omit parentheses around argument -// if false, omitting parentheses will lead to a Parse Error -const allowSimplifiedFunctionApplicationDefault$1 = true; + if (isNaN(value) || value === Infinity) { + m = isNaN(value) ? 1 : 0; + e = eMax; + } else { + e = Math.floor(Math.log(value) / Math.LN2); + if (value * (c = Math.pow(2, -e)) < 1) { + e--; + c *= 2; + } + if (e + eBias >= 1) { + value += rt / c; + } else { + value += rt * Math.pow(2, 1 - eBias); + } + if (value * c >= 2) { + e++; + c /= 2; + } + + if (e + eBias >= eMax) { + m = 0; + e = eMax; + } else if (e + eBias >= 1) { + m = (value * c - 1) * Math.pow(2, mLen); + e = e + eBias; + } else { + m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); + e = 0; + } + } + for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} -// allowed multicharacter latex symbols -// in addition to the below applied function symbols -const allowedLatexSymbolsDefault$1 = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'partial']; + e = (e << mLen) | m; + eLen += mLen; + for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} -// Applied functions must be given an argument so that -// they are applied to the argument -const appliedFunctionSymbolsDefault$1 = ["abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg']; + buffer[offset + i - d] |= s * 128; + } -// Functions could have an argument, in which case they are applied -// or, if they don't have an argument in parentheses, then they are treated -// like a variable, except that trailing ^ and ' have higher precedence -const functionSymbolsDefault$1 = ['f', 'g']; + var toString$1 = {}.toString; -// Parse Leibniz notation -const parseLeibnizNotationDefault$1 = true; + var isArray$5 = Array.isArray || function (arr) { + return toString$1.call(arr) == '[object Array]'; + }; + var INSPECT_MAX_BYTES = 50; -class latexToAst { - constructor({ - allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplicationDefault$1, - allowedLatexSymbols = allowedLatexSymbolsDefault$1, - appliedFunctionSymbols = appliedFunctionSymbolsDefault$1, - functionSymbols = functionSymbolsDefault$1, - parseLeibnizNotation = parseLeibnizNotationDefault$1, - } = {}) { - this.allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplication; - this.allowedLatexSymbols = allowedLatexSymbols; - this.appliedFunctionSymbols = appliedFunctionSymbols; - this.functionSymbols = functionSymbols; - this.parseLeibnizNotation = parseLeibnizNotation; + /** + * If `Buffer.TYPED_ARRAY_SUPPORT`: + * === true Use Uint8Array implementation (fastest) + * === false Use Object implementation (most compatible, even IE6) + * + * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, + * Opera 11.6+, iOS 4.2+. + * + * Due to various browser bugs, sometimes the Object implementation will be used even + * when the browser supports typed arrays. + * + * Note: + * + * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, + * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. + * + * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. + * + * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of + * incorrect length in some situations. - this.lexer = new lexer(latex_rules, whitespace_rule); + * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they + * get the Object implementation, which is slower but behaves correctly. + */ + Buffer.TYPED_ARRAY_SUPPORT = global$1.TYPED_ARRAY_SUPPORT !== undefined + ? global$1.TYPED_ARRAY_SUPPORT + : true; + function kMaxLength () { + return Buffer.TYPED_ARRAY_SUPPORT + ? 0x7fffffff + : 0x3fffffff } - advance(params) { - this.token = this.lexer.advance(params); - if (this.token.token_type === 'INVALID') { - throw new ParseError("Invalid symbol '" + this.token.original_text + "'", - this.lexer.location); + function createBuffer (that, length) { + if (kMaxLength() < length) { + throw new RangeError('Invalid typed array length') + } + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = new Uint8Array(length); + that.__proto__ = Buffer.prototype; + } else { + // Fallback: Return an object instance of the Buffer class + if (that === null) { + that = new Buffer(length); + } + that.length = length; } - } - - return_state() { - return ({ - lexer_state: this.lexer.return_state(), - token: Object.assign({}, this.token) - }); - } - set_state(state) { - this.lexer.set_state(state.lexer_state); - this.token = Object.assign({}, state.token); + return that } + /** + * The Buffer constructor returns instances of `Uint8Array` that have their + * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of + * `Uint8Array`, so the returned instances will have all the node `Buffer` methods + * and the `Uint8Array` methods. Square bracket notation works as expected -- it + * returns a single octet. + * + * The `Uint8Array` prototype remains unmodified. + */ - convert(input) { - - this.lexer.set_input(input); - this.advance(); - - var result = this.statement_list(); - - if (this.token.token_type !== 'EOF') { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); + function Buffer (arg, encodingOrOffset, length) { + if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { + return new Buffer(arg, encodingOrOffset, length) } - return flatten$18(result); - + // Common case. + if (typeof arg === 'number') { + if (typeof encodingOrOffset === 'string') { + throw new Error( + 'If encoding is specified then the first argument must be a string' + ) + } + return allocUnsafe(this, arg) + } + return from(this, arg, encodingOrOffset, length) } - statement_list() { + Buffer.poolSize = 8192; // not used by this implementation - var list = [this.statement()]; + // TODO: Legacy, not needed anymore. Remove in next major version. + Buffer._augment = function (arr) { + arr.__proto__ = Buffer.prototype; + return arr + }; - while (this.token.token_type === ",") { - this.advance(); - list.push(this.statement()); + function from (that, value, encodingOrOffset, length) { + if (typeof value === 'number') { + throw new TypeError('"value" argument must not be a number') } - if (list.length > 1) - list = ['list'].concat(list); - else - list = list[0]; - - return list; - } - - statement({ inside_absolute_value = 0 } = {}) { - - // \ldots can be a statement by itself - if (this.token.token_type === 'LDOTS') { - this.advance(); - return ['ldots']; + if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { + return fromArrayBuffer(that, value, encodingOrOffset, length) } - var original_state; - - try { - - original_state = this.return_state(); - - let lhs = this.statement_a({ inside_absolute_value: inside_absolute_value }); - - if (this.token.token_type !== ':' && this.token.token_type !== 'MID') - return lhs; - - let operator = this.token.token_type === ':' ? ':' : '|'; - - this.advance(); - - let rhs = this.statement_a(); - - return [operator, lhs, rhs]; - + if (typeof value === 'string') { + return fromString(that, value, encodingOrOffset) } - catch (e) { - try { - // if ran into problem parsing statement - // then try again with ignoring absolute value - // and then interpreting bar as a binary operator - - // return state to what it was before attempting to parse statement - this.set_state(original_state); + return fromObject(that, value) + } - let lhs = this.statement_a({ parse_absolute_value: false }); + /** + * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError + * if value is a number. + * Buffer.from(str[, encoding]) + * Buffer.from(array) + * Buffer.from(buffer) + * Buffer.from(arrayBuffer[, byteOffset[, length]]) + **/ + Buffer.from = function (value, encodingOrOffset, length) { + return from(null, value, encodingOrOffset, length) + }; - if (this.token.token_type[0] !== '|') { - throw (e); - } + if (Buffer.TYPED_ARRAY_SUPPORT) { + Buffer.prototype.__proto__ = Uint8Array.prototype; + Buffer.__proto__ = Uint8Array; + } - this.advance(); + function assertSize (size) { + if (typeof size !== 'number') { + throw new TypeError('"size" argument must be a number') + } else if (size < 0) { + throw new RangeError('"size" argument must not be negative') + } + } - let rhs = this.statement_a({ parse_absolute_value: false }); + function alloc (that, size, fill, encoding) { + assertSize(size); + if (size <= 0) { + return createBuffer(that, size) + } + if (fill !== undefined) { + // Only pay attention to encoding if it's a string. This + // prevents accidentally sending in a number that would + // be interpretted as a start offset. + return typeof encoding === 'string' + ? createBuffer(that, size).fill(fill, encoding) + : createBuffer(that, size).fill(fill) + } + return createBuffer(that, size) + } - return ['|', lhs, rhs]; + /** + * Creates a new filled Buffer instance. + * alloc(size[, fill[, encoding]]) + **/ + Buffer.alloc = function (size, fill, encoding) { + return alloc(null, size, fill, encoding) + }; - } - catch (e2) { - throw (e); // throw original error + function allocUnsafe (that, size) { + assertSize(size); + that = createBuffer(that, size < 0 ? 0 : checked(size) | 0); + if (!Buffer.TYPED_ARRAY_SUPPORT) { + for (var i = 0; i < size; ++i) { + that[i] = 0; } } + return that } - statement_a({ inside_absolute_value = 0, parse_absolute_value = true } = {}) { - - var lhs = this.statement_b({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value - }); + /** + * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. + * */ + Buffer.allocUnsafe = function (size) { + return allocUnsafe(null, size) + }; + /** + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. + */ + Buffer.allocUnsafeSlow = function (size) { + return allocUnsafe(null, size) + }; - while (this.token.token_type === 'OR') { + function fromString (that, string, encoding) { + if (typeof encoding !== 'string' || encoding === '') { + encoding = 'utf8'; + } - let operation = this.token.token_type.toLowerCase(); + if (!Buffer.isEncoding(encoding)) { + throw new TypeError('"encoding" must be a valid string encoding') + } - this.advance(); + var length = byteLength(string, encoding) | 0; + that = createBuffer(that, length); - let rhs = this.statement_b({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value - }); + var actual = that.write(string, encoding); - lhs = [operation, lhs, rhs]; + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + that = that.slice(0, actual); } - return lhs; + return that } + function fromArrayLike (that, array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0; + that = createBuffer(that, length); + for (var i = 0; i < length; i += 1) { + that[i] = array[i] & 255; + } + return that + } - statement_b(params) { - // split AND into second statement to give higher precedence than OR - - var lhs = this.relation(params); - - while (this.token.token_type === 'AND') { - - let operation = this.token.token_type.toLowerCase(); + function fromArrayBuffer (that, array, byteOffset, length) { + array.byteLength; // this throws if `array` is not a valid ArrayBuffer - this.advance(); + if (byteOffset < 0 || array.byteLength < byteOffset) { + throw new RangeError('\'offset\' is out of bounds') + } - let rhs = this.relation(params); + if (array.byteLength < byteOffset + (length || 0)) { + throw new RangeError('\'length\' is out of bounds') + } - lhs = [operation, lhs, rhs]; + if (byteOffset === undefined && length === undefined) { + array = new Uint8Array(array); + } else if (length === undefined) { + array = new Uint8Array(array, byteOffset); + } else { + array = new Uint8Array(array, byteOffset, length); } - return lhs; + if (Buffer.TYPED_ARRAY_SUPPORT) { + // Return an augmented `Uint8Array` instance, for best performance + that = array; + that.__proto__ = Buffer.prototype; + } else { + // Fallback: Return an object instance of the Buffer class + that = fromArrayLike(that, array); + } + return that } + function fromObject (that, obj) { + if (internalIsBuffer(obj)) { + var len = checked(obj.length) | 0; + that = createBuffer(that, len); - relation(params) { + if (that.length === 0) { + return that + } - if (this.token.token_type === 'NOT' || this.token.token_type === '!') { - this.advance(); - return ['not', this.relation(params)]; + obj.copy(that, 0, 0, len); + return that } - var lhs = this.expression(params); - - while ((this.token.token_type === '=') || (this.token.token_type === 'NE') - || (this.token.token_type === '<') || (this.token.token_type === '>') - || (this.token.token_type === 'LE') || (this.token.token_type === 'GE') - || (this.token.token_type === 'IN') || (this.token.token_type === 'NOTIN') - || (this.token.token_type === 'NI') || (this.token.token_type === 'NOTNI') - || (this.token.token_type === 'SUBSET') || (this.token.token_type === 'NOTSUBSET') - || (this.token.token_type === 'SUPERSET') || (this.token.token_type === 'NOTSUPERSET')) { + if (obj) { + if ((typeof ArrayBuffer !== 'undefined' && + obj.buffer instanceof ArrayBuffer) || 'length' in obj) { + if (typeof obj.length !== 'number' || isnan(obj.length)) { + return createBuffer(that, 0) + } + return fromArrayLike(that, obj) + } - let operation = this.token.token_type.toLowerCase(); + if (obj.type === 'Buffer' && isArray$5(obj.data)) { + return fromArrayLike(that, obj.data) + } + } - let inequality_sequence = 0; + throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') + } - if ((this.token.token_type === '<') || (this.token.token_type === 'LE')) { - inequality_sequence = -1; - } - else if ((this.token.token_type === '>') || (this.token.token_type === 'GE')) { - inequality_sequence = 1; - } + function checked (length) { + // Note: cannot use `length < kMaxLength()` here because that fails when + // length is NaN (which is otherwise coerced to zero.) + if (length >= kMaxLength()) { + throw new RangeError('Attempt to allocate Buffer larger than maximum ' + + 'size: 0x' + kMaxLength().toString(16) + ' bytes') + } + return length | 0 + } + Buffer.isBuffer = isBuffer; + function internalIsBuffer (b) { + return !!(b != null && b._isBuffer) + } - this.advance(); - let rhs = this.expression(params); - - if (inequality_sequence === -1) { - if ((this.token.token_type === '<') || this.token.token_type === 'LE') { - // sequence of multiple < or <= - let strict = ['tuple']; - if (operation === '<') - strict.push(true); - else - strict.push(false); + Buffer.compare = function compare (a, b) { + if (!internalIsBuffer(a) || !internalIsBuffer(b)) { + throw new TypeError('Arguments must be Buffers') + } - let args = ['tuple', lhs, rhs]; - while ((this.token.token_type === '<') || this.token.token_type === 'LE') { - if (this.token.token_type === '<') - strict.push(true); - else - strict.push(false); + if (a === b) return 0 - this.advance(); - args.push(this.expression(params)); - } - lhs = ['lts', args, strict]; - } - else { - lhs = [operation, lhs, rhs]; - } + var x = a.length; + var y = b.length; + for (var i = 0, len = Math.min(x, y); i < len; ++i) { + if (a[i] !== b[i]) { + x = a[i]; + y = b[i]; + break } - else if (inequality_sequence === 1) { - if ((this.token.token_type === '>') || this.token.token_type === 'GE') { - // sequence of multiple > or >= - let strict = ['tuple']; - if (operation === '>') - strict.push(true); - else - strict.push(false); + } - let args = ['tuple', lhs, rhs]; - while ((this.token.token_type === '>') || this.token.token_type === 'GE') { - if (this.token.token_type === '>') - strict.push(true); - else - strict.push(false); + if (x < y) return -1 + if (y < x) return 1 + return 0 + }; - this.advance(); - args.push(this.expression(params)); - } - lhs = ['gts', args, strict]; - } - else { - lhs = [operation, lhs, rhs]; - } + Buffer.isEncoding = function isEncoding (encoding) { + switch (String(encoding).toLowerCase()) { + case 'hex': + case 'utf8': + case 'utf-8': + case 'ascii': + case 'latin1': + case 'binary': + case 'base64': + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return true + default: + return false + } + }; - } - else if (operation === '=') { - lhs = ['=', lhs, rhs]; + Buffer.concat = function concat (list, length) { + if (!isArray$5(list)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } - // check for sequence of multiple = - while (this.token.token_type === '=') { - this.advance(); - lhs.push(this.expression(params)); - } - } - else { + if (list.length === 0) { + return Buffer.alloc(0) + } - lhs = [operation, lhs, rhs]; + var i; + if (length === undefined) { + length = 0; + for (i = 0; i < list.length; ++i) { + length += list[i].length; + } + } + + var buffer = Buffer.allocUnsafe(length); + var pos = 0; + for (i = 0; i < list.length; ++i) { + var buf = list[i]; + if (!internalIsBuffer(buf)) { + throw new TypeError('"list" argument must be an Array of Buffers') + } + buf.copy(buffer, pos); + pos += buf.length; + } + return buffer + }; + + function byteLength (string, encoding) { + if (internalIsBuffer(string)) { + return string.length + } + if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && + (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { + return string.byteLength + } + if (typeof string !== 'string') { + string = '' + string; + } + + var len = string.length; + if (len === 0) return 0 + + // Use a for loop to avoid recursion + var loweredCase = false; + for (;;) { + switch (encoding) { + case 'ascii': + case 'latin1': + case 'binary': + return len + case 'utf8': + case 'utf-8': + case undefined: + return utf8ToBytes(string).length + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return len * 2 + case 'hex': + return len >>> 1 + case 'base64': + return base64ToBytes(string).length + default: + if (loweredCase) return utf8ToBytes(string).length // assume utf8 + encoding = ('' + encoding).toLowerCase(); + loweredCase = true; } - } - - return lhs; } + Buffer.byteLength = byteLength; + function slowToString (encoding, start, end) { + var loweredCase = false; - expression(params) { - if (this.token.token_type === '+') - this.advance(); + // No need to verify that "this.length <= MAX_UINT32" since it's a read-only + // property of a typed array. - let negative_begin = false; - if (this.token.token_type === '-') { - negative_begin = true; - this.advance(); + // This behaves neither like String nor Uint8Array in that we set start/end + // to their upper/lower bounds if the value passed is out of range. + // undefined is handled specially as per ECMA-262 6th Edition, + // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization. + if (start === undefined || start < 0) { + start = 0; + } + // Return early if start > this.length. Done here to prevent potential uint32 + // coercion fail below. + if (start > this.length) { + return '' } - var lhs = this.term(params); + if (end === undefined || end > this.length) { + end = this.length; + } - if (negative_begin) { - lhs = ['-', lhs]; + if (end <= 0) { + return '' } - while ((this.token.token_type === '+') || (this.token.token_type === '-') - || (this.token.token_type === 'UNION') - || (this.token.token_type === 'INTERSECT')) { + // Force coersion to uint32. This will also coerce falsey/NaN values to 0. + end >>>= 0; + start >>>= 0; - let operation = this.token.token_type.toLowerCase(); - let negative = false; + if (end <= start) { + return '' + } - if (this.token.token_type === '-') { - operation = '+'; - negative = true; - this.advance(); - } - else { - this.advance(); - if (operation === '+' && this.token.token_type === '-') { - negative = true; - this.advance(); - } - } - let rhs = this.term(params); - if (negative) { - rhs = ['-', rhs]; - } + if (!encoding) encoding = 'utf8'; - lhs = [operation, lhs, rhs]; - } + while (true) { + switch (encoding) { + case 'hex': + return hexSlice(this, start, end) - return lhs; - } + case 'utf8': + case 'utf-8': + return utf8Slice(this, start, end) + case 'ascii': + return asciiSlice(this, start, end) - term(params) { - var lhs = this.factor(params); + case 'latin1': + case 'binary': + return latin1Slice(this, start, end) - var keepGoing = false; + case 'base64': + return base64Slice(this, start, end) - do { - keepGoing = false; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return utf16leSlice(this, start, end) - if (this.token.token_type === '*') { - this.advance(); - lhs = ['*', lhs, this.factor(params)]; - keepGoing = true; - } else if (this.token.token_type === '/') { - this.advance(); - lhs = ['/', lhs, this.factor(params)]; - keepGoing = true; - } else { - // this is the one case where a | could indicate a closing absolute value - let params2 = Object.assign({}, params); - params2.allow_absolute_value_closing = true; - let rhs = this.nonMinusFactor(params2); - if (rhs !== false) { - lhs = ['*', lhs, rhs]; - keepGoing = true; - } + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = (encoding + '').toLowerCase(); + loweredCase = true; } - } while (keepGoing); - - return lhs; + } } + // The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect + // Buffer instances. + Buffer.prototype._isBuffer = true; - factor(params) { - if (this.token.token_type === '-') { - this.advance(); - return ['-', this.factor(params)]; + function swap (b, n, m) { + var i = b[n]; + b[n] = b[m]; + b[m] = i; + } + + Buffer.prototype.swap16 = function swap16 () { + var len = this.length; + if (len % 2 !== 0) { + throw new RangeError('Buffer size must be a multiple of 16-bits') + } + for (var i = 0; i < len; i += 2) { + swap(this, i, i + 1); } + return this + }; - var result = this.nonMinusFactor(params); + Buffer.prototype.swap32 = function swap32 () { + var len = this.length; + if (len % 4 !== 0) { + throw new RangeError('Buffer size must be a multiple of 32-bits') + } + for (var i = 0; i < len; i += 4) { + swap(this, i, i + 3); + swap(this, i + 1, i + 2); + } + return this + }; - if (result === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", this.lexer.location); - } - else { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } + Buffer.prototype.swap64 = function swap64 () { + var len = this.length; + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') } - else { - return result; + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7); + swap(this, i + 1, i + 6); + swap(this, i + 2, i + 5); + swap(this, i + 3, i + 4); } + return this + }; - } + Buffer.prototype.toString = function toString () { + var length = this.length | 0; + if (length === 0) return '' + if (arguments.length === 0) return utf8Slice(this, 0, length) + return slowToString.apply(this, arguments) + }; - nonMinusFactor(params) { + Buffer.prototype.equals = function equals (b) { + if (!internalIsBuffer(b)) throw new TypeError('Argument must be a Buffer') + if (this === b) return true + return Buffer.compare(this, b) === 0 + }; - var result = this.baseFactor(params); + Buffer.prototype.inspect = function inspect () { + var str = ''; + var max = INSPECT_MAX_BYTES; + if (this.length > 0) { + str = this.toString('hex', 0, max).match(/.{2}/g).join(' '); + if (this.length > max) str += ' ... '; + } + return '' + }; - // allow arbitrary sequence of factorials - if (this.token.token_type === '!' || this.token.token_type === "'") { - if (result === false) - throw new ParseError("Invalid location of " + this.token.token_type, - this.lexer.location); - while (this.token.token_type === '!' || this.token.token_type === "'") { - if (this.token.token_type === '!') - result = ['apply', 'factorial', result]; - else - result = ['prime', result]; - this.advance(); - } + Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (!internalIsBuffer(target)) { + throw new TypeError('Argument must be a Buffer') } - if (this.token.token_type === '^') { - if (result === false) { - throw new ParseError("Invalid location of ^", this.lexer.location); - } - this.advance(); + if (start === undefined) { + start = 0; + } + if (end === undefined) { + end = target ? target.length : 0; + } + if (thisStart === undefined) { + thisStart = 0; + } + if (thisEnd === undefined) { + thisEnd = this.length; + } - // do not allow absolute value closing here - let params2 = Object.assign({}, params); - delete params2.allow_absolute_value_closing; - delete params2.inside_absolute_value; + if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) { + throw new RangeError('out of range index') + } - return ['^', result, this.factor(params2)]; + if (thisStart >= thisEnd && start >= end) { + return 0 + } + if (thisStart >= thisEnd) { + return -1 + } + if (start >= end) { + return 1 } - return result; - } + start >>>= 0; + end >>>= 0; + thisStart >>>= 0; + thisEnd >>>= 0; + if (this === target) return 0 - baseFactor({ inside_absolute_value = 0, - parse_absolute_value = true, - allow_absolute_value_closing = false - } = {}) { + var x = thisEnd - thisStart; + var y = end - start; + var len = Math.min(x, y); - var result = false; + var thisCopy = this.slice(thisStart, thisEnd); + var targetCopy = target.slice(start, end); - if (this.token.token_type === 'FRAC') { - this.advance(); + for (var i = 0; i < len; ++i) { + if (thisCopy[i] !== targetCopy[i]) { + x = thisCopy[i]; + y = targetCopy[i]; + break + } + } - if (this.token.token_type !== '{') { - throw new ParseError("Expecting {", this.lexer.location); + if (x < y) return -1 + if (y < x) return 1 + return 0 + }; + + // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, + // OR the last index of `val` in `buffer` at offset <= `byteOffset`. + // + // Arguments: + // - buffer - a Buffer to search + // - val - a string, Buffer, or number + // - byteOffset - an index into `buffer`; will be clamped to an int32 + // - encoding - an optional encoding, relevant is val is a string + // - dir - true for indexOf, false for lastIndexOf + function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset; + byteOffset = 0; + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff; + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000; + } + byteOffset = +byteOffset; // Coerce to Number. + if (isNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1); + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset; + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1; + } else if (byteOffset < 0) { + if (dir) byteOffset = 0; + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding); + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (internalIsBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF; // Search for a byte value [0-255] + if (Buffer.TYPED_ARRAY_SUPPORT && + typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } } - this.advance(); + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') + } - // determine if may be a derivative in Leibniz notation - if (this.parseLeibnizNotation) { + function arrayIndexOf (arr, val, byteOffset, encoding, dir) { + var indexSize = 1; + var arrLength = arr.length; + var valLength = val.length; - let original_state = this.return_state(); + if (encoding !== undefined) { + encoding = String(encoding).toLowerCase(); + if (encoding === 'ucs2' || encoding === 'ucs-2' || + encoding === 'utf16le' || encoding === 'utf-16le') { + if (arr.length < 2 || val.length < 2) { + return -1 + } + indexSize = 2; + arrLength /= 2; + valLength /= 2; + byteOffset /= 2; + } + } - let r = this.leibniz_notation(); + function read$$1 (buf, i) { + if (indexSize === 1) { + return buf[i] + } else { + return buf.readUInt16BE(i * indexSize) + } + } - if (r) { - // successfully parsed derivative in Leibniz notation, so return - return r; + var i; + if (dir) { + var foundIndex = -1; + for (i = byteOffset; i < arrLength; i++) { + if (read$$1(arr, i) === read$$1(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i; + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex; + foundIndex = -1; } - else { - // didn't find a properly format Leibniz notation - // so reset state and continue - this.set_state(original_state); + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength; + for (i = byteOffset; i >= 0; i--) { + var found = true; + for (var j = 0; j < valLength; j++) { + if (read$$1(arr, i + j) !== read$$1(val, j)) { + found = false; + break + } } + if (found) return i } + } - let numerator = this.statement({ parse_absolute_value: parse_absolute_value }); + return -1 + } - if (this.token.token_type !== '}') { - throw new ParseError("Expecting }", this.lexer.location); - } - this.advance(); + Buffer.prototype.includes = function includes (val, byteOffset, encoding) { + return this.indexOf(val, byteOffset, encoding) !== -1 + }; - if (this.token.token_type !== '{') { - throw new ParseError("Expecting {", this.lexer.location); - } - this.advance(); + Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) + }; - let denominator = this.statement({ parse_absolute_value: parse_absolute_value }); + Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) + }; - if (this.token.token_type !== '}') { - throw new ParseError("Expecting }", this.lexer.location); + function hexWrite (buf, string, offset, length) { + offset = Number(offset) || 0; + var remaining = buf.length - offset; + if (!length) { + length = remaining; + } else { + length = Number(length); + if (length > remaining) { + length = remaining; } - this.advance(); + } - return ['/', numerator, denominator]; + // must be an even number of digits + var strLen = string.length; + if (strLen % 2 !== 0) throw new TypeError('Invalid hex string') + + if (length > strLen / 2) { + length = strLen / 2; + } + for (var i = 0; i < length; ++i) { + var parsed = parseInt(string.substr(i * 2, 2), 16); + if (isNaN(parsed)) return i + buf[offset + i] = parsed; } + return i + } - if (this.token.token_type === 'BEGINENVIRONMENT') { - let environment = /\\begin\s*{\s*([a-zA-Z0-9]+)\s*}/.exec(this.token.token_text)[1]; + function utf8Write (buf, string, offset, length) { + return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) + } - if (['matrix', 'pmatrix', 'bmatrix'].includes(environment)) { + function asciiWrite (buf, string, offset, length) { + return blitBuffer(asciiToBytes(string), buf, offset, length) + } - let n_rows = 0; - let n_cols = 0; + function latin1Write (buf, string, offset, length) { + return asciiWrite(buf, string, offset, length) + } - let all_rows = []; - let row = []; - let n_this_row = 0; - let last_token = this.token.token_type; + function base64Write (buf, string, offset, length) { + return blitBuffer(base64ToBytes(string), buf, offset, length) + } - this.advance(); + function ucs2Write (buf, string, offset, length) { + return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) + } + Buffer.prototype.write = function write$$1 (string, offset, length, encoding) { + // Buffer#write(string) + if (offset === undefined) { + encoding = 'utf8'; + length = this.length; + offset = 0; + // Buffer#write(string, encoding) + } else if (length === undefined && typeof offset === 'string') { + encoding = offset; + length = this.length; + offset = 0; + // Buffer#write(string, offset[, length][, encoding]) + } else if (isFinite(offset)) { + offset = offset | 0; + if (isFinite(length)) { + length = length | 0; + if (encoding === undefined) encoding = 'utf8'; + } else { + encoding = length; + length = undefined; + } + // legacy write(string, encoding, offset, length) - remove in v0.13 + } else { + throw new Error( + 'Buffer.write(string, encoding, offset[, length]) is no longer supported' + ) + } - while (this.token.token_type !== 'ENDENVIRONMENT') { - if (this.token.token_type === '&') { - if (last_token === '&' || last_token === 'LINEBREAK') { - // blank entry, let entry be zero - row.push(0); - n_this_row += 1; - } - last_token = this.token.token_type; - this.advance(); - } - else if (this.token.token_type === 'LINEBREAK') { - if (last_token === '&' || last_token === 'LINEBREAK') { - // blank entry, let entry be zero - row.push(0); - n_this_row += 1; - } - all_rows.push(row); - if (n_this_row > n_cols) - n_cols = n_this_row; - - n_rows += 1; - n_this_row = 0; - row = []; - last_token = this.token.token_type; - this.advance(); - } - else { - if (last_token === '&' || last_token === 'LINEBREAK' || 'BEGINENVIRONMENT') { - row.push(this.statement({ parse_absolute_value: parse_absolute_value })); - n_this_row += 1; - last_token = ' '; + var remaining = this.length - offset; + if (length === undefined || length > remaining) length = remaining; - } - else { - throw new ParseError("Invalid location of " + this.token.original_text, this.lexer.location); - } - } - } + if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { + throw new RangeError('Attempt to write outside buffer bounds') + } - // token is ENDENVIRONMENT - let environment2 = /\\end\s*{\s*([a-zA-Z0-9]+)\s*}/.exec(this.token.token_text)[1]; - if (environment2 !== environment) { - throw new ParseError("Expecting \\end{" + environment + "}", this.lexer.location); - } + if (!encoding) encoding = 'utf8'; - // add last row - if (last_token === '&') { - // blank entry, let entry be zero - row.push(0); - n_this_row += 1; - } - all_rows.push(row); - if (n_this_row > n_cols) - n_cols = n_this_row; - n_rows += 1; + var loweredCase = false; + for (;;) { + switch (encoding) { + case 'hex': + return hexWrite(this, string, offset, length) + case 'utf8': + case 'utf-8': + return utf8Write(this, string, offset, length) - this.advance(); + case 'ascii': + return asciiWrite(this, string, offset, length) - // create matrix - result = ["matrix", ["tuple", n_rows, n_cols]]; - let body = ["tuple"]; - for (let r of all_rows) { - let new_row = ["tuple"].concat(r); - for (let i = r.length; i < n_cols; i += 1) - new_row.push(0); + case 'latin1': + case 'binary': + return latin1Write(this, string, offset, length) - body.push(new_row); + case 'base64': + // Warning: maxLength not taken into account in base64Write + return base64Write(this, string, offset, length) - } - result.push(body); + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return ucs2Write(this, string, offset, length) - return result; - } - else { - throw new ParseError("Unrecognized environment " + environment, this.lexer.location); + default: + if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) + encoding = ('' + encoding).toLowerCase(); + loweredCase = true; } - } + }; - if (this.token.token_type === 'NUMBER') { - result = parseFloat(this.token.token_text); - this.advance(); - } else if (this.token.token_type === 'INFINITY') { - result = Infinity; - this.advance(); - } else if (this.token.token_type === 'SQRT') { - this.advance(); + Buffer.prototype.toJSON = function toJSON () { + return { + type: 'Buffer', + data: Array.prototype.slice.call(this._arr || this, 0) + } + }; - let root = 2; - if (this.token.token_type === '[') { - this.advance(); - let parameter = this.statement({ parse_absolute_value: parse_absolute_value }); - if (this.token.token_type !== ']') { - throw new ParseError("Expecting ]", this.lexer.location); - } - this.advance(); + function base64Slice (buf, start, end) { + if (start === 0 && end === buf.length) { + return fromByteArray(buf) + } else { + return fromByteArray(buf.slice(start, end)) + } + } - root = parameter; - } + function utf8Slice (buf, start, end) { + end = Math.min(buf.length, end); + var res = []; - if (this.token.token_type !== '{') { - throw new ParseError("Expecting {", this.lexer.location); - } + var i = start; + while (i < end) { + var firstByte = buf[i]; + var codePoint = null; + var bytesPerSequence = (firstByte > 0xEF) ? 4 + : (firstByte > 0xDF) ? 3 + : (firstByte > 0xBF) ? 2 + : 1; - this.advance(); - let parameter = this.statement({ parse_absolute_value: parse_absolute_value }); - if (this.token.token_type !== '}') { - throw new ParseError("Expecting }", this.lexer.location); - } - this.advance(); + if (i + bytesPerSequence <= end) { + var secondByte, thirdByte, fourthByte, tempCodePoint; - if (root === 2) - result = ['apply', 'sqrt', parameter]; - else - result = ['^', parameter, ['/', 1, root]]; - } else if (this.token.token_type === 'VAR' || this.token.token_type === 'LATEXCOMMAND' - || this.token.token_type === 'VARMULTICHAR') { - result = this.token.token_text; - - if (this.token.token_type === 'LATEXCOMMAND') { - result = result.slice(1); - if (!(this.appliedFunctionSymbols.includes(result) - || this.functionSymbols.includes(result) - || this.allowedLatexSymbols.includes(result) - )) { - throw new ParseError("Unrecognized latex command " + this.token.original_text, - this.lexer.location); + switch (bytesPerSequence) { + case 1: + if (firstByte < 0x80) { + codePoint = firstByte; + } + break + case 2: + secondByte = buf[i + 1]; + if ((secondByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F); + if (tempCodePoint > 0x7F) { + codePoint = tempCodePoint; + } + } + break + case 3: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F); + if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { + codePoint = tempCodePoint; + } + } + break + case 4: + secondByte = buf[i + 1]; + thirdByte = buf[i + 2]; + fourthByte = buf[i + 3]; + if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { + tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F); + if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { + codePoint = tempCodePoint; + } + } } } - else if (this.token.token_type === 'VARMULTICHAR') { - // strip out name of variable from \var command - result = /\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(result)[1]; + + if (codePoint === null) { + // we did not generate a valid codePoint so insert a + // replacement char (U+FFFD) and advance only 1 byte + codePoint = 0xFFFD; + bytesPerSequence = 1; + } else if (codePoint > 0xFFFF) { + // encode to utf16 (surrogate pair dance) + codePoint -= 0x10000; + res.push(codePoint >>> 10 & 0x3FF | 0xD800); + codePoint = 0xDC00 | codePoint & 0x3FF; } - if (this.appliedFunctionSymbols.includes(result) - || this.functionSymbols.includes(result)) { - let must_apply = false; - if (this.appliedFunctionSymbols.includes(result)) - must_apply = true; + res.push(codePoint); + i += bytesPerSequence; + } - this.advance(); + return decodeCodePointsArray(res) + } - if (this.token.token_type === '_') { - this.advance(); - let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); + // Based on http://stackoverflow.com/a/22747272/680742, the browser with + // the lowest limit is Chrome, with 0x10000 args. + // We go 1 magnitude less, for safety + var MAX_ARGUMENTS_LENGTH = 0x1000; - // since baseFactor could return false, must check - if (subresult === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", - this.lexer.location); - } - else { - throw new ParseError("Invalid location of '" + this.token.original_text - + "'", this.lexer.location); - } - } - result = ['_', result, subresult]; - } + function decodeCodePointsArray (codePoints) { + var len = codePoints.length; + if (len <= MAX_ARGUMENTS_LENGTH) { + return String.fromCharCode.apply(String, codePoints) // avoid extra slice() + } - while (this.token.token_type === "'") { - result = ['prime', result]; - this.advance(); - } + // Decode in chunks to avoid "call stack size exceeded". + var res = ''; + var i = 0; + while (i < len) { + res += String.fromCharCode.apply( + String, + codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) + ); + } + return res + } - if (this.token.token_type === '^') { - this.advance(); - result = ['^', result, this.factor({ parse_absolute_value: parse_absolute_value })]; - } + function asciiSlice (buf, start, end) { + var ret = ''; + end = Math.min(buf.length, end); - if (this.token.token_type === '{' || this.token.token_type === '(') { - let expected_right; - if (this.token.token_type === '{') - expected_right = '}'; - else - expected_right = ')'; + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i] & 0x7F); + } + return ret + } - this.advance(); - let parameters = this.statement_list(); + function latin1Slice (buf, start, end) { + var ret = ''; + end = Math.min(buf.length, end); - if (this.token.token_type !== expected_right) { - throw new ParseError('Expecting ' + expected_right, - this.lexer.location); - } - this.advance(); + for (var i = start; i < end; ++i) { + ret += String.fromCharCode(buf[i]); + } + return ret + } - if (parameters[0] === 'list') { - // rename from list to tuple - parameters[0] = 'tuple'; - } + function hexSlice (buf, start, end) { + var len = buf.length; - result = ['apply', result, parameters]; + if (!start || start < 0) start = 0; + if (!end || end < 0 || end > len) end = len; - } - else { - // if was an applied function symbol, - // cannot omit argument - if (must_apply) { - if (!this.allowSimplifiedFunctionApplication) - throw new ParseError("Expecting ( after function", - this.lexer.location); + var out = ''; + for (var i = start; i < end; ++i) { + out += toHex(buf[i]); + } + return out + } - // if allow simplied function application - // let the argument be the next factor - result = ['apply', result, this.factor({ parse_absolute_value: parse_absolute_value })]; - } - } - } - else { - this.advance(); - } - } else if (this.token.token_type === '(' || this.token.token_type === '[' - || this.token.token_type === '{' - || this.token.token_type === 'LBRACE') { - let token_left = this.token.token_type; - let expected_right, other_right; - if (this.token.token_type === '(') { - expected_right = ')'; - other_right = ']'; - } - else if (this.token.token_type === '[') { - expected_right = ']'; - other_right = ')'; - } - else if (this.token.token_type === '{') { - expected_right = '}'; - other_right = null; - } - else { - expected_right = 'RBRACE'; - other_right = null; - } + function utf16leSlice (buf, start, end) { + var bytes = buf.slice(start, end); + var res = ''; + for (var i = 0; i < bytes.length; i += 2) { + res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256); + } + return res + } - this.advance(); - result = this.statement_list(); + Buffer.prototype.slice = function slice (start, end) { + var len = this.length; + start = ~~start; + end = end === undefined ? len : ~~end; - let n_elements = 1; - if (result[0] === "list") { - n_elements = result.length - 1; - } + if (start < 0) { + start += len; + if (start < 0) start = 0; + } else if (start > len) { + start = len; + } - if (this.token.token_type !== expected_right) { - if (n_elements !== 2 || other_right === null) { - throw new ParseError('Expecting ' + expected_right, - this.lexer.location); - } - else if (this.token.token_type !== other_right) { - throw new ParseError('Expecting ) or ]', this.lexer.location); - } + if (end < 0) { + end += len; + if (end < 0) end = 0; + } else if (end > len) { + end = len; + } - // half-open interval - result[0] = 'tuple'; - result = ['interval', result]; - let closed; - if (token_left === '(') - closed = ['tuple', false, true]; - else - closed = ['tuple', true, false]; - result.push(closed); + if (end < start) end = start; + var newBuf; + if (Buffer.TYPED_ARRAY_SUPPORT) { + newBuf = this.subarray(start, end); + newBuf.__proto__ = Buffer.prototype; + } else { + var sliceLen = end - start; + newBuf = new Buffer(sliceLen, undefined); + for (var i = 0; i < sliceLen; ++i) { + newBuf[i] = this[i + start]; } - else if (n_elements >= 2) { - if (token_left === '(' || token_left === '{') { - result[0] = 'tuple'; - } - else if (token_left === '[') { - result[0] = 'array'; - } - else { - result[0] = 'set'; - } - } - else if (token_left === 'LBRACE') { - if (result[0] === '|' || result[0] === ':') { - result = ['set', result]; // set builder notation - } - else { - result = ['set', result]; // singleton set - } - } - - this.advance(); + } - } else if (this.token.token_type[0] === '|' && parse_absolute_value && - (inside_absolute_value === 0 || !allow_absolute_value_closing || - this.token.token_type[1] === 'L')) { + return newBuf + }; - // allow the opening of an absolute value here if either - // - we aren't already inside an absolute value (inside_absolute_value==0), - // - we don't allows an absolute value closing, or - // - the | was marked as a left - // otherwise, skip this token so that will drop out the factor (and entire statement) - // to where the absolute value will close + /* + * Need to make sure that buffer isn't trying to write out of bounds. + */ + function checkOffset (offset, ext, length) { + if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') + if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') + } - inside_absolute_value += 1; + Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); - this.advance(); + var val = this[offset]; + var mul = 1; + var i = 0; + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul; + } - result = this.statement({ inside_absolute_value: inside_absolute_value }); - result = ['apply', 'abs', result]; + return val + }; - if (this.token.token_type !== '|') { - throw new ParseError('Expecting |', this.lexer.location); - } + Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + checkOffset(offset, byteLength, this.length); + } - this.advance(); + var val = this[offset + --byteLength]; + var mul = 1; + while (byteLength > 0 && (mul *= 0x100)) { + val += this[offset + --byteLength] * mul; } - if (this.token.token_type === '_') { - if (result === false) { - throw new ParseError("Invalid location of _", this.lexer.location); - } - this.advance(); - let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); + return val + }; - if (subresult === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", this.lexer.location); - } - else { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } - } - return ['_', result, subresult]; + Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length); + return this[offset] + }; + + Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + return this[offset] | (this[offset + 1] << 8) + }; + + Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + return (this[offset] << 8) | this[offset + 1] + }; + + Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + + return ((this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16)) + + (this[offset + 3] * 0x1000000) + }; + + Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + + return (this[offset] * 0x1000000) + + ((this[offset + 1] << 16) | + (this[offset + 2] << 8) | + this[offset + 3]) + }; + + Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); + + var val = this[offset]; + var mul = 1; + var i = 0; + while (++i < byteLength && (mul *= 0x100)) { + val += this[offset + i] * mul; } + mul *= 0x80; - return result; - } + if (val >= mul) val -= Math.pow(2, 8 * byteLength); + return val + }; - leibniz_notation() { - // attempt to find and return a derivative in Leibniz notation - // if unsuccessful, return false + Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) checkOffset(offset, byteLength, this.length); - var result = this.token.token_text; + var i = byteLength; + var mul = 1; + var val = this[offset + --i]; + while (i > 0 && (mul *= 0x100)) { + val += this[offset + --i] * mul; + } + mul *= 0x80; - let deriv_symbol = ""; + if (val >= mul) val -= Math.pow(2, 8 * byteLength); - let n_deriv = 1; + return val + }; - let var1 = ""; - let var2s = []; - let var2_exponents = []; + Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + if (!noAssert) checkOffset(offset, 1, this.length); + if (!(this[offset] & 0x80)) return (this[offset]) + return ((0xff - this[offset] + 1) * -1) + }; - if (this.token.token_type === "LATEXCOMMAND" && result.slice(1) === "partial") - deriv_symbol = "∂"; - else if (this.token.token_type === "VAR" && result === "d") - deriv_symbol = "d"; - else - return false; + Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + var val = this[offset] | (this[offset + 1] << 8); + return (val & 0x8000) ? val | 0xFFFF0000 : val + }; - // since have just a d or ∂ - // one option is that have a ^ followed by an integer next possibly in {} + Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 2, this.length); + var val = this[offset + 1] | (this[offset] << 8); + return (val & 0x8000) ? val | 0xFFFF0000 : val + }; - this.advance(); + Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); - if (this.token.token_type === '^') { - // so far have d or ∂ followed by ^ - // must be followed by an integer - this.advance(); + return (this[offset]) | + (this[offset + 1] << 8) | + (this[offset + 2] << 16) | + (this[offset + 3] << 24) + }; - let in_braces = false; - if (this.token.token_type === '{') { - in_braces = true; + Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); - this.advance(); - } + return (this[offset] << 24) | + (this[offset + 1] << 16) | + (this[offset + 2] << 8) | + (this[offset + 3]) + }; - if (this.token.token_type !== 'NUMBER') { - return false; - } + Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + return read(this, offset, true, 23, 4) + }; - n_deriv = parseFloat(this.token.token_text); - if (!Number.isInteger(n_deriv)) { - return false; - } + Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 4, this.length); + return read(this, offset, false, 23, 4) + }; - // found integer, + Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length); + return read(this, offset, true, 52, 8) + }; - // if in braces, require } - if (in_braces) { - this.advance(); + Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + if (!noAssert) checkOffset(offset, 8, this.length); + return read(this, offset, false, 52, 8) + }; - if (this.token.token_type !== '}') { - return false; - } - } + function checkInt (buf, value, offset, ext, max, min) { + if (!internalIsBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance') + if (value > max || value < min) throw new RangeError('"value" argument is out of bounds') + if (offset + ext > buf.length) throw new RangeError('Index out of range') + } - this.advance(); + Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1; + checkInt(this, value, offset, byteLength, maxBytes, 0); } + var mul = 1; + var i = 0; + this[offset] = value & 0xFF; + while (++i < byteLength && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF; + } - // since have a d or ∂, optionally followed by ^ and integer - // next we must have: - // a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols + return offset + byteLength + }; - if (this.token.token_type === 'VAR') - var1 = this.token.token_text; - else if (this.token.token_type === 'VARMULTICHAR') { - // strip out name of variable from \var command - var1 = /\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(this.token.token_text)[1]; + Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + byteLength = byteLength | 0; + if (!noAssert) { + var maxBytes = Math.pow(2, 8 * byteLength) - 1; + checkInt(this, value, offset, byteLength, maxBytes, 0); } - else if (this.token.token_type === 'LATEXCOMMAND') { - result = this.token.token_text.slice(1); - if (this.allowedLatexSymbols.includes(result)) - var1 = result; - else - return false; + + var i = byteLength - 1; + var mul = 1; + this[offset + i] = value & 0xFF; + while (--i >= 0 && (mul *= 0x100)) { + this[offset + i] = (value / mul) & 0xFF; } - // Finished numerator. - // Next need a } and { + return offset + byteLength + }; - this.advance(); + Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0); + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value); + this[offset] = (value & 0xff); + return offset + 1 + }; - if (this.token.token_type !== '}') { - return false; + function objectWriteUInt16 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffff + value + 1; + for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) { + buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> + (littleEndian ? i : 1 - i) * 8; } + } - this.advance(); - - if (this.token.token_type !== '{') { - return false; + Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff); + this[offset + 1] = (value >>> 8); + } else { + objectWriteUInt16(this, value, offset, true); } - else { - this.advance(); + return offset + 2 + }; + Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8); + this[offset + 1] = (value & 0xff); + } else { + objectWriteUInt16(this, value, offset, false); } + return offset + 2 + }; - // In denominator now - // find sequence of - // derivative symbol followed by - // - a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols - // optionally followed by a ^ and an integer - // End when sum of exponents meets or exceeds n_deriv + function objectWriteUInt32 (buf, value, offset, littleEndian) { + if (value < 0) value = 0xffffffff + value + 1; + for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) { + buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff; + } + } - let exponent_sum = 0; + Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset + 3] = (value >>> 24); + this[offset + 2] = (value >>> 16); + this[offset + 1] = (value >>> 8); + this[offset] = (value & 0xff); + } else { + objectWriteUInt32(this, value, offset, true); + } + return offset + 4 + }; - while (true) { + Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24); + this[offset + 1] = (value >>> 16); + this[offset + 2] = (value >>> 8); + this[offset + 3] = (value & 0xff); + } else { + objectWriteUInt32(this, value, offset, false); + } + return offset + 4 + }; - // next must be - // - a VAR equal to deriv_symbol="d" or \partial when deriv_symbol = "∂" + Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1); + checkInt(this, value, offset, byteLength, limit - 1, -limit); + } - if (!((deriv_symbol === "d" && this.token.token_type === "VAR" && this.token.token_text === "d") - || (deriv_symbol === "∂" && this.token.token_type === "LATEXCOMMAND" - && this.token.token_text.slice(1) === "partial"))) { - return false; + var i = 0; + var mul = 1; + var sub = 0; + this[offset] = value & 0xFF; + while (++i < byteLength && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) { + sub = 1; } + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF; + } - // followed by - // - a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols + return offset + byteLength + }; - this.advance(); + Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) { + var limit = Math.pow(2, 8 * byteLength - 1); - if (this.token.token_type === 'VAR') - var2s.push(this.token.token_text); - else if (this.token.token_type === 'VARMULTICHAR') { - // strip out name of variable from \var command - var2s.push(/\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(this.token.token_text)[1]); - } - else if (this.token.token_type === 'LATEXCOMMAND') { - let r = this.token.token_text.slice(1); - if (this.allowedLatexSymbols.includes(r)) - var2s.push(r); - else { - return false; - } - } - else { - return false; + checkInt(this, value, offset, byteLength, limit - 1, -limit); + } + + var i = byteLength - 1; + var mul = 1; + var sub = 0; + this[offset + i] = value & 0xFF; + while (--i >= 0 && (mul *= 0x100)) { + if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) { + sub = 1; } - // have derivative and variable, now check for optional ^ followed by number + this[offset + i] = ((value / mul) >> 0) - sub & 0xFF; + } - let this_exponent = 1; + return offset + byteLength + }; - this.advance(); + Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80); + if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value); + if (value < 0) value = 0xff + value + 1; + this[offset] = (value & 0xff); + return offset + 1 + }; - if (this.token.token_type === '^') { + Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff); + this[offset + 1] = (value >>> 8); + } else { + objectWriteUInt16(this, value, offset, true); + } + return offset + 2 + }; - this.advance(); + Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 8); + this[offset + 1] = (value & 0xff); + } else { + objectWriteUInt16(this, value, offset, false); + } + return offset + 2 + }; - let in_braces = false; - if (this.token.token_type === '{') { - in_braces = true; + Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value & 0xff); + this[offset + 1] = (value >>> 8); + this[offset + 2] = (value >>> 16); + this[offset + 3] = (value >>> 24); + } else { + objectWriteUInt32(this, value, offset, true); + } + return offset + 4 + }; - this.advance(); - } + Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { + value = +value; + offset = offset | 0; + if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000); + if (value < 0) value = 0xffffffff + value + 1; + if (Buffer.TYPED_ARRAY_SUPPORT) { + this[offset] = (value >>> 24); + this[offset + 1] = (value >>> 16); + this[offset + 2] = (value >>> 8); + this[offset + 3] = (value & 0xff); + } else { + objectWriteUInt32(this, value, offset, false); + } + return offset + 4 + }; - if (this.token.token_type !== 'NUMBER') { - return false; - } + function checkIEEE754 (buf, value, offset, ext, max, min) { + if (offset + ext > buf.length) throw new RangeError('Index out of range') + if (offset < 0) throw new RangeError('Index out of range') + } - this_exponent = parseFloat(this.token.token_text); - if (!Number.isInteger(this_exponent)) { - return false; - } + function writeFloat (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38); + } + write(buf, value, offset, littleEndian, 23, 4); + return offset + 4 + } - // if in braces, require } - if (in_braces) { - this.advance(); + Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { + return writeFloat(this, value, offset, true, noAssert) + }; - if (this.token.token_type !== '}') { - return false; - } - } + Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { + return writeFloat(this, value, offset, false, noAssert) + }; - this.advance(); + function writeDouble (buf, value, offset, littleEndian, noAssert) { + if (!noAssert) { + checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308); + } + write(buf, value, offset, littleEndian, 52, 8); + return offset + 8 + } - } + Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { + return writeDouble(this, value, offset, true, noAssert) + }; - var2_exponents.push(this_exponent); - exponent_sum += this_exponent; + Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { + return writeDouble(this, value, offset, false, noAssert) + }; - if (exponent_sum > n_deriv) { - return false; - } + // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) + Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!start) start = 0; + if (!end && end !== 0) end = this.length; + if (targetStart >= target.length) targetStart = target.length; + if (!targetStart) targetStart = 0; + if (end > 0 && end < start) end = start; - // possibly found derivative - if (exponent_sum === n_deriv) { + // Copy 0 bytes; we're done + if (end === start) return 0 + if (target.length === 0 || this.length === 0) return 0 - // next token must be a } - if (this.token.token_type !== '}') { - return false; + // Fatal error conditions + if (targetStart < 0) { + throw new RangeError('targetStart out of bounds') + } + if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') + if (end < 0) throw new RangeError('sourceEnd out of bounds') - } + // Are we oob? + if (end > this.length) end = this.length; + if (target.length - targetStart < end - start) { + end = target.length - targetStart + start; + } - // found derivative! + var len = end - start; + var i; - this.advance(); + if (this === target && start < targetStart && targetStart < end) { + // descending copy from end + for (i = len - 1; i >= 0; --i) { + target[i + targetStart] = this[i + start]; + } + } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { + // ascending copy from start + for (i = 0; i < len; ++i) { + target[i + targetStart] = this[i + start]; + } + } else { + Uint8Array.prototype.set.call( + target, + this.subarray(start, start + len), + targetStart + ); + } - let result_name = "derivative_leibniz"; - if (deriv_symbol === "∂") - result_name = "partial_" + result_name; + return len + }; - result = [result_name]; + // Usage: + // buffer.fill(number[, offset[, end]]) + // buffer.fill(buffer[, offset[, end]]) + // buffer.fill(string[, offset[, end]][, encoding]) + Buffer.prototype.fill = function fill (val, start, end, encoding) { + // Handle string cases: + if (typeof val === 'string') { + if (typeof start === 'string') { + encoding = start; + start = 0; + end = this.length; + } else if (typeof end === 'string') { + encoding = end; + end = this.length; + } + if (val.length === 1) { + var code = val.charCodeAt(0); + if (code < 256) { + val = code; + } + } + if (encoding !== undefined && typeof encoding !== 'string') { + throw new TypeError('encoding must be a string') + } + if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { + throw new TypeError('Unknown encoding: ' + encoding) + } + } else if (typeof val === 'number') { + val = val & 255; + } - if (n_deriv === 1) - result.push(var1); - else - result.push(["tuple", var1, n_deriv]); + // Invalid ranges are not set to a default, so can range check early. + if (start < 0 || this.length < start || this.length < end) { + throw new RangeError('Out of range index') + } - let r2 = []; - for (let i = 0; i < var2s.length; i += 1) { - if (var2_exponents[i] === 1) - r2.push(var2s[i]); - else - r2.push(["tuple", var2s[i], var2_exponents[i]]); - } - r2 = ["tuple"].concat(r2); + if (end <= start) { + return this + } - result.push(r2); + start = start >>> 0; + end = end === undefined ? this.length : end >>> 0; - return result; + if (!val) val = 0; + var i; + if (typeof val === 'number') { + for (i = start; i < end; ++i) { + this[i] = val; + } + } else { + var bytes = internalIsBuffer(val) + ? val + : utf8ToBytes(new Buffer(val, encoding).toString()); + var len = bytes.length; + for (i = 0; i < end - start; ++i) { + this[i + start] = bytes[i % len]; } } - } -} -class latexToGuppy{ - constructor(){ - this.latexToAst = new latexToAst(); - this.astToGuppy = new astToGuppy(); - } + return this + }; - convert(latex){ - return this.astToGuppy.convert(this.latexToAst.convert(latex)); - } -} + // HELPER FUNCTIONS + // ================ -class latexToMathjs{ - constructor(){ - this.latexToAst = new latexToAst(); - this.astToMathjs = new astToMathjs(); - } + var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g; - convert(latex){ - return this.astToMathjs.convert(this.latexToAst.convert(latex)); + function base64clean (str) { + // Node strips out invalid characters like \n and \t from the string, base64-js does not + str = stringtrim(str).replace(INVALID_BASE64_RE, ''); + // Node converts strings with length < 2 to '' + if (str.length < 2) return '' + // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not + while (str.length % 4 !== 0) { + str = str + '='; + } + return str } -} -class latexToText{ - constructor(){ - this.latexToAst = new latexToAst(); - this.astToText = new astToText(); + function stringtrim (str) { + if (str.trim) return str.trim() + return str.replace(/^\s+|\s+$/g, '') } - convert(latex){ - return this.astToText.convert(this.latexToAst.convert(latex)); + function toHex (n) { + if (n < 16) return '0' + n.toString(16) + return n.toString(16) } -} -/* - * convert math.s tree to AST - * - * Copyright 2014-2017 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ + function utf8ToBytes (string, units) { + units = units || Infinity; + var codePoint; + var length = string.length; + var leadSurrogate = null; + var bytes = []; + for (var i = 0; i < length; ++i) { + codePoint = string.charCodeAt(i); + // is surrogate component + if (codePoint > 0xD7FF && codePoint < 0xE000) { + // last char was a lead + if (!leadSurrogate) { + // no lead yet + if (codePoint > 0xDBFF) { + // unexpected trail + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + continue + } else if (i + 1 === length) { + // unpaired lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + continue + } -const operators$4 = { - "+,add": function(operands) { return ['+'].concat(operands); }, - "*,multiply": function(operands) { return ['*'].concat(operands); }, - "/,divide": function(operands) { return ['/', operands[0], operands[1]]; }, - "-,unaryMinus": function(operands) { return ['-', operands[0]]; }, - "-,subtract": function(operands) { return ['+', operands[0], ['-', operands[1]]]; }, - "^,pow": function(operands) { return ['^', operands[0], operands[1]]; }, - "and,and": function(operands) { return ['and'].concat(operands); }, - "or,or": function(operands) { return ['or'].concat(operands); }, - "not,not": function(operands) { return ['not', operands[0]]; }, - "==,equal": function(operands) { return ['='].concat(operands); }, - "<,smaller": function(operands) { return ['<', operands[0], operands[1]]; }, - ">,larger": function(operands) { return ['>', operands[0], operands[1]]; }, - "<=,smallerEq": function(operands) { return ['le', operands[0], operands[1]]; }, - ">=,largerEq": function(operands) { return ['ge', operands[0], operands[1]]; }, - "!=,unequal": function(operands) { return ['ne', operands[0], operands[1]]; }, - "!,factorial": function(operands) { return ['apply', 'factorial', operands[0]];}, -}; + // valid lead + leadSurrogate = codePoint; -class mathjsToAst { + continue + } - convert(mathnode){ - if(mathnode.isConstantNode) - return mathnode.value; - if(mathnode.isSymbolNode) - return mathnode.name; + // 2 leads in a row + if (codePoint < 0xDC00) { + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + leadSurrogate = codePoint; + continue + } - if(mathnode.isOperatorNode) { - var key = [mathnode.op, mathnode.fn].join(','); - if(key in operators$4) - return operators$4[key]( - mathnode.args.map( function(v,i) { return this.convert(v); }.bind(this) ) ); - else - throw Error("Unsupported operator: " + mathnode.op - + ", " + mathnode.fn); - } + // valid surrogate pair + codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000; + } else if (leadSurrogate) { + // valid bmp char, but last char was a lead + if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD); + } - if(mathnode.isFunctionNode) { - var args = mathnode.args.map( - function(v,i) { return this.convert(v); }.bind(this) ); + leadSurrogate = null; - if( args.length > 1) - args = ["tuple"].concat(args); - else - args = args[0]; + // encode utf8 + if (codePoint < 0x80) { + if ((units -= 1) < 0) break + bytes.push(codePoint); + } else if (codePoint < 0x800) { + if ((units -= 2) < 0) break + bytes.push( + codePoint >> 0x6 | 0xC0, + codePoint & 0x3F | 0x80 + ); + } else if (codePoint < 0x10000) { + if ((units -= 3) < 0) break + bytes.push( + codePoint >> 0xC | 0xE0, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ); + } else if (codePoint < 0x110000) { + if ((units -= 4) < 0) break + bytes.push( + codePoint >> 0x12 | 0xF0, + codePoint >> 0xC & 0x3F | 0x80, + codePoint >> 0x6 & 0x3F | 0x80, + codePoint & 0x3F | 0x80 + ); + } else { + throw new Error('Invalid code point') + } + } - var result = ["apply", mathnode.name]; - result.push(args); - return result; + return bytes + } + function asciiToBytes (str) { + var byteArray = []; + for (var i = 0; i < str.length; ++i) { + // Node's code seems to be doing this and not & 0x7F.. + byteArray.push(str.charCodeAt(i) & 0xFF); } - - if(mathnode.isArrayNode) { - return ["vector"].concat(mathnode.args.map( - function(v,i) { return this.convert(v); }.bind(this) ) ); + return byteArray + } + + function utf16leToBytes (str, units) { + var c, hi, lo; + var byteArray = []; + for (var i = 0; i < str.length; ++i) { + if ((units -= 2) < 0) break + + c = str.charCodeAt(i); + hi = c >> 8; + lo = c % 256; + byteArray.push(lo); + byteArray.push(hi); } - - if(mathnode.isParenthesisNode) - return this.convert(mathnode.content); - - throw Error("Unsupported node type: " + mathnode.type); + return byteArray } - -} -class mathjsToGuppy{ - constructor(){ - this.mathjsToAst = new mathjsToAst(); - this.astToGuppy = new astToGuppy(); - } - convert(mathjs){ - return this.astToGuppy.convert(this.mathjsToAst.convert(mathjs)); + function base64ToBytes (str) { + return toByteArray(base64clean(str)) } -} -class mathjsToLatex{ - constructor(){ - this.mathjsToAst = new mathjsToAst(); - this.astToLatex = new astToLatex(); + function blitBuffer (src, dst, offset, length) { + for (var i = 0; i < length; ++i) { + if ((i + offset >= dst.length) || (i >= src.length)) break + dst[i + offset] = src[i]; + } + return i } - convert(mathjs){ - return this.astToLatex.convert(this.mathjsToAst.convert(mathjs)); + function isnan (val) { + return val !== val // eslint-disable-line no-self-compare } -} -class mathjsToText{ - constructor(){ - this.mathjsToAst = new mathjsToAst(); - this.astToText = new astToText(); + + // the following is from is-buffer, also by Feross Aboukhadijeh and with same lisence + // The _isBuffer check is for Safari 5-7 support, because it's missing + // Object.prototype.constructor. Remove this eventually + function isBuffer(obj) { + return obj != null && (!!obj._isBuffer || isFastBuffer(obj) || isSlowBuffer(obj)) } - convert(mathjs){ - return this.astToText.convert(this.mathjsToAst.convert(mathjs)); + function isFastBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) } -} -/** - * Helpers. - */ + // For Node v0.10 support. Remove this eventually. + function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isFastBuffer(obj.slice(0, 0)) + } -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; + var inherits; + if (typeof Object.create === 'function'){ + inherits = function inherits(ctor, superCtor) { + // implementation from standard node.js 'util' module + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; + } else { + inherits = function inherits(ctor, superCtor) { + ctor.super_ = superCtor; + var TempCtor = function () {}; + TempCtor.prototype = superCtor.prototype; + ctor.prototype = new TempCtor(); + ctor.prototype.constructor = ctor; + }; + } + var inherits$1 = inherits; -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public - */ + var formatRegExp = /%[sdj%]/g; + function format$10(f) { + if (!isString$6(f)) { + var objects = []; + for (var i = 0; i < arguments.length; i++) { + objects.push(inspect(arguments[i])); + } + return objects.join(' '); + } -var ms = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse$2(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse$2(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; + var i = 1; + var args = arguments; + var len = args.length; + var str = String(f).replace(formatRegExp, function(x) { + if (x === '%%') return '%'; + if (i >= len) return x; + switch (x) { + case '%s': return String(args[i++]); + case '%d': return Number(args[i++]); + case '%j': + try { + return JSON.stringify(args[i++]); + } catch (_) { + return '[Circular]'; + } + default: + return x; + } + }); + for (var x = args[i]; i < len; x = args[++i]) { + if (isNull(x) || !isObject(x)) { + str += ' ' + x; + } else { + str += ' ' + inspect(x); + } + } + return str; } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} + // Mark that a method should not be used. + // Returns a modified function which warns once by default. + // If --no-deprecation is set, then it is a no-op. + function deprecate(fn, msg) { + // Allow for deprecating things in the process of starting up. + if (isUndefined(global$1.process)) { + return function() { + return deprecate(fn, msg).apply(this, arguments); + }; + } -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} + if (process.noDeprecation === true) { + return fn; + } -/** - * Pluralization helper. - */ + var warned = false; + function deprecated() { + if (!warned) { + if (process.throwDeprecation) { + throw new Error(msg); + } else if (process.traceDeprecation) { + console.trace(msg); + } else { + console.error(msg); + } + warned = true; + } + return fn.apply(this, arguments); + } -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; + return deprecated; } - return Math.ceil(ms / n) + ' ' + name + 's'; -} -var debug = createCommonjsModule(function (module, exports) { -/** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = ms; - -/** - * The currently active debug mode names, and names to skip. - */ - -exports.names = []; -exports.skips = []; + var debugs = {}; + var debugEnviron; + function debuglog(set) { + if (isUndefined(debugEnviron)) + debugEnviron = process.env.NODE_DEBUG || ''; + set = set.toUpperCase(); + if (!debugs[set]) { + if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { + var pid = 0; + debugs[set] = function() { + var msg = format$10.apply(null, arguments); + console.error('%s %d: %s', set, pid, msg); + }; + } else { + debugs[set] = function() {}; + } + } + return debugs[set]; + } -/** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ + /** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Object} opts Optional options object that alters the output. + */ + /* legacy: obj, showHidden, depth, colors*/ + function inspect(obj, opts) { + // default options + var ctx = { + seen: [], + stylize: stylizeNoColor + }; + // legacy... + if (arguments.length >= 3) ctx.depth = arguments[2]; + if (arguments.length >= 4) ctx.colors = arguments[3]; + if (isBoolean$1(opts)) { + // legacy... + ctx.showHidden = opts; + } else if (opts) { + // got an "options" object + _extend(ctx, opts); + } + // set default options + if (isUndefined(ctx.showHidden)) ctx.showHidden = false; + if (isUndefined(ctx.depth)) ctx.depth = 2; + if (isUndefined(ctx.colors)) ctx.colors = false; + if (isUndefined(ctx.customInspect)) ctx.customInspect = true; + if (ctx.colors) ctx.stylize = stylizeWithColor; + return formatValue(ctx, obj, ctx.depth); + } + + // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics + inspect.colors = { + 'bold' : [1, 22], + 'italic' : [3, 23], + 'underline' : [4, 24], + 'inverse' : [7, 27], + 'white' : [37, 39], + 'grey' : [90, 39], + 'black' : [30, 39], + 'blue' : [34, 39], + 'cyan' : [36, 39], + 'green' : [32, 39], + 'magenta' : [35, 39], + 'red' : [31, 39], + 'yellow' : [33, 39] + }; + + // Don't use 'blue' not visible on cmd.exe + inspect.styles = { + 'special': 'cyan', + 'number': 'yellow', + 'boolean': 'yellow', + 'undefined': 'grey', + 'null': 'bold', + 'string': 'green', + 'date': 'magenta', + // "name": intentionally not styling + 'regexp': 'red' + }; + + + function stylizeWithColor(str, styleType) { + var style = inspect.styles[styleType]; + + if (style) { + return '\u001b[' + inspect.colors[style][0] + 'm' + str + + '\u001b[' + inspect.colors[style][1] + 'm'; + } else { + return str; + } + } -exports.formatters = {}; -/** - * Previous log timestamp. - */ + function stylizeNoColor(str, styleType) { + return str; + } -var prevTime; -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ + function arrayToHash(array) { + var hash = {}; -function selectColor(namespace) { - var hash = 0, i; + array.forEach(function(val, idx) { + hash[val] = true; + }); - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer + return hash; } - return exports.colors[Math.abs(hash) % exports.colors.length]; -} -/** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - -function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms$$1 = curr - (prevTime || curr); - self.diff = ms$$1; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; + function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (ctx.customInspect && + value && + isFunction(value.inspect) && + // Filter out the util module, it's inspect function is special + value.inspect !== inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes, ctx); + if (!isString$6(ret)) { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; } - args[0] = exports.coerce(args[0]); + // Look up the keys of the object. + var keys = Object.keys(value); + var visibleKeys = arrayToHash(keys); - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); + if (ctx.showHidden) { + keys = Object.getOwnPropertyNames(value); } - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); + // IE doesn't make error fields non-enumerable + // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx + if (isError(value) + && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { + return formatError(value); + } - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; + // Some type of object without properties can be shortcutted. + if (keys.length === 0) { + if (isFunction(value)) { + var name = value.name ? ': ' + value.name : ''; + return ctx.stylize('[Function' + name + ']', 'special'); } - return match; - }); + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); + var base = '', array = false, braces = ['{', '}']; - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } + // Make Array say that they are Array + if (isArray$6(value)) { + array = true; + braces = ['[', ']']; + } - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); + // Make functions say that they are functions + if (isFunction(value)) { + var n = value.name ? ': ' + value.name : ''; + base = ' [Function' + n + ']'; + } - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } - return debug; -} + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ + // Make error with message first say the error + if (isError(value)) { + base = ' ' + formatError(value); + } -function enable(namespaces) { - exports.save(namespaces); + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } - exports.names = []; - exports.skips = []; + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; + ctx.seen.push(value); - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); } else { - exports.names.push(new RegExp('^' + namespaces + '$')); + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); } - } -} -/** - * Disable debug output. - * - * @api public - */ + ctx.seen.pop(); -function disable() { - exports.enable(''); -} + return reduceToSingleString(output, base, braces); + } -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; + function formatPrimitive(ctx, value) { + if (isUndefined(value)) + return ctx.stylize('undefined', 'undefined'); + if (isString$6(value)) { + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; -} - -/** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} -}); -var debug_1 = debug.coerce; -var debug_2 = debug.disable; -var debug_3 = debug.enable; -var debug_4 = debug.enabled; -var debug_5 = debug.humanize; -var debug_6 = debug.names; -var debug_7 = debug.skips; -var debug_8 = debug.formatters; - -var browser = createCommonjsModule(function (module, exports) { -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = debug; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - -/** - * Colors. - */ - -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; - -/** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; + if (isNumber$5(value)) + return ctx.stylize('' + value, 'number'); + if (isBoolean$1(value)) + return ctx.stylize('' + value, 'boolean'); + // For some reason typeof null is "object", so special case here. + if (isNull(value)) + return ctx.stylize('null', 'null'); } - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} - -/** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } -}; - - -/** - * Colorize log arguments if enabled. - * - * @api public - */ - -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit'); - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - args.splice(lastC, 0, c); -} - -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; -} - -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ - -exports.enable(load()); - -/** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} -}); -var browser_1 = browser.log; -var browser_2 = browser.formatArgs; -var browser_3 = browser.save; -var browser_4 = browser.load; -var browser_5 = browser.useColors; -var browser_6 = browser.storage; -var browser_7 = browser.colors; - -// MIT lisence -// from https://github.com/substack/tty-browserify/blob/1ba769a6429d242f36226538835b4034bf6b7886/index.js - -function isatty() { - return false; -} - -function ReadStream() { - throw new Error('tty.ReadStream is not implemented'); -} - -function WriteStream() { - throw new Error('tty.ReadStream is not implemented'); -} - -var tty = { - isatty: isatty, - ReadStream: ReadStream, - WriteStream: WriteStream -} - -// shim for using process in browser -// based off https://github.com/defunctzombie/node-process/blob/master/browser.js - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -var cachedSetTimeout = defaultSetTimout; -var cachedClearTimeout = defaultClearTimeout; -if (typeof global.setTimeout === 'function') { - cachedSetTimeout = setTimeout; -} -if (typeof global.clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; -} - -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } + function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; + } -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } + function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (hasOwnProperty$5(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; + } - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); + function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str, desc; + desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; + if (desc.get) { + if (desc.set) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); + if (desc.set) { + str = ctx.stylize('[Setter]', 'special'); + } } -} - -function drainQueue() { - if (draining) { - return; + if (!hasOwnProperty$5(visibleKeys, key)) { + name = '[' + key + ']'; } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } + if (!str) { + if (ctx.seen.indexOf(desc.value) < 0) { + if (isNull(recurseTimes)) { + str = formatValue(ctx, desc.value, null); + } else { + str = formatValue(ctx, desc.value, recurseTimes - 1); } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} -function nextTick(fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -} -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -var title = 'browser'; -var platform = 'browser'; -var browser$1 = true; -var env = {}; -var argv = []; -var version$2 = ''; // empty string to avoid regexp issues -var versions = {}; -var release = {}; -var config$2 = {}; - -function noop() {} - -var on = noop; -var addListener = noop; -var once = noop; -var off = noop; -var removeListener = noop; -var removeAllListeners = noop; -var emit = noop; - -function binding(name) { - throw new Error('process.binding is not supported'); -} - -function cwd () { return '/' } -function chdir (dir) { - throw new Error('process.chdir is not supported'); -}function umask() { return 0; } - -// from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js -var performance = global.performance || {}; -var performanceNow = - performance.now || - performance.mozNow || - performance.msNow || - performance.oNow || - performance.webkitNow || - function(){ return (new Date()).getTime() }; - -// generate timestamp or delta -// see http://nodejs.org/api/process.html#process_process_hrtime -function hrtime(previousTimestamp){ - var clocktime = performanceNow.call(performance)*1e-3; - var seconds = Math.floor(clocktime); - var nanoseconds = Math.floor((clocktime%1)*1e9); - if (previousTimestamp) { - seconds = seconds - previousTimestamp[0]; - nanoseconds = nanoseconds - previousTimestamp[1]; - if (nanoseconds<0) { - seconds--; - nanoseconds += 1e9; - } - } - return [seconds,nanoseconds] -} - -var startTime = new Date(); -function uptime() { - var currentTime = new Date(); - var dif = currentTime - startTime; - return dif / 1000; -} - -var process$1 = { - nextTick: nextTick, - title: title, - browser: browser$1, - env: env, - argv: argv, - version: version$2, - versions: versions, - on: on, - addListener: addListener, - once: once, - off: off, - removeListener: removeListener, - removeAllListeners: removeAllListeners, - emit: emit, - binding: binding, - cwd: cwd, - chdir: chdir, - umask: umask, - hrtime: hrtime, - platform: platform, - release: release, - config: config$2, - uptime: uptime -}; - -var inherits; -if (typeof Object.create === 'function'){ - inherits = function inherits(ctor, superCtor) { - // implementation from standard node.js 'util' module - ctor.super_ = superCtor; - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - inherits = function inherits(ctor, superCtor) { - ctor.super_ = superCtor; - var TempCtor = function () {}; - TempCtor.prototype = superCtor.prototype; - ctor.prototype = new TempCtor(); - ctor.prototype.constructor = ctor; - }; -} -var inherits$1 = inherits; - -// Copyright Joyent, Inc. and other Node contributors. -var formatRegExp = /%[sdj%]/g; -function format$10(f) { - if (!isString$6(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); + } else { + str = ctx.stylize('[Circular]', 'special'); + } } - } - return str; -} - -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -function deprecate(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return deprecate(fn, msg).apply(this, arguments); - }; - } - - if (process$1.noDeprecation === true) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (process$1.throwDeprecation) { - throw new Error(msg); - } else if (process$1.traceDeprecation) { - console.trace(msg); + if (isUndefined(name)) { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); } else { - console.error(msg); + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); } - warned = true; } - return fn.apply(this, arguments); - } - - return deprecated; -} -var debugs = {}; -var debugEnviron; -function debuglog(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process$1.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = 0; - debugs[set] = function() { - var msg = format$10.apply(null, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; -} - -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean$1(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - _extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; + return name + ': ' + str; } -} - - -function stylizeNoColor(str, styleType) { - return str; -} - - -function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - return hash; -} + function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; + }, 0); -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString$6(ret)) { - ret = formatValue(ctx, ret, recurseTimes); + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; } - return ret; - } - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; } - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); + // NOTE: These type checking functions intentionally don't use `instanceof` + // because it is fragile and can be easily faked with `Object.create()`. + function isArray$6(ar) { + return Array.isArray(ar); } - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); + function isBoolean$1(arg) { + return typeof arg === 'boolean'; } - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } + function isNull(arg) { + return arg === null; } - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray$5(value)) { - array = true; - braces = ['[', ']']; + function isNullOrUndefined(arg) { + return arg == null; } - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; + function isNumber$5(arg) { + return typeof arg === 'number'; } - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); + function isString$6(arg) { + return typeof arg === 'string'; } - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); + function isSymbol(arg) { + return typeof arg === 'symbol'; } - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); + function isUndefined(arg) { + return arg === void 0; } - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; + function isRegExp(re) { + return isObject(re) && objectToString(re) === '[object RegExp]'; } - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } + function isObject(arg) { + return typeof arg === 'object' && arg !== null; } - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); + function isDate(d) { + return isObject(d) && objectToString(d) === '[object Date]'; } - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); -} - - -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString$6(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); + function isError(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); } - if (isNumber$5(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean$1(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} + function isFunction(arg) { + return typeof arg === 'function'; + } -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} + function isPrimitive(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; + } + function isBuffer$1(maybeBuf) { + return isBuffer(maybeBuf); + } -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty$5(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } + function objectToString(o) { + return Object.prototype.toString.call(o); } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty$5(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } + function pad(n) { + return n < 10 ? '0' + n.toString(10) : n.toString(10); } - return name + ': ' + str; -} - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); + var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', + 'Oct', 'Nov', 'Dec']; - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; + // 26 Feb 16:19:34 + function timestamp() { + var d = new Date(); + var time = [pad(d.getHours()), + pad(d.getMinutes()), + pad(d.getSeconds())].join(':'); + return [d.getDate(), months[d.getMonth()], time].join(' '); } - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} + // log is just a thin wrapper to console.log that prepends a timestamp + function log$3() { + console.log('%s - %s', timestamp(), format$10.apply(null, arguments)); + } -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray$5(ar) { - return Array.isArray(ar); -} + function _extend(origin, add) { + // Don't do anything if add isn't an object + if (!add || !isObject(add)) return origin; -function isBoolean$1(arg) { - return typeof arg === 'boolean'; -} + var keys = Object.keys(add); + var i = keys.length; + while (i--) { + origin[keys[i]] = add[keys[i]]; + } + return origin; + } + function hasOwnProperty$5(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); + } -function isNull(arg) { - return arg === null; -} + var util$1 = { + inherits: inherits$1, + _extend: _extend, + log: log$3, + isBuffer: isBuffer$1, + isPrimitive: isPrimitive, + isFunction: isFunction, + isError: isError, + isDate: isDate, + isObject: isObject, + isRegExp: isRegExp, + isUndefined: isUndefined, + isSymbol: isSymbol, + isString: isString$6, + isNumber: isNumber$5, + isNullOrUndefined: isNullOrUndefined, + isNull: isNull, + isBoolean: isBoolean$1, + isArray: isArray$6, + inspect: inspect, + deprecate: deprecate, + format: format$10, + debuglog: debuglog + } -function isNullOrUndefined(arg) { - return arg == null; -} - -function isNumber$5(arg) { - return typeof arg === 'number'; -} - -function isString$6(arg) { - return typeof arg === 'string'; -} - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} - -function isUndefined(arg) { - return arg === void 0; -} - -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} - -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} - -function isBuffer(maybeBuf) { - return Buffer.isBuffer(maybeBuf); -} - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - - -// log is just a thin wrapper to console.log that prepends a timestamp -function log$3() { - console.log('%s - %s', timestamp(), format$10.apply(null, arguments)); -} - -function _extend(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -} -function hasOwnProperty$5(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -var util$1 = { - inherits: inherits$1, - _extend: _extend, - log: log$3, - isBuffer: isBuffer, - isPrimitive: isPrimitive, - isFunction: isFunction, - isError: isError, - isDate: isDate, - isObject: isObject, - isRegExp: isRegExp, - isUndefined: isUndefined, - isSymbol: isSymbol, - isString: isString$6, - isNumber: isNumber$5, - isNullOrUndefined: isNullOrUndefined, - isNull: isNull, - isBoolean: isBoolean$1, - isArray: isArray$5, - inspect: inspect, - deprecate: deprecate, - format: format$10, - debuglog: debuglog -} - -var node$2 = createCommonjsModule(function (module, exports) { -/** - * Module dependencies. - */ - - - - -/** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - -exports = module.exports = debug; -exports.init = init; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; - -/** - * Colors. - */ - -exports.colors = [6, 2, 3, 4, 5, 1]; - -/** - * Build up the default `inspectOpts` object from the environment variables. - * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js - */ - -exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); -}).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); - - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); - - obj[prop] = val; - return obj; -}, {}); - -/** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ - -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; - -if (1 !== fd && 2 !== fd) { - util$1.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')(); -} - -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); - -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ - -function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); -} - -/** - * Map %o to `util.inspect()`, all on a single line. - */ - -exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util$1.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); -}; - -/** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ - -exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util$1.inspect(v, this.inspectOpts); -}; - -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ - -function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; - - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; - - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } -} - -/** - * Invokes `util.format()` with the specified arguments and writes to `stream`. - */ - -function log() { - return stream.write(util$1.format.apply(util$1, arguments) + '\n'); -} - -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } -} - -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - -function load() { - return process.env.DEBUG; -} - -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ - -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - case 'FILE': - var fs = require$$2; - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = require$$2; - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); + var node$2 = createCommonjsModule(function (module, exports) { + /** + * Module dependencies. + */ - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - // For supporting legacy API we put the FD here. - stream.fd = fd; + /** + * This is the Node.js implementation of `debug()`. + * + * Expose `debug()` as the module. + */ - stream._isStdio = true; + exports = module.exports = debug; + exports.init = init; + exports.log = log; + exports.formatArgs = formatArgs; + exports.save = save; + exports.load = load; + exports.useColors = useColors; - return stream; -} + /** + * Colors. + */ -/** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ + exports.colors = [6, 2, 3, 4, 5, 1]; -function init (debug$$1) { - debug$$1.inspectOpts = {}; + /** + * Build up the default `inspectOpts` object from the environment variables. + * + * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js + */ - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug$$1.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } -} + exports.inspectOpts = Object.keys(process.env).filter(function (key) { + return /^debug_/i.test(key); + }).reduce(function (obj, key) { + // camel-case + var prop = key + .substring(6) + .toLowerCase() + .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ + // coerce string value into JS value + var val = process.env[key]; + if (/^(yes|on|true|enabled)$/i.test(val)) val = true; + else if (/^(no|off|false|disabled)$/i.test(val)) val = false; + else if (val === 'null') val = null; + else val = Number(val); -exports.enable(load()); -}); -var node_1 = node$2.init; -var node_2 = node$2.log; -var node_3 = node$2.formatArgs; -var node_4 = node$2.save; -var node_5 = node$2.load; -var node_6 = node$2.useColors; -var node_7 = node$2.colors; -var node_8 = node$2.inspectOpts; + obj[prop] = val; + return obj; + }, {}); -var src = createCommonjsModule(function (module) { -/** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. - */ + /** + * The file descriptor to write the `debug()` calls to. + * Set the `DEBUG_FD` env variable to override with another value. i.e.: + * + * $ DEBUG_FD=3 node script.js 3>debug.log + */ -if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = browser; -} else { - module.exports = node$2; -} -}); + var fd = parseInt(process.env.DEBUG_FD, 10) || 2; -/** - * Module dependencies. - */ + if (1 !== fd && 2 !== fd) { + util$1.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')(); + } -var debug$1 = src('xml-parser'); + var stream = 1 === fd ? process.stdout : + 2 === fd ? process.stderr : + createWritableStdioStream(fd); -/** - * Expose `parse`. - */ + /** + * Is stdout a TTY? Colored output is enabled when `true`. + */ -var xmlParser = parse$3; + function useColors() { + return 'colors' in exports.inspectOpts + ? Boolean(exports.inspectOpts.colors) + : tty.isatty(fd); + } -/** - * Parse the given string of `xml`. - * - * @param {String} xml - * @return {Object} - * @api public - */ + /** + * Map %o to `util.inspect()`, all on a single line. + */ -function parse$3(xml) { - xml = xml.trim(); + exports.formatters.o = function(v) { + this.inspectOpts.colors = this.useColors; + return util$1.inspect(v, this.inspectOpts) + .split('\n').map(function(str) { + return str.trim() + }).join(' '); + }; - // strip comments - xml = xml.replace(//g, ''); + /** + * Map %o to `util.inspect()`, allowing multiple lines if needed. + */ - return document(); + exports.formatters.O = function(v) { + this.inspectOpts.colors = this.useColors; + return util$1.inspect(v, this.inspectOpts); + }; /** - * XML document. + * Adds ANSI color escape codes if enabled. + * + * @api public */ - function document() { - return { - declaration: declaration(), - root: tag() + function formatArgs(args) { + var name = this.namespace; + var useColors = this.useColors; + + if (useColors) { + var c = this.color; + var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; + + args[0] = prefix + args[0].split('\n').join('\n' + prefix); + args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); + } else { + args[0] = new Date().toUTCString() + + ' ' + name + ' ' + args[0]; } } /** - * Declaration. + * Invokes `util.format()` with the specified arguments and writes to `stream`. */ - function declaration() { - var m = match(/^<\?xml\s*/); - if (!m) return; + function log() { + return stream.write(util$1.format.apply(util$1, arguments) + '\n'); + } - // tag - var node = { - attributes: {} - }; + /** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ - // attributes - while (!(eos() || is('?>'))) { - var attr = attribute(); - if (!attr) return node; - node.attributes[attr.name] = attr.value; + function save(namespaces) { + if (null == namespaces) { + // If you set a process.env field to null or undefined, it gets cast to the + // string 'null' or 'undefined'. Just delete instead. + delete process.env.DEBUG; + } else { + process.env.DEBUG = namespaces; } + } - match(/\?>\s*/); + /** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ - return node; + function load() { + return process.env.DEBUG; } /** - * Tag. + * Copied from `node/src/node.js`. + * + * XXX: It's lame that node doesn't expose this API out-of-the-box. It also + * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. */ - function tag() { - debug$1('tag %j', xml); - var m = match(/^<([\w-:.]+)\s*/); - if (!m) return; + function createWritableStdioStream (fd) { + var stream; + var tty_wrap = process.binding('tty_wrap'); - // name - var node = { - name: m[1], - attributes: {}, - children: [] - }; + // Note stream._type is used for test-module-load-list.js - // attributes - while (!(eos() || is('>') || is('?>') || is('/>'))) { - var attr = attribute(); - if (!attr) return node; - node.attributes[attr.name] = attr.value; - } + switch (tty_wrap.guessHandleType(fd)) { + case 'TTY': + stream = new tty.WriteStream(fd); + stream._type = 'tty'; - // self closing tag - if (match(/^\s*\/>\s*/)) { - return node; - } + // Hack to have stream not keep the event loop alive. + // See https://github.com/joyent/node/issues/1726 + if (stream._handle && stream._handle.unref) { + stream._handle.unref(); + } + break; + + case 'FILE': + var fs = require$$2; + stream = new fs.SyncWriteStream(fd, { autoClose: false }); + stream._type = 'fs'; + break; - match(/\??>\s*/); + case 'PIPE': + case 'TCP': + var net = require$$2; + stream = new net.Socket({ + fd: fd, + readable: false, + writable: true + }); + + // FIXME Should probably have an option in net.Socket to create a + // stream from an existing fd which is writable only. But for now + // we'll just add this hack and set the `readable` member to false. + // Test: ./node test/fixtures/echo.js < /etc/passwd + stream.readable = false; + stream.read = null; + stream._type = 'pipe'; - // content - node.content = content(); + // FIXME Hack to have stream not keep the event loop alive. + // See https://github.com/joyent/node/issues/1726 + if (stream._handle && stream._handle.unref) { + stream._handle.unref(); + } + break; - // children - var child; - while (child = tag()) { - node.children.push(child); + default: + // Probably an error on in uv_guess_handle() + throw new Error('Implement me. Unknown stream file type!'); } - // closing - match(/^<\/[\w-:.]+>\s*/); + // For supporting legacy API we put the FD here. + stream.fd = fd; + + stream._isStdio = true; - return node; + return stream; } /** - * Text content. + * Init logic for `debug` instances. + * + * Create a new `inspectOpts` object in case `useColors` is set + * differently for a particular `debug` instance. */ - function content() { - debug$1('content %j', xml); - var m = match(/^([^<]*)/); - if (m) return m[1]; - return ''; + function init (debug$$1) { + debug$$1.inspectOpts = {}; + + var keys = Object.keys(exports.inspectOpts); + for (var i = 0; i < keys.length; i++) { + debug$$1.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; + } } /** - * Attribute. + * Enable namespaces listed in `process.env.DEBUG` initially. */ - function attribute() { - debug$1('attribute %j', xml); - var m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/); - if (!m) return; - return { name: m[1], value: strip(m[2]) } - } + exports.enable(load()); + }); + var node_1 = node$2.init; + var node_2 = node$2.log; + var node_3 = node$2.formatArgs; + var node_4 = node$2.save; + var node_5 = node$2.load; + var node_6 = node$2.useColors; + var node_7 = node$2.colors; + var node_8 = node$2.inspectOpts; + var src = createCommonjsModule(function (module) { /** - * Strip quotes from `val`. + * Detect Electron renderer process, which is node, but we should + * treat as a browser. */ - function strip(val) { - return val.replace(/^['"]|['"]$/g, ''); + if (typeof process !== 'undefined' && process.type === 'renderer') { + module.exports = browser$1; + } else { + module.exports = node$2; } + }); /** - * Match `re` and advance the string. + * Module dependencies. */ - function match(re) { - var m = xml.match(re); - if (!m) return; - xml = xml.slice(m[0].length); - return m; - } + var debug$1 = src('xml-parser'); /** - * End-of-source. + * Expose `parse`. */ - function eos() { - return 0 == xml.length; - } + var xmlParser = parse$3; /** - * Check for `prefix`. + * Parse the given string of `xml`. + * + * @param {String} xml + * @return {Object} + * @api public */ - function is(prefix) { - return 0 == xml.indexOf(prefix); - } -} - -// I would need var parseString = require('../node_modules/xml-parser/index.js'); for urequire? - -// fix missing semicolons -const entities = { - "Α": "\\Alpha", - "Α": "\\Alpha", - "Α": "\\Alpha", - "\\u0391;": "\\Alpha", - "Β": "\\Beta", - "Β": "\\Beta", - "Β": "\\Beta", - "\\u0392;": "\\Beta", - "Γ": "\\Gamma", - "Γ": "\\Gamma", - "Γ": "\\Gamma", - "\\u0393;": "\\Gamma", - "Δ": "\\Delta", - "Δ": "\\Delta", - "Δ": "\\Delta", - "\\u0394;": "\\Delta", - "Ε": "\\Epsilon", - "Ε": "\\Epsilon", - "Ε": "\\Epsilon", - "\\u0395;": "\\Epsilon", - "Ζ": "\\Zeta", - "Ζ": "\\Zeta", - "Ζ": "\\Zeta", - "\\u0396;": "\\Zeta", - "Η": "\\Eta", - "Η": "\\Eta", - "Η": "\\Eta", - "\\u0397;": "\\Eta", - "Θ": "\\Theta", - "Θ": "\\Theta", - "Θ": "\\Theta", - "\\u0398;": "\\Theta", - "Ι": "\\Iota", - "Ι": "\\Iota", - "Ι": "\\Iota", - "\\u0399;": "\\Iota", - "Κ": "\\Kappa", - "Κ": "\\Kappa", - "Κ": "\\Kappa", - "\\u039A;": "\\Kappa", - "Λ": "\\Lambda", - "Λ": "\\Lambda", - "Λ": "\\Lambda", - "\\u039B;": "\\Lambda", - "Μ": "\\Mu", - "Μ": "\\Mu", - "Μ": "\\Mu", - "\\u039C;": "\\Mu", - "Ν": "\\Nu", - "Ν": "\\Nu", - "Ν": "\\Nu", - "\\u039D;": "\\Nu", - "Ξ": "\\Xi", - "Ξ": "\\Xi", - "Ξ": "\\Xi", - "\\u039E;": "\\Xi", - "Ο": "\\Omicron", - "Ο": "\\Omicron", - "Ο": "\\Omicron", - "\\u039F;": "\\Omicron", - "Π": "\\Pi", - "Π": "\\Pi", - "Π": "\\Pi", - "\\u03A0;": "\\Pi", - "Ρ": "\\Rho", - "Ρ": "\\Rho", - "Ρ": "\\Rho", - "\\u03A1;": "\\Rho", - "Σ": "\\Sigma", - "Σ": "\\Sigma", - "Σ": "\\Sigma", - "\\u03A3;": "\\Sigma", - "Τ": "\\Tau", - "Τ": "\\Tau", - "Τ": "\\Tau", - "\\u03A4;": "\\Tau", - "Υ": "\\Upsilon", - "Υ": "\\Upsilon", - "Υ": "\\Upsilon", - "\\u03A5;": "\\Upsilon", - "Φ": "\\Phi", - "Φ": "\\Phi", - "Φ": "\\Phi", - "\\u03A6;": "\\Phi", - "Χ": "\\Chi", - "Χ": "\\Chi", - "Χ": "\\Chi", - "\\u03A7;": "\\Chi", - "Ψ": "\\Psi", - "Ψ": "\\Psi", - "Ψ": "\\Psi", - "\\u03A8;": "\\Psi", - "Ω": "\\Omega", - "Ω": "\\Omega", - "Ω": "\\Omega", - "\\u03A9;": "\\Omega", - "α": "\\alpha", - "α": "\\alpha", - "α": "\\alpha", - "\\u03B1;": "\\alpha", - "β": "\\beta", - "β": "\\beta", - "β": "\\beta", - "\\u03B2;": "\\beta", - "γ": "\\gamma", - "γ": "\\gamma", - "γ": "\\gamma", - "\\u03B3;": "\\gamma", - "δ": "\\delta", - "δ": "\\delta", - "δ": "\\delta", - "\\u03B4;": "\\delta", - "ε": "\\epsilon", - "ε": "\\epsilon", - "ε": "\\epsilon", - "\\u03B5;": "\\epsilon", - "ζ": "\\zeta", - "ζ": "\\zeta", - "ζ": "\\zeta", - "\\u03B6;": "\\zeta", - "η": "\\eta", - "η": "\\eta", - "η": "\\eta", - "\\u03B7;": "\\eta", - "θ": "\\theta", - "θ": "\\theta", - "θ": "\\theta", - "\\u03B8;": "\\theta", - "ι": "\\iota", - "ι": "\\iota", - "ι": "\\iota", - "\\u03B9;": "\\iota", - "κ": "\\kappa", - "κ": "\\kappa", - "κ": "\\kappa", - "\\u03BA;": "\\kappa", - "λ": "\\lambda", - "λ": "\\lambda", - "λ": "\\lambda", - "\\u03BB;": "\\lambda", - "μ": "\\mu", - "μ": "\\mu", - "μ": "\\mu", - "\\u03BC;": "\\mu", - "ν": "\\nu", - "ν": "\\nu", - "ν": "\\nu", - "\\u03BD;": "\\nu", - "ξ": "\\xi", - "ξ": "\\xi", - "ξ": "\\xi", - "\\u03BE;": "\\xi", - "ο": "\\omicron", - "ο": "\\omicron", - "ο": "\\omicron", - "\\u03BF;": "\\omicron", - "π": "\\pi", - "π": "\\pi", - "π": "\\pi", - "\\u03C0;": "\\pi", - "ρ": "\\rho", - "ρ": "\\rho", - "ρ": "\\rho", - "\\u03C1;": "\\rho", - "ς": "\\sigma", - ";": "\\sigma", - "ς": "\\sigma", - "\\u03C2;": "\\sigma", - "σ": "\\sigma", - "σ": "\\sigma", - "σ": "\\sigma", - "\\u03C3;": "\\sigma", - "τ": "\\tau", - "τ": "\\tau", - "τ": "\\tau", - "\\u03C4;": "\\tau", - "υ": "\\upsilon", - "υ": "\\upsilon", - "υ": "\\upsilon", - "\\u03C5;": "\\upsilon", - "φ": "\\phi", - "φ": "\\phi", - "φ": "\\phi", - "\\u03C6;": "\\phi", - "χ": "\\chi", - "χ": "\\chi", - "χ": "\\chi", - "\\u03C7;": "\\chi", - "ψ": "\\psi", - "ψ": "\\psi", - "ψ": "\\psi", - "\\u03C8;": "\\psi", - "ω": "\\omega", - "ω": "\\omega", - "ω": "\\omega", - "\\u03C9;": "\\omega", - "−": "-", - "−": "-", - "∞": "\\infty", - "∞": "\\infty", - "∞": "\\infty", - "⋅": "\\cdot", - "⋅": "\\cdot", - "⋅": "\\cdot", - "×": "\\times", - "×": "\\times", - "×": "\\times" -}; - -class mmlToLatex{ - - // This is an awfully weak MathML parser, but it's good enough for what MathJax generates - parse(mml) { - // math identifier - if (mml.name === 'mi') { - if (entities[mml.content]) { - return entities[mml.content]; - } + function parse$3(xml) { + xml = xml.trim(); - if (mml.content.length > 1) { - return "\\" + mml.content; - } else { - return mml.content; - } - }else if (mml.name === 'mn') { // math number - return mml.content; - }else if (mml.name === 'msup') { // superscript - return this.parse( mml.children[0] ) + '^{' + this.parse( mml.children[1] ) + "}"; - }else if (mml.name === 'mroot') {// root - return "\\sqrt[" + this.parse( mml.children[1] ) + ']{' + this.parse( mml.children[1] ) + "}"; - }else if (mml.name === 'mfrac') { - return "\\frac{" + this.parse( mml.children[0] ) + '}{' + this.parse( mml.children[1] ) + "}"; - }else if (mml.name === 'msqrt') { // superscript - return "\\sqrt{" + mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' ') + "}"; - }else if (mml.name === 'mo') { // math operator - if (entities[mml.content]) { - return entities[mml.content]; - } else if (mml.content === '⁡') { - return ' '; - } else { - return mml.content; - } - }else if ((mml.name === "mrow") && (mml.attributes.class === "MJX-TeXAtom-ORD")) { - return mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' '); - } else if ((mml.name === 'math') || (mml.name === 'mrow')) { - return '(' + mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' ') + ')'; - } - } + // strip comments + xml = xml.replace(//g, ''); - convert(xml) { - var result = this.parse( xmlParser(xml).root ); - // console.log( "parsed =", JSON.stringify(result) ); - return result; - }; + return document(); -} + /** + * XML document. + */ -class mmlToAst{ - constructor(){ - this.mmlToLatex = new mmlToLatex(); - this.latexToAst = new latexToAst(); - } + function document() { + return { + declaration: declaration(), + root: tag() + } + } - convert(mml){ - return this.latexToAst.convert(this.mmlToLatex.convert(mml)); - } -} + /** + * Declaration. + */ -class mmlToGuppy{ - constructor(){ - this.mmlToLatex = new mmlToLatex(); - this.latexToAst = new latexToAst(); - this.astToGuppy = new astToGuppy(); - } + function declaration() { + var m = match(/^<\?xml\s*/); + if (!m) return; - convert(mml){ - return this.astToGuppy.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); - } -} + // tag + var node = { + attributes: {} + }; -class mmlToMathjs{ - constructor(){ - this.mmlToLatex = new mmlToLatex(); - this.latexToAst = new latexToAst(); - this.astToMathjs = new astToMathjs(); - } + // attributes + while (!(eos() || is('?>'))) { + var attr = attribute(); + if (!attr) return node; + node.attributes[attr.name] = attr.value; + } - convert(mml){ - return this.astToMathjs.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); - } -} + match(/\?>\s*/); + + return node; + } + + /** + * Tag. + */ + + function tag() { + debug$1('tag %j', xml); + var m = match(/^<([\w-:.]+)\s*/); + if (!m) return; + + // name + var node = { + name: m[1], + attributes: {}, + children: [] + }; + + // attributes + while (!(eos() || is('>') || is('?>') || is('/>'))) { + var attr = attribute(); + if (!attr) return node; + node.attributes[attr.name] = attr.value; + } + + // self closing tag + if (match(/^\s*\/>\s*/)) { + return node; + } + + match(/\??>\s*/); + + // content + node.content = content(); + + // children + var child; + while (child = tag()) { + node.children.push(child); + } + + // closing + match(/^<\/[\w-:.]+>\s*/); + + return node; + } + + /** + * Text content. + */ + + function content() { + debug$1('content %j', xml); + var m = match(/^([^<]*)/); + if (m) return m[1]; + return ''; + } + + /** + * Attribute. + */ + + function attribute() { + debug$1('attribute %j', xml); + var m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/); + if (!m) return; + return { name: m[1], value: strip(m[2]) } + } + + /** + * Strip quotes from `val`. + */ + + function strip(val) { + return val.replace(/^['"]|['"]$/g, ''); + } + + /** + * Match `re` and advance the string. + */ + + function match(re) { + var m = xml.match(re); + if (!m) return; + xml = xml.slice(m[0].length); + return m; + } + + /** + * End-of-source. + */ + + function eos() { + return 0 == xml.length; + } + + /** + * Check for `prefix`. + */ + + function is(prefix) { + return 0 == xml.indexOf(prefix); + } + } + + // I would need var parseString = require('../node_modules/xml-parser/index.js'); for urequire? + + // fix missing semicolons + const entities = { + "Α": "\\Alpha", + "Α": "\\Alpha", + "Α": "\\Alpha", + "\\u0391;": "\\Alpha", + "Β": "\\Beta", + "Β": "\\Beta", + "Β": "\\Beta", + "\\u0392;": "\\Beta", + "Γ": "\\Gamma", + "Γ": "\\Gamma", + "Γ": "\\Gamma", + "\\u0393;": "\\Gamma", + "Δ": "\\Delta", + "Δ": "\\Delta", + "Δ": "\\Delta", + "\\u0394;": "\\Delta", + "Ε": "\\Epsilon", + "Ε": "\\Epsilon", + "Ε": "\\Epsilon", + "\\u0395;": "\\Epsilon", + "Ζ": "\\Zeta", + "Ζ": "\\Zeta", + "Ζ": "\\Zeta", + "\\u0396;": "\\Zeta", + "Η": "\\Eta", + "Η": "\\Eta", + "Η": "\\Eta", + "\\u0397;": "\\Eta", + "Θ": "\\Theta", + "Θ": "\\Theta", + "Θ": "\\Theta", + "\\u0398;": "\\Theta", + "Ι": "\\Iota", + "Ι": "\\Iota", + "Ι": "\\Iota", + "\\u0399;": "\\Iota", + "Κ": "\\Kappa", + "Κ": "\\Kappa", + "Κ": "\\Kappa", + "\\u039A;": "\\Kappa", + "Λ": "\\Lambda", + "Λ": "\\Lambda", + "Λ": "\\Lambda", + "\\u039B;": "\\Lambda", + "Μ": "\\Mu", + "Μ": "\\Mu", + "Μ": "\\Mu", + "\\u039C;": "\\Mu", + "Ν": "\\Nu", + "Ν": "\\Nu", + "Ν": "\\Nu", + "\\u039D;": "\\Nu", + "Ξ": "\\Xi", + "Ξ": "\\Xi", + "Ξ": "\\Xi", + "\\u039E;": "\\Xi", + "Ο": "\\Omicron", + "Ο": "\\Omicron", + "Ο": "\\Omicron", + "\\u039F;": "\\Omicron", + "Π": "\\Pi", + "Π": "\\Pi", + "Π": "\\Pi", + "\\u03A0;": "\\Pi", + "Ρ": "\\Rho", + "Ρ": "\\Rho", + "Ρ": "\\Rho", + "\\u03A1;": "\\Rho", + "Σ": "\\Sigma", + "Σ": "\\Sigma", + "Σ": "\\Sigma", + "\\u03A3;": "\\Sigma", + "Τ": "\\Tau", + "Τ": "\\Tau", + "Τ": "\\Tau", + "\\u03A4;": "\\Tau", + "Υ": "\\Upsilon", + "Υ": "\\Upsilon", + "Υ": "\\Upsilon", + "\\u03A5;": "\\Upsilon", + "Φ": "\\Phi", + "Φ": "\\Phi", + "Φ": "\\Phi", + "\\u03A6;": "\\Phi", + "Χ": "\\Chi", + "Χ": "\\Chi", + "Χ": "\\Chi", + "\\u03A7;": "\\Chi", + "Ψ": "\\Psi", + "Ψ": "\\Psi", + "Ψ": "\\Psi", + "\\u03A8;": "\\Psi", + "Ω": "\\Omega", + "Ω": "\\Omega", + "Ω": "\\Omega", + "\\u03A9;": "\\Omega", + "α": "\\alpha", + "α": "\\alpha", + "α": "\\alpha", + "\\u03B1;": "\\alpha", + "β": "\\beta", + "β": "\\beta", + "β": "\\beta", + "\\u03B2;": "\\beta", + "γ": "\\gamma", + "γ": "\\gamma", + "γ": "\\gamma", + "\\u03B3;": "\\gamma", + "δ": "\\delta", + "δ": "\\delta", + "δ": "\\delta", + "\\u03B4;": "\\delta", + "ε": "\\epsilon", + "ε": "\\epsilon", + "ε": "\\epsilon", + "\\u03B5;": "\\epsilon", + "ζ": "\\zeta", + "ζ": "\\zeta", + "ζ": "\\zeta", + "\\u03B6;": "\\zeta", + "η": "\\eta", + "η": "\\eta", + "η": "\\eta", + "\\u03B7;": "\\eta", + "θ": "\\theta", + "θ": "\\theta", + "θ": "\\theta", + "\\u03B8;": "\\theta", + "ι": "\\iota", + "ι": "\\iota", + "ι": "\\iota", + "\\u03B9;": "\\iota", + "κ": "\\kappa", + "κ": "\\kappa", + "κ": "\\kappa", + "\\u03BA;": "\\kappa", + "λ": "\\lambda", + "λ": "\\lambda", + "λ": "\\lambda", + "\\u03BB;": "\\lambda", + "μ": "\\mu", + "μ": "\\mu", + "μ": "\\mu", + "\\u03BC;": "\\mu", + "ν": "\\nu", + "ν": "\\nu", + "ν": "\\nu", + "\\u03BD;": "\\nu", + "ξ": "\\xi", + "ξ": "\\xi", + "ξ": "\\xi", + "\\u03BE;": "\\xi", + "ο": "\\omicron", + "ο": "\\omicron", + "ο": "\\omicron", + "\\u03BF;": "\\omicron", + "π": "\\pi", + "π": "\\pi", + "π": "\\pi", + "\\u03C0;": "\\pi", + "ρ": "\\rho", + "ρ": "\\rho", + "ρ": "\\rho", + "\\u03C1;": "\\rho", + "ς": "\\sigma", + ";": "\\sigma", + "ς": "\\sigma", + "\\u03C2;": "\\sigma", + "σ": "\\sigma", + "σ": "\\sigma", + "σ": "\\sigma", + "\\u03C3;": "\\sigma", + "τ": "\\tau", + "τ": "\\tau", + "τ": "\\tau", + "\\u03C4;": "\\tau", + "υ": "\\upsilon", + "υ": "\\upsilon", + "υ": "\\upsilon", + "\\u03C5;": "\\upsilon", + "φ": "\\phi", + "φ": "\\phi", + "φ": "\\phi", + "\\u03C6;": "\\phi", + "χ": "\\chi", + "χ": "\\chi", + "χ": "\\chi", + "\\u03C7;": "\\chi", + "ψ": "\\psi", + "ψ": "\\psi", + "ψ": "\\psi", + "\\u03C8;": "\\psi", + "ω": "\\omega", + "ω": "\\omega", + "ω": "\\omega", + "\\u03C9;": "\\omega", + "−": "-", + "−": "-", + "∞": "\\infty", + "∞": "\\infty", + "∞": "\\infty", + "⋅": "\\cdot", + "⋅": "\\cdot", + "⋅": "\\cdot", + "×": "\\times", + "×": "\\times", + "×": "\\times" + }; + + class mmlToLatex{ + + // This is an awfully weak MathML parser, but it's good enough for what MathJax generates + parse(mml) { + // math identifier + if (mml.name === 'mi') { + if (entities[mml.content]) { + return entities[mml.content]; + } + + if (mml.content.length > 1) { + return "\\" + mml.content; + } else { + return mml.content; + } + }else if (mml.name === 'mn') { // math number + return mml.content; + }else if (mml.name === 'msup') { // superscript + return this.parse( mml.children[0] ) + '^{' + this.parse( mml.children[1] ) + "}"; + }else if (mml.name === 'mroot') {// root + return "\\sqrt[" + this.parse( mml.children[1] ) + ']{' + this.parse( mml.children[1] ) + "}"; + }else if (mml.name === 'mfrac') { + return "\\frac{" + this.parse( mml.children[0] ) + '}{' + this.parse( mml.children[1] ) + "}"; + }else if (mml.name === 'msqrt') { // superscript + return "\\sqrt{" + mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' ') + "}"; + }else if (mml.name === 'mo') { // math operator + if (entities[mml.content]) { + return entities[mml.content]; + } else if (mml.content === '⁡') { + return ' '; + } else { + return mml.content; + } + }else if ((mml.name === "mrow") && (mml.attributes.class === "MJX-TeXAtom-ORD")) { + return mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' '); + } else if ((mml.name === 'math') || (mml.name === 'mrow')) { + return '(' + mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' ') + ')'; + } + } + + convert(xml) { + var result = this.parse( xmlParser(xml).root ); + // console.log( "parsed =", JSON.stringify(result) ); + return result; + }; -class mmlToText{ - constructor(){ - this.mmlToLatex = new mmlToLatex(); - this.latexToAst = new latexToAst(); - this.astToText = new astToText(); } - convert(mml){ - return this.astToText.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); + class mmlToAst{ + constructor(){ + this.mmlToLatex = new mmlToLatex(); + this.latexToAst = new latexToAst(); + } + + convert(mml){ + return this.latexToAst.convert(this.mmlToLatex.convert(mml)); + } } -} -class textToGuppy{ - constructor(){ - this.textToAst = new textToAst(); - this.astToGuppy = new astToGuppy(); + class mmlToGuppy{ + constructor(){ + this.mmlToLatex = new mmlToLatex(); + this.latexToAst = new latexToAst(); + this.astToGuppy = new astToGuppy(); + } + + convert(mml){ + return this.astToGuppy.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); + } } - convert(text){ - return this.astToGuppy.convert(this.textToAst.convert(text)); + class mmlToMathjs{ + constructor(){ + this.mmlToLatex = new mmlToLatex(); + this.latexToAst = new latexToAst(); + this.astToMathjs = new astToMathjs(); + } + + convert(mml){ + return this.astToMathjs.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); + } } -} -class textToLatex{ - constructor(){ - this.textToAst = new textToAst(); - this.astToLatex = new astToLatex(); + class mmlToText{ + constructor(){ + this.mmlToLatex = new mmlToLatex(); + this.latexToAst = new latexToAst(); + this.astToText = new astToText(); + } + + convert(mml){ + return this.astToText.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); + } } - convert(text){ - return this.astToLatex.convert(this.textToAst.convert(text)); + class textToGuppy{ + constructor(){ + this.textToAst = new textToAst(); + this.astToGuppy = new astToGuppy(); + } + + convert(text){ + return this.astToGuppy.convert(this.textToAst.convert(text)); + } } -} -class textToMathjs{ - constructor(){ - this.textToAst = new textToAst(); - this.astToMathjs = new astToMathjs(); + class textToLatex{ + constructor(){ + this.textToAst = new textToAst(); + this.astToLatex = new astToLatex(); + } + + convert(text){ + return this.astToLatex.convert(this.textToAst.convert(text)); + } } - convert(text){ - return this.astToMathjs.convert(this.textToAst.convert(text)); + class textToMathjs{ + constructor(){ + this.textToAst = new textToAst(); + this.astToMathjs = new astToMathjs(); + } + + convert(text){ + return this.astToMathjs.convert(this.textToAst.convert(text)); + } } -} -var converters = /*#__PURE__*/Object.freeze({ - astToLatexObj: astToLatex, - astToTextObj: astToText, - astToGuppyObj: astToGuppy, - astToMathjsObj: astToMathjs, - latexToAstObj: latexToAst, - latexToGuppyObj: latexToGuppy, - latexToMathjsObj: latexToMathjs, - latexToTextObj: latexToText, - mathjsToAstObj: mathjsToAst, - mathjsToGuppyObj: mathjsToGuppy, - mathjsToLatexObj: mathjsToLatex, - mathjsToTextObj: mathjsToText, - mmlToAstObj: mmlToAst, - mmlToGuppyObj: mmlToGuppy, - mmlToLatexObj: mmlToLatex, - mmlToMathjsObj: mmlToMathjs, - mmlToTextObj: mmlToText, - textToAstObj: textToAst, - textToGuppyObj: textToGuppy, - textToLatexObj: textToLatex, - textToMathjsObj: textToMathjs, - astToGLSL: astToGLSL -}); + var converters = /*#__PURE__*/Object.freeze({ + astToLatexObj: astToLatex, + astToTextObj: astToText, + astToGuppyObj: astToGuppy, + astToMathjsObj: astToMathjs, + latexToAstObj: latexToAst, + latexToGuppyObj: latexToGuppy, + latexToMathjsObj: latexToMathjs, + latexToTextObj: latexToText, + mathjsToAstObj: mathjsToAst, + mathjsToGuppyObj: mathjsToGuppy, + mathjsToLatexObj: mathjsToLatex, + mathjsToTextObj: mathjsToText, + mmlToAstObj: mmlToAst, + mmlToGuppyObj: mmlToGuppy, + mmlToLatexObj: mmlToLatex, + mmlToMathjsObj: mmlToMathjs, + mmlToTextObj: mmlToText, + textToAstObj: textToAst, + textToGuppyObj: textToGuppy, + textToLatexObj: textToLatex, + textToMathjsObj: textToMathjs, + astToGLSL: astToGLSL + }); + + var textToAst$4 = new textToAst(); + var latexToAst$1 = new latexToAst(); + var mmlToAst$1 = new mmlToAst(); -var textToAst$4 = new textToAst(); -var latexToAst$1 = new latexToAst(); -var mmlToAst$1 = new mmlToAst(); + var utils$2 = { match, flatten, unflattenLeft, unflattenRight }; -var utils$2 = { match, flatten, unflattenLeft, unflattenRight }; + function Expression(ast, context) { + this.tree = flatten(ast); + this.context = context; -function Expression(ast, context) { - this.tree = flatten(ast); - this.context = context; + this.toJSON = function () { + let serializedExpression = { + objectType: "math-expression", + tree: this.tree, + }; + let assumptions = {}; + for(let item in this.context.assumptions) { + if(Object.keys(this.context.assumptions[item]).length > 0) { + assumptions[item] = this.context.assumptions[item]; + } + } + if(Object.keys(assumptions).length > 0) { + serializedExpression.assumptions = assumptions; + } - this.toJSON = function () { - let serializedExpression = { - objectType: "math-expression", - tree: this.tree, + return serializedExpression; }; - let assumptions = {}; - for(let item in this.context.assumptions) { - if(Object.keys(this.context.assumptions[item]).length > 0) { - assumptions[item] = this.context.assumptions[item]; + } + + function extend$4(object, tree_to_expression) { + // if tree_to_expression, convert ast to expression + + // arguments object is NOT an array + var args = flatten_array(Array.prototype.slice.call(arguments, 2)); + + args.forEach( + function (rhs) { + if (rhs) { + for (var property in rhs) { + if (tree_to_expression) { + (function () { + var prop = property; + object[prop] = function () { + return this.fromAst( + rhs[prop].apply(null, arguments)); + }; + })(); + } + else + object[property] = rhs[property]; + } + } } - } - if(Object.keys(assumptions).length > 0) { - serializedExpression.assumptions = assumptions; - } + ); - return serializedExpression; - }; -} + return object; + } -function extend$4(object, tree_to_expression) { - // if tree_to_expression, convert ast to expression + function extend_prototype(object, tree_to_expression) { + // append a properties to object prepending this as first argument + // if tree_to_expression, convert ast to expression - // arguments object is NOT an array - var args = flatten_array(Array.prototype.slice.call(arguments, 2)); + // arguments object is NOT an array + var args = flatten_array(Array.prototype.slice.call(arguments, 2)); - args.forEach( - function (rhs) { - if (rhs) { - for (var property in rhs) { - if (tree_to_expression) { + args.forEach( + function (rhs) { + if (rhs) { + for (var property in rhs) { + // prepend this as first argument (function () { var prop = property; object[prop] = function () { - return this.fromAst( - rhs[prop].apply(null, arguments)); + var arg2 = [this].concat( + Array.prototype.slice.call(arguments)); + // convert to expression if output_expression + if (tree_to_expression) + return this.context.fromAst( + rhs[prop].apply(null, arg2)); + else + return rhs[prop].apply(null, arg2); }; })(); } - else - object[property] = rhs[property]; - } - } - } - ); - - return object; -} - -function extend_prototype(object, tree_to_expression) { - // append a properties to object prepending this as first argument - // if tree_to_expression, convert ast to expression - - // arguments object is NOT an array - var args = flatten_array(Array.prototype.slice.call(arguments, 2)); - - args.forEach( - function (rhs) { - if (rhs) { - for (var property in rhs) { - // prepend this as first argument - (function () { - var prop = property; - object[prop] = function () { - var arg2 = [this].concat( - Array.prototype.slice.call(arguments)); - // convert to expression if output_expression - if (tree_to_expression) - return this.context.fromAst( - rhs[prop].apply(null, arg2)); - else - return rhs[prop].apply(null, arg2); - }; - })(); } } - } - ); + ); - return object; -} + return object; + } -/****************************************************************/ -/* Factory methods */ + /****************************************************************/ + /* Factory methods */ -function create_from_multiple(expr, pars) { - if (Array.isArray(expr) || (typeof expr === 'number')) { - return new Expression(expr, Context); - } - else if (typeof expr === 'string') { - try { - return new Expression(textToAst$4.convert(expr), Context); + function create_from_multiple(expr, pars) { + if (Array.isArray(expr) || (typeof expr === 'number')) { + return new Expression(expr, Context); } - catch (e_text) { + else if (typeof expr === 'string') { try { - return new Expression(latexToAst$1.convert(expr), Context); + return new Expression(textToAst$4.convert(expr), Context); } - catch (e_latex) { + catch (e_text) { try { - return new Expression(mmlToAst$1.convert(expr), Context); - } - catch (e_mml) { - if (expr.indexOf("\\") !== -1) - throw (e_latex) - if (expr.indexOf(" 2 && is_associative[operator]) { - var result = [operator, operands[0], undefined]; - var next = result; - - for (var i = 1; i < operands.length - 1; i++) { - next[2] = [operator, operands[i], undefined]; - next = next[2]; - } - - next[2] = operands[operands.length - 1]; - - return result; - } - - return [operator].concat(operands); - }; - - const unflattenLeft = function (expr) { - // unflatten tree with associate operator op - // into a left heavy tree; - - var tree = get_tree(expr); - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - - operands = operands.map(function (v, i) { - return unflattenLeft(v); - }); - - if (operands.length > 2 && is_associative[operator]) { - var result = [operator, undefined, operands[operands.length-1]]; - var next = result; - - for (var i = operands.length - 2; i > 0; i--) { - next[1] = [operator, undefined, operands[i]]; - next = next[1]; - } - - next[1] = operands[0]; - - return result; - } - - return [operator].concat(operands); - }; - - const allChildren = function (tree) { - // find all children of operator of tree as though it had been flattened - - if (!Array.isArray(tree)) - return []; - - var operator = tree[0]; - var operands = tree.slice(1); - - if (!is_associative[operator]) - return operands; - - return operands.reduce(function (a, b) { - if (Array.isArray(b) && b[0] === operator) { - return a.concat(allChildren(b)); - } - else - return a.concat([b]); - }, []); - - }; - - function remove_duplicate_negatives(tree) { - // remove pairs of consecutive minus signs - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === '-' && operands[0][0] === '-') { - return remove_duplicate_negatives(operands[0][1]); - } - - operands = operands.map(remove_duplicate_negatives); - - return [operator].concat(operands); - - } - - function normalize_negatives_in_factors(tree) { - // if any factors contain a negative, - // place negative outside factor - // - // run remove_duplicates_negatives before and after - // running this function to make sure all negatives are addressed - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - - operands = operands.map(normalize_negatives_in_factors); - - if (operator !== '*' && operator !== '/') - return [operator].concat(operands); - - var sign = 1; - var operands_no_negatives = []; - - for (var i = 0; i < operands.length; i++) { - if (operands[i][0] === '-') { - sign *= -1; - operands_no_negatives.push(operands[i][1]); - } - else { - operands_no_negatives.push(operands[i]); - } - } - var result = [operator].concat(operands_no_negatives); - if (sign === -1) - result = ['-', result]; - - return result; - } - - - function normalize_negatives(expr_or_tree) { - // Remove duplicate negatives and pull all negatives outside factors - var tree = get_tree(expr_or_tree); - - tree = remove_duplicate_negatives(tree); - tree = normalize_negatives_in_factors(tree); - tree = remove_duplicate_negatives(tree); - - return tree; - } - - - function sort_key(tree, params={}) { - if (typeof tree === 'number') { - if (params.ignore_negatives) - return [0, 'number', Math.abs(tree)]; - return [0, 'number', tree]; - } - if (typeof tree === 'string') { - // if string is a constant, return number with value? - return [1, 'symbol', tree]; - } - if (typeof tree === 'boolean') { - return [1, 'boolean', tree]; - } - - - if (!Array.isArray(tree)) - return [-1, 'unknown', tree]; - - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === 'apply') { - var key = [2, 'function', operands[0]]; - - var f_args = operands[1]; - - var n_args = 1; - - var arg_keys = []; - - if (Array.isArray(f_args)) { - - f_args = f_args.slice(1); // remove vector operator - - n_args = f_args.length; - - arg_keys = f_args.map(x=>sort_key(x,params)); - - - } - else { - arg_keys = [sort_key(f_args,params)]; - } - - key.push([n_args, arg_keys]); - - return key; - } - - var n_factors = operands.length; - - var factor_keys = operands.map(sort_key, params); - - - if (operator === "*") { - return [4, 'product', n_factors, factor_keys]; - } - - if (operator === "/") { - return [4, 'quotient', n_factors, factor_keys]; - } - - if (operator === "+") { - return [5, 'sum', n_factors, factor_keys]; - } - - if (operator === "-") { - if (params.ignore_negatives) - return factor_keys[0]; - return [6, 'minus', n_factors, factor_keys]; - } - - - return [7, operator, n_factors, factor_keys]; - - } - - - function arrayCompare(a,b) { - if(Array.isArray(a)) { - if(Array.isArray(b)) { - let minLength = Math.min(a.length, b.length); - for(let i=0; i < minLength; i++) { - let comp = arrayCompare(a[i], b[i]); - if(comp !== 0) { - return comp; - } - } - - // shorter array comes first - return a.length < b.length ? -1 : (a.length > b.length ? 1: 0); - - }else { - // non array comes before array - // a is the array - return 1; - } - } else { - if(Array.isArray(b)) { - // non-array comes before array - // b is the array - return -1; - } else { - // got to two scalar - return a < b ? -1 : (a > b ? 1: 0) - } - } - } - - function compare_function(a, b, params={}) { - - var key_a = sort_key(a, params); - var key_b = sort_key(b, params); - - return arrayCompare(key_a, key_b); - } - - - function coeff_factors_from_term(term, string_factors) { - if(typeof term === "string") { - let ind = string_factors.indexOf(term); - if(ind === -1) { - string_factors.push(term); - ind = string_factors.length - 1; - } - let f = []; - f[ind] = 1; - return { factor_contains: f, coeff: 1} - } else if(Array.isArray(term)) { - let operator = term[0]; - let operands = term.slice(1); - if(operator === '*') { - let coeff = []; - let f = []; - for(let factor of operands) { - if(typeof factor === "string") { - let ind = string_factors.indexOf(factor); - if(ind === -1) { - string_factors.push(factor); - ind = string_factors.length - 1; - } - if(f[ind] === undefined) { - f[ind] = 0; - } - f[ind]++; - continue; - } else if(Array.isArray(factor) && factor[0] === "^" || factor[0] === '-') { - let result = coeff_factors_from_term(factor, string_factors); - for(let ind in result.factor_contains) { - if(f[ind] === undefined) { - f[ind] = 0; - } - f[ind] += result.factor_contains[ind]; - } - if(result.coeff !== 1) { - coeff.push(result.coeff); - } - continue; - } - coeff.push(factor); - } - - if(coeff.length === 0) { - coeff = 1; - } else if(coeff.length === 1) { - coeff = coeff[0]; - } else { - coeff = ['*', ...coeff]; - } - return { factor_contains: f, coeff: coeff}; - } else if(operator === '^') { - let base = operands[0]; - let exponent = operands[1]; - let f=[]; - if(typeof base === "string" && Number.isFinite(exponent)) { - let ind = string_factors.indexOf(base); - if(ind === -1) { - string_factors.push(base); - ind = string_factors.length - 1; - } - f[ind] = exponent; - return {factor_contains: f, coeff: 1} - } - } else if(operator === '-') { - let result = coeff_factors_from_term(operands[0], string_factors); - let coeff = -1; - if(typeof result.coeff === "number") { - coeff *= result.coeff; - } else { - coeff = ['-', result.coeff]; - } - return {factor_contains: result.factor_contains, coeff: coeff}; - } else if(operator === '/') { - let result = coeff_factors_from_term(operands[0], string_factors); - let coeff = ['/', result.coeff, operands[1]]; - return {factor_contains: result.factor_contains, coeff: coeff}; - } - } - - return {factor_contains: [], coeff: term} - } - - function default_order(expr_or_tree, params) { - - if (params === undefined) - params = {}; - - var tree = get_tree(expr_or_tree); - - tree = flatten(tree); - tree = normalize_negatives(tree); - - function sort_ast(subTree) { - if (!Array.isArray(subTree)) - return subTree; - - var operator = subTree[0]; - var operands = subTree.slice(1); - - operands = operands.map(sort_ast); - - if (operator === "+" ) { - - // kludge to get sort order closer to lexographic order - - // TODO: clean this up - - // find all string factors - let string_factors = []; - let factors_by_term = []; - let coeffs_by_term = []; - for(let term of operands) { - let result = coeff_factors_from_term(term, string_factors); - factors_by_term.push(result.factor_contains); - coeffs_by_term.push(result.coeff); - } - - // factors_by_term = factors_by_term.map(x => Array.from(x, item => item || 0)) - - let variableInfo = []; - for(let [ind, varname] of string_factors.entries()) { - let thisvar = {varname: varname, exponents_in_term: []}; - for(let j=0; j< factors_by_term.length; j++) { - thisvar.exponents_in_term.push(factors_by_term[j][ind] || 0); - } - variableInfo.push(thisvar); - } - - variableInfo.sort((a,b) => a.varname < b.varname ? -1 : 1); - - let sort_keys_by_term = []; - - for(let i=0; i< coeffs_by_term.length; i++) { - let this_sort_key = variableInfo.reduce((a,c) => [...a, -c.exponents_in_term[i]],[]); - this_sort_key.push(sort_key(coeffs_by_term[i], params)); - sort_keys_by_term.push(this_sort_key); - } - - let terms_with_sort_key = []; - - for(let [ind,term] of operands.entries()) { - terms_with_sort_key.push({ - term: term, - sort_key: sort_keys_by_term[ind], - }); - } - - terms_with_sort_key.sort((a,b) => arrayCompare(a.sort_key, b.sort_key)); - - operands = terms_with_sort_key.map(x => x.term); - - // sort all operands of these arguments in default order - // determined by compare function - // operands.sort((a, b) => compare_function(a, b, params)); - } - else if (operator === "*" || operator === "=" - || operator === "and" || operator === "or" || operator === "ne" - || operator === "union" || operator === "intersect") { - - // TODO: determine if commutative - - // sort all operands of these arguments in default order - // determined by compare function - operands.sort((a, b) => compare_function(a, b, params)); - } - else if (operator === ">" || operator === "ge") { - // turn all greater thans to less thans - - operands = operands.reverse(); - if (operator === ">") - operator = "<"; - else - operator = "le"; - } - else if (operator === "gts") { - // turn all greater thans to less thans - var args = operands[0]; - var strict = operands[1]; - - if (args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); - - args = ['tuple'].concat(args.slice(1).reverse()); - strict = ['tuple'].concat(strict.slice(1).reverse()); - - operator = "lts"; - operands = [args, strict]; - - } - else if (operator === 'ni' || operator === 'notni' - || operator === 'superset' || operator === 'notsuperset') { - // turn all containment operators to have larger set at right - - operands = operands.reverse(); - if (operator === 'ni') - operator = 'in'; - else if (operator === 'notni') - operator = 'notin'; - else if (operator === 'superset') - operator = 'subset'; - else - operator = 'notsubset'; - } - else if (operator === '-') { - // when negating a product with a numerical first factor - // put negative sign in that first factor - if (operands[0][0] === '*') { - operands[0][1] = ['-', operands[0][1]]; - return operands[0]; - } - } - - return [operator].concat(operands); - } - - return normalize_negatives(sort_ast(tree)); - } - - var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - - function unwrapExports (x) { - return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; - } - - function createCommonjsModule(fn, module) { - return module = { exports: {} }, fn(module, module.exports), module.exports; - } - - /** - * Test whether a value is a BigNumber - * @param {*} x - * @return {boolean} - */ - var isBigNumber = function isBigNumber(x) { - return x && x.constructor.prototype.isBigNumber || false - }; - - var object = createCommonjsModule(function (module, exports) { - - - - /** - * 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 (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 (typeof a === typeof b) && (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 () {} }); - 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 ( 3) - ? param.slice(3) - : 'any'; - - var typeNames = types.split('|').map(trim) - .filter(notEmpty) - .filter(notIgnore); - - var matchingConversions = filterConversions(conversions, typeNames); - - var exactTypes = typeNames.map(function (typeName) { - var type = findTypeByName(typeName); - - return { - name: typeName, - typeIndex: findTypeIndex(type), - test: type.test, - conversion: null, - conversionIndex: -1 - }; - }); - - var convertibleTypes = matchingConversions.map(function (conversion) { - var type = findTypeByName(conversion.from); - - return { - name: conversion.from, - typeIndex: findTypeIndex(type), - test: type.test, - conversion: conversion, - conversionIndex: conversions.indexOf(conversion) - }; - }); - - return { - types: exactTypes.concat(convertibleTypes), - restParam: restParam - }; - } - - /** - * Parse a signature with comma separated parameters, - * like "number | boolean, ...string" - * @param {string} signature - * @param {function} fn - * @param {ConversionDef[]} conversions - * @return {Signature | null} signature - */ - function parseSignature (signature, fn, conversions) { - var params = []; - - if (signature.trim() !== '') { - params = signature - .split(',') - .map(trim) - .map(function (param, index, array) { - var parsedParam = parseParam(param, conversions); - - if (parsedParam.restParam && (index !== array.length - 1)) { - throw new SyntaxError('Unexpected rest parameter "' + param + '": ' + - 'only allowed for the last parameter'); - } - - return parsedParam; - }); - } - - if (params.some(isInvalidParam)) { - // invalid signature: at least one parameter has no types - // (they may have been filtered) - return null; - } - - return { - params: params, - fn: fn - }; - } - - /** - * Test whether a set of params contains a restParam - * @param {Param[]} params - * @return {boolean} Returns true when the last parameter is a restParam - */ - function hasRestParam(params) { - var param = last(params); - return param ? param.restParam : false; - } - - /** - * Test whether a parameter contains conversions - * @param {Param} param - * @return {boolean} Returns true when at least one of the parameters - * contains a conversion. - */ - function hasConversions(param) { - return param.types.some(function (type) { - return type.conversion != null; - }); - } - - /** - * Create a type test for a single parameter, which can have one or multiple - * types. - * @param {Param} param - * @return {function(x: *) : boolean} Returns a test function - */ - function compileTest(param) { - if (!param || param.types.length === 0) { - // nothing to do - return ok; - } - else if (param.types.length === 1) { - return findTypeByName(param.types[0].name).test; - } - else if (param.types.length === 2) { - var test0 = findTypeByName(param.types[0].name).test; - var test1 = findTypeByName(param.types[1].name).test; - return function or(x) { - return test0(x) || test1(x); - } - } - else { // param.types.length > 2 - var tests = param.types.map(function (type) { - return findTypeByName(type.name).test; - }); - return function or(x) { - for (var i = 0; i < tests.length; i++) { - if (tests[i](x)) { - return true; - } - } - return false; - } - } - } - - /** - * Create a test for all parameters of a signature - * @param {Param[]} params - * @return {function(args: Array<*>) : boolean} - */ - function compileTests(params) { - var tests, test0, test1; - - if (hasRestParam(params)) { - // variable arguments like '...number' - tests = initial(params).map(compileTest); - var varIndex = tests.length; - var lastTest = compileTest(last(params)); - var testRestParam = function (args) { - for (var i = varIndex; i < args.length; i++) { - if (!lastTest(args[i])) { - return false; - } - } - return true; - }; - - return function testArgs(args) { - for (var i = 0; i < tests.length; i++) { - if (!tests[i](args[i])) { - return false; - } - } - return testRestParam(args) && (args.length >= varIndex + 1); - }; - } - else { - // no variable arguments - if (params.length === 0) { - return function testArgs(args) { - return args.length === 0; - }; - } - else if (params.length === 1) { - test0 = compileTest(params[0]); - return function testArgs(args) { - return test0(args[0]) && args.length === 1; - }; - } - else if (params.length === 2) { - test0 = compileTest(params[0]); - test1 = compileTest(params[1]); - return function testArgs(args) { - return test0(args[0]) && test1(args[1]) && args.length === 2; - }; - } - else { // arguments.length > 2 - tests = params.map(compileTest); - return function testArgs(args) { - for (var i = 0; i < tests.length; i++) { - if (!tests[i](args[i])) { - return false; - } - } - return args.length === tests.length; - }; - } - } - } - - /** - * Find the parameter at a specific index of a signature. - * Handles rest parameters. - * @param {Signature} signature - * @param {number} index - * @return {Param | null} Returns the matching parameter when found, - * null otherwise. - */ - function getParamAtIndex(signature, index) { - return index < signature.params.length - ? signature.params[index] - : hasRestParam(signature.params) - ? last(signature.params) - : null - } - - /** - * Get all type names of a parameter - * @param {Signature} signature - * @param {number} index - * @param {boolean} excludeConversions - * @return {string[]} Returns an array with type names - */ - function getExpectedTypeNames (signature, index, excludeConversions) { - var param = getParamAtIndex(signature, index); - var types = param - ? excludeConversions - ? param.types.filter(isExactType) - : param.types - : []; - - return types.map(getTypeName); - } - - /** - * Returns the name of a type - * @param {Type} type - * @return {string} Returns the type name - */ - function getTypeName(type) { - return type.name; - } - - /** - * Test whether a type is an exact type or conversion - * @param {Type} type - * @return {boolean} Returns true when - */ - function isExactType(type) { - return type.conversion === null || type.conversion === undefined; - } - - /** - * Helper function for creating error messages: create an array with - * all available types on a specific argument index. - * @param {Signature[]} signatures - * @param {number} index - * @return {string[]} Returns an array with available types - */ - function mergeExpectedParams(signatures, index) { - var typeNames = uniq(flatMap(signatures, function (signature) { - return getExpectedTypeNames(signature, index, false); - })); - - return (typeNames.indexOf('any') !== -1) ? ['any'] : typeNames; - } - - /** - * Create - * @param {string} name The name of the function - * @param {array.<*>} args The actual arguments passed to the function - * @param {Signature[]} signatures A list with available signatures - * @return {TypeError} Returns a type error with additional data - * attached to it in the property `data` - */ - function createError(name, args, signatures) { - var err, expected; - var _name = name || 'unnamed'; - - // test for wrong type at some index - var matchingSignatures = signatures; - var index; - for (index = 0; index < args.length; index++) { - var nextMatchingDefs = matchingSignatures.filter(function (signature) { - var test = compileTest(getParamAtIndex(signature, index)); - return (index < signature.params.length || hasRestParam(signature.params)) && - test(args[index]); - }); - - if (nextMatchingDefs.length === 0) { - // no matching signatures anymore, throw error "wrong type" - expected = mergeExpectedParams(matchingSignatures, index); - if (expected.length > 0) { - var actualType = findTypeName(args[index]); - - err = new TypeError('Unexpected type of argument in function ' + _name + - ' (expected: ' + expected.join(' or ') + - ', actual: ' + actualType + ', index: ' + index + ')'); - err.data = { - category: 'wrongType', - fn: _name, - index: index, - actual: actualType, - expected: expected - }; - return err; - } - } - else { - matchingSignatures = nextMatchingDefs; - } - } - - // test for too few arguments - var lengths = matchingSignatures.map(function (signature) { - return hasRestParam(signature.params) ? Infinity : signature.params.length; - }); - if (args.length < Math.min.apply(null, lengths)) { - expected = mergeExpectedParams(matchingSignatures, index); - err = new TypeError('Too few arguments in function ' + _name + - ' (expected: ' + expected.join(' or ') + - ', index: ' + args.length + ')'); - err.data = { - category: 'tooFewArgs', - fn: _name, - index: args.length, - expected: expected - }; - return err; - } - - // test for too many arguments - var maxLength = Math.max.apply(null, lengths); - if (args.length > maxLength) { - err = new TypeError('Too many arguments in function ' + _name + - ' (expected: ' + maxLength + ', actual: ' + args.length + ')'); - err.data = { - category: 'tooManyArgs', - fn: _name, - index: args.length, - expectedLength: maxLength - }; - return err; - } - - err = new TypeError('Arguments of type "' + args.join(', ') + - '" do not match any of the defined signatures of function ' + _name + '.'); - err.data = { - category: 'mismatch', - actual: args.map(findTypeName) - }; - return err; - } - - /** - * Find the lowest index of all exact types of a parameter (no conversions) - * @param {Param} param - * @return {number} Returns the index of the lowest type in typed.types - */ - function getLowestTypeIndex (param) { - var min = 999; - - for (var i = 0; i < param.types.length; i++) { - if (isExactType(param.types[i])) { - min = Math.min(min, param.types[i].typeIndex); - } - } - - return min; - } - - /** - * Find the lowest index of the conversion of all types of the parameter - * having a conversion - * @param {Param} param - * @return {number} Returns the lowest index of the conversions of this type - */ - function getLowestConversionIndex (param) { - var min = 999; - - for (var i = 0; i < param.types.length; i++) { - if (!isExactType(param.types[i])) { - min = Math.min(min, param.types[i].conversionIndex); - } - } - - return min; - } - - /** - * Compare two params - * @param {Param} param1 - * @param {Param} param2 - * @return {number} returns a negative number when param1 must get a lower - * index than param2, a positive number when the opposite, - * or zero when both are equal - */ - function compareParams (param1, param2) { - var c; - - // compare having a rest parameter or not - c = param1.restParam - param2.restParam; - if (c !== 0) { - return c; - } - - // compare having conversions or not - c = hasConversions(param1) - hasConversions(param2); - if (c !== 0) { - return c; - } - - // compare the index of the types - c = getLowestTypeIndex(param1) - getLowestTypeIndex(param2); - if (c !== 0) { - return c; - } - - // compare the index of any conversion - return getLowestConversionIndex(param1) - getLowestConversionIndex(param2); - } - - /** - * Compare two signatures - * @param {Signature} signature1 - * @param {Signature} signature2 - * @return {number} returns a negative number when param1 must get a lower - * index than param2, a positive number when the opposite, - * or zero when both are equal - */ - function compareSignatures (signature1, signature2) { - var len = Math.min(signature1.params.length, signature2.params.length); - var i; - var c; - - // compare whether the params have conversions at all or not - c = signature1.params.some(hasConversions) - signature2.params.some(hasConversions); - if (c !== 0) { - return c; - } - - // next compare whether the params have conversions one by one - for (i = 0; i < len; i++) { - c = hasConversions(signature1.params[i]) - hasConversions(signature2.params[i]); - if (c !== 0) { - return c; - } - } - - // compare the types of the params one by one - for (i = 0; i < len; i++) { - c = compareParams(signature1.params[i], signature2.params[i]); - if (c !== 0) { - return c; - } - } - - // compare the number of params - return signature1.params.length - signature2.params.length; - } - - /** - * Get params containing all types that can be converted to the defined types. - * - * @param {ConversionDef[]} conversions - * @param {string[]} typeNames - * @return {ConversionDef[]} Returns the conversions that are available - * for every type (if any) - */ - function filterConversions(conversions, typeNames) { - var matches = {}; - - conversions.forEach(function (conversion) { - if (typeNames.indexOf(conversion.from) === -1 && - typeNames.indexOf(conversion.to) !== -1 && - !matches[conversion.from]) { - matches[conversion.from] = conversion; - } - }); - - return Object.keys(matches).map(function (from) { - return matches[from]; - }); - } - - /** - * Preprocess arguments before calling the original function: - * - if needed convert the parameters - * - in case of rest parameters, move the rest parameters into an Array - * @param {Param[]} params - * @param {function} fn - * @return {function} Returns a wrapped function - */ - function compileArgsPreprocessing(params, fn) { - var fnConvert = fn; - - // TODO: can we make this wrapper function smarter/simpler? - - if (params.some(hasConversions)) { - var restParam = hasRestParam(params); - var compiledConversions = params.map(compileArgConversion); - - fnConvert = function convertArgs() { - var args = []; - var last = restParam ? arguments.length - 1 : arguments.length; - for (var i = 0; i < last; i++) { - args[i] = compiledConversions[i](arguments[i]); - } - if (restParam) { - args[last] = arguments[last].map(compiledConversions[last]); - } - - return fn.apply(null, args); - }; - } - - var fnPreprocess = fnConvert; - if (hasRestParam(params)) { - var offset = params.length - 1; - - fnPreprocess = function preprocessRestParams () { - return fnConvert.apply(null, - slice(arguments, 0, offset).concat([slice(arguments, offset)])); - }; - } - - return fnPreprocess; - } - - /** - * Compile conversion for a parameter to the right type - * @param {Param} param - * @return {function} Returns the wrapped function that will convert arguments - * - */ - function compileArgConversion(param) { - var test0, test1, conversion0, conversion1; - var tests = []; - var conversions = []; - - param.types.forEach(function (type) { - if (type.conversion) { - tests.push(findTypeByName(type.conversion.from).test); - conversions.push(type.conversion.convert); - } - }); - - // create optimized conversion functions depending on the number of conversions - switch (conversions.length) { - case 0: - return function convertArg(arg) { - return arg; - } - - case 1: - test0 = tests[0]; - conversion0 = conversions[0]; - return function convertArg(arg) { - if (test0(arg)) { - return conversion0(arg) - } - return arg; - } - - case 2: - test0 = tests[0]; - test1 = tests[1]; - conversion0 = conversions[0]; - conversion1 = conversions[1]; - return function convertArg(arg) { - if (test0(arg)) { - return conversion0(arg) - } - if (test1(arg)) { - return conversion1(arg) - } - return arg; - } - - default: - return function convertArg(arg) { - for (var i = 0; i < conversions.length; i++) { - if (tests[i](arg)) { - return conversions[i](arg); - } - } - return arg; - } - } - } - - /** - * Convert an array with signatures into a map with signatures, - * where signatures with union types are split into separate signatures - * - * Throws an error when there are conflicting types - * - * @param {Signature[]} signatures - * @return {Object.} Returns a map with signatures - * as key and the original function - * of this signature as value. - */ - function createSignaturesMap(signatures) { - var signaturesMap = {}; - signatures.forEach(function (signature) { - if (!signature.params.some(hasConversions)) { - splitParams(signature.params, true).forEach(function (params) { - signaturesMap[stringifyParams(params)] = signature.fn; - }); - } - }); - - return signaturesMap; - } - - /** - * Split params with union types in to separate params. - * - * For example: - * - * splitParams([['Array', 'Object'], ['string', 'RegExp']) - * // returns: - * // [ - * // ['Array', 'string'], - * // ['Array', 'RegExp'], - * // ['Object', 'string'], - * // ['Object', 'RegExp'] - * // ] - * - * @param {Param[]} params - * @param {boolean} ignoreConversionTypes - * @return {Param[]} - */ - function splitParams(params, ignoreConversionTypes) { - function _splitParams(params, index, types) { - if (index < params.length) { - var param = params[index]; - var filteredTypes = ignoreConversionTypes - ? param.types.filter(isExactType) - : param.types; - var typeGroups; - - if (param.restParam) { - // split the types of a rest parameter in two: - // one with only exact types, and one with exact types and conversions - var exactTypes = filteredTypes.filter(isExactType); - typeGroups = exactTypes.length < filteredTypes.length - ? [exactTypes, filteredTypes] - : [filteredTypes]; - - } - else { - // split all the types of a regular parameter into one type per group - typeGroups = filteredTypes.map(function (type) { - return [type] - }); - } - - // recurse over the groups with types - return flatMap(typeGroups, function (typeGroup) { - return _splitParams(params, index + 1, types.concat([typeGroup])); - }); - - } - else { - // we've reached the end of the parameters. Now build a new Param - var splittedParams = types.map(function (type, typeIndex) { - return { - types: type, - restParam: (typeIndex === params.length - 1) && hasRestParam(params) - } - }); - - return [splittedParams]; - } - } - - return _splitParams(params, 0, []); - } - - /** - * Test whether two signatures have a conflicting signature - * @param {Signature} signature1 - * @param {Signature} signature2 - * @return {boolean} Returns true when the signatures conflict, false otherwise. - */ - function hasConflictingParams(signature1, signature2) { - var ii = Math.max(signature1.params.length, signature2.params.length); - - for (var i = 0; i < ii; i++) { - var typesNames1 = getExpectedTypeNames(signature1, i, true); - var typesNames2 = getExpectedTypeNames(signature2, i, true); - - if (!hasOverlap(typesNames1, typesNames2)) { - return false; - } - } - - var len1 = signature1.params.length; - var len2 = signature2.params.length; - var restParam1 = hasRestParam(signature1.params); - var restParam2 = hasRestParam(signature2.params); - - return restParam1 - ? restParam2 ? (len1 === len2) : (len2 >= len1) - : restParam2 ? (len1 >= len2) : (len1 === len2) - } - - /** - * Create a typed function - * @param {String} name The name for the typed function - * @param {Object.} signaturesMap - * An object with one or - * multiple signatures as key, and the - * function corresponding to the - * signature as value. - * @return {function} Returns the created typed function. - */ - function createTypedFunction(name, signaturesMap) { - if (Object.keys(signaturesMap).length === 0) { - throw new SyntaxError('No signatures provided'); - } - - // parse the signatures, and check for conflicts - var parsedSignatures = []; - Object.keys(signaturesMap) - .map(function (signature) { - return parseSignature(signature, signaturesMap[signature], typed.conversions); - }) - .filter(notNull) - .forEach(function (parsedSignature) { - // check whether this parameter conflicts with already parsed signatures - var conflictingSignature = findInArray(parsedSignatures, function (s) { - return hasConflictingParams(s, parsedSignature) - }); - if (conflictingSignature) { - throw new TypeError('Conflicting signatures "' + - stringifyParams(conflictingSignature.params) + '" and "' + - stringifyParams(parsedSignature.params) + '".'); - } - - parsedSignatures.push(parsedSignature); - }); - - // split and filter the types of the signatures, and then order them - var signatures = flatMap(parsedSignatures, function (parsedSignature) { - var params = parsedSignature ? splitParams(parsedSignature.params, false) : []; - - return params.map(function (params) { - return { - params: params, - fn: parsedSignature.fn - }; - }); - }).filter(notNull); - - signatures.sort(compareSignatures); - - // we create a highly optimized checks for the first couple of signatures with max 2 arguments - var ok0 = signatures[0] && signatures[0].params.length <= 2 && !hasRestParam(signatures[0].params); - var ok1 = signatures[1] && signatures[1].params.length <= 2 && !hasRestParam(signatures[1].params); - var ok2 = signatures[2] && signatures[2].params.length <= 2 && !hasRestParam(signatures[2].params); - var ok3 = signatures[3] && signatures[3].params.length <= 2 && !hasRestParam(signatures[3].params); - var ok4 = signatures[4] && signatures[4].params.length <= 2 && !hasRestParam(signatures[4].params); - var ok5 = signatures[5] && signatures[5].params.length <= 2 && !hasRestParam(signatures[5].params); - var allOk = ok0 && ok1 && ok2 && ok3 && ok4 && ok5; - - // compile the tests - var tests = signatures.map(function (signature) { - return compileTests(signature.params); - }); - - var test00 = ok0 ? compileTest(signatures[0].params[0]) : notOk; - var test10 = ok1 ? compileTest(signatures[1].params[0]) : notOk; - var test20 = ok2 ? compileTest(signatures[2].params[0]) : notOk; - var test30 = ok3 ? compileTest(signatures[3].params[0]) : notOk; - var test40 = ok4 ? compileTest(signatures[4].params[0]) : notOk; - var test50 = ok5 ? compileTest(signatures[5].params[0]) : notOk; - - var test01 = ok0 ? compileTest(signatures[0].params[1]) : notOk; - var test11 = ok1 ? compileTest(signatures[1].params[1]) : notOk; - var test21 = ok2 ? compileTest(signatures[2].params[1]) : notOk; - var test31 = ok3 ? compileTest(signatures[3].params[1]) : notOk; - var test41 = ok4 ? compileTest(signatures[4].params[1]) : notOk; - var test51 = ok5 ? compileTest(signatures[5].params[1]) : notOk; - - // compile the functions - var fns = signatures.map(function(signature) { - return compileArgsPreprocessing(signature.params, signature.fn) - }); - - var fn0 = ok0 ? fns[0] : undef; - var fn1 = ok1 ? fns[1] : undef; - var fn2 = ok2 ? fns[2] : undef; - var fn3 = ok3 ? fns[3] : undef; - var fn4 = ok4 ? fns[4] : undef; - var fn5 = ok5 ? fns[5] : undef; - - var len0 = ok0 ? signatures[0].params.length : -1; - var len1 = ok1 ? signatures[1].params.length : -1; - var len2 = ok2 ? signatures[2].params.length : -1; - var len3 = ok3 ? signatures[3].params.length : -1; - var len4 = ok4 ? signatures[4].params.length : -1; - var len5 = ok5 ? signatures[5].params.length : -1; - - // simple and generic, but also slow - var iStart = allOk ? 6 : 0; - var iEnd = signatures.length; - var generic = function generic() { - - for (var i = iStart; i < iEnd; i++) { - if (tests[i](arguments)) { - return fns[i].apply(null, arguments); - } - } - - throw createError(name, arguments, signatures); - }; - - // create the typed function - // fast, specialized version. Falls back to the slower, generic one if needed - var fn = function fn(arg0, arg1) { - - if (arguments.length === len0 && test00(arg0) && test01(arg1)) { return fn0.apply(null, arguments); } - if (arguments.length === len1 && test10(arg0) && test11(arg1)) { return fn1.apply(null, arguments); } - if (arguments.length === len2 && test20(arg0) && test21(arg1)) { return fn2.apply(null, arguments); } - if (arguments.length === len3 && test30(arg0) && test31(arg1)) { return fn3.apply(null, arguments); } - if (arguments.length === len4 && test40(arg0) && test41(arg1)) { return fn4.apply(null, arguments); } - if (arguments.length === len5 && test50(arg0) && test51(arg1)) { return fn5.apply(null, arguments); } - - return generic.apply(null, arguments); - }; - - // attach name the typed function - try { - Object.defineProperty(fn, 'name', {value: name}); - } - catch (err) { - // old browsers do not support Object.defineProperty and some don't support setting the name property - // the function name is not essential for the functioning, it's mostly useful for debugging, - // so it's fine to have unnamed functions. - } - - // attach signatures to the function - fn.signatures = createSignaturesMap(signatures); - - return fn; - } - - /** - * Test whether a type should be NOT be ignored - * @param {string} typeName - * @return {boolean} - */ - function notIgnore(typeName) { - return typed.ignore.indexOf(typeName) === -1; - } - - /** - * trim a string - * @param {string} str - * @return {string} - */ - function trim(str) { - return str.trim(); - } - - /** - * Test whether a string is not empty - * @param {string} str - * @return {boolean} - */ - function notEmpty(str) { - return !!str; - } - - /** - * test whether a value is not strict equal to null - * @param {*} value - * @return {boolean} - */ - function notNull(value) { - return value !== null; - } - - /** - * Test whether a parameter has no types defined - * @param {Param} param - * @return {boolean} - */ - function isInvalidParam (param) { - return param.types.length === 0; - } - - /** - * Return all but the last items of an array - * @param {Array} arr - * @return {Array} - */ - function initial(arr) { - return arr.slice(0, arr.length - 1); - } - - /** - * return the last item of an array - * @param {Array} arr - * @return {*} - */ - function last(arr) { - return arr[arr.length - 1]; - } - - /** - * Slice an array or function Arguments - * @param {Array | Arguments | IArguments} arr - * @param {number} start - * @param {number} [end] - * @return {Array} - */ - function slice(arr, start, end) { - return Array.prototype.slice.call(arr, start, end); - } - - /** - * Test whether an array contains some item - * @param {Array} array - * @param {*} item - * @return {boolean} Returns true if array contains item, false if not. - */ - function contains(array, item) { - return array.indexOf(item) !== -1; - } - - /** - * Test whether two arrays have overlapping items - * @param {Array} array1 - * @param {Array} array2 - * @return {boolean} Returns true when at least one item exists in both arrays - */ - function hasOverlap(array1, array2) { - for (var i = 0; i < array1.length; i++) { - if (contains(array2, array1[i])) { - return true; - } - } - - return false; - } - - /** - * Return the first item from an array for which test(arr[i]) returns true - * @param {Array} arr - * @param {function} test - * @return {* | undefined} Returns the first matching item - * or undefined when there is no match - */ - function findInArray(arr, test) { - for (var i = 0; i < arr.length; i++) { - if (test(arr[i])) { - return arr[i]; - } - } - return undefined; - } - - /** - * Filter unique items of an array with strings - * @param {string[]} arr - * @return {string[]} - */ - function uniq(arr) { - var entries = {}; - for (var i = 0; i < arr.length; i++) { - entries[arr[i]] = true; - } - return Object.keys(entries); - } - - /** - * Flat map the result invoking a callback for every item in an array. - * https://gist.github.com/samgiles/762ee337dff48623e729 - * @param {Array} arr - * @param {function} callback - * @return {Array} - */ - function flatMap(arr, callback) { - return Array.prototype.concat.apply([], arr.map(callback)); - } - - /** - * Retrieve the function name from a set of typed functions, - * and check whether the name of all functions match (if given) - * @param {function[]} fns - */ - function getName (fns) { - var name = ''; - - for (var i = 0; i < fns.length; i++) { - var fn = fns[i]; - - // check whether the names are the same when defined - if (fn.signatures && fn.name !== '') { - if (name === '') { - name = fn.name; - } - else if (name !== fn.name) { - var err = new Error('Function names do not match (expected: ' + name + ', actual: ' + fn.name + ')'); - err.data = { - actual: fn.name, - expected: name - }; - throw err; - } - } - } - - return name; - } - - typed = createTypedFunction('typed', { - 'string, Object': createTypedFunction, - 'Object': function (signaturesMap) { - // find existing name - var fns = []; - for (var signature in signaturesMap) { - if (signaturesMap.hasOwnProperty(signature)) { - fns.push(signaturesMap[signature]); - } - } - var name = getName(fns); - return createTypedFunction(name, signaturesMap); - }, - '...Function': function (fns) { - var err; - var name = getName(fns); - var signaturesMap = {}; - - for (var i = 0; i < fns.length; i++) { - var fn = fns[i]; - - // test whether this is a typed-function - if (!(typeof fn.signatures === 'object')) { - err = new TypeError('Function is no typed-function (index: ' + i + ')'); - err.data = {index: i}; - throw err; - } - - // merge the signatures - for (var signature in fn.signatures) { - if (fn.signatures.hasOwnProperty(signature)) { - if (signaturesMap.hasOwnProperty(signature)) { - if (fn.signatures[signature] !== signaturesMap[signature]) { - err = new Error('Signature "' + signature + '" is defined twice'); - err.data = {signature: signature}; - throw err; - } - // else: both signatures point to the same function, that's fine - } - else { - signaturesMap[signature] = fn.signatures[signature]; - } - } - } - } - - return createTypedFunction(name, signaturesMap); - } - }); - - typed.create = create; - typed.types = _types; - typed.conversions = _conversions; - typed.ignore = _ignore; - typed.convert = convert; - typed.find = find; - - // add a type - typed.addType = function (type) { - if (!type || typeof type.name !== 'string' || typeof type.test !== 'function') { - throw new TypeError('Object with properties {name: string, test: function} expected'); - } - - typed.types.push(type); - }; - - // add a conversion - typed.addConversion = function (conversion) { - if (!conversion - || typeof conversion.from !== 'string' - || typeof conversion.to !== 'string' - || typeof conversion.convert !== 'function') { - throw new TypeError('Object with properties {from: string, to: string, convert: function} expected'); - } - - typed.conversions.push(conversion); - }; - - return typed; - } - - return create(); - })); - }); - - var number = createCommonjsModule(function (module, exports) { - - - - /** - * @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) { - 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' 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 = undefined; - - if (options) { - // determine notation from options - if (options.notation) { - notation = options.notation; - } - - // determine precision from options - if (exports.isNumber(options)) { - precision = options; - } - else if (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 = object.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=0] Optional number of decimals after the - * decimal point. Zero by default. - */ - 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)); - - // 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, don't add a decimal value. - // otherwise concat with the rest of the coefficients - var decimals = c.slice(decimalIdx).join(''); - var decimalVal = 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) { - return x == y; - } - - // use "==" operator, handles infinities - 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; - }; - }); - var number_1 = number.isNumber; - var number_2 = number.isInteger; - var number_3 = number.sign; - var number_4 = number.format; - var number_5 = number.splitNumber; - var number_6 = number.toEngineering; - var number_7 = number.toFixed; - var number_8 = number.toExponential; - var number_9 = number.toPrecision; - var number_10 = number.roundDigits; - var number_11 = number.digits; - var number_12 = number.DBL_EPSILON; - var number_13 = number.nearlyEqual; - - /** - * Test whether a value is a Matrix - * @param {*} x - * @returns {boolean} returns true with input is a Matrix - * (like a DenseMatrix or SparseMatrix) - */ - var isMatrix = function isMatrix (x) { - return x && x.constructor.prototype.isMatrix || false; - }; - - var digits = number.digits; - - - - // returns a new instance of typed-function - var createTyped = function () { - // initially, return the original instance of typed-function - // consecutively, return a new instance from typed.create. - createTyped = typedFunction.create; - return typedFunction; - }; - - /** - * Factory function for creating a new typed instance - * @param {Object} type Object with data types like Complex and BigNumber - * @returns {Function} - */ - var create = function create(type) { - // TODO: typed-function must be able to silently ignore signatures with unknown data types - - // type checks for all known types - // - // note that: - // - // - check by duck-typing on a property like `isUnit`, instead of checking instanceof. - // instanceof cannot be used because that would not allow to pass data from - // one instance of math.js to another since each has it's own instance of Unit. - // - check the `isUnit` property via the constructor, so there will be no - // matches for "fake" instances like plain objects with a property `isUnit`. - // That is important for security reasons. - // - It must not be possible to override the type checks used internally, - // for security reasons, so these functions are not exposed in the expression - // parser. - type.isNumber = function (x) { return typeof x === 'number' }; - type.isComplex = function (x) { return type.Complex && x instanceof type.Complex || false }; - type.isBigNumber = isBigNumber; - type.isFraction = function (x) { return type.Fraction && x instanceof type.Fraction || false }; - type.isUnit = function (x) { return x && x.constructor.prototype.isUnit || false }; - type.isString = function (x) { return typeof x === 'string' }; - type.isArray = Array.isArray; - type.isMatrix = isMatrix; - type.isDenseMatrix = function (x) { return x && x.isDenseMatrix && x.constructor.prototype.isMatrix || false }; - type.isSparseMatrix = function (x) { return x && x.isSparseMatrix && x.constructor.prototype.isMatrix || false }; - type.isRange = function (x) { return x && x.constructor.prototype.isRange || false }; - type.isIndex = function (x) { return x && x.constructor.prototype.isIndex || false }; - type.isBoolean = function (x) { return typeof x === 'boolean' }; - type.isResultSet = function (x) { return x && x.constructor.prototype.isResultSet || false }; - type.isHelp = function (x) { return x && x.constructor.prototype.isHelp || false }; - type.isFunction = function (x) { return typeof x === 'function'}; - type.isDate = function (x) { return x instanceof Date }; - type.isRegExp = function (x) { return x instanceof RegExp }; - type.isObject = function (x) { - return typeof x === 'object' && - x.constructor === Object && - !type.isComplex(x) && - !type.isFraction(x) - }; - type.isNull = function (x) { return x === null }; - type.isUndefined = function (x) { return x === undefined }; - - type.isAccessorNode = function (x) { return x && x.isAccessorNode && x.constructor.prototype.isNode || false }; - type.isArrayNode = function (x) { return x && x.isArrayNode && x.constructor.prototype.isNode || false }; - type.isAssignmentNode = function (x) { return x && x.isAssignmentNode && x.constructor.prototype.isNode || false }; - type.isBlockNode = function (x) { return x && x.isBlockNode && x.constructor.prototype.isNode || false }; - type.isConditionalNode = function (x) { return x && x.isConditionalNode && x.constructor.prototype.isNode || false }; - type.isConstantNode = function (x) { return x && x.isConstantNode && x.constructor.prototype.isNode || false }; - type.isFunctionAssignmentNode = function (x) { return x && x.isFunctionAssignmentNode && x.constructor.prototype.isNode || false }; - type.isFunctionNode = function (x) { return x && x.isFunctionNode && x.constructor.prototype.isNode || false }; - type.isIndexNode = function (x) { return x && x.isIndexNode && x.constructor.prototype.isNode || false }; - type.isNode = function (x) { return x && x.isNode && x.constructor.prototype.isNode || false }; - type.isObjectNode = function (x) { return x && x.isObjectNode && x.constructor.prototype.isNode || false }; - type.isOperatorNode = function (x) { return x && x.isOperatorNode && x.constructor.prototype.isNode || false }; - type.isParenthesisNode = function (x) { return x && x.isParenthesisNode && x.constructor.prototype.isNode || false }; - type.isRangeNode = function (x) { return x && x.isRangeNode && x.constructor.prototype.isNode || false }; - type.isSymbolNode = function (x) { return x && x.isSymbolNode && x.constructor.prototype.isNode || false }; - - type.isChain = function (x) { return x && x.constructor.prototype.isChain || false }; - - // get a new instance of typed-function - var typed = createTyped(); - - // define all types. The order of the types determines in which order function - // arguments are type-checked (so for performance it's important to put the - // most used types first). - typed.types = [ - { name: 'number', test: type.isNumber }, - { name: 'Complex', test: type.isComplex }, - { name: 'BigNumber', test: type.isBigNumber }, - { name: 'Fraction', test: type.isFraction }, - { name: 'Unit', test: type.isUnit }, - { name: 'string', test: type.isString }, - { name: 'Array', test: type.isArray }, - { name: 'Matrix', test: type.isMatrix }, - { name: 'DenseMatrix', test: type.isDenseMatrix }, - { name: 'SparseMatrix', test: type.isSparseMatrix }, - { name: 'Range', test: type.isRange }, - { name: 'Index', test: type.isIndex }, - { name: 'boolean', test: type.isBoolean }, - { name: 'ResultSet', test: type.isResultSet }, - { name: 'Help', test: type.isHelp }, - { name: 'function', test: type.isFunction }, - { name: 'Date', test: type.isDate }, - { name: 'RegExp', test: type.isRegExp }, - { name: 'null', test: type.isNull }, - { name: 'undefined', test: type.isUndefined }, - - { name: 'OperatorNode', test: type.isOperatorNode }, - { name: 'ConstantNode', test: type.isConstantNode }, - { name: 'SymbolNode', test: type.isSymbolNode }, - { name: 'ParenthesisNode', test: type.isParenthesisNode }, - { name: 'FunctionNode', test: type.isFunctionNode }, - { name: 'FunctionAssignmentNode', test: type.isFunctionAssignmentNode }, - { name: 'ArrayNode', test: type.isArrayNode }, - { name: 'AssignmentNode', test: type.isAssignmentNode }, - { name: 'BlockNode', test: type.isBlockNode }, - { name: 'ConditionalNode', test: type.isConditionalNode }, - { name: 'IndexNode', test: type.isIndexNode }, - { name: 'RangeNode', test: type.isRangeNode }, - { name: 'Node', test: type.isNode }, - - { name: 'Object', test: type.isObject } // order 'Object' last, it's a tricky one - ]; - - // TODO: add conversion from BigNumber to number? - typed.conversions = [ - { - from: 'number', - to: 'BigNumber', - convert: function (x) { - // note: conversion from number to BigNumber can fail if x has >15 digits - if (digits(x) > 15) { - throw new TypeError('Cannot implicitly convert a number with >15 significant digits to BigNumber ' + - '(value: ' + x + '). ' + - 'Use function bignumber(x) to convert to BigNumber.'); - } - return new type.BigNumber(x); - } - }, { - from: 'number', - to: 'Complex', - convert: function (x) { - return new type.Complex(x, 0); - } - }, { - from: 'number', - to: 'string', - convert: function (x) { - return x + ''; - } - }, { - from: 'BigNumber', - to: 'Complex', - convert: function (x) { - return new type.Complex(x.toNumber(), 0); - } - }, { - from: 'Fraction', - to: 'BigNumber', - convert: function (x) { - throw new TypeError('Cannot implicitly convert a Fraction to BigNumber or vice versa. ' + - 'Use function bignumber(x) to convert to BigNumber or fraction(x) to convert to Fraction.'); - } - }, { - from: 'Fraction', - to: 'Complex', - convert: function (x) { - return new type.Complex(x.valueOf(), 0); - } - }, { - from: 'number', - to: 'Fraction', - convert: function (x) { - var f = new type.Fraction(x); - if (f.valueOf() !== x) { - throw new TypeError('Cannot implicitly convert a number to a Fraction when there will be a loss of precision ' + - '(value: ' + x + '). ' + - 'Use function fraction(x) to convert to Fraction.'); - } - return new type.Fraction(x); - } - }, { - // FIXME: add conversion from Fraction to number, for example for `sqrt(fraction(1,3))` - // from: 'Fraction', - // to: 'number', - // convert: function (x) { - // return x.valueOf(); - // } - //}, { - from: 'string', - to: 'number', - convert: function (x) { - var n = Number(x); - if (isNaN(n)) { - throw new Error('Cannot convert "' + x + '" to a number'); - } - return n; - } - }, { - from: 'string', - to: 'BigNumber', - convert: function (x) { - try { - return new type.BigNumber(x); - } - catch (err) { - throw new Error('Cannot convert "' + x + '" to BigNumber'); - } - } - }, { - from: 'string', - to: 'Fraction', - convert: function (x) { - try { - return new type.Fraction(x); - } - catch (err) { - throw new Error('Cannot convert "' + x + '" to Fraction'); - } - } - }, { - from: 'string', - to: 'Complex', - convert: function (x) { - try { - return new type.Complex(x); - } - catch (err) { - throw new Error('Cannot convert "' + x + '" to Complex'); - } - } - }, { - from: 'boolean', - to: 'number', - convert: function (x) { - return +x; - } - }, { - from: 'boolean', - to: 'BigNumber', - convert: function (x) { - return new type.BigNumber(+x); - } - }, { - from: 'boolean', - to: 'Fraction', - convert: function (x) { - return new type.Fraction(+x); - } - }, { - from: 'boolean', - to: 'string', - convert: function (x) { - return +x; - } - }, { - from: 'Array', - to: 'Matrix', - convert: function (array) { - return new type.DenseMatrix(array); - } - }, { - from: 'Matrix', - to: 'Array', - convert: function (matrix) { - return matrix.valueOf(); - } - } - ]; - - return typed; - }; - - var typed = { - create: create - }; - - function E () { - // Keep this empty so it's easier to inherit from - // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) - } - - E.prototype = { - on: function (name, callback, ctx) { - var e = this.e || (this.e = {}); - - (e[name] || (e[name] = [])).push({ - fn: callback, - ctx: ctx - }); - - return this; - }, - - once: function (name, callback, ctx) { - var self = this; - function listener () { - self.off(name, listener); - callback.apply(ctx, arguments); - } - listener._ = callback; - return this.on(name, listener, ctx); - }, - - emit: function (name) { - var data = [].slice.call(arguments, 1); - var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); - var i = 0; - var len = evtArr.length; - - for (i; i < len; i++) { - evtArr[i].fn.apply(evtArr[i].ctx, data); - } - - return this; - }, - - off: function (name, callback) { - var e = this.e || (this.e = {}); - var evts = e[name]; - var liveEvents = []; - - if (evts && callback) { - for (var i = 0, len = evts.length; i < len; i++) { - if (evts[i].fn !== callback && evts[i].fn._ !== callback) - liveEvents.push(evts[i]); - } - } - - // Remove event from queue to prevent memory leak - // Suggested by https://github.com/lazd - // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 - - (liveEvents.length) - ? e[name] = liveEvents - : delete e[name]; - - return this; - } - }; - - var tinyEmitter = E; - - /** - * Extend given object with emitter functions `on`, `off`, `once`, `emit` - * @param {Object} obj - * @return {Object} obj - */ - var mixin = function (obj) { - // create event emitter - var emitter = new tinyEmitter(); - - // bind methods to obj (we don't want to expose the emitter.e Array...) - obj.on = emitter.on.bind(emitter); - obj.off = emitter.off.bind(emitter); - obj.once = emitter.once.bind(emitter); - obj.emit = emitter.emit.bind(emitter); - - return obj; - }; - - var emitter = { - mixin: mixin - }; - - /** - * Create a syntax error with the message: - * 'Wrong number of arguments in function ( provided, - expected)' - * @param {string} fn Function name - * @param {number} count Actual argument count - * @param {number} min Minimum required argument count - * @param {number} [max] Maximum required argument count - * @extends Error - */ - function ArgumentsError(fn, count, min, max) { - if (!(this instanceof ArgumentsError)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.fn = fn; - this.count = count; - this.min = min; - this.max = max; - - this.message = 'Wrong number of arguments in function ' + fn + - ' (' + count + ' provided, ' + - min + ((max != undefined) ? ('-' + max) : '') + ' expected)'; - - this.stack = (new Error()).stack; - } - - ArgumentsError.prototype = new Error(); - ArgumentsError.prototype.constructor = Error; - ArgumentsError.prototype.name = 'ArgumentsError'; - ArgumentsError.prototype.isArgumentsError = true; - - var ArgumentsError_1 = ArgumentsError; - - var lazy = object.lazy; - var isFactory = object.isFactory; - var traverse = object.traverse; - - - function factory (type, config, load, typed, math) { - /** - * Import functions from an object or a module - * - * Syntax: - * - * math.import(object) - * math.import(object, options) - * - * Where: - * - * - `object: Object` - * An object with functions to be imported. - * - `options: Object` An object with import options. Available options: - * - `override: boolean` - * If true, existing functions will be overwritten. False by default. - * - `silent: boolean` - * If true, the function will not throw errors on duplicates or invalid - * types. False by default. - * - `wrap: boolean` - * If true, the functions will be wrapped in a wrapper function - * which converts data types like Matrix to primitive data types like Array. - * The wrapper is needed when extending math.js with libraries which do not - * support these data type. False by default. - * - * Examples: - * - * // define new functions and variables - * math.import({ - * myvalue: 42, - * hello: function (name) { - * return 'hello, ' + name + '!'; - * } - * }); - * - * // use the imported function and variable - * math.myvalue * 2; // 84 - * math.hello('user'); // 'hello, user!' - * - * // import the npm module 'numbers' - * // (must be installed first with `npm install numbers`) - * math.import(require('numbers'), {wrap: true}); - * - * math.fibonacci(7); // returns 13 - * - * @param {Object | Array} object Object with functions to be imported. - * @param {Object} [options] Import options. - */ - function math_import(object$$1, options) { - var num = arguments.length; - if (num !== 1 && num !== 2) { - throw new ArgumentsError_1('import', num, 1, 2); - } - - if (!options) { - options = {}; - } - - if (isFactory(object$$1)) { - _importFactory(object$$1, options); - } - // TODO: allow a typed-function with name too - else if (Array.isArray(object$$1)) { - object$$1.forEach(function (entry) { - math_import(entry, options); - }); - } - else if (typeof object$$1 === 'object') { - // a map with functions - for (var name in object$$1) { - if (object$$1.hasOwnProperty(name)) { - var value = object$$1[name]; - if (isSupportedType(value)) { - _import(name, value, options); - } - else if (isFactory(object$$1)) { - _importFactory(object$$1, options); - } - else { - math_import(value, options); - } - } - } - } - else { - if (!options.silent) { - throw new TypeError('Factory, Object, or Array expected'); - } - } - } - - /** - * Add a property to the math namespace and create a chain proxy for it. - * @param {string} name - * @param {*} value - * @param {Object} options See import for a description of the options - * @private - */ - function _import(name, value, options) { - // TODO: refactor this function, it's to complicated and contains duplicate code - if (options.wrap && typeof value === 'function') { - // create a wrapper around the function - value = _wrap(value); - } - - if (isTypedFunction(math[name]) && isTypedFunction(value)) { - if (options.override) { - // give the typed function the right name - value = typed(name, value.signatures); - } - else { - // merge the existing and typed function - value = typed(math[name], value); - } - - math[name] = value; - _importTransform(name, value); - math.emit('import', name, function resolver() { - return value; - }); - return; - } - - if (math[name] === undefined || options.override) { - math[name] = value; - _importTransform(name, value); - math.emit('import', name, function resolver() { - return value; - }); - return; - } - - if (!options.silent) { - throw new Error('Cannot import "' + name + '": already exists'); - } - } - - function _importTransform (name, value) { - if (value && typeof value.transform === 'function') { - math.expression.transform[name] = value.transform; - if (allowedInExpressions(name)) { - math.expression.mathWithTransform[name] = value.transform; - } - } - else { - // remove existing transform - delete math.expression.transform[name]; - if (allowedInExpressions(name)) { - math.expression.mathWithTransform[name] = value; - } - } - } - - /** - * Create a wrapper a round an function which converts the arguments - * to their primitive values (like convert a Matrix to Array) - * @param {Function} fn - * @return {Function} Returns the wrapped function - * @private - */ - function _wrap (fn) { - var wrapper = function wrapper () { - var args = []; - for (var i = 0, len = arguments.length; i < len; i++) { - var arg = arguments[i]; - args[i] = arg && arg.valueOf(); - } - return fn.apply(math, args); - }; - - if (fn.transform) { - wrapper.transform = fn.transform; - } - - return wrapper; - } - - /** - * Import an instance of a factory into math.js - * @param {{factory: Function, name: string, path: string, math: boolean}} factory - * @param {Object} options See import for a description of the options - * @private - */ - function _importFactory(factory, options) { - if (typeof factory.name === 'string') { - var name = factory.name; - var existingTransform = name in math.expression.transform; - var namespace = factory.path ? traverse(math, factory.path) : math; - var existing = namespace.hasOwnProperty(name) ? namespace[name] : undefined; - - var resolver = function () { - var instance = load(factory); - if (instance && typeof instance.transform === 'function') { - throw new Error('Transforms cannot be attached to factory functions. ' + - 'Please create a separate function for it with exports.path="expression.transform"'); - } - - if (isTypedFunction(existing) && isTypedFunction(instance)) { - if (options.override) { - // replace the existing typed function (nothing to do) - } - else { - // merge the existing and new typed function - instance = typed(existing, instance); - } - - return instance; - } - - if (existing === undefined || options.override) { - return instance; - } - - if (!options.silent) { - throw new Error('Cannot import "' + name + '": already exists'); - } - }; - - if (factory.lazy !== false) { - lazy(namespace, name, resolver); - - if (!existingTransform) { - if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) { - lazy(math.expression.mathWithTransform, name, resolver); - } - } - } - else { - namespace[name] = resolver(); - - if (!existingTransform) { - if (factory.path === 'expression.transform' || factoryAllowedInExpressions(factory)) { - math.expression.mathWithTransform[name] = resolver(); - } - } - } - - math.emit('import', name, resolver, factory.path); - } - else { - // unnamed factory. - // no lazy loading - load(factory); - } - } - - /** - * Check whether given object is a type which can be imported - * @param {Function | number | string | boolean | null | Unit | Complex} object - * @return {boolean} - * @private - */ - function isSupportedType(object$$1) { - return typeof object$$1 === 'function' - || typeof object$$1 === 'number' - || typeof object$$1 === 'string' - || typeof object$$1 === 'boolean' - || object$$1 === null - || (object$$1 && type.isUnit(object$$1)) - || (object$$1 && type.isComplex(object$$1)) - || (object$$1 && type.isBigNumber(object$$1)) - || (object$$1 && type.isFraction(object$$1)) - || (object$$1 && type.isMatrix(object$$1)) - || (object$$1 && Array.isArray(object$$1)) - } - - /** - * Test whether a given thing is a typed-function - * @param {*} fn - * @return {boolean} Returns true when `fn` is a typed-function - */ - function isTypedFunction (fn) { - return typeof fn === 'function' && typeof fn.signatures === 'object'; - } - - function allowedInExpressions (name) { - return !unsafe.hasOwnProperty(name); - } - - function factoryAllowedInExpressions (factory) { - return factory.path === undefined && !unsafe.hasOwnProperty(factory.name); - } - - // namespaces and functions not available in the parser for safety reasons - var unsafe = { - 'expression': true, - 'type': true, - 'docs': true, - 'error': true, - 'json': true, - 'chain': true // chain method not supported. Note that there is a unit chain too. - }; - - return math_import; - } - - var math = true; // request access to the math namespace as 5th argument of the factory function - var name = 'import'; - var factory_1 = factory; - var lazy_1 = true; - - var _import = { - math: math, - name: name, - factory: factory_1, - lazy: lazy_1 - }; - - function factory$1 (type, config, load, typed, math) { - var MATRIX = ['Matrix', 'Array']; // valid values for option matrix - var NUMBER = ['number', 'BigNumber', 'Fraction']; // valid values for option number - - /** - * Set configuration options for math.js, and get current options. - * Will emit a 'config' event, with arguments (curr, prev, changes). - * - * Syntax: - * - * math.config(config: Object): Object - * - * Examples: - * - * math.config().number; // outputs 'number' - * math.eval('0.4'); // outputs number 0.4 - * math.config({number: 'Fraction'}); - * math.eval('0.4'); // outputs Fraction 2/5 - * - * @param {Object} [options] Available options: - * {number} epsilon - * Minimum relative difference between two - * compared values, used by all comparison functions. - * {string} matrix - * A string 'Matrix' (default) or 'Array'. - * {string} number - * A string 'number' (default), 'BigNumber', or 'Fraction' - * {number} precision - * The number of significant digits for BigNumbers. - * Not applicable for Numbers. - * {string} parenthesis - * How to display parentheses in LaTeX and string - * output. - * {string} randomSeed - * Random seed for seeded pseudo random number generator. - * Set to null to randomly seed. - * @return {Object} Returns the current configuration - */ - function _config(options) { - if (options) { - var prev = object.map(config, object.clone); - - // validate some of the options - validateOption(options, 'matrix', MATRIX); - validateOption(options, 'number', NUMBER); - - // merge options - object.deepExtend(config, options); - - var curr = object.map(config, object.clone); - - var changes = object.map(options, object.clone); - - // emit 'config' event - math.emit('config', curr, prev, changes); - - return curr; - } - else { - return object.map(config, object.clone); - } - } - - // attach the valid options to the function so they can be extended - _config.MATRIX = MATRIX; - _config.NUMBER = NUMBER; - - return _config; - } - - /** - * Test whether an Array contains a specific item. - * @param {Array.} array - * @param {string} item - * @return {boolean} - */ - function contains (array, item) { - return array.indexOf(item) !== -1; - } - - /** - * Find a string in an array. Case insensitive search - * @param {Array.} array - * @param {string} item - * @return {number} Returns the index when found. Returns -1 when not found - */ - function findIndex (array, item) { - return array - .map(function (i) { - return i.toLowerCase(); - }) - .indexOf(item.toLowerCase()); - } - - /** - * Validate an option - * @param {Object} options Object with options - * @param {string} name Name of the option to validate - * @param {Array.} values Array with valid values for this option - */ - function validateOption(options, name, values) { - if (options[name] !== undefined && !contains(values, options[name])) { - var index = findIndex(values, options[name]); - if (index !== -1) { - // right value, wrong casing - // TODO: lower case values are deprecated since v3, remove this warning some day. - console.warn('Warning: Wrong casing for configuration option "' + name + '", should be "' + values[index] + '" instead of "' + options[name] + '".'); - - options[name] = values[index]; // change the option to the right casing - } - else { - // unknown value - console.warn('Warning: Unknown value "' + options[name] + '" for configuration option "' + name + '". Available options: ' + values.map(JSON.stringify).join(', ') + '.'); - } - } - } - - var name$1 = 'config'; - var math$1 = true; // request the math namespace as fifth argument - var factory_1$1 = factory$1; - - var config = { - name: name$1, - math: math$1, - factory: factory_1$1 - }; - - var isFactory$1 = object.isFactory; - - - - - - - /** - * Math.js core. Creates a new, empty math.js instance - * @param {Object} [options] Available options: - * {number} epsilon - * Minimum relative difference between two - * compared values, used by all comparison functions. - * {string} matrix - * A string 'Matrix' (default) or 'Array'. - * {string} number - * A string 'number' (default), 'BigNumber', or 'Fraction' - * {number} precision - * The number of significant digits for BigNumbers. - * Not applicable for Numbers. - * {boolean} predictable - * Predictable output type of functions. When true, - * output type depends only on the input types. When - * false (default), output type can vary depending - * on input values. For example `math.sqrt(-4)` - * returns `complex('2i')` when predictable is false, and - * returns `NaN` when true. - * {string} randomSeed - * Random seed for seeded pseudo random number generator. - * Set to null to randomly seed. - * @returns {Object} Returns a bare-bone math.js instance containing - * functions: - * - `import` to add new functions - * - `config` to change configuration - * - `on`, `off`, `once`, `emit` for events - */ - var create$1 = function create (options) { - // 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.'); - } - - // cached factories and instances - var factories = []; - var instances = []; - - // create a namespace for the mathjs instance, and attach emitter functions - var math = emitter.mixin({}); - math.type = {}; - math.expression = { - transform: {}, - mathWithTransform: {} - }; - - // create a new typed instance - math.typed = typed.create(math.type); - - // create configuration options. These are private - var _config = { - // minimum relative difference between two compared values, - // used by all comparison functions - epsilon: 1e-12, - - // type of default matrix output. Choose 'matrix' (default) or 'array' - matrix: 'Matrix', - - // type of default number output. Choose 'number' (default) 'BigNumber', or 'Fraction - number: 'number', - - // number of significant digits in BigNumbers - precision: 64, - - // predictable output type of functions. When true, output type depends only - // on the input types. When false (default), output type can vary depending - // on input values. For example `math.sqrt(-4)` returns `complex('2i')` when - // predictable is false, and returns `NaN` when true. - predictable: false, - - // random seed for seeded pseudo random number generation - // null = randomly seed - randomSeed: null - }; - - /** - * Load a function or data type from a factory. - * If the function or data type already exists, the existing instance is - * returned. - * @param {{type: string, name: string, factory: Function}} factory - * @returns {*} - */ - function load (factory) { - if (!isFactory$1(factory)) { - throw new Error('Factory object with properties `type`, `name`, and `factory` expected'); - } - - var index = factories.indexOf(factory); - var instance; - if (index === -1) { - // doesn't yet exist - if (factory.math === true) { - // pass with math namespace - instance = factory.factory(math.type, _config, load, math.typed, math); - } - else { - instance = factory.factory(math.type, _config, load, math.typed); - } - - // append to the cache - factories.push(factory); - instances.push(instance); - } - else { - // already existing function, return the cached instance - instance = instances[index]; - } - - return instance; - } - - // load the import and config functions - math['import'] = load(_import); - math['config'] = load(config); - math.expression.mathWithTransform['config'] = math['config']; - - // apply options - if (options) { - math.config(options); - } - - return math; - }; - - var core = { - create: create$1 - }; - - var core$1 = core; - - var decimal = createCommonjsModule(function (module) { - (function (globalScope) { - - - /* - * decimal.js v9.0.1 - * An arbitrary-precision Decimal type for JavaScript. - * https://github.com/MikeMcl/decimal.js - * Copyright (c) 2017 Michael Mclaughlin - * MIT Licence - */ - - - // ----------------------------------- EDITABLE DEFAULTS ------------------------------------ // - - - // The maximum exponent magnitude. - // The limit on the value of `toExpNeg`, `toExpPos`, `minE` and `maxE`. - var EXP_LIMIT = 9e15, // 0 to 9e15 - - // The limit on the value of `precision`, and on the value of the first argument to - // `toDecimalPlaces`, `toExponential`, `toFixed`, `toPrecision` and `toSignificantDigits`. - MAX_DIGITS = 1e9, // 0 to 1e9 - - // Base conversion alphabet. - NUMERALS = '0123456789abcdef', - - // The natural logarithm of 10 (1025 digits). - LN10 = '2.3025850929940456840179914546843642076011014886287729760333279009675726096773524802359972050895982983419677840422862486334095254650828067566662873690987816894829072083255546808437998948262331985283935053089653777326288461633662222876982198867465436674744042432743651550489343149393914796194044002221051017141748003688084012647080685567743216228355220114804663715659121373450747856947683463616792101806445070648000277502684916746550586856935673420670581136429224554405758925724208241314695689016758940256776311356919292033376587141660230105703089634572075440370847469940168269282808481184289314848524948644871927809676271275775397027668605952496716674183485704422507197965004714951050492214776567636938662976979522110718264549734772662425709429322582798502585509785265383207606726317164309505995087807523710333101197857547331541421808427543863591778117054309827482385045648019095610299291824318237525357709750539565187697510374970888692180205189339507238539205144634197265287286965110862571492198849978748873771345686209167058', - - // Pi (1025 digits). - PI = '3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632789', - - - // The initial configuration properties of the Decimal constructor. - DEFAULTS = { - - // These values must be integers within the stated ranges (inclusive). - // Most of these values can be changed at run-time using the `Decimal.config` method. - - // The maximum number of significant digits of the result of a calculation or base conversion. - // E.g. `Decimal.config({ precision: 20 });` - precision: 20, // 1 to MAX_DIGITS - - // The rounding mode used when rounding to `precision`. - // - // ROUND_UP 0 Away from zero. - // ROUND_DOWN 1 Towards zero. - // ROUND_CEIL 2 Towards +Infinity. - // ROUND_FLOOR 3 Towards -Infinity. - // ROUND_HALF_UP 4 Towards nearest neighbour. If equidistant, up. - // ROUND_HALF_DOWN 5 Towards nearest neighbour. If equidistant, down. - // ROUND_HALF_EVEN 6 Towards nearest neighbour. If equidistant, towards even neighbour. - // ROUND_HALF_CEIL 7 Towards nearest neighbour. If equidistant, towards +Infinity. - // ROUND_HALF_FLOOR 8 Towards nearest neighbour. If equidistant, towards -Infinity. - // - // E.g. - // `Decimal.rounding = 4;` - // `Decimal.rounding = Decimal.ROUND_HALF_UP;` - rounding: 4, // 0 to 8 - - // The modulo mode used when calculating the modulus: a mod n. - // The quotient (q = a / n) is calculated according to the corresponding rounding mode. - // The remainder (r) is calculated as: r = a - n * q. - // - // UP 0 The remainder is positive if the dividend is negative, else is negative. - // DOWN 1 The remainder has the same sign as the dividend (JavaScript %). - // FLOOR 3 The remainder has the same sign as the divisor (Python %). - // HALF_EVEN 6 The IEEE 754 remainder function. - // EUCLID 9 Euclidian division. q = sign(n) * floor(a / abs(n)). Always positive. - // - // Truncated division (1), floored division (3), the IEEE 754 remainder (6), and Euclidian - // division (9) are commonly used for the modulus operation. The other rounding modes can also - // be used, but they may not give useful results. - modulo: 1, // 0 to 9 - - // The exponent value at and beneath which `toString` returns exponential notation. - // JavaScript numbers: -7 - toExpNeg: -7, // 0 to -EXP_LIMIT - - // The exponent value at and above which `toString` returns exponential notation. - // JavaScript numbers: 21 - toExpPos: 21, // 0 to EXP_LIMIT - - // The minimum exponent value, beneath which underflow to zero occurs. - // JavaScript numbers: -324 (5e-324) - minE: -EXP_LIMIT, // -1 to -EXP_LIMIT - - // The maximum exponent value, above which overflow to Infinity occurs. - // JavaScript numbers: 308 (1.7976931348623157e+308) - maxE: EXP_LIMIT, // 1 to EXP_LIMIT - - // Whether to use cryptographically-secure random number generation, if available. - crypto: false // true/false - }, - - - // ----------------------------------- END OF EDITABLE DEFAULTS ------------------------------- // - - - Decimal, inexact, noConflict, quadrant, - external = true, - - decimalError = '[DecimalError] ', - invalidArgument = decimalError + 'Invalid argument: ', - precisionLimitExceeded = decimalError + 'Precision limit exceeded', - cryptoUnavailable = decimalError + 'crypto unavailable', - - mathfloor = Math.floor, - mathpow = Math.pow, - - isBinary = /^0b([01]+(\.[01]*)?|\.[01]+)(p[+-]?\d+)?$/i, - isHex = /^0x([0-9a-f]+(\.[0-9a-f]*)?|\.[0-9a-f]+)(p[+-]?\d+)?$/i, - isOctal = /^0o([0-7]+(\.[0-7]*)?|\.[0-7]+)(p[+-]?\d+)?$/i, - isDecimal = /^(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i, - - BASE = 1e7, - LOG_BASE = 7, - MAX_SAFE_INTEGER = 9007199254740991, - - LN10_PRECISION = LN10.length - 1, - PI_PRECISION = PI.length - 1, - - // Decimal.prototype object - P = { name: '[object Decimal]' }; - - - // Decimal prototype methods - - - /* - * absoluteValue abs - * ceil - * comparedTo cmp - * cosine cos - * cubeRoot cbrt - * decimalPlaces dp - * dividedBy div - * dividedToIntegerBy divToInt - * equals eq - * floor - * greaterThan gt - * greaterThanOrEqualTo gte - * hyperbolicCosine cosh - * hyperbolicSine sinh - * hyperbolicTangent tanh - * inverseCosine acos - * inverseHyperbolicCosine acosh - * inverseHyperbolicSine asinh - * inverseHyperbolicTangent atanh - * inverseSine asin - * inverseTangent atan - * isFinite - * isInteger isInt - * isNaN - * isNegative isNeg - * isPositive isPos - * isZero - * lessThan lt - * lessThanOrEqualTo lte - * logarithm log - * [maximum] [max] - * [minimum] [min] - * minus sub - * modulo mod - * naturalExponential exp - * naturalLogarithm ln - * negated neg - * plus add - * precision sd - * round - * sine sin - * squareRoot sqrt - * tangent tan - * times mul - * toBinary - * toDecimalPlaces toDP - * toExponential - * toFixed - * toFraction - * toHexadecimal toHex - * toNearest - * toNumber - * toOctal - * toPower pow - * toPrecision - * toSignificantDigits toSD - * toString - * truncated trunc - * valueOf toJSON - */ - - - /* - * Return a new Decimal whose value is the absolute value of this Decimal. - * - */ - P.absoluteValue = P.abs = function () { - var x = new this.constructor(this); - if (x.s < 0) x.s = 1; - return finalise(x); - }; - - - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a whole number in the - * direction of positive Infinity. - * - */ - P.ceil = function () { - return finalise(new this.constructor(this), this.e + 1, 2); - }; - - - /* - * Return - * 1 if the value of this Decimal is greater than the value of `y`, - * -1 if the value of this Decimal is less than the value of `y`, - * 0 if they have the same value, - * NaN if the value of either Decimal is NaN. - * - */ - P.comparedTo = P.cmp = function (y) { - var i, j, xdL, ydL, - x = this, - xd = x.d, - yd = (y = new x.constructor(y)).d, - xs = x.s, - ys = y.s; - - // Either NaN or ±Infinity? - if (!xd || !yd) { - return !xs || !ys ? NaN : xs !== ys ? xs : xd === yd ? 0 : !xd ^ xs < 0 ? 1 : -1; - } - - // Either zero? - if (!xd[0] || !yd[0]) return xd[0] ? xs : yd[0] ? -ys : 0; - - // Signs differ? - if (xs !== ys) return xs; - - // Compare exponents. - if (x.e !== y.e) return x.e > y.e ^ xs < 0 ? 1 : -1; - - xdL = xd.length; - ydL = yd.length; - - // Compare digit by digit. - for (i = 0, j = xdL < ydL ? xdL : ydL; i < j; ++i) { - if (xd[i] !== yd[i]) return xd[i] > yd[i] ^ xs < 0 ? 1 : -1; - } - - // Compare lengths. - return xdL === ydL ? 0 : xdL > ydL ^ xs < 0 ? 1 : -1; - }; - - - /* - * Return a new Decimal whose value is the cosine of the value in radians of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-1, 1] - * - * cos(0) = 1 - * cos(-0) = 1 - * cos(Infinity) = NaN - * cos(-Infinity) = NaN - * cos(NaN) = NaN - * - */ - P.cosine = P.cos = function () { - var pr, rm, - x = this, - Ctor = x.constructor; - - if (!x.d) return new Ctor(NaN); - - // cos(0) = cos(-0) = 1 - if (!x.d[0]) return new Ctor(1); - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(x.e, x.sd()) + LOG_BASE; - Ctor.rounding = 1; - - x = cosine(Ctor, toLessThanHalfPi(Ctor, x)); - - Ctor.precision = pr; - Ctor.rounding = rm; - - return finalise(quadrant == 2 || quadrant == 3 ? x.neg() : x, pr, rm, true); - }; - - - /* - * - * Return a new Decimal whose value is the cube root of the value of this Decimal, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * cbrt(0) = 0 - * cbrt(-0) = -0 - * cbrt(1) = 1 - * cbrt(-1) = -1 - * cbrt(N) = N - * cbrt(-I) = -I - * cbrt(I) = I - * - * Math.cbrt(x) = (x < 0 ? -Math.pow(-x, 1/3) : Math.pow(x, 1/3)) - * - */ - P.cubeRoot = P.cbrt = function () { - var e, m, n, r, rep, s, sd, t, t3, t3plusx, - x = this, - Ctor = x.constructor; - - if (!x.isFinite() || x.isZero()) return new Ctor(x); - external = false; - - // Initial estimate. - s = x.s * Math.pow(x.s * x, 1 / 3); - - // Math.cbrt underflow/overflow? - // Pass x to Math.pow as integer, then adjust the exponent of the result. - if (!s || Math.abs(s) == 1 / 0) { - n = digitsToString(x.d); - e = x.e; - - // Adjust n exponent so it is a multiple of 3 away from x exponent. - if (s = (e - n.length + 1) % 3) n += (s == 1 || s == -2 ? '0' : '00'); - s = Math.pow(n, 1 / 3); - - // Rarely, e may be one less than the result exponent value. - e = mathfloor((e + 1) / 3) - (e % 3 == (e < 0 ? -1 : 2)); - - if (s == 1 / 0) { - n = '5e' + e; - } else { - n = s.toExponential(); - n = n.slice(0, n.indexOf('e') + 1) + e; - } - - r = new Ctor(n); - r.s = x.s; - } else { - r = new Ctor(s.toString()); - } - - sd = (e = Ctor.precision) + 3; - - // Halley's method. - // TODO? Compare Newton's method. - for (;;) { - t = r; - t3 = t.times(t).times(t); - t3plusx = t3.plus(x); - r = divide(t3plusx.plus(x).times(t), t3plusx.plus(t3), sd + 2, 1); - - // TODO? Replace with for-loop and checkRoundingDigits. - if (digitsToString(t.d).slice(0, sd) === (n = digitsToString(r.d)).slice(0, sd)) { - n = n.slice(sd - 3, sd + 1); - - // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or 4999 - // , i.e. approaching a rounding boundary, continue the iteration. - if (n == '9999' || !rep && n == '4999') { - - // On the first iteration only, check to see if rounding up gives the exact result as the - // nines may infinitely repeat. - if (!rep) { - finalise(t, e + 1, 0); - - if (t.times(t).times(t).eq(x)) { - r = t; - break; - } - } - - sd += 4; - rep = 1; - } else { - - // If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result. - // If not, then there are further digits and m will be truthy. - if (!+n || !+n.slice(1) && n.charAt(0) == '5') { - - // Truncate to the first rounding digit. - finalise(r, e + 1, 1); - m = !r.times(r).times(r).eq(x); - } - - break; - } - } - } - - external = true; - - return finalise(r, e, Ctor.rounding, m); - }; - - - /* - * Return the number of decimal places of the value of this Decimal. - * - */ - P.decimalPlaces = P.dp = function () { - var w, - d = this.d, - n = NaN; - - if (d) { - w = d.length - 1; - n = (w - mathfloor(this.e / LOG_BASE)) * LOG_BASE; - - // Subtract the number of trailing zeros of the last word. - w = d[w]; - if (w) for (; w % 10 == 0; w /= 10) n--; - if (n < 0) n = 0; - } - - return n; - }; - - - /* - * n / 0 = I - * n / N = N - * n / I = 0 - * 0 / n = 0 - * 0 / 0 = N - * 0 / N = N - * 0 / I = 0 - * N / n = N - * N / 0 = N - * N / N = N - * N / I = N - * I / n = I - * I / 0 = I - * I / N = N - * I / I = N - * - * Return a new Decimal whose value is the value of this Decimal divided by `y`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - */ - P.dividedBy = P.div = function (y) { - return divide(this, new this.constructor(y)); - }; - - - /* - * Return a new Decimal whose value is the integer part of dividing the value of this Decimal - * by the value of `y`, rounded to `precision` significant digits using rounding mode `rounding`. - * - */ - P.dividedToIntegerBy = P.divToInt = function (y) { - var x = this, - Ctor = x.constructor; - return finalise(divide(x, new Ctor(y), 0, 1, 1), Ctor.precision, Ctor.rounding); - }; - - - /* - * Return true if the value of this Decimal is equal to the value of `y`, otherwise return false. - * - */ - P.equals = P.eq = function (y) { - return this.cmp(y) === 0; - }; - - - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a whole number in the - * direction of negative Infinity. - * - */ - P.floor = function () { - return finalise(new this.constructor(this), this.e + 1, 3); - }; - - - /* - * Return true if the value of this Decimal is greater than the value of `y`, otherwise return - * false. - * - */ - P.greaterThan = P.gt = function (y) { - return this.cmp(y) > 0; - }; - - - /* - * Return true if the value of this Decimal is greater than or equal to the value of `y`, - * otherwise return false. - * - */ - P.greaterThanOrEqualTo = P.gte = function (y) { - var k = this.cmp(y); - return k == 1 || k === 0; - }; - - - /* - * Return a new Decimal whose value is the hyperbolic cosine of the value in radians of this - * Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [1, Infinity] - * - * cosh(x) = 1 + x^2/2! + x^4/4! + x^6/6! + ... - * - * cosh(0) = 1 - * cosh(-0) = 1 - * cosh(Infinity) = Infinity - * cosh(-Infinity) = Infinity - * cosh(NaN) = NaN - * - * x time taken (ms) result - * 1000 9 9.8503555700852349694e+433 - * 10000 25 4.4034091128314607936e+4342 - * 100000 171 1.4033316802130615897e+43429 - * 1000000 3817 1.5166076984010437725e+434294 - * 10000000 abandoned after 2 minute wait - * - * TODO? Compare performance of cosh(x) = 0.5 * (exp(x) + exp(-x)) - * - */ - P.hyperbolicCosine = P.cosh = function () { - var k, n, pr, rm, len, - x = this, - Ctor = x.constructor, - one = new Ctor(1); - - if (!x.isFinite()) return new Ctor(x.s ? 1 / 0 : NaN); - if (x.isZero()) return one; - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(x.e, x.sd()) + 4; - Ctor.rounding = 1; - len = x.d.length; - - // Argument reduction: cos(4x) = 1 - 8cos^2(x) + 8cos^4(x) + 1 - // i.e. cos(x) = 1 - cos^2(x/4)(8 - 8cos^2(x/4)) - - // Estimate the optimum number of times to use the argument reduction. - // TODO? Estimation reused from cosine() and may not be optimal here. - if (len < 32) { - k = Math.ceil(len / 3); - n = Math.pow(4, -k).toString(); - } else { - k = 16; - n = '2.3283064365386962890625e-10'; - } - - x = taylorSeries(Ctor, 1, x.times(n), new Ctor(1), true); - - // Reverse argument reduction - var cosh2_x, - i = k, - d8 = new Ctor(8); - for (; i--;) { - cosh2_x = x.times(x); - x = one.minus(cosh2_x.times(d8.minus(cosh2_x.times(d8)))); - } - - return finalise(x, Ctor.precision = pr, Ctor.rounding = rm, true); - }; - - - /* - * Return a new Decimal whose value is the hyperbolic sine of the value in radians of this - * Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-Infinity, Infinity] - * - * sinh(x) = x + x^3/3! + x^5/5! + x^7/7! + ... - * - * sinh(0) = 0 - * sinh(-0) = -0 - * sinh(Infinity) = Infinity - * sinh(-Infinity) = -Infinity - * sinh(NaN) = NaN - * - * x time taken (ms) - * 10 2 ms - * 100 5 ms - * 1000 14 ms - * 10000 82 ms - * 100000 886 ms 1.4033316802130615897e+43429 - * 200000 2613 ms - * 300000 5407 ms - * 400000 8824 ms - * 500000 13026 ms 8.7080643612718084129e+217146 - * 1000000 48543 ms - * - * TODO? Compare performance of sinh(x) = 0.5 * (exp(x) - exp(-x)) - * - */ - P.hyperbolicSine = P.sinh = function () { - var k, pr, rm, len, - x = this, - Ctor = x.constructor; - - if (!x.isFinite() || x.isZero()) return new Ctor(x); - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(x.e, x.sd()) + 4; - Ctor.rounding = 1; - len = x.d.length; - - if (len < 3) { - x = taylorSeries(Ctor, 2, x, x, true); - } else { - - // Alternative argument reduction: sinh(3x) = sinh(x)(3 + 4sinh^2(x)) - // i.e. sinh(x) = sinh(x/3)(3 + 4sinh^2(x/3)) - // 3 multiplications and 1 addition - - // Argument reduction: sinh(5x) = sinh(x)(5 + sinh^2(x)(20 + 16sinh^2(x))) - // i.e. sinh(x) = sinh(x/5)(5 + sinh^2(x/5)(20 + 16sinh^2(x/5))) - // 4 multiplications and 2 additions - - // Estimate the optimum number of times to use the argument reduction. - k = 1.4 * Math.sqrt(len); - k = k > 16 ? 16 : k | 0; - - x = x.times(Math.pow(5, -k)); - - x = taylorSeries(Ctor, 2, x, x, true); - - // Reverse argument reduction - var sinh2_x, - d5 = new Ctor(5), - d16 = new Ctor(16), - d20 = new Ctor(20); - for (; k--;) { - sinh2_x = x.times(x); - x = x.times(d5.plus(sinh2_x.times(d16.times(sinh2_x).plus(d20)))); - } - } - - Ctor.precision = pr; - Ctor.rounding = rm; - - return finalise(x, pr, rm, true); - }; - - - /* - * Return a new Decimal whose value is the hyperbolic tangent of the value in radians of this - * Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-1, 1] - * - * tanh(x) = sinh(x) / cosh(x) - * - * tanh(0) = 0 - * tanh(-0) = -0 - * tanh(Infinity) = 1 - * tanh(-Infinity) = -1 - * tanh(NaN) = NaN - * - */ - P.hyperbolicTangent = P.tanh = function () { - var pr, rm, - x = this, - Ctor = x.constructor; - - if (!x.isFinite()) return new Ctor(x.s); - if (x.isZero()) return new Ctor(x); - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + 7; - Ctor.rounding = 1; - - return divide(x.sinh(), x.cosh(), Ctor.precision = pr, Ctor.rounding = rm); - }; - - - /* - * Return a new Decimal whose value is the arccosine (inverse cosine) in radians of the value of - * this Decimal. - * - * Domain: [-1, 1] - * Range: [0, pi] - * - * acos(x) = pi/2 - asin(x) - * - * acos(0) = pi/2 - * acos(-0) = pi/2 - * acos(1) = 0 - * acos(-1) = pi - * acos(1/2) = pi/3 - * acos(-1/2) = 2*pi/3 - * acos(|x| > 1) = NaN - * acos(NaN) = NaN - * - */ - P.inverseCosine = P.acos = function () { - var halfPi, - x = this, - Ctor = x.constructor, - k = x.abs().cmp(1), - pr = Ctor.precision, - rm = Ctor.rounding; - - if (k !== -1) { - return k === 0 - // |x| is 1 - ? x.isNeg() ? getPi(Ctor, pr, rm) : new Ctor(0) - // |x| > 1 or x is NaN - : new Ctor(NaN); - } - - if (x.isZero()) return getPi(Ctor, pr + 4, rm).times(0.5); - - // TODO? Special case acos(0.5) = pi/3 and acos(-0.5) = 2*pi/3 - - Ctor.precision = pr + 6; - Ctor.rounding = 1; - - x = x.asin(); - halfPi = getPi(Ctor, pr + 4, rm).times(0.5); - - Ctor.precision = pr; - Ctor.rounding = rm; - - return halfPi.minus(x); - }; - - - /* - * Return a new Decimal whose value is the inverse of the hyperbolic cosine in radians of the - * value of this Decimal. - * - * Domain: [1, Infinity] - * Range: [0, Infinity] - * - * acosh(x) = ln(x + sqrt(x^2 - 1)) - * - * acosh(x < 1) = NaN - * acosh(NaN) = NaN - * acosh(Infinity) = Infinity - * acosh(-Infinity) = NaN - * acosh(0) = NaN - * acosh(-0) = NaN - * acosh(1) = 0 - * acosh(-1) = NaN - * - */ - P.inverseHyperbolicCosine = P.acosh = function () { - var pr, rm, - x = this, - Ctor = x.constructor; - - if (x.lte(1)) return new Ctor(x.eq(1) ? 0 : NaN); - if (!x.isFinite()) return new Ctor(x); - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(Math.abs(x.e), x.sd()) + 4; - Ctor.rounding = 1; - external = false; - - x = x.times(x).minus(1).sqrt().plus(x); - - external = true; - Ctor.precision = pr; - Ctor.rounding = rm; - - return x.ln(); - }; - - - /* - * Return a new Decimal whose value is the inverse of the hyperbolic sine in radians of the value - * of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-Infinity, Infinity] - * - * asinh(x) = ln(x + sqrt(x^2 + 1)) - * - * asinh(NaN) = NaN - * asinh(Infinity) = Infinity - * asinh(-Infinity) = -Infinity - * asinh(0) = 0 - * asinh(-0) = -0 - * - */ - P.inverseHyperbolicSine = P.asinh = function () { - var pr, rm, - x = this, - Ctor = x.constructor; - - if (!x.isFinite() || x.isZero()) return new Ctor(x); - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + 2 * Math.max(Math.abs(x.e), x.sd()) + 6; - Ctor.rounding = 1; - external = false; - - x = x.times(x).plus(1).sqrt().plus(x); - - external = true; - Ctor.precision = pr; - Ctor.rounding = rm; - - return x.ln(); - }; - - - /* - * Return a new Decimal whose value is the inverse of the hyperbolic tangent in radians of the - * value of this Decimal. - * - * Domain: [-1, 1] - * Range: [-Infinity, Infinity] - * - * atanh(x) = 0.5 * ln((1 + x) / (1 - x)) - * - * atanh(|x| > 1) = NaN - * atanh(NaN) = NaN - * atanh(Infinity) = NaN - * atanh(-Infinity) = NaN - * atanh(0) = 0 - * atanh(-0) = -0 - * atanh(1) = Infinity - * atanh(-1) = -Infinity - * - */ - P.inverseHyperbolicTangent = P.atanh = function () { - var pr, rm, wpr, xsd, - x = this, - Ctor = x.constructor; - - if (!x.isFinite()) return new Ctor(NaN); - if (x.e >= 0) return new Ctor(x.abs().eq(1) ? x.s / 0 : x.isZero() ? x : NaN); - - pr = Ctor.precision; - rm = Ctor.rounding; - xsd = x.sd(); - - if (Math.max(xsd, pr) < 2 * -x.e - 1) return finalise(new Ctor(x), pr, rm, true); - - Ctor.precision = wpr = xsd - x.e; - - x = divide(x.plus(1), new Ctor(1).minus(x), wpr + pr, 1); - - Ctor.precision = pr + 4; - Ctor.rounding = 1; - - x = x.ln(); - - Ctor.precision = pr; - Ctor.rounding = rm; - - return x.times(0.5); - }; - - - /* - * Return a new Decimal whose value is the arcsine (inverse sine) in radians of the value of this - * Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-pi/2, pi/2] - * - * asin(x) = 2*atan(x/(1 + sqrt(1 - x^2))) - * - * asin(0) = 0 - * asin(-0) = -0 - * asin(1/2) = pi/6 - * asin(-1/2) = -pi/6 - * asin(1) = pi/2 - * asin(-1) = -pi/2 - * asin(|x| > 1) = NaN - * asin(NaN) = NaN - * - * TODO? Compare performance of Taylor series. - * - */ - P.inverseSine = P.asin = function () { - var halfPi, k, - pr, rm, - x = this, - Ctor = x.constructor; - - if (x.isZero()) return new Ctor(x); - - k = x.abs().cmp(1); - pr = Ctor.precision; - rm = Ctor.rounding; - - if (k !== -1) { - - // |x| is 1 - if (k === 0) { - halfPi = getPi(Ctor, pr + 4, rm).times(0.5); - halfPi.s = x.s; - return halfPi; - } - - // |x| > 1 or x is NaN - return new Ctor(NaN); - } - - // TODO? Special case asin(1/2) = pi/6 and asin(-1/2) = -pi/6 - - Ctor.precision = pr + 6; - Ctor.rounding = 1; - - x = x.div(new Ctor(1).minus(x.times(x)).sqrt().plus(1)).atan(); - - Ctor.precision = pr; - Ctor.rounding = rm; - - return x.times(2); - }; - - - /* - * Return a new Decimal whose value is the arctangent (inverse tangent) in radians of the value - * of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-pi/2, pi/2] - * - * atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... - * - * atan(0) = 0 - * atan(-0) = -0 - * atan(1) = pi/4 - * atan(-1) = -pi/4 - * atan(Infinity) = pi/2 - * atan(-Infinity) = -pi/2 - * atan(NaN) = NaN - * - */ - P.inverseTangent = P.atan = function () { - var i, j, k, n, px, t, r, wpr, x2, - x = this, - Ctor = x.constructor, - pr = Ctor.precision, - rm = Ctor.rounding; - - if (!x.isFinite()) { - if (!x.s) return new Ctor(NaN); - if (pr + 4 <= PI_PRECISION) { - r = getPi(Ctor, pr + 4, rm).times(0.5); - r.s = x.s; - return r; - } - } else if (x.isZero()) { - return new Ctor(x); - } else if (x.abs().eq(1) && pr + 4 <= PI_PRECISION) { - r = getPi(Ctor, pr + 4, rm).times(0.25); - r.s = x.s; - return r; - } - - Ctor.precision = wpr = pr + 10; - Ctor.rounding = 1; - - // TODO? if (x >= 1 && pr <= PI_PRECISION) atan(x) = halfPi * x.s - atan(1 / x); - - // Argument reduction - // Ensure |x| < 0.42 - // atan(x) = 2 * atan(x / (1 + sqrt(1 + x^2))) - - k = Math.min(28, wpr / LOG_BASE + 2 | 0); - - for (i = k; i; --i) x = x.div(x.times(x).plus(1).sqrt().plus(1)); - - external = false; - - j = Math.ceil(wpr / LOG_BASE); - n = 1; - x2 = x.times(x); - r = new Ctor(x); - px = x; - - // atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... - for (; i !== -1;) { - px = px.times(x2); - t = r.minus(px.div(n += 2)); - - px = px.times(x2); - r = t.plus(px.div(n += 2)); - - if (r.d[j] !== void 0) for (i = j; r.d[i] === t.d[i] && i--;); - } - - if (k) r = r.times(2 << (k - 1)); - - external = true; - - return finalise(r, Ctor.precision = pr, Ctor.rounding = rm, true); - }; - - - /* - * Return true if the value of this Decimal is a finite number, otherwise return false. - * - */ - P.isFinite = function () { - return !!this.d; - }; - - - /* - * Return true if the value of this Decimal is an integer, otherwise return false. - * - */ - P.isInteger = P.isInt = function () { - return !!this.d && mathfloor(this.e / LOG_BASE) > this.d.length - 2; - }; - - - /* - * Return true if the value of this Decimal is NaN, otherwise return false. - * - */ - P.isNaN = function () { - return !this.s; - }; - - - /* - * Return true if the value of this Decimal is negative, otherwise return false. - * - */ - P.isNegative = P.isNeg = function () { - return this.s < 0; - }; - - - /* - * Return true if the value of this Decimal is positive, otherwise return false. - * - */ - P.isPositive = P.isPos = function () { - return this.s > 0; - }; - - - /* - * Return true if the value of this Decimal is 0 or -0, otherwise return false. - * - */ - P.isZero = function () { - return !!this.d && this.d[0] === 0; - }; - - - /* - * Return true if the value of this Decimal is less than `y`, otherwise return false. - * - */ - P.lessThan = P.lt = function (y) { - return this.cmp(y) < 0; - }; - - - /* - * Return true if the value of this Decimal is less than or equal to `y`, otherwise return false. - * - */ - P.lessThanOrEqualTo = P.lte = function (y) { - return this.cmp(y) < 1; - }; - - - /* - * Return the logarithm of the value of this Decimal to the specified base, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * If no base is specified, return log[10](arg). - * - * log[base](arg) = ln(arg) / ln(base) - * - * The result will always be correctly rounded if the base of the log is 10, and 'almost always' - * otherwise: - * - * Depending on the rounding mode, the result may be incorrectly rounded if the first fifteen - * rounding digits are [49]99999999999999 or [50]00000000000000. In that case, the maximum error - * between the result and the correctly rounded result will be one ulp (unit in the last place). - * - * log[-b](a) = NaN - * log[0](a) = NaN - * log[1](a) = NaN - * log[NaN](a) = NaN - * log[Infinity](a) = NaN - * log[b](0) = -Infinity - * log[b](-0) = -Infinity - * log[b](-a) = NaN - * log[b](1) = 0 - * log[b](Infinity) = Infinity - * log[b](NaN) = NaN - * - * [base] {number|string|Decimal} The base of the logarithm. - * - */ - P.logarithm = P.log = function (base) { - var isBase10, d, denominator, k, inf, num, sd, r, - arg = this, - Ctor = arg.constructor, - pr = Ctor.precision, - rm = Ctor.rounding, - guard = 5; - - // Default base is 10. - if (base == null) { - base = new Ctor(10); - isBase10 = true; - } else { - base = new Ctor(base); - d = base.d; - - // Return NaN if base is negative, or non-finite, or is 0 or 1. - if (base.s < 0 || !d || !d[0] || base.eq(1)) return new Ctor(NaN); - - isBase10 = base.eq(10); - } - - d = arg.d; - - // Is arg negative, non-finite, 0 or 1? - if (arg.s < 0 || !d || !d[0] || arg.eq(1)) { - return new Ctor(d && !d[0] ? -1 / 0 : arg.s != 1 ? NaN : d ? 0 : 1 / 0); - } - - // The result will have a non-terminating decimal expansion if base is 10 and arg is not an - // integer power of 10. - if (isBase10) { - if (d.length > 1) { - inf = true; - } else { - for (k = d[0]; k % 10 === 0;) k /= 10; - inf = k !== 1; - } - } - - external = false; - sd = pr + guard; - num = naturalLogarithm(arg, sd); - denominator = isBase10 ? getLn10(Ctor, sd + 10) : naturalLogarithm(base, sd); - - // The result will have 5 rounding digits. - r = divide(num, denominator, sd, 1); - - // If at a rounding boundary, i.e. the result's rounding digits are [49]9999 or [50]0000, - // calculate 10 further digits. - // - // If the result is known to have an infinite decimal expansion, repeat this until it is clear - // that the result is above or below the boundary. Otherwise, if after calculating the 10 - // further digits, the last 14 are nines, round up and assume the result is exact. - // Also assume the result is exact if the last 14 are zero. - // - // Example of a result that will be incorrectly rounded: - // log[1048576](4503599627370502) = 2.60000000000000009610279511444746... - // The above result correctly rounded using ROUND_CEIL to 1 decimal place should be 2.7, but it - // will be given as 2.6 as there are 15 zeros immediately after the requested decimal place, so - // the exact result would be assumed to be 2.6, which rounded using ROUND_CEIL to 1 decimal - // place is still 2.6. - if (checkRoundingDigits(r.d, k = pr, rm)) { - - do { - sd += 10; - num = naturalLogarithm(arg, sd); - denominator = isBase10 ? getLn10(Ctor, sd + 10) : naturalLogarithm(base, sd); - r = divide(num, denominator, sd, 1); - - if (!inf) { - - // Check for 14 nines from the 2nd rounding digit, as the first may be 4. - if (+digitsToString(r.d).slice(k + 1, k + 15) + 1 == 1e14) { - r = finalise(r, pr + 1, 0); - } - - break; - } - } while (checkRoundingDigits(r.d, k += 10, rm)); - } - - external = true; - - return finalise(r, pr, rm); - }; - - - /* - * Return a new Decimal whose value is the maximum of the arguments and the value of this Decimal. - * - * arguments {number|string|Decimal} - * - P.max = function () { - Array.prototype.push.call(arguments, this); - return maxOrMin(this.constructor, arguments, 'lt'); - }; - */ - - - /* - * Return a new Decimal whose value is the minimum of the arguments and the value of this Decimal. - * - * arguments {number|string|Decimal} - * - P.min = function () { - Array.prototype.push.call(arguments, this); - return maxOrMin(this.constructor, arguments, 'gt'); - }; - */ - - - /* - * n - 0 = n - * n - N = N - * n - I = -I - * 0 - n = -n - * 0 - 0 = 0 - * 0 - N = N - * 0 - I = -I - * N - n = N - * N - 0 = N - * N - N = N - * N - I = N - * I - n = I - * I - 0 = I - * I - N = N - * I - I = N - * - * Return a new Decimal whose value is the value of this Decimal minus `y`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - */ - P.minus = P.sub = function (y) { - var d, e, i, j, k, len, pr, rm, xd, xe, xLTy, yd, - x = this, - Ctor = x.constructor; - - y = new Ctor(y); - - // If either is not finite... - if (!x.d || !y.d) { - - // Return NaN if either is NaN. - if (!x.s || !y.s) y = new Ctor(NaN); - - // Return y negated if x is finite and y is ±Infinity. - else if (x.d) y.s = -y.s; - - // Return x if y is finite and x is ±Infinity. - // Return x if both are ±Infinity with different signs. - // Return NaN if both are ±Infinity with the same sign. - else y = new Ctor(y.d || x.s !== y.s ? x : NaN); - - return y; - } - - // If signs differ... - if (x.s != y.s) { - y.s = -y.s; - return x.plus(y); - } - - xd = x.d; - yd = y.d; - pr = Ctor.precision; - rm = Ctor.rounding; - - // If either is zero... - if (!xd[0] || !yd[0]) { - - // Return y negated if x is zero and y is non-zero. - if (yd[0]) y.s = -y.s; - - // Return x if y is zero and x is non-zero. - else if (xd[0]) y = new Ctor(x); - - // Return zero if both are zero. - // From IEEE 754 (2008) 6.3: 0 - 0 = -0 - -0 = -0 when rounding to -Infinity. - else return new Ctor(rm === 3 ? -0 : 0); - - return external ? finalise(y, pr, rm) : y; - } - - // x and y are finite, non-zero numbers with the same sign. - - // Calculate base 1e7 exponents. - e = mathfloor(y.e / LOG_BASE); - xe = mathfloor(x.e / LOG_BASE); - - xd = xd.slice(); - k = xe - e; - - // If base 1e7 exponents differ... - if (k) { - xLTy = k < 0; - - if (xLTy) { - d = xd; - k = -k; - len = yd.length; - } else { - d = yd; - e = xe; - len = xd.length; - } - - // Numbers with massively different exponents would result in a very high number of - // zeros needing to be prepended, but this can be avoided while still ensuring correct - // rounding by limiting the number of zeros to `Math.ceil(pr / LOG_BASE) + 2`. - i = Math.max(Math.ceil(pr / LOG_BASE), len) + 2; - - if (k > i) { - k = i; - d.length = 1; - } - - // Prepend zeros to equalise exponents. - d.reverse(); - for (i = k; i--;) d.push(0); - d.reverse(); - - // Base 1e7 exponents equal. - } else { - - // Check digits to determine which is the bigger number. - - i = xd.length; - len = yd.length; - xLTy = i < len; - if (xLTy) len = i; - - for (i = 0; i < len; i++) { - if (xd[i] != yd[i]) { - xLTy = xd[i] < yd[i]; - break; - } - } - - k = 0; - } - - if (xLTy) { - d = xd; - xd = yd; - yd = d; - y.s = -y.s; - } - - len = xd.length; - - // Append zeros to `xd` if shorter. - // Don't add zeros to `yd` if shorter as subtraction only needs to start at `yd` length. - for (i = yd.length - len; i > 0; --i) xd[len++] = 0; - - // Subtract yd from xd. - for (i = yd.length; i > k;) { - - if (xd[--i] < yd[i]) { - for (j = i; j && xd[--j] === 0;) xd[j] = BASE - 1; - --xd[j]; - xd[i] += BASE; - } - - xd[i] -= yd[i]; - } - - // Remove trailing zeros. - for (; xd[--len] === 0;) xd.pop(); - - // Remove leading zeros and adjust exponent accordingly. - for (; xd[0] === 0; xd.shift()) --e; - - // Zero? - if (!xd[0]) return new Ctor(rm === 3 ? -0 : 0); - - y.d = xd; - y.e = getBase10Exponent(xd, e); - - return external ? finalise(y, pr, rm) : y; - }; - - - /* - * n % 0 = N - * n % N = N - * n % I = n - * 0 % n = 0 - * -0 % n = -0 - * 0 % 0 = N - * 0 % N = N - * 0 % I = 0 - * N % n = N - * N % 0 = N - * N % N = N - * N % I = N - * I % n = N - * I % 0 = N - * I % N = N - * I % I = N - * - * Return a new Decimal whose value is the value of this Decimal modulo `y`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * The result depends on the modulo mode. - * - */ - P.modulo = P.mod = function (y) { - var q, - x = this, - Ctor = x.constructor; - - y = new Ctor(y); - - // Return NaN if x is ±Infinity or NaN, or y is NaN or ±0. - if (!x.d || !y.s || y.d && !y.d[0]) return new Ctor(NaN); - - // Return x if y is ±Infinity or x is ±0. - if (!y.d || x.d && !x.d[0]) { - return finalise(new Ctor(x), Ctor.precision, Ctor.rounding); - } - - // Prevent rounding of intermediate calculations. - external = false; - - if (Ctor.modulo == 9) { - - // Euclidian division: q = sign(y) * floor(x / abs(y)) - // result = x - q * y where 0 <= result < abs(y) - q = divide(x, y.abs(), 0, 3, 1); - q.s *= y.s; - } else { - q = divide(x, y, 0, Ctor.modulo, 1); - } - - q = q.times(y); - - external = true; - - return x.minus(q); - }; - - - /* - * Return a new Decimal whose value is the natural exponential of the value of this Decimal, - * i.e. the base e raised to the power the value of this Decimal, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - */ - P.naturalExponential = P.exp = function () { - return naturalExponential(this); - }; - - - /* - * Return a new Decimal whose value is the natural logarithm of the value of this Decimal, - * rounded to `precision` significant digits using rounding mode `rounding`. - * - */ - P.naturalLogarithm = P.ln = function () { - return naturalLogarithm(this); - }; - - - /* - * Return a new Decimal whose value is the value of this Decimal negated, i.e. as if multiplied by - * -1. - * - */ - P.negated = P.neg = function () { - var x = new this.constructor(this); - x.s = -x.s; - return finalise(x); - }; - - - /* - * n + 0 = n - * n + N = N - * n + I = I - * 0 + n = n - * 0 + 0 = 0 - * 0 + N = N - * 0 + I = I - * N + n = N - * N + 0 = N - * N + N = N - * N + I = N - * I + n = I - * I + 0 = I - * I + N = N - * I + I = I - * - * Return a new Decimal whose value is the value of this Decimal plus `y`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - */ - P.plus = P.add = function (y) { - var carry, d, e, i, k, len, pr, rm, xd, yd, - x = this, - Ctor = x.constructor; - - y = new Ctor(y); - - // If either is not finite... - if (!x.d || !y.d) { - - // Return NaN if either is NaN. - if (!x.s || !y.s) y = new Ctor(NaN); - - // Return x if y is finite and x is ±Infinity. - // Return x if both are ±Infinity with the same sign. - // Return NaN if both are ±Infinity with different signs. - // Return y if x is finite and y is ±Infinity. - else if (!x.d) y = new Ctor(y.d || x.s === y.s ? x : NaN); - - return y; - } - - // If signs differ... - if (x.s != y.s) { - y.s = -y.s; - return x.minus(y); - } - - xd = x.d; - yd = y.d; - pr = Ctor.precision; - rm = Ctor.rounding; - - // If either is zero... - if (!xd[0] || !yd[0]) { - - // Return x if y is zero. - // Return y if y is non-zero. - if (!yd[0]) y = new Ctor(x); - - return external ? finalise(y, pr, rm) : y; - } - - // x and y are finite, non-zero numbers with the same sign. - - // Calculate base 1e7 exponents. - k = mathfloor(x.e / LOG_BASE); - e = mathfloor(y.e / LOG_BASE); - - xd = xd.slice(); - i = k - e; - - // If base 1e7 exponents differ... - if (i) { - - if (i < 0) { - d = xd; - i = -i; - len = yd.length; - } else { - d = yd; - e = k; - len = xd.length; - } - - // Limit number of zeros prepended to max(ceil(pr / LOG_BASE), len) + 1. - k = Math.ceil(pr / LOG_BASE); - len = k > len ? k + 1 : len + 1; - - if (i > len) { - i = len; - d.length = 1; - } - - // Prepend zeros to equalise exponents. Note: Faster to use reverse then do unshifts. - d.reverse(); - for (; i--;) d.push(0); - d.reverse(); - } - - len = xd.length; - i = yd.length; - - // If yd is longer than xd, swap xd and yd so xd points to the longer array. - if (len - i < 0) { - i = len; - d = yd; - yd = xd; - xd = d; - } - - // Only start adding at yd.length - 1 as the further digits of xd can be left as they are. - for (carry = 0; i;) { - carry = (xd[--i] = xd[i] + yd[i] + carry) / BASE | 0; - xd[i] %= BASE; - } - - if (carry) { - xd.unshift(carry); - ++e; - } - - // Remove trailing zeros. - // No need to check for zero, as +x + +y != 0 && -x + -y != 0 - for (len = xd.length; xd[--len] == 0;) xd.pop(); - - y.d = xd; - y.e = getBase10Exponent(xd, e); - - return external ? finalise(y, pr, rm) : y; - }; - - - /* - * Return the number of significant digits of the value of this Decimal. - * - * [z] {boolean|number} Whether to count integer-part trailing zeros: true, false, 1 or 0. - * - */ - P.precision = P.sd = function (z) { - var k, - x = this; - - if (z !== void 0 && z !== !!z && z !== 1 && z !== 0) throw Error(invalidArgument + z); - - if (x.d) { - k = getPrecision(x.d); - if (z && x.e + 1 > k) k = x.e + 1; - } else { - k = NaN; - } - - return k; - }; - - - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a whole number using - * rounding mode `rounding`. - * - */ - P.round = function () { - var x = this, - Ctor = x.constructor; - - return finalise(new Ctor(x), x.e + 1, Ctor.rounding); - }; - - - /* - * Return a new Decimal whose value is the sine of the value in radians of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-1, 1] - * - * sin(x) = x - x^3/3! + x^5/5! - ... - * - * sin(0) = 0 - * sin(-0) = -0 - * sin(Infinity) = NaN - * sin(-Infinity) = NaN - * sin(NaN) = NaN - * - */ - P.sine = P.sin = function () { - var pr, rm, - x = this, - Ctor = x.constructor; - - if (!x.isFinite()) return new Ctor(NaN); - if (x.isZero()) return new Ctor(x); - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + Math.max(x.e, x.sd()) + LOG_BASE; - Ctor.rounding = 1; - - x = sine(Ctor, toLessThanHalfPi(Ctor, x)); - - Ctor.precision = pr; - Ctor.rounding = rm; - - return finalise(quadrant > 2 ? x.neg() : x, pr, rm, true); - }; - - - /* - * Return a new Decimal whose value is the square root of this Decimal, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * sqrt(-n) = N - * sqrt(N) = N - * sqrt(-I) = N - * sqrt(I) = I - * sqrt(0) = 0 - * sqrt(-0) = -0 - * - */ - P.squareRoot = P.sqrt = function () { - var m, n, sd, r, rep, t, - x = this, - d = x.d, - e = x.e, - s = x.s, - Ctor = x.constructor; - - // Negative/NaN/Infinity/zero? - if (s !== 1 || !d || !d[0]) { - return new Ctor(!s || s < 0 && (!d || d[0]) ? NaN : d ? x : 1 / 0); - } - - external = false; - - // Initial estimate. - s = Math.sqrt(+x); - - // Math.sqrt underflow/overflow? - // Pass x to Math.sqrt as integer, then adjust the exponent of the result. - if (s == 0 || s == 1 / 0) { - n = digitsToString(d); - - if ((n.length + e) % 2 == 0) n += '0'; - s = Math.sqrt(n); - e = mathfloor((e + 1) / 2) - (e < 0 || e % 2); - - if (s == 1 / 0) { - n = '1e' + e; - } else { - n = s.toExponential(); - n = n.slice(0, n.indexOf('e') + 1) + e; - } - - r = new Ctor(n); - } else { - r = new Ctor(s.toString()); - } - - sd = (e = Ctor.precision) + 3; - - // Newton-Raphson iteration. - for (;;) { - t = r; - r = t.plus(divide(x, t, sd + 2, 1)).times(0.5); - - // TODO? Replace with for-loop and checkRoundingDigits. - if (digitsToString(t.d).slice(0, sd) === (n = digitsToString(r.d)).slice(0, sd)) { - n = n.slice(sd - 3, sd + 1); - - // The 4th rounding digit may be in error by -1 so if the 4 rounding digits are 9999 or - // 4999, i.e. approaching a rounding boundary, continue the iteration. - if (n == '9999' || !rep && n == '4999') { - - // On the first iteration only, check to see if rounding up gives the exact result as the - // nines may infinitely repeat. - if (!rep) { - finalise(t, e + 1, 0); - - if (t.times(t).eq(x)) { - r = t; - break; - } - } - - sd += 4; - rep = 1; - } else { - - // If the rounding digits are null, 0{0,4} or 50{0,3}, check for an exact result. - // If not, then there are further digits and m will be truthy. - if (!+n || !+n.slice(1) && n.charAt(0) == '5') { - - // Truncate to the first rounding digit. - finalise(r, e + 1, 1); - m = !r.times(r).eq(x); - } - - break; - } - } - } - - external = true; - - return finalise(r, e, Ctor.rounding, m); - }; - - - /* - * Return a new Decimal whose value is the tangent of the value in radians of this Decimal. - * - * Domain: [-Infinity, Infinity] - * Range: [-Infinity, Infinity] - * - * tan(0) = 0 - * tan(-0) = -0 - * tan(Infinity) = NaN - * tan(-Infinity) = NaN - * tan(NaN) = NaN - * - */ - P.tangent = P.tan = function () { - var pr, rm, - x = this, - Ctor = x.constructor; - - if (!x.isFinite()) return new Ctor(NaN); - if (x.isZero()) return new Ctor(x); - - pr = Ctor.precision; - rm = Ctor.rounding; - Ctor.precision = pr + 10; - Ctor.rounding = 1; - - x = x.sin(); - x.s = 1; - x = divide(x, new Ctor(1).minus(x.times(x)).sqrt(), pr + 10, 0); - - Ctor.precision = pr; - Ctor.rounding = rm; - - return finalise(quadrant == 2 || quadrant == 4 ? x.neg() : x, pr, rm, true); - }; - - - /* - * n * 0 = 0 - * n * N = N - * n * I = I - * 0 * n = 0 - * 0 * 0 = 0 - * 0 * N = N - * 0 * I = N - * N * n = N - * N * 0 = N - * N * N = N - * N * I = N - * I * n = I - * I * 0 = N - * I * N = N - * I * I = I - * - * Return a new Decimal whose value is this Decimal times `y`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - */ - P.times = P.mul = function (y) { - var carry, e, i, k, r, rL, t, xdL, ydL, - x = this, - Ctor = x.constructor, - xd = x.d, - yd = (y = new Ctor(y)).d; - - y.s *= x.s; - - // If either is NaN, ±Infinity or ±0... - if (!xd || !xd[0] || !yd || !yd[0]) { - - return new Ctor(!y.s || xd && !xd[0] && !yd || yd && !yd[0] && !xd - - // Return NaN if either is NaN. - // Return NaN if x is ±0 and y is ±Infinity, or y is ±0 and x is ±Infinity. - ? NaN - - // Return ±Infinity if either is ±Infinity. - // Return ±0 if either is ±0. - : !xd || !yd ? y.s / 0 : y.s * 0); - } - - e = mathfloor(x.e / LOG_BASE) + mathfloor(y.e / LOG_BASE); - xdL = xd.length; - ydL = yd.length; - - // Ensure xd points to the longer array. - if (xdL < ydL) { - r = xd; - xd = yd; - yd = r; - rL = xdL; - xdL = ydL; - ydL = rL; - } - - // Initialise the result array with zeros. - r = []; - rL = xdL + ydL; - for (i = rL; i--;) r.push(0); - - // Multiply! - for (i = ydL; --i >= 0;) { - carry = 0; - for (k = xdL + i; k > i;) { - t = r[k] + yd[i] * xd[k - i - 1] + carry; - r[k--] = t % BASE | 0; - carry = t / BASE | 0; - } - - r[k] = (r[k] + carry) % BASE | 0; - } - - // Remove trailing zeros. - for (; !r[--rL];) r.pop(); - - if (carry) ++e; - else r.shift(); - - y.d = r; - y.e = getBase10Exponent(r, e); - - return external ? finalise(y, Ctor.precision, Ctor.rounding) : y; - }; - - - /* - * Return a string representing the value of this Decimal in base 2, round to `sd` significant - * digits using rounding mode `rm`. - * - * If the optional `sd` argument is present then return binary exponential notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toBinary = function (sd, rm) { - return toStringBinary(this, 2, sd, rm); - }; - - - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `dp` - * decimal places using rounding mode `rm` or `rounding` if `rm` is omitted. - * - * If `dp` is omitted, return a new Decimal whose value is the value of this Decimal. - * - * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toDecimalPlaces = P.toDP = function (dp, rm) { - var x = this, - Ctor = x.constructor; - - x = new Ctor(x); - if (dp === void 0) return x; - - checkInt32(dp, 0, MAX_DIGITS); - - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); - - return finalise(x, dp + x.e + 1, rm); - }; - - - /* - * Return a string representing the value of this Decimal in exponential notation rounded to - * `dp` fixed decimal places using rounding mode `rounding`. - * - * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toExponential = function (dp, rm) { - var str, - x = this, - Ctor = x.constructor; - - if (dp === void 0) { - str = finiteToString(x, true); - } else { - checkInt32(dp, 0, MAX_DIGITS); - - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); - - x = finalise(new Ctor(x), dp + 1, rm); - str = finiteToString(x, true, dp + 1); - } - - return x.isNeg() && !x.isZero() ? '-' + str : str; - }; - - - /* - * Return a string representing the value of this Decimal in normal (fixed-point) notation to - * `dp` fixed decimal places and rounded using rounding mode `rm` or `rounding` if `rm` is - * omitted. - * - * As with JavaScript numbers, (-0).toFixed(0) is '0', but e.g. (-0.00001).toFixed(0) is '-0'. - * - * [dp] {number} Decimal places. Integer, 0 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * (-0).toFixed(0) is '0', but (-0.1).toFixed(0) is '-0'. - * (-0).toFixed(1) is '0.0', but (-0.01).toFixed(1) is '-0.0'. - * (-0).toFixed(3) is '0.000'. - * (-0.5).toFixed(0) is '-0'. - * - */ - P.toFixed = function (dp, rm) { - var str, y, - x = this, - Ctor = x.constructor; - - if (dp === void 0) { - str = finiteToString(x); - } else { - checkInt32(dp, 0, MAX_DIGITS); - - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); - - y = finalise(new Ctor(x), dp + x.e + 1, rm); - str = finiteToString(y, false, dp + y.e + 1); - } - - // To determine whether to add the minus sign look at the value before it was rounded, - // i.e. look at `x` rather than `y`. - return x.isNeg() && !x.isZero() ? '-' + str : str; - }; - - - /* - * Return an array representing the value of this Decimal as a simple fraction with an integer - * numerator and an integer denominator. - * - * The denominator will be a positive non-zero value less than or equal to the specified maximum - * denominator. If a maximum denominator is not specified, the denominator will be the lowest - * value necessary to represent the number exactly. - * - * [maxD] {number|string|Decimal} Maximum denominator. Integer >= 1 and < Infinity. - * - */ - P.toFraction = function (maxD) { - var d, d0, d1, d2, e, k, n, n0, n1, pr, q, r, - x = this, - xd = x.d, - Ctor = x.constructor; - - if (!xd) return new Ctor(x); - - n1 = d0 = new Ctor(1); - d1 = n0 = new Ctor(0); - - d = new Ctor(d1); - e = d.e = getPrecision(xd) - x.e - 1; - k = e % LOG_BASE; - d.d[0] = mathpow(10, k < 0 ? LOG_BASE + k : k); - - if (maxD == null) { - - // d is 10**e, the minimum max-denominator needed. - maxD = e > 0 ? d : n1; - } else { - n = new Ctor(maxD); - if (!n.isInt() || n.lt(n1)) throw Error(invalidArgument + n); - maxD = n.gt(d) ? (e > 0 ? d : n1) : n; - } - - external = false; - n = new Ctor(digitsToString(xd)); - pr = Ctor.precision; - Ctor.precision = e = xd.length * LOG_BASE * 2; - - for (;;) { - q = divide(n, d, 0, 1, 1); - d2 = d0.plus(q.times(d1)); - if (d2.cmp(maxD) == 1) break; - d0 = d1; - d1 = d2; - d2 = n1; - n1 = n0.plus(q.times(d2)); - n0 = d2; - d2 = d; - d = n.minus(q.times(d2)); - n = d2; - } - - d2 = divide(maxD.minus(d0), d1, 0, 1, 1); - n0 = n0.plus(d2.times(n1)); - d0 = d0.plus(d2.times(d1)); - n0.s = n1.s = x.s; - - // Determine which fraction is closer to x, n0/d0 or n1/d1? - r = divide(n1, d1, e, 1).minus(x).abs().cmp(divide(n0, d0, e, 1).minus(x).abs()) < 1 - ? [n1, d1] : [n0, d0]; - - Ctor.precision = pr; - external = true; - - return r; - }; - - - /* - * Return a string representing the value of this Decimal in base 16, round to `sd` significant - * digits using rounding mode `rm`. - * - * If the optional `sd` argument is present then return binary exponential notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toHexadecimal = P.toHex = function (sd, rm) { - return toStringBinary(this, 16, sd, rm); - }; - - - - /* - * Returns a new Decimal whose value is the nearest multiple of the magnitude of `y` to the value - * of this Decimal. - * - * If the value of this Decimal is equidistant from two multiples of `y`, the rounding mode `rm`, - * or `Decimal.rounding` if `rm` is omitted, determines the direction of the nearest multiple. - * - * In the context of this method, rounding mode 4 (ROUND_HALF_UP) is the same as rounding mode 0 - * (ROUND_UP), and so on. - * - * The return value will always have the same sign as this Decimal, unless either this Decimal - * or `y` is NaN, in which case the return value will be also be NaN. - * - * The return value is not affected by the value of `precision`. - * - * y {number|string|Decimal} The magnitude to round to a multiple of. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toNearest() rounding mode not an integer: {rm}' - * 'toNearest() rounding mode out of range: {rm}' - * - */ - P.toNearest = function (y, rm) { - var x = this, - Ctor = x.constructor; - - x = new Ctor(x); - - if (y == null) { - - // If x is not finite, return x. - if (!x.d) return x; - - y = new Ctor(1); - rm = Ctor.rounding; - } else { - y = new Ctor(y); - if (rm !== void 0) checkInt32(rm, 0, 8); - - // If x is not finite, return x if y is not NaN, else NaN. - if (!x.d) return y.s ? x : y; - - // If y is not finite, return Infinity with the sign of x if y is Infinity, else NaN. - if (!y.d) { - if (y.s) y.s = x.s; - return y; - } - } - - // If y is not zero, calculate the nearest multiple of y to x. - if (y.d[0]) { - external = false; - if (rm < 4) rm = [4, 5, 7, 8][rm]; - x = divide(x, y, 0, rm, 1).times(y); - external = true; - finalise(x); - - // If y is zero, return zero with the sign of x. - } else { - y.s = x.s; - x = y; - } - - return x; - }; - - - /* - * Return the value of this Decimal converted to a number primitive. - * Zero keeps its sign. - * - */ - P.toNumber = function () { - return +this; - }; - - - /* - * Return a string representing the value of this Decimal in base 8, round to `sd` significant - * digits using rounding mode `rm`. - * - * If the optional `sd` argument is present then return binary exponential notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toOctal = function (sd, rm) { - return toStringBinary(this, 8, sd, rm); - }; - - - /* - * Return a new Decimal whose value is the value of this Decimal raised to the power `y`, rounded - * to `precision` significant digits using rounding mode `rounding`. - * - * ECMAScript compliant. - * - * pow(x, NaN) = NaN - * pow(x, ±0) = 1 - - * pow(NaN, non-zero) = NaN - * pow(abs(x) > 1, +Infinity) = +Infinity - * pow(abs(x) > 1, -Infinity) = +0 - * pow(abs(x) == 1, ±Infinity) = NaN - * pow(abs(x) < 1, +Infinity) = +0 - * pow(abs(x) < 1, -Infinity) = +Infinity - * pow(+Infinity, y > 0) = +Infinity - * pow(+Infinity, y < 0) = +0 - * pow(-Infinity, odd integer > 0) = -Infinity - * pow(-Infinity, even integer > 0) = +Infinity - * pow(-Infinity, odd integer < 0) = -0 - * pow(-Infinity, even integer < 0) = +0 - * pow(+0, y > 0) = +0 - * pow(+0, y < 0) = +Infinity - * pow(-0, odd integer > 0) = -0 - * pow(-0, even integer > 0) = +0 - * pow(-0, odd integer < 0) = -Infinity - * pow(-0, even integer < 0) = +Infinity - * pow(finite x < 0, finite non-integer) = NaN - * - * For non-integer or very large exponents pow(x, y) is calculated using - * - * x^y = exp(y*ln(x)) - * - * Assuming the first 15 rounding digits are each equally likely to be any digit 0-9, the - * probability of an incorrectly rounded result - * P([49]9{14} | [50]0{14}) = 2 * 0.2 * 10^-14 = 4e-15 = 1/2.5e+14 - * i.e. 1 in 250,000,000,000,000 - * - * If a result is incorrectly rounded the maximum error will be 1 ulp (unit in last place). - * - * y {number|string|Decimal} The power to which to raise this Decimal. - * - */ - P.toPower = P.pow = function (y) { - var e, k, pr, r, rm, s, - x = this, - Ctor = x.constructor, - yn = +(y = new Ctor(y)); - - // Either ±Infinity, NaN or ±0? - if (!x.d || !y.d || !x.d[0] || !y.d[0]) return new Ctor(mathpow(+x, yn)); - - x = new Ctor(x); - - if (x.eq(1)) return x; - - pr = Ctor.precision; - rm = Ctor.rounding; - - if (y.eq(1)) return finalise(x, pr, rm); - - // y exponent - e = mathfloor(y.e / LOG_BASE); - - // If y is a small integer use the 'exponentiation by squaring' algorithm. - if (e >= y.d.length - 1 && (k = yn < 0 ? -yn : yn) <= MAX_SAFE_INTEGER) { - r = intPow(Ctor, x, k, pr); - return y.s < 0 ? new Ctor(1).div(r) : finalise(r, pr, rm); - } - - s = x.s; - - // if x is negative - if (s < 0) { - - // if y is not an integer - if (e < y.d.length - 1) return new Ctor(NaN); - - // Result is positive if x is negative and the last digit of integer y is even. - if ((y.d[e] & 1) == 0) s = 1; - - // if x.eq(-1) - if (x.e == 0 && x.d[0] == 1 && x.d.length == 1) { - x.s = s; - return x; - } - } - - // Estimate result exponent. - // x^y = 10^e, where e = y * log10(x) - // log10(x) = log10(x_significand) + x_exponent - // log10(x_significand) = ln(x_significand) / ln(10) - k = mathpow(+x, yn); - e = k == 0 || !isFinite(k) - ? mathfloor(yn * (Math.log('0.' + digitsToString(x.d)) / Math.LN10 + x.e + 1)) - : new Ctor(k + '').e; - - // Exponent estimate may be incorrect e.g. x: 0.999999999999999999, y: 2.29, e: 0, r.e: -1. - - // Overflow/underflow? - if (e > Ctor.maxE + 1 || e < Ctor.minE - 1) return new Ctor(e > 0 ? s / 0 : 0); - - external = false; - Ctor.rounding = x.s = 1; - - // Estimate the extra guard digits needed to ensure five correct rounding digits from - // naturalLogarithm(x). Example of failure without these extra digits (precision: 10): - // new Decimal(2.32456).pow('2087987436534566.46411') - // should be 1.162377823e+764914905173815, but is 1.162355823e+764914905173815 - k = Math.min(12, (e + '').length); - - // r = x^y = exp(y*ln(x)) - r = naturalExponential(y.times(naturalLogarithm(x, pr + k)), pr); - - // r may be Infinity, e.g. (0.9999999999999999).pow(-1e+40) - if (r.d) { - - // Truncate to the required precision plus five rounding digits. - r = finalise(r, pr + 5, 1); - - // If the rounding digits are [49]9999 or [50]0000 increase the precision by 10 and recalculate - // the result. - if (checkRoundingDigits(r.d, pr, rm)) { - e = pr + 10; - - // Truncate to the increased precision plus five rounding digits. - r = finalise(naturalExponential(y.times(naturalLogarithm(x, e + k)), e), e + 5, 1); - - // Check for 14 nines from the 2nd rounding digit (the first rounding digit may be 4 or 9). - if (+digitsToString(r.d).slice(pr + 1, pr + 15) + 1 == 1e14) { - r = finalise(r, pr + 1, 0); - } - } - } - - r.s = s; - external = true; - Ctor.rounding = rm; - - return finalise(r, pr, rm); - }; - - - /* - * Return a string representing the value of this Decimal rounded to `sd` significant digits - * using rounding mode `rounding`. - * - * Return exponential notation if `sd` is less than the number of digits necessary to represent - * the integer part of the value in normal notation. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - */ - P.toPrecision = function (sd, rm) { - var str, - x = this, - Ctor = x.constructor; - - if (sd === void 0) { - str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); - } else { - checkInt32(sd, 1, MAX_DIGITS); - - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); - - x = finalise(new Ctor(x), sd, rm); - str = finiteToString(x, sd <= x.e || x.e <= Ctor.toExpNeg, sd); - } - - return x.isNeg() && !x.isZero() ? '-' + str : str; - }; - - - /* - * Return a new Decimal whose value is the value of this Decimal rounded to a maximum of `sd` - * significant digits using rounding mode `rm`, or to `precision` and `rounding` respectively if - * omitted. - * - * [sd] {number} Significant digits. Integer, 1 to MAX_DIGITS inclusive. - * [rm] {number} Rounding mode. Integer, 0 to 8 inclusive. - * - * 'toSD() digits out of range: {sd}' - * 'toSD() digits not an integer: {sd}' - * 'toSD() rounding mode not an integer: {rm}' - * 'toSD() rounding mode out of range: {rm}' - * - */ - P.toSignificantDigits = P.toSD = function (sd, rm) { - var x = this, - Ctor = x.constructor; - - if (sd === void 0) { - sd = Ctor.precision; - rm = Ctor.rounding; - } else { - checkInt32(sd, 1, MAX_DIGITS); - - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); - } - - return finalise(new Ctor(x), sd, rm); - }; - - - /* - * Return a string representing the value of this Decimal. - * - * Return exponential notation if this Decimal has a positive exponent equal to or greater than - * `toExpPos`, or a negative exponent equal to or less than `toExpNeg`. - * - */ - P.toString = function () { - var x = this, - Ctor = x.constructor, - str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); - - return x.isNeg() && !x.isZero() ? '-' + str : str; - }; - - - /* - * Return a new Decimal whose value is the value of this Decimal truncated to a whole number. - * - */ - P.truncated = P.trunc = function () { - return finalise(new this.constructor(this), this.e + 1, 1); - }; - - - /* - * Return a string representing the value of this Decimal. - * Unlike `toString`, negative zero will include the minus sign. - * - */ - P.valueOf = P.toJSON = function () { - var x = this, - Ctor = x.constructor, - str = finiteToString(x, x.e <= Ctor.toExpNeg || x.e >= Ctor.toExpPos); - - return x.isNeg() ? '-' + str : str; - }; - - - /* - // Add aliases to match BigDecimal method names. - // P.add = P.plus; - P.subtract = P.minus; - P.multiply = P.times; - P.divide = P.div; - P.remainder = P.mod; - P.compareTo = P.cmp; - P.negate = P.neg; - */ - - - // Helper functions for Decimal.prototype (P) and/or Decimal methods, and their callers. - - - /* - * digitsToString P.cubeRoot, P.logarithm, P.squareRoot, P.toFraction, P.toPower, - * finiteToString, naturalExponential, naturalLogarithm - * checkInt32 P.toDecimalPlaces, P.toExponential, P.toFixed, P.toNearest, - * P.toPrecision, P.toSignificantDigits, toStringBinary, random - * checkRoundingDigits P.logarithm, P.toPower, naturalExponential, naturalLogarithm - * convertBase toStringBinary, parseOther - * cos P.cos - * divide P.atanh, P.cubeRoot, P.dividedBy, P.dividedToIntegerBy, - * P.logarithm, P.modulo, P.squareRoot, P.tan, P.tanh, P.toFraction, - * P.toNearest, toStringBinary, naturalExponential, naturalLogarithm, - * taylorSeries, atan2, parseOther - * finalise P.absoluteValue, P.atan, P.atanh, P.ceil, P.cos, P.cosh, - * P.cubeRoot, P.dividedToIntegerBy, P.floor, P.logarithm, P.minus, - * P.modulo, P.negated, P.plus, P.round, P.sin, P.sinh, P.squareRoot, - * P.tan, P.times, P.toDecimalPlaces, P.toExponential, P.toFixed, - * P.toNearest, P.toPower, P.toPrecision, P.toSignificantDigits, - * P.truncated, divide, getLn10, getPi, naturalExponential, - * naturalLogarithm, ceil, floor, round, trunc - * finiteToString P.toExponential, P.toFixed, P.toPrecision, P.toString, P.valueOf, - * toStringBinary - * getBase10Exponent P.minus, P.plus, P.times, parseOther - * getLn10 P.logarithm, naturalLogarithm - * getPi P.acos, P.asin, P.atan, toLessThanHalfPi, atan2 - * getPrecision P.precision, P.toFraction - * getZeroString digitsToString, finiteToString - * intPow P.toPower, parseOther - * isOdd toLessThanHalfPi - * maxOrMin max, min - * naturalExponential P.naturalExponential, P.toPower - * naturalLogarithm P.acosh, P.asinh, P.atanh, P.logarithm, P.naturalLogarithm, - * P.toPower, naturalExponential - * nonFiniteToString finiteToString, toStringBinary - * parseDecimal Decimal - * parseOther Decimal - * sin P.sin - * taylorSeries P.cosh, P.sinh, cos, sin - * toLessThanHalfPi P.cos, P.sin - * toStringBinary P.toBinary, P.toHexadecimal, P.toOctal - * truncate intPow - * - * Throws: P.logarithm, P.precision, P.toFraction, checkInt32, getLn10, getPi, - * naturalLogarithm, config, parseOther, random, Decimal - */ - - - function digitsToString(d) { - var i, k, ws, - indexOfLastWord = d.length - 1, - str = '', - w = d[0]; - - if (indexOfLastWord > 0) { - str += w; - for (i = 1; i < indexOfLastWord; i++) { - ws = d[i] + ''; - k = LOG_BASE - ws.length; - if (k) str += getZeroString(k); - str += ws; - } - - w = d[i]; - ws = w + ''; - k = LOG_BASE - ws.length; - if (k) str += getZeroString(k); - } else if (w === 0) { - return '0'; - } - - // Remove trailing zeros of last w. - for (; w % 10 === 0;) w /= 10; - - return str + w; - } - - - function checkInt32(i, min, max) { - if (i !== ~~i || i < min || i > max) { - throw Error(invalidArgument + i); - } - } - - - /* - * Check 5 rounding digits if `repeating` is null, 4 otherwise. - * `repeating == null` if caller is `log` or `pow`, - * `repeating != null` if caller is `naturalLogarithm` or `naturalExponential`. - */ - function checkRoundingDigits(d, i, rm, repeating) { - var di, k, r, rd; - - // Get the length of the first word of the array d. - for (k = d[0]; k >= 10; k /= 10) --i; - - // Is the rounding digit in the first word of d? - if (--i < 0) { - i += LOG_BASE; - di = 0; - } else { - di = Math.ceil((i + 1) / LOG_BASE); - i %= LOG_BASE; - } - - // i is the index (0 - 6) of the rounding digit. - // E.g. if within the word 3487563 the first rounding digit is 5, - // then i = 4, k = 1000, rd = 3487563 % 1000 = 563 - k = mathpow(10, LOG_BASE - i); - rd = d[di] % k | 0; - - if (repeating == null) { - if (i < 3) { - if (i == 0) rd = rd / 100 | 0; - else if (i == 1) rd = rd / 10 | 0; - r = rm < 4 && rd == 99999 || rm > 3 && rd == 49999 || rd == 50000 || rd == 0; - } else { - r = (rm < 4 && rd + 1 == k || rm > 3 && rd + 1 == k / 2) && - (d[di + 1] / k / 100 | 0) == mathpow(10, i - 2) - 1 || - (rd == k / 2 || rd == 0) && (d[di + 1] / k / 100 | 0) == 0; - } - } else { - if (i < 4) { - if (i == 0) rd = rd / 1000 | 0; - else if (i == 1) rd = rd / 100 | 0; - else if (i == 2) rd = rd / 10 | 0; - r = (repeating || rm < 4) && rd == 9999 || !repeating && rm > 3 && rd == 4999; - } else { - r = ((repeating || rm < 4) && rd + 1 == k || - (!repeating && rm > 3) && rd + 1 == k / 2) && - (d[di + 1] / k / 1000 | 0) == mathpow(10, i - 3) - 1; - } - } - - return r; - } - - - // Convert string of `baseIn` to an array of numbers of `baseOut`. - // Eg. convertBase('255', 10, 16) returns [15, 15]. - // Eg. convertBase('ff', 16, 10) returns [2, 5, 5]. - function convertBase(str, baseIn, baseOut) { - var j, - arr = [0], - arrL, - i = 0, - strL = str.length; - - for (; i < strL;) { - for (arrL = arr.length; arrL--;) arr[arrL] *= baseIn; - arr[0] += NUMERALS.indexOf(str.charAt(i++)); - for (j = 0; j < arr.length; j++) { - if (arr[j] > baseOut - 1) { - if (arr[j + 1] === void 0) arr[j + 1] = 0; - arr[j + 1] += arr[j] / baseOut | 0; - arr[j] %= baseOut; - } - } - } - - return arr.reverse(); - } - - - /* - * cos(x) = 1 - x^2/2! + x^4/4! - ... - * |x| < pi/2 - * - */ - function cosine(Ctor, x) { - var k, y, - len = x.d.length; - - // Argument reduction: cos(4x) = 8*(cos^4(x) - cos^2(x)) + 1 - // i.e. cos(x) = 8*(cos^4(x/4) - cos^2(x/4)) + 1 - - // Estimate the optimum number of times to use the argument reduction. - if (len < 32) { - k = Math.ceil(len / 3); - y = Math.pow(4, -k).toString(); - } else { - k = 16; - y = '2.3283064365386962890625e-10'; - } - - Ctor.precision += k; - - x = taylorSeries(Ctor, 1, x.times(y), new Ctor(1)); - - // Reverse argument reduction - for (var i = k; i--;) { - var cos2x = x.times(x); - x = cos2x.times(cos2x).minus(cos2x).times(8).plus(1); - } - - Ctor.precision -= k; - - return x; - } - - - /* - * Perform division in the specified base. - */ - var divide = (function () { - - // Assumes non-zero x and k, and hence non-zero result. - function multiplyInteger(x, k, base) { - var temp, - carry = 0, - i = x.length; - - for (x = x.slice(); i--;) { - temp = x[i] * k + carry; - x[i] = temp % base | 0; - carry = temp / base | 0; - } - - if (carry) x.unshift(carry); - - return x; - } - - function compare(a, b, aL, bL) { - var i, r; - - if (aL != bL) { - r = aL > bL ? 1 : -1; - } else { - for (i = r = 0; i < aL; i++) { - if (a[i] != b[i]) { - r = a[i] > b[i] ? 1 : -1; - break; - } - } - } - - return r; - } - - function subtract(a, b, aL, base) { - var i = 0; - - // Subtract b from a. - for (; aL--;) { - a[aL] -= i; - i = a[aL] < b[aL] ? 1 : 0; - a[aL] = i * base + a[aL] - b[aL]; - } - - // Remove leading zeros. - for (; !a[0] && a.length > 1;) a.shift(); - } - - return function (x, y, pr, rm, dp, base) { - var cmp, e, i, k, logBase, more, prod, prodL, q, qd, rem, remL, rem0, sd, t, xi, xL, yd0, - yL, yz, - Ctor = x.constructor, - sign = x.s == y.s ? 1 : -1, - xd = x.d, - yd = y.d; - - // Either NaN, Infinity or 0? - if (!xd || !xd[0] || !yd || !yd[0]) { - - return new Ctor(// Return NaN if either NaN, or both Infinity or 0. - !x.s || !y.s || (xd ? yd && xd[0] == yd[0] : !yd) ? NaN : - - // Return ±0 if x is 0 or y is ±Infinity, or return ±Infinity as y is 0. - xd && xd[0] == 0 || !yd ? sign * 0 : sign / 0); - } - - if (base) { - logBase = 1; - e = x.e - y.e; - } else { - base = BASE; - logBase = LOG_BASE; - e = mathfloor(x.e / logBase) - mathfloor(y.e / logBase); - } - - yL = yd.length; - xL = xd.length; - q = new Ctor(sign); - qd = q.d = []; - - // Result exponent may be one less than e. - // The digit array of a Decimal from toStringBinary may have trailing zeros. - for (i = 0; yd[i] == (xd[i] || 0); i++); - - if (yd[i] > (xd[i] || 0)) e--; - - if (pr == null) { - sd = pr = Ctor.precision; - rm = Ctor.rounding; - } else if (dp) { - sd = pr + (x.e - y.e) + 1; - } else { - sd = pr; - } - - if (sd < 0) { - qd.push(1); - more = true; - } else { - - // Convert precision in number of base 10 digits to base 1e7 digits. - sd = sd / logBase + 2 | 0; - i = 0; - - // divisor < 1e7 - if (yL == 1) { - k = 0; - yd = yd[0]; - sd++; - - // k is the carry. - for (; (i < xL || k) && sd--; i++) { - t = k * base + (xd[i] || 0); - qd[i] = t / yd | 0; - k = t % yd | 0; - } - - more = k || i < xL; - - // divisor >= 1e7 - } else { - - // Normalise xd and yd so highest order digit of yd is >= base/2 - k = base / (yd[0] + 1) | 0; - - if (k > 1) { - yd = multiplyInteger(yd, k, base); - xd = multiplyInteger(xd, k, base); - yL = yd.length; - xL = xd.length; - } - - xi = yL; - rem = xd.slice(0, yL); - remL = rem.length; - - // Add zeros to make remainder as long as divisor. - for (; remL < yL;) rem[remL++] = 0; - - yz = yd.slice(); - yz.unshift(0); - yd0 = yd[0]; - - if (yd[1] >= base / 2) ++yd0; - - do { - k = 0; - - // Compare divisor and remainder. - cmp = compare(yd, rem, yL, remL); - - // If divisor < remainder. - if (cmp < 0) { - - // Calculate trial digit, k. - rem0 = rem[0]; - if (yL != remL) rem0 = rem0 * base + (rem[1] || 0); - - // k will be how many times the divisor goes into the current remainder. - k = rem0 / yd0 | 0; - - // Algorithm: - // 1. product = divisor * trial digit (k) - // 2. if product > remainder: product -= divisor, k-- - // 3. remainder -= product - // 4. if product was < remainder at 2: - // 5. compare new remainder and divisor - // 6. If remainder > divisor: remainder -= divisor, k++ - - if (k > 1) { - if (k >= base) k = base - 1; - - // product = divisor * trial digit. - prod = multiplyInteger(yd, k, base); - prodL = prod.length; - remL = rem.length; - - // Compare product and remainder. - cmp = compare(prod, rem, prodL, remL); - - // product > remainder. - if (cmp == 1) { - k--; - - // Subtract divisor from product. - subtract(prod, yL < prodL ? yz : yd, prodL, base); - } - } else { - - // cmp is -1. - // If k is 0, there is no need to compare yd and rem again below, so change cmp to 1 - // to avoid it. If k is 1 there is a need to compare yd and rem again below. - if (k == 0) cmp = k = 1; - prod = yd.slice(); - } - - prodL = prod.length; - if (prodL < remL) prod.unshift(0); - - // Subtract product from remainder. - subtract(rem, prod, remL, base); - - // If product was < previous remainder. - if (cmp == -1) { - remL = rem.length; - - // Compare divisor and new remainder. - cmp = compare(yd, rem, yL, remL); - - // If divisor < new remainder, subtract divisor from remainder. - if (cmp < 1) { - k++; - - // Subtract divisor from remainder. - subtract(rem, yL < remL ? yz : yd, remL, base); - } - } - - remL = rem.length; - } else if (cmp === 0) { - k++; - rem = [0]; - } // if cmp === 1, k will be 0 - - // Add the next digit, k, to the result array. - qd[i++] = k; - - // Update the remainder. - if (cmp && rem[0]) { - rem[remL++] = xd[xi] || 0; - } else { - rem = [xd[xi]]; - remL = 1; - } - - } while ((xi++ < xL || rem[0] !== void 0) && sd--); - - more = rem[0] !== void 0; - } - - // Leading zero? - if (!qd[0]) qd.shift(); - } - - // logBase is 1 when divide is being used for base conversion. - if (logBase == 1) { - q.e = e; - inexact = more; - } else { - - // To calculate q.e, first get the number of digits of qd[0]. - for (i = 1, k = qd[0]; k >= 10; k /= 10) i++; - q.e = i + e * logBase - 1; - - finalise(q, dp ? pr + q.e + 1 : pr, rm, more); - } - - return q; - }; - })(); - - - /* - * Round `x` to `sd` significant digits using rounding mode `rm`. - * Check for over/under-flow. - */ - function finalise(x, sd, rm, isTruncated) { - var digits, i, j, k, rd, roundUp, w, xd, xdi, - Ctor = x.constructor; - - // Don't round if sd is null or undefined. - out: if (sd != null) { - xd = x.d; - - // Infinity/NaN. - if (!xd) return x; - - // rd: the rounding digit, i.e. the digit after the digit that may be rounded up. - // w: the word of xd containing rd, a base 1e7 number. - // xdi: the index of w within xd. - // digits: the number of digits of w. - // i: what would be the index of rd within w if all the numbers were 7 digits long (i.e. if - // they had leading zeros) - // j: if > 0, the actual index of rd within w (if < 0, rd is a leading zero). - - // Get the length of the first word of the digits array xd. - for (digits = 1, k = xd[0]; k >= 10; k /= 10) digits++; - i = sd - digits; - - // Is the rounding digit in the first word of xd? - if (i < 0) { - i += LOG_BASE; - j = sd; - w = xd[xdi = 0]; - - // Get the rounding digit at index j of w. - rd = w / mathpow(10, digits - j - 1) % 10 | 0; - } else { - xdi = Math.ceil((i + 1) / LOG_BASE); - k = xd.length; - if (xdi >= k) { - if (isTruncated) { - - // Needed by `naturalExponential`, `naturalLogarithm` and `squareRoot`. - for (; k++ <= xdi;) xd.push(0); - w = rd = 0; - digits = 1; - i %= LOG_BASE; - j = i - LOG_BASE + 1; - } else { - break out; - } - } else { - w = k = xd[xdi]; - - // Get the number of digits of w. - for (digits = 1; k >= 10; k /= 10) digits++; - - // Get the index of rd within w. - i %= LOG_BASE; - - // Get the index of rd within w, adjusted for leading zeros. - // The number of leading zeros of w is given by LOG_BASE - digits. - j = i - LOG_BASE + digits; - - // Get the rounding digit at index j of w. - rd = j < 0 ? 0 : w / mathpow(10, digits - j - 1) % 10 | 0; - } - } - - // Are there any non-zero digits after the rounding digit? - isTruncated = isTruncated || sd < 0 || - xd[xdi + 1] !== void 0 || (j < 0 ? w : w % mathpow(10, digits - j - 1)); - - // The expression `w % mathpow(10, digits - j - 1)` returns all the digits of w to the right - // of the digit at (left-to-right) index j, e.g. if w is 908714 and j is 2, the expression - // will give 714. - - roundUp = rm < 4 - ? (rd || isTruncated) && (rm == 0 || rm == (x.s < 0 ? 3 : 2)) - : rd > 5 || rd == 5 && (rm == 4 || isTruncated || rm == 6 && - - // Check whether the digit to the left of the rounding digit is odd. - ((i > 0 ? j > 0 ? w / mathpow(10, digits - j) : 0 : xd[xdi - 1]) % 10) & 1 || - rm == (x.s < 0 ? 8 : 7)); - - if (sd < 1 || !xd[0]) { - xd.length = 0; - if (roundUp) { - - // Convert sd to decimal places. - sd -= x.e + 1; - - // 1, 0.1, 0.01, 0.001, 0.0001 etc. - xd[0] = mathpow(10, (LOG_BASE - sd % LOG_BASE) % LOG_BASE); - x.e = -sd || 0; - } else { - - // Zero. - xd[0] = x.e = 0; - } - - return x; - } - - // Remove excess digits. - if (i == 0) { - xd.length = xdi; - k = 1; - xdi--; - } else { - xd.length = xdi + 1; - k = mathpow(10, LOG_BASE - i); - - // E.g. 56700 becomes 56000 if 7 is the rounding digit. - // j > 0 means i > number of leading zeros of w. - xd[xdi] = j > 0 ? (w / mathpow(10, digits - j) % mathpow(10, j) | 0) * k : 0; - } - - if (roundUp) { - for (;;) { - - // Is the digit to be rounded up in the first word of xd? - if (xdi == 0) { - - // i will be the length of xd[0] before k is added. - for (i = 1, j = xd[0]; j >= 10; j /= 10) i++; - j = xd[0] += k; - for (k = 1; j >= 10; j /= 10) k++; - - // if i != k the length has increased. - if (i != k) { - x.e++; - if (xd[0] == BASE) xd[0] = 1; - } - - break; - } else { - xd[xdi] += k; - if (xd[xdi] != BASE) break; - xd[xdi--] = 0; - k = 1; - } - } - } - - // Remove trailing zeros. - for (i = xd.length; xd[--i] === 0;) xd.pop(); - } - - if (external) { - - // Overflow? - if (x.e > Ctor.maxE) { - - // Infinity. - x.d = null; - x.e = NaN; - - // Underflow? - } else if (x.e < Ctor.minE) { - - // Zero. - x.e = 0; - x.d = [0]; - // Ctor.underflow = true; - } // else Ctor.underflow = false; - } - - return x; - } - - - function finiteToString(x, isExp, sd) { - if (!x.isFinite()) return nonFiniteToString(x); - var k, - e = x.e, - str = digitsToString(x.d), - len = str.length; - - if (isExp) { - if (sd && (k = sd - len) > 0) { - str = str.charAt(0) + '.' + str.slice(1) + getZeroString(k); - } else if (len > 1) { - str = str.charAt(0) + '.' + str.slice(1); - } - - str = str + (x.e < 0 ? 'e' : 'e+') + x.e; - } else if (e < 0) { - str = '0.' + getZeroString(-e - 1) + str; - if (sd && (k = sd - len) > 0) str += getZeroString(k); - } else if (e >= len) { - str += getZeroString(e + 1 - len); - if (sd && (k = sd - e - 1) > 0) str = str + '.' + getZeroString(k); - } else { - if ((k = e + 1) < len) str = str.slice(0, k) + '.' + str.slice(k); - if (sd && (k = sd - len) > 0) { - if (e + 1 === len) str += '.'; - str += getZeroString(k); - } - } - - return str; - } - - - // Calculate the base 10 exponent from the base 1e7 exponent. - function getBase10Exponent(digits, e) { - var w = digits[0]; - - // Add the number of digits of the first word of the digits array. - for ( e *= LOG_BASE; w >= 10; w /= 10) e++; - return e; - } - - - function getLn10(Ctor, sd, pr) { - if (sd > LN10_PRECISION) { - - // Reset global state in case the exception is caught. - external = true; - if (pr) Ctor.precision = pr; - throw Error(precisionLimitExceeded); - } - return finalise(new Ctor(LN10), sd, 1, true); - } - - - function getPi(Ctor, sd, rm) { - if (sd > PI_PRECISION) throw Error(precisionLimitExceeded); - return finalise(new Ctor(PI), sd, rm, true); - } - - - function getPrecision(digits) { - var w = digits.length - 1, - len = w * LOG_BASE + 1; - - w = digits[w]; - - // If non-zero... - if (w) { - - // Subtract the number of trailing zeros of the last word. - for (; w % 10 == 0; w /= 10) len--; - - // Add the number of digits of the first word. - for (w = digits[0]; w >= 10; w /= 10) len++; - } - - return len; - } - - - function getZeroString(k) { - var zs = ''; - for (; k--;) zs += '0'; - return zs; - } - - - /* - * Return a new Decimal whose value is the value of Decimal `x` to the power `n`, where `n` is an - * integer of type number. - * - * Implements 'exponentiation by squaring'. Called by `pow` and `parseOther`. - * - */ - function intPow(Ctor, x, n, pr) { - var isTruncated, - r = new Ctor(1), - - // Max n of 9007199254740991 takes 53 loop iterations. - // Maximum digits array length; leaves [28, 34] guard digits. - k = Math.ceil(pr / LOG_BASE + 4); - - external = false; - - for (;;) { - if (n % 2) { - r = r.times(x); - if (truncate(r.d, k)) isTruncated = true; - } - - n = mathfloor(n / 2); - if (n === 0) { - - // To ensure correct rounding when r.d is truncated, increment the last word if it is zero. - n = r.d.length - 1; - if (isTruncated && r.d[n] === 0) ++r.d[n]; - break; - } - - x = x.times(x); - truncate(x.d, k); - } - - external = true; - - return r; - } - - - function isOdd(n) { - return n.d[n.d.length - 1] & 1; - } - - - /* - * Handle `max` and `min`. `ltgt` is 'lt' or 'gt'. - */ - function maxOrMin(Ctor, args, ltgt) { - var y, - x = new Ctor(args[0]), - i = 0; - - for (; ++i < args.length;) { - y = new Ctor(args[i]); - if (!y.s) { - x = y; - break; - } else if (x[ltgt](y)) { - x = y; - } - } - - return x; - } - - - /* - * Return a new Decimal whose value is the natural exponential of `x` rounded to `sd` significant - * digits. - * - * Taylor/Maclaurin series. - * - * exp(x) = x^0/0! + x^1/1! + x^2/2! + x^3/3! + ... - * - * Argument reduction: - * Repeat x = x / 32, k += 5, until |x| < 0.1 - * exp(x) = exp(x / 2^k)^(2^k) - * - * Previously, the argument was initially reduced by - * exp(x) = exp(r) * 10^k where r = x - k * ln10, k = floor(x / ln10) - * to first put r in the range [0, ln10], before dividing by 32 until |x| < 0.1, but this was - * found to be slower than just dividing repeatedly by 32 as above. - * - * Max integer argument: exp('20723265836946413') = 6.3e+9000000000000000 - * Min integer argument: exp('-20723265836946411') = 1.2e-9000000000000000 - * (Math object integer min/max: Math.exp(709) = 8.2e+307, Math.exp(-745) = 5e-324) - * - * exp(Infinity) = Infinity - * exp(-Infinity) = 0 - * exp(NaN) = NaN - * exp(±0) = 1 - * - * exp(x) is non-terminating for any finite, non-zero x. - * - * The result will always be correctly rounded. - * - */ - function naturalExponential(x, sd) { - var denominator, guard, j, pow, sum, t, wpr, - rep = 0, - i = 0, - k = 0, - Ctor = x.constructor, - rm = Ctor.rounding, - pr = Ctor.precision; - - // 0/NaN/Infinity? - if (!x.d || !x.d[0] || x.e > 17) { - - return new Ctor(x.d - ? !x.d[0] ? 1 : x.s < 0 ? 0 : 1 / 0 - : x.s ? x.s < 0 ? 0 : x : 0 / 0); - } - - if (sd == null) { - external = false; - wpr = pr; - } else { - wpr = sd; - } - - t = new Ctor(0.03125); - - // while abs(x) >= 0.1 - while (x.e > -2) { - - // x = x / 2^5 - x = x.times(t); - k += 5; - } - - // Use 2 * log10(2^k) + 5 (empirically derived) to estimate the increase in precision - // necessary to ensure the first 4 rounding digits are correct. - guard = Math.log(mathpow(2, k)) / Math.LN10 * 2 + 5 | 0; - wpr += guard; - denominator = pow = sum = new Ctor(1); - Ctor.precision = wpr; - - for (;;) { - pow = finalise(pow.times(x), wpr, 1); - denominator = denominator.times(++i); - t = sum.plus(divide(pow, denominator, wpr, 1)); - - if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) { - j = k; - while (j--) sum = finalise(sum.times(sum), wpr, 1); - - // Check to see if the first 4 rounding digits are [49]999. - // If so, repeat the summation with a higher precision, otherwise - // e.g. with precision: 18, rounding: 1 - // exp(18.404272462595034083567793919843761) = 98372560.1229999999 (should be 98372560.123) - // `wpr - guard` is the index of first rounding digit. - if (sd == null) { - - if (rep < 3 && checkRoundingDigits(sum.d, wpr - guard, rm, rep)) { - Ctor.precision = wpr += 10; - denominator = pow = t = new Ctor(1); - i = 0; - rep++; - } else { - return finalise(sum, Ctor.precision = pr, rm, external = true); - } - } else { - Ctor.precision = pr; - return sum; - } - } - - sum = t; - } - } - - - /* - * Return a new Decimal whose value is the natural logarithm of `x` rounded to `sd` significant - * digits. - * - * ln(-n) = NaN - * ln(0) = -Infinity - * ln(-0) = -Infinity - * ln(1) = 0 - * ln(Infinity) = Infinity - * ln(-Infinity) = NaN - * ln(NaN) = NaN - * - * ln(n) (n != 1) is non-terminating. - * - */ - function naturalLogarithm(y, sd) { - var c, c0, denominator, e, numerator, rep, sum, t, wpr, x1, x2, - n = 1, - guard = 10, - x = y, - xd = x.d, - Ctor = x.constructor, - rm = Ctor.rounding, - pr = Ctor.precision; - - // Is x negative or Infinity, NaN, 0 or 1? - if (x.s < 0 || !xd || !xd[0] || !x.e && xd[0] == 1 && xd.length == 1) { - return new Ctor(xd && !xd[0] ? -1 / 0 : x.s != 1 ? NaN : xd ? 0 : x); - } - - if (sd == null) { - external = false; - wpr = pr; - } else { - wpr = sd; - } - - Ctor.precision = wpr += guard; - c = digitsToString(xd); - c0 = c.charAt(0); - - if (Math.abs(e = x.e) < 1.5e15) { - - // Argument reduction. - // The series converges faster the closer the argument is to 1, so using - // ln(a^b) = b * ln(a), ln(a) = ln(a^b) / b - // multiply the argument by itself until the leading digits of the significand are 7, 8, 9, - // 10, 11, 12 or 13, recording the number of multiplications so the sum of the series can - // later be divided by this number, then separate out the power of 10 using - // ln(a*10^b) = ln(a) + b*ln(10). - - // max n is 21 (gives 0.9, 1.0 or 1.1) (9e15 / 21 = 4.2e14). - //while (c0 < 9 && c0 != 1 || c0 == 1 && c.charAt(1) > 1) { - // max n is 6 (gives 0.7 - 1.3) - while (c0 < 7 && c0 != 1 || c0 == 1 && c.charAt(1) > 3) { - x = x.times(y); - c = digitsToString(x.d); - c0 = c.charAt(0); - n++; - } - - e = x.e; - - if (c0 > 1) { - x = new Ctor('0.' + c); - e++; - } else { - x = new Ctor(c0 + '.' + c.slice(1)); - } - } else { - - // The argument reduction method above may result in overflow if the argument y is a massive - // number with exponent >= 1500000000000000 (9e15 / 6 = 1.5e15), so instead recall this - // function using ln(x*10^e) = ln(x) + e*ln(10). - t = getLn10(Ctor, wpr + 2, pr).times(e + ''); - x = naturalLogarithm(new Ctor(c0 + '.' + c.slice(1)), wpr - guard).plus(t); - Ctor.precision = pr; - - return sd == null ? finalise(x, pr, rm, external = true) : x; - } - - // x1 is x reduced to a value near 1. - x1 = x; - - // Taylor series. - // ln(y) = ln((1 + x)/(1 - x)) = 2(x + x^3/3 + x^5/5 + x^7/7 + ...) - // where x = (y - 1)/(y + 1) (|x| < 1) - sum = numerator = x = divide(x.minus(1), x.plus(1), wpr, 1); - x2 = finalise(x.times(x), wpr, 1); - denominator = 3; - - for (;;) { - numerator = finalise(numerator.times(x2), wpr, 1); - t = sum.plus(divide(numerator, new Ctor(denominator), wpr, 1)); - - if (digitsToString(t.d).slice(0, wpr) === digitsToString(sum.d).slice(0, wpr)) { - sum = sum.times(2); - - // Reverse the argument reduction. Check that e is not 0 because, besides preventing an - // unnecessary calculation, -0 + 0 = +0 and to ensure correct rounding -0 needs to stay -0. - if (e !== 0) sum = sum.plus(getLn10(Ctor, wpr + 2, pr).times(e + '')); - sum = divide(sum, new Ctor(n), wpr, 1); - - // Is rm > 3 and the first 4 rounding digits 4999, or rm < 4 (or the summation has - // been repeated previously) and the first 4 rounding digits 9999? - // If so, restart the summation with a higher precision, otherwise - // e.g. with precision: 12, rounding: 1 - // ln(135520028.6126091714265381533) = 18.7246299999 when it should be 18.72463. - // `wpr - guard` is the index of first rounding digit. - if (sd == null) { - if (checkRoundingDigits(sum.d, wpr - guard, rm, rep)) { - Ctor.precision = wpr += guard; - t = numerator = x = divide(x1.minus(1), x1.plus(1), wpr, 1); - x2 = finalise(x.times(x), wpr, 1); - denominator = rep = 1; - } else { - return finalise(sum, Ctor.precision = pr, rm, external = true); - } - } else { - Ctor.precision = pr; - return sum; - } - } - - sum = t; - denominator += 2; - } - } - - - // ±Infinity, NaN. - function nonFiniteToString(x) { - // Unsigned. - return String(x.s * x.s / 0); - } - - - /* - * Parse the value of a new Decimal `x` from string `str`. - */ - function parseDecimal(x, str) { - var e, i, len; - - // Decimal point? - if ((e = str.indexOf('.')) > -1) str = str.replace('.', ''); - - // Exponential form? - if ((i = str.search(/e/i)) > 0) { - - // Determine exponent. - if (e < 0) e = i; - e += +str.slice(i + 1); - str = str.substring(0, i); - } else if (e < 0) { - - // Integer. - e = str.length; - } - - // Determine leading zeros. - for (i = 0; str.charCodeAt(i) === 48; i++); - - // Determine trailing zeros. - for (len = str.length; str.charCodeAt(len - 1) === 48; --len); - str = str.slice(i, len); - - if (str) { - len -= i; - x.e = e = e - i - 1; - x.d = []; - - // Transform base - - // e is the base 10 exponent. - // i is where to slice str to get the first word of the digits array. - i = (e + 1) % LOG_BASE; - if (e < 0) i += LOG_BASE; - - if (i < len) { - if (i) x.d.push(+str.slice(0, i)); - for (len -= LOG_BASE; i < len;) x.d.push(+str.slice(i, i += LOG_BASE)); - str = str.slice(i); - i = LOG_BASE - str.length; - } else { - i -= len; - } - - for (; i--;) str += '0'; - x.d.push(+str); - - if (external) { - - // Overflow? - if (x.e > x.constructor.maxE) { - - // Infinity. - x.d = null; - x.e = NaN; - - // Underflow? - } else if (x.e < x.constructor.minE) { - - // Zero. - x.e = 0; - x.d = [0]; - // x.constructor.underflow = true; - } // else x.constructor.underflow = false; - } - } else { - - // Zero. - x.e = 0; - x.d = [0]; - } - - return x; - } - - - /* - * Parse the value of a new Decimal `x` from a string `str`, which is not a decimal value. - */ - function parseOther(x, str) { - var base, Ctor, divisor, i, isFloat, len, p, xd, xe; - - if (str === 'Infinity' || str === 'NaN') { - if (!+str) x.s = NaN; - x.e = NaN; - x.d = null; - return x; - } - - if (isHex.test(str)) { - base = 16; - str = str.toLowerCase(); - } else if (isBinary.test(str)) { - base = 2; - } else if (isOctal.test(str)) { - base = 8; - } else { - throw Error(invalidArgument + str); - } - - // Is there a binary exponent part? - i = str.search(/p/i); - - if (i > 0) { - p = +str.slice(i + 1); - str = str.substring(2, i); - } else { - str = str.slice(2); - } - - // Convert `str` as an integer then divide the result by `base` raised to a power such that the - // fraction part will be restored. - i = str.indexOf('.'); - isFloat = i >= 0; - Ctor = x.constructor; - - if (isFloat) { - str = str.replace('.', ''); - len = str.length; - i = len - i; - - // log[10](16) = 1.2041... , log[10](88) = 1.9444.... - divisor = intPow(Ctor, new Ctor(base), i, i * 2); - } - - xd = convertBase(str, base, BASE); - xe = xd.length - 1; - - // Remove trailing zeros. - for (i = xe; xd[i] === 0; --i) xd.pop(); - if (i < 0) return new Ctor(x.s * 0); - x.e = getBase10Exponent(xd, xe); - x.d = xd; - external = false; - - // At what precision to perform the division to ensure exact conversion? - // maxDecimalIntegerPartDigitCount = ceil(log[10](b) * otherBaseIntegerPartDigitCount) - // log[10](2) = 0.30103, log[10](8) = 0.90309, log[10](16) = 1.20412 - // E.g. ceil(1.2 * 3) = 4, so up to 4 decimal digits are needed to represent 3 hex int digits. - // maxDecimalFractionPartDigitCount = {Hex:4|Oct:3|Bin:1} * otherBaseFractionPartDigitCount - // Therefore using 4 * the number of digits of str will always be enough. - if (isFloat) x = divide(x, divisor, len * 4); - - // Multiply by the binary exponent part if present. - if (p) x = x.times(Math.abs(p) < 54 ? Math.pow(2, p) : Decimal.pow(2, p)); - external = true; - - return x; - } - - - /* - * sin(x) = x - x^3/3! + x^5/5! - ... - * |x| < pi/2 - * - */ - function sine(Ctor, x) { - var k, - len = x.d.length; - - if (len < 3) return taylorSeries(Ctor, 2, x, x); - - // Argument reduction: sin(5x) = 16*sin^5(x) - 20*sin^3(x) + 5*sin(x) - // i.e. sin(x) = 16*sin^5(x/5) - 20*sin^3(x/5) + 5*sin(x/5) - // and sin(x) = sin(x/5)(5 + sin^2(x/5)(16sin^2(x/5) - 20)) - - // Estimate the optimum number of times to use the argument reduction. - k = 1.4 * Math.sqrt(len); - k = k > 16 ? 16 : k | 0; - - // Max k before Math.pow precision loss is 22 - x = x.times(Math.pow(5, -k)); - x = taylorSeries(Ctor, 2, x, x); - - // Reverse argument reduction - var sin2_x, - d5 = new Ctor(5), - d16 = new Ctor(16), - d20 = new Ctor(20); - for (; k--;) { - sin2_x = x.times(x); - x = x.times(d5.plus(sin2_x.times(d16.times(sin2_x).minus(d20)))); - } - - return x; - } - - - // Calculate Taylor series for `cos`, `cosh`, `sin` and `sinh`. - function taylorSeries(Ctor, n, x, y, isHyperbolic) { - var j, t, u, x2, - pr = Ctor.precision, - k = Math.ceil(pr / LOG_BASE); - - external = false; - x2 = x.times(x); - u = new Ctor(y); - - for (;;) { - t = divide(u.times(x2), new Ctor(n++ * n++), pr, 1); - u = isHyperbolic ? y.plus(t) : y.minus(t); - y = divide(t.times(x2), new Ctor(n++ * n++), pr, 1); - t = u.plus(y); - - if (t.d[k] !== void 0) { - for (j = k; t.d[j] === u.d[j] && j--;); - if (j == -1) break; - } - - j = u; - u = y; - y = t; - t = j; - } - - external = true; - t.d.length = k + 1; - - return t; - } - - - // Return the absolute value of `x` reduced to less than or equal to half pi. - function toLessThanHalfPi(Ctor, x) { - var t, - isNeg = x.s < 0, - pi = getPi(Ctor, Ctor.precision, 1), - halfPi = pi.times(0.5); - - x = x.abs(); - - if (x.lte(halfPi)) { - quadrant = isNeg ? 4 : 1; - return x; - } - - t = x.divToInt(pi); - - if (t.isZero()) { - quadrant = isNeg ? 3 : 2; - } else { - x = x.minus(t.times(pi)); - - // 0 <= x < pi - if (x.lte(halfPi)) { - quadrant = isOdd(t) ? (isNeg ? 2 : 3) : (isNeg ? 4 : 1); - return x; - } - - quadrant = isOdd(t) ? (isNeg ? 1 : 4) : (isNeg ? 3 : 2); - } - - return x.minus(pi).abs(); - } - - - /* - * Return the value of Decimal `x` as a string in base `baseOut`. - * - * If the optional `sd` argument is present include a binary exponent suffix. - */ - function toStringBinary(x, baseOut, sd, rm) { - var base, e, i, k, len, roundUp, str, xd, y, - Ctor = x.constructor, - isExp = sd !== void 0; - - if (isExp) { - checkInt32(sd, 1, MAX_DIGITS); - if (rm === void 0) rm = Ctor.rounding; - else checkInt32(rm, 0, 8); - } else { - sd = Ctor.precision; - rm = Ctor.rounding; - } - - if (!x.isFinite()) { - str = nonFiniteToString(x); - } else { - str = finiteToString(x); - i = str.indexOf('.'); - - // Use exponential notation according to `toExpPos` and `toExpNeg`? No, but if required: - // maxBinaryExponent = floor((decimalExponent + 1) * log[2](10)) - // minBinaryExponent = floor(decimalExponent * log[2](10)) - // log[2](10) = 3.321928094887362347870319429489390175864 - - if (isExp) { - base = 2; - if (baseOut == 16) { - sd = sd * 4 - 3; - } else if (baseOut == 8) { - sd = sd * 3 - 2; - } - } else { - base = baseOut; - } - - // Convert the number as an integer then divide the result by its base raised to a power such - // that the fraction part will be restored. - - // Non-integer. - if (i >= 0) { - str = str.replace('.', ''); - y = new Ctor(1); - y.e = str.length - i; - y.d = convertBase(finiteToString(y), 10, base); - y.e = y.d.length; - } - - xd = convertBase(str, 10, base); - e = len = xd.length; - - // Remove trailing zeros. - for (; xd[--len] == 0;) xd.pop(); - - if (!xd[0]) { - str = isExp ? '0p+0' : '0'; - } else { - if (i < 0) { - e--; - } else { - x = new Ctor(x); - x.d = xd; - x.e = e; - x = divide(x, y, sd, rm, 0, base); - xd = x.d; - e = x.e; - roundUp = inexact; - } - - // The rounding digit, i.e. the digit after the digit that may be rounded up. - i = xd[sd]; - k = base / 2; - roundUp = roundUp || xd[sd + 1] !== void 0; - - roundUp = rm < 4 - ? (i !== void 0 || roundUp) && (rm === 0 || rm === (x.s < 0 ? 3 : 2)) - : i > k || i === k && (rm === 4 || roundUp || rm === 6 && xd[sd - 1] & 1 || - rm === (x.s < 0 ? 8 : 7)); - - xd.length = sd; - - if (roundUp) { - - // Rounding up may mean the previous digit has to be rounded up and so on. - for (; ++xd[--sd] > base - 1;) { - xd[sd] = 0; - if (!sd) { - ++e; - xd.unshift(1); - } - } - } - - // Determine trailing zeros. - for (len = xd.length; !xd[len - 1]; --len); - - // E.g. [4, 11, 15] becomes 4bf. - for (i = 0, str = ''; i < len; i++) str += NUMERALS.charAt(xd[i]); - - // Add binary exponent suffix? - if (isExp) { - if (len > 1) { - if (baseOut == 16 || baseOut == 8) { - i = baseOut == 16 ? 4 : 3; - for (--len; len % i; len++) str += '0'; - xd = convertBase(str, base, baseOut); - for (len = xd.length; !xd[len - 1]; --len); - - // xd[0] will always be be 1 - for (i = 1, str = '1.'; i < len; i++) str += NUMERALS.charAt(xd[i]); - } else { - str = str.charAt(0) + '.' + str.slice(1); - } - } - - str = str + (e < 0 ? 'p' : 'p+') + e; - } else if (e < 0) { - for (; ++e;) str = '0' + str; - str = '0.' + str; - } else { - if (++e > len) for (e -= len; e-- ;) str += '0'; - else if (e < len) str = str.slice(0, e) + '.' + str.slice(e); - } - } - - str = (baseOut == 16 ? '0x' : baseOut == 2 ? '0b' : baseOut == 8 ? '0o' : '') + str; - } - - return x.s < 0 ? '-' + str : str; - } - - - // Does not strip trailing zeros. - function truncate(arr, len) { - if (arr.length > len) { - arr.length = len; - return true; - } - } - - - // Decimal methods - - - /* - * abs - * acos - * acosh - * add - * asin - * asinh - * atan - * atanh - * atan2 - * cbrt - * ceil - * clone - * config - * cos - * cosh - * div - * exp - * floor - * hypot - * ln - * log - * log2 - * log10 - * max - * min - * mod - * mul - * pow - * random - * round - * set - * sign - * sin - * sinh - * sqrt - * sub - * tan - * tanh - * trunc - */ - - - /* - * Return a new Decimal whose value is the absolute value of `x`. - * - * x {number|string|Decimal} - * - */ - function abs(x) { - return new this(x).abs(); - } - - - /* - * Return a new Decimal whose value is the arccosine in radians of `x`. - * - * x {number|string|Decimal} - * - */ - function acos(x) { - return new this(x).acos(); - } - - - /* - * Return a new Decimal whose value is the inverse of the hyperbolic cosine of `x`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function acosh(x) { - return new this(x).acosh(); - } - - - /* - * Return a new Decimal whose value is the sum of `x` and `y`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function add(x, y) { - return new this(x).plus(y); - } - - - /* - * Return a new Decimal whose value is the arcsine in radians of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function asin(x) { - return new this(x).asin(); - } - - - /* - * Return a new Decimal whose value is the inverse of the hyperbolic sine of `x`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function asinh(x) { - return new this(x).asinh(); - } - - - /* - * Return a new Decimal whose value is the arctangent in radians of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function atan(x) { - return new this(x).atan(); - } - - - /* - * Return a new Decimal whose value is the inverse of the hyperbolic tangent of `x`, rounded to - * `precision` significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function atanh(x) { - return new this(x).atanh(); - } - - - /* - * Return a new Decimal whose value is the arctangent in radians of `y/x` in the range -pi to pi - * (inclusive), rounded to `precision` significant digits using rounding mode `rounding`. - * - * Domain: [-Infinity, Infinity] - * Range: [-pi, pi] - * - * y {number|string|Decimal} The y-coordinate. - * x {number|string|Decimal} The x-coordinate. - * - * atan2(±0, -0) = ±pi - * atan2(±0, +0) = ±0 - * atan2(±0, -x) = ±pi for x > 0 - * atan2(±0, x) = ±0 for x > 0 - * atan2(-y, ±0) = -pi/2 for y > 0 - * atan2(y, ±0) = pi/2 for y > 0 - * atan2(±y, -Infinity) = ±pi for finite y > 0 - * atan2(±y, +Infinity) = ±0 for finite y > 0 - * atan2(±Infinity, x) = ±pi/2 for finite x - * atan2(±Infinity, -Infinity) = ±3*pi/4 - * atan2(±Infinity, +Infinity) = ±pi/4 - * atan2(NaN, x) = NaN - * atan2(y, NaN) = NaN - * - */ - function atan2(y, x) { - y = new this(y); - x = new this(x); - var r, - pr = this.precision, - rm = this.rounding, - wpr = pr + 4; - - // Either NaN - if (!y.s || !x.s) { - r = new this(NaN); - - // Both ±Infinity - } else if (!y.d && !x.d) { - r = getPi(this, wpr, 1).times(x.s > 0 ? 0.25 : 0.75); - r.s = y.s; - - // x is ±Infinity or y is ±0 - } else if (!x.d || y.isZero()) { - r = x.s < 0 ? getPi(this, pr, rm) : new this(0); - r.s = y.s; - - // y is ±Infinity or x is ±0 - } else if (!y.d || x.isZero()) { - r = getPi(this, wpr, 1).times(0.5); - r.s = y.s; - - // Both non-zero and finite - } else if (x.s < 0) { - this.precision = wpr; - this.rounding = 1; - r = this.atan(divide(y, x, wpr, 1)); - x = getPi(this, wpr, 1); - this.precision = pr; - this.rounding = rm; - r = y.s < 0 ? r.minus(x) : r.plus(x); - } else { - r = this.atan(divide(y, x, wpr, 1)); - } - - return r; - } - - - /* - * Return a new Decimal whose value is the cube root of `x`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function cbrt(x) { - return new this(x).cbrt(); - } - - - /* - * Return a new Decimal whose value is `x` rounded to an integer using `ROUND_CEIL`. - * - * x {number|string|Decimal} - * - */ - function ceil(x) { - return finalise(x = new this(x), x.e + 1, 2); - } - - - /* - * Configure global settings for a Decimal constructor. - * - * `obj` is an object with one or more of the following properties, - * - * precision {number} - * rounding {number} - * toExpNeg {number} - * toExpPos {number} - * maxE {number} - * minE {number} - * modulo {number} - * crypto {boolean|number} - * defaults {true} - * - * E.g. Decimal.config({ precision: 20, rounding: 4 }) - * - */ - function config(obj) { - if (!obj || typeof obj !== 'object') throw Error(decimalError + 'Object expected'); - var i, p, v, - useDefaults = obj.defaults === true, - ps = [ - 'precision', 1, MAX_DIGITS, - 'rounding', 0, 8, - 'toExpNeg', -EXP_LIMIT, 0, - 'toExpPos', 0, EXP_LIMIT, - 'maxE', 0, EXP_LIMIT, - 'minE', -EXP_LIMIT, 0, - 'modulo', 0, 9 - ]; - - for (i = 0; i < ps.length; i += 3) { - if (p = ps[i], useDefaults) this[p] = DEFAULTS[p]; - if ((v = obj[p]) !== void 0) { - if (mathfloor(v) === v && v >= ps[i + 1] && v <= ps[i + 2]) this[p] = v; - else throw Error(invalidArgument + p + ': ' + v); - } - } - - if (p = 'crypto', useDefaults) this[p] = DEFAULTS[p]; - if ((v = obj[p]) !== void 0) { - if (v === true || v === false || v === 0 || v === 1) { - if (v) { - if (typeof crypto != 'undefined' && crypto && - (crypto.getRandomValues || crypto.randomBytes)) { - this[p] = true; - } else { - throw Error(cryptoUnavailable); - } - } else { - this[p] = false; - } - } else { - throw Error(invalidArgument + p + ': ' + v); - } - } - - return this; - } - - - /* - * Return a new Decimal whose value is the cosine of `x`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function cos(x) { - return new this(x).cos(); - } - - - /* - * Return a new Decimal whose value is the hyperbolic cosine of `x`, rounded to precision - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function cosh(x) { - return new this(x).cosh(); - } - - - /* - * Create and return a Decimal constructor with the same configuration properties as this Decimal - * constructor. - * - */ - function clone(obj) { - var i, p, ps; - - /* - * The Decimal constructor and exported function. - * Return a new Decimal instance. - * - * v {number|string|Decimal} A numeric value. - * - */ - function Decimal(v) { - var e, i, t, - x = this; - - // Decimal called without new. - if (!(x instanceof Decimal)) return new Decimal(v); - - // Retain a reference to this Decimal constructor, and shadow Decimal.prototype.constructor - // which points to Object. - x.constructor = Decimal; - - // Duplicate. - if (v instanceof Decimal) { - x.s = v.s; - x.e = v.e; - x.d = (v = v.d) ? v.slice() : v; - return; - } - - t = typeof v; - - if (t === 'number') { - if (v === 0) { - x.s = 1 / v < 0 ? -1 : 1; - x.e = 0; - x.d = [0]; - return; - } - - if (v < 0) { - v = -v; - x.s = -1; - } else { - x.s = 1; - } - - // Fast path for small integers. - if (v === ~~v && v < 1e7) { - for (e = 0, i = v; i >= 10; i /= 10) e++; - x.e = e; - x.d = [v]; - return; - - // Infinity, NaN. - } else if (v * 0 !== 0) { - if (!v) x.s = NaN; - x.e = NaN; - x.d = null; - return; - } - - return parseDecimal(x, v.toString()); - - } else if (t !== 'string') { - throw Error(invalidArgument + v); - } - - // Minus sign? - if (v.charCodeAt(0) === 45) { - v = v.slice(1); - x.s = -1; - } else { - x.s = 1; - } - - return isDecimal.test(v) ? parseDecimal(x, v) : parseOther(x, v); - } - - Decimal.prototype = P; - - Decimal.ROUND_UP = 0; - Decimal.ROUND_DOWN = 1; - Decimal.ROUND_CEIL = 2; - Decimal.ROUND_FLOOR = 3; - Decimal.ROUND_HALF_UP = 4; - Decimal.ROUND_HALF_DOWN = 5; - Decimal.ROUND_HALF_EVEN = 6; - Decimal.ROUND_HALF_CEIL = 7; - Decimal.ROUND_HALF_FLOOR = 8; - Decimal.EUCLID = 9; - - Decimal.config = Decimal.set = config; - Decimal.clone = clone; - Decimal.isDecimal = isDecimalInstance; - - Decimal.abs = abs; - Decimal.acos = acos; - Decimal.acosh = acosh; // ES6 - Decimal.add = add; - Decimal.asin = asin; - Decimal.asinh = asinh; // ES6 - Decimal.atan = atan; - Decimal.atanh = atanh; // ES6 - Decimal.atan2 = atan2; - Decimal.cbrt = cbrt; // ES6 - Decimal.ceil = ceil; - Decimal.cos = cos; - Decimal.cosh = cosh; // ES6 - Decimal.div = div; - Decimal.exp = exp; - Decimal.floor = floor; - Decimal.hypot = hypot; // ES6 - Decimal.ln = ln; - Decimal.log = log; - Decimal.log10 = log10; // ES6 - Decimal.log2 = log2; // ES6 - Decimal.max = max; - Decimal.min = min; - Decimal.mod = mod; - Decimal.mul = mul; - Decimal.pow = pow; - Decimal.random = random; - Decimal.round = round; - Decimal.sign = sign; // ES6 - Decimal.sin = sin; - Decimal.sinh = sinh; // ES6 - Decimal.sqrt = sqrt; - Decimal.sub = sub; - Decimal.tan = tan; - Decimal.tanh = tanh; // ES6 - Decimal.trunc = trunc; // ES6 - - if (obj === void 0) obj = {}; - if (obj) { - if (obj.defaults !== true) { - ps = ['precision', 'rounding', 'toExpNeg', 'toExpPos', 'maxE', 'minE', 'modulo', 'crypto']; - for (i = 0; i < ps.length;) if (!obj.hasOwnProperty(p = ps[i++])) obj[p] = this[p]; - } - } - - Decimal.config(obj); - - return Decimal; - } - - - /* - * Return a new Decimal whose value is `x` divided by `y`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function div(x, y) { - return new this(x).div(y); - } - - - /* - * Return a new Decimal whose value is the natural exponential of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} The power to which to raise the base of the natural log. - * - */ - function exp(x) { - return new this(x).exp(); - } - - - /* - * Return a new Decimal whose value is `x` round to an integer using `ROUND_FLOOR`. - * - * x {number|string|Decimal} - * - */ - function floor(x) { - return finalise(x = new this(x), x.e + 1, 3); - } - - - /* - * Return a new Decimal whose value is the square root of the sum of the squares of the arguments, - * rounded to `precision` significant digits using rounding mode `rounding`. - * - * hypot(a, b, ...) = sqrt(a^2 + b^2 + ...) - * - */ - function hypot() { - var i, n, - t = new this(0); - - external = false; - - for (i = 0; i < arguments.length;) { - n = new this(arguments[i++]); - if (!n.d) { - if (n.s) { - external = true; - return new this(1 / 0); - } - t = n; - } else if (t.d) { - t = t.plus(n.times(n)); - } - } - - external = true; - - return t.sqrt(); - } - - - /* - * Return true if object is a Decimal instance (where Decimal is any Decimal constructor), - * otherwise return false. - * - */ - function isDecimalInstance(obj) { - return obj instanceof Decimal || obj && obj.name === '[object Decimal]' || false; - } - - - /* - * Return a new Decimal whose value is the natural logarithm of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function ln(x) { - return new this(x).ln(); - } - - - /* - * Return a new Decimal whose value is the log of `x` to the base `y`, or to base 10 if no base - * is specified, rounded to `precision` significant digits using rounding mode `rounding`. - * - * log[y](x) - * - * x {number|string|Decimal} The argument of the logarithm. - * y {number|string|Decimal} The base of the logarithm. - * - */ - function log(x, y) { - return new this(x).log(y); - } - - - /* - * Return a new Decimal whose value is the base 2 logarithm of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function log2(x) { - return new this(x).log(2); - } - - - /* - * Return a new Decimal whose value is the base 10 logarithm of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function log10(x) { - return new this(x).log(10); - } - - - /* - * Return a new Decimal whose value is the maximum of the arguments. - * - * arguments {number|string|Decimal} - * - */ - function max() { - return maxOrMin(this, arguments, 'lt'); - } - - - /* - * Return a new Decimal whose value is the minimum of the arguments. - * - * arguments {number|string|Decimal} - * - */ - function min() { - return maxOrMin(this, arguments, 'gt'); - } - - - /* - * Return a new Decimal whose value is `x` modulo `y`, rounded to `precision` significant digits - * using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function mod(x, y) { - return new this(x).mod(y); - } - - - /* - * Return a new Decimal whose value is `x` multiplied by `y`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function mul(x, y) { - return new this(x).mul(y); - } - - - /* - * Return a new Decimal whose value is `x` raised to the power `y`, rounded to precision - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} The base. - * y {number|string|Decimal} The exponent. - * - */ - function pow(x, y) { - return new this(x).pow(y); - } - - - /* - * Returns a new Decimal with a random value equal to or greater than 0 and less than 1, and with - * `sd`, or `Decimal.precision` if `sd` is omitted, significant digits (or less if trailing zeros - * are produced). - * - * [sd] {number} Significant digits. Integer, 0 to MAX_DIGITS inclusive. - * - */ - function random(sd) { - var d, e, k, n, - i = 0, - r = new this(1), - rd = []; - - if (sd === void 0) sd = this.precision; - else checkInt32(sd, 1, MAX_DIGITS); - - k = Math.ceil(sd / LOG_BASE); - - if (!this.crypto) { - for (; i < k;) rd[i++] = Math.random() * 1e7 | 0; - - // Browsers supporting crypto.getRandomValues. - } else if (crypto.getRandomValues) { - d = crypto.getRandomValues(new Uint32Array(k)); - - for (; i < k;) { - n = d[i]; - - // 0 <= n < 4294967296 - // Probability n >= 4.29e9, is 4967296 / 4294967296 = 0.00116 (1 in 865). - if (n >= 4.29e9) { - d[i] = crypto.getRandomValues(new Uint32Array(1))[0]; - } else { - - // 0 <= n <= 4289999999 - // 0 <= (n % 1e7) <= 9999999 - rd[i++] = n % 1e7; - } - } - - // Node.js supporting crypto.randomBytes. - } else if (crypto.randomBytes) { - - // buffer - d = crypto.randomBytes(k *= 4); - - for (; i < k;) { - - // 0 <= n < 2147483648 - n = d[i] + (d[i + 1] << 8) + (d[i + 2] << 16) + ((d[i + 3] & 0x7f) << 24); - - // Probability n >= 2.14e9, is 7483648 / 2147483648 = 0.0035 (1 in 286). - if (n >= 2.14e9) { - crypto.randomBytes(4).copy(d, i); - } else { - - // 0 <= n <= 2139999999 - // 0 <= (n % 1e7) <= 9999999 - rd.push(n % 1e7); - i += 4; - } - } - - i = k / 4; - } else { - throw Error(cryptoUnavailable); - } - - k = rd[--i]; - sd %= LOG_BASE; - - // Convert trailing digits to zeros according to sd. - if (k && sd) { - n = mathpow(10, LOG_BASE - sd); - rd[i] = (k / n | 0) * n; - } - - // Remove trailing words which are zero. - for (; rd[i] === 0; i--) rd.pop(); - - // Zero? - if (i < 0) { - e = 0; - rd = [0]; - } else { - e = -1; - - // Remove leading words which are zero and adjust exponent accordingly. - for (; rd[0] === 0; e -= LOG_BASE) rd.shift(); - - // Count the digits of the first word of rd to determine leading zeros. - for (k = 1, n = rd[0]; n >= 10; n /= 10) k++; - - // Adjust the exponent for leading zeros of the first word of rd. - if (k < LOG_BASE) e -= LOG_BASE - k; - } - - r.e = e; - r.d = rd; - - return r; - } - - - /* - * Return a new Decimal whose value is `x` rounded to an integer using rounding mode `rounding`. - * - * To emulate `Math.round`, set rounding to 7 (ROUND_HALF_CEIL). - * - * x {number|string|Decimal} - * - */ - function round(x) { - return finalise(x = new this(x), x.e + 1, this.rounding); - } - - - /* - * Return - * 1 if x > 0, - * -1 if x < 0, - * 0 if x is 0, - * -0 if x is -0, - * NaN otherwise - * - */ - function sign(x) { - x = new this(x); - return x.d ? (x.d[0] ? x.s : 0 * x.s) : x.s || NaN; - } - - - /* - * Return a new Decimal whose value is the sine of `x`, rounded to `precision` significant digits - * using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function sin(x) { - return new this(x).sin(); - } - - - /* - * Return a new Decimal whose value is the hyperbolic sine of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function sinh(x) { - return new this(x).sinh(); - } - - - /* - * Return a new Decimal whose value is the square root of `x`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} - * - */ - function sqrt(x) { - return new this(x).sqrt(); - } - - - /* - * Return a new Decimal whose value is `x` minus `y`, rounded to `precision` significant digits - * using rounding mode `rounding`. - * - * x {number|string|Decimal} - * y {number|string|Decimal} - * - */ - function sub(x, y) { - return new this(x).sub(y); - } - - - /* - * Return a new Decimal whose value is the tangent of `x`, rounded to `precision` significant - * digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function tan(x) { - return new this(x).tan(); - } - - - /* - * Return a new Decimal whose value is the hyperbolic tangent of `x`, rounded to `precision` - * significant digits using rounding mode `rounding`. - * - * x {number|string|Decimal} A value in radians. - * - */ - function tanh(x) { - return new this(x).tanh(); - } - - - /* - * Return a new Decimal whose value is `x` truncated to an integer. - * - * x {number|string|Decimal} - * - */ - function trunc(x) { - return finalise(x = new this(x), x.e + 1, 1); - } - - - // Create and configure initial Decimal constructor. - Decimal = clone(DEFAULTS); - - Decimal['default'] = Decimal.Decimal = Decimal; - - // Create the internal constants from their string values. - LN10 = new Decimal(LN10); - PI = new Decimal(PI); - - - // Export. - - - // AMD. - if (typeof undefined == 'function' && undefined.amd) { - undefined(function () { - return Decimal; - }); - - // Node and other environments that support module.exports. - } else if ('object' != 'undefined' && module.exports) { - module.exports = Decimal; - - // Browser. - } else { - if (!globalScope) { - globalScope = typeof self != 'undefined' && self && self.self == self - ? self : Function('return this')(); - } - - noConflict = globalScope.Decimal; - Decimal.noConflict = function () { - globalScope.Decimal = noConflict; - return Decimal; - }; - - globalScope.Decimal = Decimal; - } - })(commonjsGlobal); - }); - - // make sure to pick the es5 version - - function factory$2 (type, config, load, typed, math) { - var BigNumber = decimal.clone({precision: config.precision}); - - /** - * Attach type information - */ - BigNumber.prototype.type = 'BigNumber'; - BigNumber.prototype.isBigNumber = true; - - /** - * Get a JSON representation of a BigNumber containing - * type information - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "BigNumber", "value": "0.2"}` - */ - BigNumber.prototype.toJSON = function () { - return { - mathjs: 'BigNumber', - value: this.toString() - }; - }; - - /** - * Instantiate a BigNumber from a JSON object - * @param {Object} json a JSON object structured as: - * `{"mathjs": "BigNumber", "value": "0.2"}` - * @return {BigNumber} - */ - BigNumber.fromJSON = function (json) { - return new BigNumber(json.value); - }; - - // listen for changed in the configuration, automatically apply changed precision - math.on('config', function (curr, prev) { - if (curr.precision !== prev.precision) { - BigNumber.config({ precision: curr.precision }); - } - }); - - return BigNumber; - } - - var name$2 = 'BigNumber'; - var path = 'type'; - var factory_1$2 = factory$2; - var math$2 = true; // request access to the math namespace - - var BigNumber = { - name: name$2, - path: path, - factory: factory_1$2, - math: math$2 - }; - - /** - * 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 - */ - var deepMap = 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); - } - }; - - function factory$3 (type, config, load, typed) { - /** - * Create a BigNumber, which can store numbers with arbitrary precision. - * When a matrix is provided, all elements will be converted to BigNumber. - * - * Syntax: - * - * math.bignumber(x) - * - * Examples: - * - * 0.1 + 0.2; // returns number 0.30000000000000004 - * math.bignumber(0.1) + math.bignumber(0.2); // returns BigNumber 0.3 - * - * - * 7.2e500; // returns number Infinity - * math.bignumber('7.2e500'); // returns BigNumber 7.2e500 - * - * See also: - * - * boolean, complex, index, matrix, string, unit - * - * @param {number | string | Fraction | BigNumber | Array | Matrix | boolean | null} [value] Value for the big number, - * 0 by default. - * @returns {BigNumber} The created bignumber - */ - var bignumber = typed('bignumber', { - '': function () { - return new type.BigNumber(0); - }, - - 'number': function (x) { - // convert to string to prevent errors in case of >15 digits - return new type.BigNumber(x + ''); - }, - - 'string': function (x) { - return new type.BigNumber(x); - }, - - 'BigNumber': function (x) { - // we assume a BigNumber is immutable - return x; - }, - - 'Fraction': function (x) { - return new type.BigNumber(x.n).div(x.d); - }, - - 'null': function (x) { - return new type.BigNumber(0); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, bignumber); - } - }); - - bignumber.toTex = { - 0: '0', - 1: '\\left(${args[0]}\\right)' - }; - - return bignumber; - } - - var name$3 = 'bignumber'; - var factory_1$3 = factory$3; - - var bignumber = { - name: name$3, - factory: factory_1$3 - }; - - var bignumber$1 = [ - // type - BigNumber, - - // construction function - bignumber - ]; - - function factory$4 (type, config, load, typed) { - /** - * Create a boolean or convert a string or number to a boolean. - * In case of a number, `true` is returned for non-zero numbers, and `false` in - * case of zero. - * Strings can be `'true'` or `'false'`, or can contain a number. - * When value is a matrix, all elements will be converted to boolean. - * - * Syntax: - * - * math.boolean(x) - * - * Examples: - * - * math.boolean(0); // returns false - * math.boolean(1); // returns true - * math.boolean(-3); // returns true - * math.boolean('true'); // returns true - * math.boolean('false'); // returns false - * math.boolean([1, 0, 1, 1]); // returns [true, false, true, true] - * - * See also: - * - * bignumber, complex, index, matrix, string, unit - * - * @param {string | number | boolean | Array | Matrix | null} value A value of any type - * @return {boolean | Array | Matrix} The boolean value - */ - var bool = typed('bool', { - '': function () { - return false; - }, - - 'boolean': function (x) { - return x; - }, - - 'number': function (x) { - return !!x; - }, - - 'null': function (x) { - return false; - }, - - 'BigNumber': function (x) { - return !x.isZero(); - }, - - 'string': function (x) { - // try case insensitive - var lcase = x.toLowerCase(); - if (lcase === 'true') { - return true; - } - else if (lcase === 'false') { - return false; - } - - // test whether value is a valid number - var num = Number(x); - if (x != '' && !isNaN(num)) { - return !!num; - } - - throw new Error('Cannot convert "' + x + '" to a boolean'); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, bool); - } - }); - - return bool; - } - - var name$4 = 'boolean'; - var factory_1$4 = factory$4; - - var boolean_1 = { - name: name$4, - factory: factory_1$4 - }; - - var formatter = createCommonjsModule(function (module, exports) { - - - - /** - * Convert a BigNumber 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' - * 'auto' (default) Regular number notation for numbers - * having an absolute value between - * `lower` and `upper` 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' 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. - * {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(12e8, {notation: 'fixed'}); // returns '1200000000' - * format(2.3, {notation: 'fixed', precision: 4}); // returns '2.3000' - * format(52.8, {notation: 'exponential'}); // returns '5.28e+1' - * format(12400, {notation: 'engineering'}); // returns '12.400e+3' - * - * @param {BigNumber} 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.isFinite()) { - return value.isNaN() ? 'NaN' : (value.gt(0) ? 'Infinity' : '-Infinity'); - } - - // default values for options - var notation = 'auto'; - var precision = undefined; - - if (options !== undefined) { - // determine notation from options - if (options.notation) { - notation = options.notation; - } - - // determine precision from options - if (typeof options === 'number') { - precision = options; - } - else if (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 '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 = object.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.format(value, fixedOptions); - } - - // determine lower and upper bound for exponential notation. - // TODO: implement support for upper and lower to be BigNumbers themselves - var lowerExp = (options && options.lowerExp !== undefined) ? options.lowerExp : -3; - var upperExp = (options && options.upperExp !== undefined) ? options.upperExp : 5; - - // handle special case zero - if (value.isZero()) return '0'; - - // determine whether or not to output exponential notation - var str; - var exp = value.logarithm(); - if (exp.gte(lowerExp) && exp.lt(upperExp)) { - // normal number notation - str = value.toSignificantDigits(precision).toFixed(); - } - else { - // exponential notation - str = exports.toExponential(value, precision); - } - - // remove trailing zeros after the decimal point - return str.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".'); - } - }; - - /** - * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3' - * @param {BigNumber} value - * @param {number} [precision] Number of digits in formatted output. - * If not provided, the maximum available digits - * is used. - * @returns {string} str - */ - exports.toExponential = function (value, precision) { - if (precision !== undefined) { - return value.toExponential(precision - 1); // Note the offset of one - } - else { - return value.toExponential(); - } - }; - - /** - * Format a number with fixed notation. - * @param {BigNumber} value - * @param {number} [precision=undefined] Optional number of decimals after the - * decimal point. Undefined by default. - */ - exports.toFixed = function (value, precision) { - return value.toFixed(precision); - }; - }); - var formatter_1 = formatter.format; - var formatter_2 = formatter.toExponential; - var formatter_3 = formatter.toFixed; - - var string = createCommonjsModule(function (module, exports) { - - var formatNumber = number.format; - var formatBigNumber = formatter.format; - - - /** - * Test whether value is a string - * @param {*} value - * @return {boolean} isString - */ - exports.isString = function(value) { - return typeof value === 'string'; - }; - - /** - * Check if a text ends with a certain string. - * @param {string} text - * @param {string} search - */ - exports.endsWith = function(text, search) { - var start = text.length - search.length; - var end = text.length; - return (text.substring(start, end) === search); - }; - - /** - * Format a value of any type into a string. - * - * Usage: - * math.format(value) - * math.format(value, precision) - * - * When value is a function: - * - * - When the function has a property `syntax`, it returns this - * syntax description. - * - In other cases, a string `'function'` is returned. - * - * When `value` is an Object: - * - * - When the object contains a property `format` being a function, this - * function is invoked as `value.format(options)` and the result is returned. - * - When the object has its own `toString` method, this method is invoked - * and the result is returned. - * - In other cases the function will loop over all object properties and - * return JSON object notation like '{"a": 2, "b": 3}'. - * - * Example usage: - * math.format(2/7); // '0.2857142857142857' - * math.format(math.pi, 3); // '3.14' - * math.format(new Complex(2, 3)); // '2 + 3i' - * math.format('hello'); // '"hello"' - * - * @param {*} value Value to be stringified - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @return {string} str - */ - exports.format = function(value, options) { - if (typeof value === 'number') { - return formatNumber(value, options); - } - - if (isBigNumber(value)) { - return formatBigNumber(value, options); - } - - // note: we use unsafe duck-typing here to check for Fractions, this is - // ok here since we're only invoking toString or concatenating its values - if (looksLikeFraction(value)) { - if (!options || options.fraction !== 'decimal') { - // output as ratio, like '1/3' - return (value.s * value.n) + '/' + value.d; - } - else { - // output as decimal, like '0.(3)' - return value.toString(); - } - } - - if (Array.isArray(value)) { - return formatArray(value, options); - } - - if (exports.isString(value)) { - return '"' + value + '"'; - } - - if (typeof value === 'function') { - return value.syntax ? String(value.syntax) : 'function'; - } - - if (value && typeof value === 'object') { - if (typeof value.format === 'function') { - return value.format(options); - } - else if (value && value.toString() !== {}.toString()) { - // this object has a non-native toString method, use that one - return value.toString(); - } - else { - var entries = []; - - for (var key in value) { - if (value.hasOwnProperty(key)) { - entries.push('"' + key + '": ' + exports.format(value[key], options)); - } - } - - return '{' + entries.join(', ') + '}'; - } - } - - return String(value); - }; - - /** - * Stringify a value into a string enclosed in double quotes. - * Unescaped double quotes and backslashes inside the value are escaped. - * @param {*} value - * @return {string} - */ - exports.stringify = function (value) { - var text = String(value); - var escaped = ''; - var i = 0; - while (i < text.length) { - var c = text.charAt(i); - - if (c === '\\') { - escaped += c; - i++; - - c = text.charAt(i); - if (c === '' || '"\\/bfnrtu'.indexOf(c) === -1) { - escaped += '\\'; // no valid escape character -> escape it - } - escaped += c; - } - else if (c === '"') { - escaped += '\\"'; - } - else { - escaped += c; - } - i++; - } - - return '"' + escaped + '"'; - }; - - /** - * Escape special HTML characters - * @param {*} value - * @return {string} - */ - exports.escape = function (value) { - var text = String(value); - text = text.replace(/&/g, '&') - .replace(/"/g, '"') - .replace(/'/g, ''') - .replace(//g, '>'); - - return text; - }; - - /** - * Recursively format an n-dimensional matrix - * Example output: "[[1, 2], [3, 4]]" - * @param {Array} array - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ - function formatArray (array, options) { - if (Array.isArray(array)) { - var str = '['; - var len = array.length; - for (var i = 0; i < len; i++) { - if (i != 0) { - str += ', '; - } - str += formatArray(array[i], options); - } - str += ']'; - return str; - } - else { - return exports.format(array, options); - } - } - - /** - * Check whether a value looks like a Fraction (unsafe duck-type check) - * @param {*} value - * @return {boolean} - */ - function looksLikeFraction (value) { - return (value && - typeof value === 'object' && - typeof value.s === 'number' && - typeof value.n === 'number' && - typeof value.d === 'number') || false; - } - }); - var string_1 = string.isString; - var string_2 = string.endsWith; - var string_3 = string.format; - var string_4 = string.stringify; - var string_5 = string.escape; - - var format = string.format; - var lazy$1 = object.lazy; - - function factory$5 (type, config, load, typed, math) { - /** - * @constructor Chain - * Wrap any value in a chain, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the chain, - * and then will be evaluated with the value itself as first argument. - * The chain can be closed by executing chain.done(), which will return - * the final value. - * - * The Chain has a number of special functions: - * - done() Finalize the chained operation and return the - * chain's value. - * - valueOf() The same as done() - * - toString() Returns a string representation of the chain's value. - * - * @param {*} [value] - */ - function Chain (value) { - if (!(this instanceof Chain)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - if (type.isChain(value)) { - this.value = value.value; - } - else { - this.value = value; - } - } - - /** - * Attach type information - */ - Chain.prototype.type = 'Chain'; - Chain.prototype.isChain = true; - - /** - * Close the chain. Returns the final value. - * Does the same as method valueOf() - * @returns {*} value - */ - Chain.prototype.done = function () { - return this.value; - }; - - /** - * Close the chain. Returns the final value. - * Does the same as method done() - * @returns {*} value - */ - Chain.prototype.valueOf = function () { - return this.value; - }; - - /** - * Get a string representation of the value in the chain - * @returns {string} - */ - Chain.prototype.toString = function () { - return format(this.value); - }; - - /** - * Get a JSON representation of the chain - * @returns {Object} - */ - Chain.prototype.toJSON = function () { - return { - mathjs: 'Chain', - value: this.value - }; - }; - - /** - * Instantiate a Chain from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "Chain", value: ...}`, - * where mathjs is optional - * @returns {Chain} - */ - Chain.fromJSON = function (json) { - return new Chain(json.value); - }; - - /** - * Create a proxy method for the chain - * @param {string} name - * @param {Function} fn The function to be proxied - * If fn is no function, it is silently ignored. - * @private - */ - function createProxy(name, fn) { - if (typeof fn === 'function') { - Chain.prototype[name] = chainify(fn); - } - } - - /** - * Create a proxy method for the chain - * @param {string} name - * @param {function} resolver The function resolving with the - * function to be proxied - * @private - */ - function createLazyProxy(name, resolver) { - lazy$1(Chain.prototype, name, function outerResolver() { - var fn = resolver(); - if (typeof fn === 'function') { - return chainify(fn); - } - - return undefined; // if not a function, ignore - }); - } - - /** - * Make a function chainable - * @param {function} fn - * @return {Function} chain function - * @private - */ - function chainify (fn) { - return function () { - var args = [this.value]; // `this` will be the context of a Chain instance - for (var i = 0; i < arguments.length; i++) { - args[i + 1] = arguments[i]; - } - - return new Chain(fn.apply(fn, args)); - } - } - - /** - * Create a proxy for a single method, or an object with multiple methods. - * Example usage: - * - * Chain.createProxy('add', function add (x, y) {...}); - * Chain.createProxy({ - * add: function add (x, y) {...}, - * subtract: function subtract (x, y) {...} - * } - * - * @param {string | Object} arg0 A name (string), or an object with - * functions - * @param {*} [arg1] A function, when arg0 is a name - */ - Chain.createProxy = function (arg0, arg1) { - if (typeof arg0 === 'string') { - // createProxy(name, value) - createProxy(arg0, arg1); - } - else { - // createProxy(values) - for (var prop in arg0) { - if (arg0.hasOwnProperty(prop)) { - createProxy(prop, arg0[prop]); - } - } - } - }; - - // create proxy for everything that is in math.js - Chain.createProxy(math); - - // register on the import event, automatically add a proxy for every imported function. - math.on('import', function (name, resolver, path) { - if (path === undefined) { - // an imported function (not a data type or something special) - createLazyProxy(name, resolver); - } - }); - - return Chain; - } - - var name$5 = 'Chain'; - var path$1 = 'type'; - var factory_1$5 = factory$5; - var math$3 = true; // require providing the math namespace as 5th argument - var lazy_1$1 = false; // we need to register a listener on the import events, so no lazy loading - - var Chain = { - name: name$5, - path: path$1, - factory: factory_1$5, - math: math$3, - lazy: lazy_1$1 - }; - - function factory$6 (type, config, load, typed) { - /** - * Wrap any value in a chain, allowing to perform chained operations on - * the value. - * - * All methods available in the math.js library can be called upon the chain, - * and then will be evaluated with the value itself as first argument. - * The chain can be closed by executing `chain.done()`, which returns - * the final value. - * - * The chain has a number of special functions: - * - * - `done()` Finalize the chain and return the chain's value. - * - `valueOf()` The same as `done()` - * - `toString()` Executes `math.format()` onto the chain's value, returning - * a string representation of the value. - * - * Syntax: - * - * math.chain(value) - * - * Examples: - * - * math.chain(3) - * .add(4) - * .subtract(2) - * .done(); // 5 - * - * math.chain( [[1, 2], [3, 4]] ) - * .subset(math.index(0, 0), 8) - * .multiply(3) - * .done(); // [[24, 6], [9, 12]] - * - * @param {*} [value] A value of any type on which to start a chained operation. - * @return {math.type.Chain} The created chain - */ - return typed('chain', { - '': function() { - return new type.Chain(); - }, - - 'any': function(value) { - return new type.Chain(value); - } - }); - } - - var name$6 = 'chain'; - var factory_1$6 = factory$6; - - var chain = { - name: name$6, - factory: factory_1$6 - }; - - var chain$1 = [ - // type - Chain, - - // construction function - chain - ]; - - var complex = createCommonjsModule(function (module, exports) { - /** - * @license Complex.js v2.0.10 11/02/2016 - * - * Copyright (c) 2016, Robert Eisele (robert@xarg.org) - * Dual licensed under the MIT or GPL Version 2 licenses. - **/ - - /** - * - * This class allows the manipulation of complex numbers. - * You can pass a complex number in different formats. Either as object, double, string or two integer parameters. - * - * Object form - * { re: , im: } - * { arg: , abs: } - * { phi: , r: } - * - * Array / Vector form - * [ real, imaginary ] - * - * Double form - * 99.3 - Single double value - * - * String form - * '23.1337' - Simple real number - * '15+3i' - a simple complex number - * '3-i' - a simple complex number - * - * Example: - * - * var c = new Complex('99.3+8i'); - * c.mul({r: 3, i: 9}).div(4.9).sub(3, 2); - * - */ - - (function(root) { - - var cosh = function(x) { - return (Math.exp(x) + Math.exp(-x)) * 0.5; - }; - - var sinh = function(x) { - return (Math.exp(x) - Math.exp(-x)) * 0.5; - }; - - /** - * Calculates cos(x) - 1 using Taylor series if x is small. - * - * @param {number} x - * @returns {number} cos(x) - 1 - */ - - var cosm1 = function(x) { - var limit = Math.PI/4; - if (x < -limit || x > limit) { - return (Math.cos(x) - 1.0); - } - - var xx = x * x; - return xx * - (-0.5 + xx * - (1/24 + xx * - (-1/720 + xx * - (1/40320 + xx * - (-1/3628800 + xx * - (1/4790014600 + xx * - (-1/87178291200 + xx * - (1/20922789888000) - ) - ) - ) - ) - ) - ) - ) - }; - - var hypot = function(x, y) { - - var a = Math.abs(x); - var b = Math.abs(y); - - if (a < 3000 && b < 3000) { - return Math.sqrt(a * a + b * b); - } - - if (a < b) { - a = b; - b = x / y; - } else { - b = y / x; - } - return a * Math.sqrt(1 + b * b); - }; - - var parser_exit = function() { - throw SyntaxError('Invalid Param'); - }; - - /** - * Calculates log(sqrt(a^2+b^2)) in a way to avoid overflows - * - * @param {number} a - * @param {number} b - * @returns {number} - */ - function logHypot(a, b) { - - var _a = Math.abs(a); - var _b = Math.abs(b); - - if (a === 0) { - return Math.log(_b); - } - - if (b === 0) { - return Math.log(_a); - } - - if (_a < 3000 && _b < 3000) { - return Math.log(a * a + b * b) * 0.5; - } - - /* I got 4 ideas to compute this property without overflow: - * - * Testing 1000000 times with random samples for a,b ∈ [1, 1000000000] against a big decimal library to get an error estimate - * - * 1. Only eliminate the square root: (OVERALL ERROR: 3.9122483030951116e-11) - - Math.log(a * a + b * b) / 2 - - * - * - * 2. Try to use the non-overflowing pythagoras: (OVERALL ERROR: 8.889760039210159e-10) - - var fn = function(a, b) { - a = Math.abs(a); - b = Math.abs(b); - var t = Math.min(a, b); - a = Math.max(a, b); - t = t / a; - - return Math.log(a) + Math.log(1 + t * t) / 2; - }; - - * 3. Abuse the identity cos(atan(y/x) = x / sqrt(x^2+y^2): (OVERALL ERROR: 3.4780178737037204e-10) - - Math.log(a / Math.cos(Math.atan2(b, a))) - - * 4. Use 3. and apply log rules: (OVERALL ERROR: 1.2014087502620896e-9) - - Math.log(a) - Math.log(Math.cos(Math.atan2(b, a))) - - */ - - return Math.log(a / Math.cos(Math.atan2(b, a))); - } - - var parse = function(a, b) { - - var z = {'re': 0, 'im': 0}; - - if (a === undefined || a === null) { - z['re'] = - z['im'] = 0; - } else if (b !== undefined) { - z['re'] = a; - z['im'] = b; - } else - switch (typeof a) { - - case 'object': - - if ('im' in a && 're' in a) { - z['re'] = a['re']; - z['im'] = a['im']; - } else if ('abs' in a && 'arg' in a) { - if (!Number.isFinite(a['abs']) && Number.isFinite(a['arg'])) { - return Complex['INFINITY']; - } - z['re'] = a['abs'] * Math.cos(a['arg']); - z['im'] = a['abs'] * Math.sin(a['arg']); - } else if ('r' in a && 'phi' in a) { - if (!Number.isFinite(a['r']) && Number.isFinite(a['phi'])) { - return Complex['INFINITY']; - } - z['re'] = a['r'] * Math.cos(a['phi']); - z['im'] = a['r'] * Math.sin(a['phi']); - } else if (a.length === 2) { // Quick array check - z['re'] = a[0]; - z['im'] = a[1]; - } else { - parser_exit(); - } - break; - - case 'string': - - z['im'] = /* void */ - z['re'] = 0; - - var tokens = a.match(/\d+\.?\d*e[+-]?\d+|\d+\.?\d*|\.\d+|./g); - var plus = 1; - var minus = 0; - - if (tokens === null) { - parser_exit(); - } - - for (var i = 0; i < tokens.length; i++) { - - var c = tokens[i]; - - if (c === ' ' || c === '\t' || c === '\n') { - /* void */ - } else if (c === '+') { - plus++; - } else if (c === '-') { - minus++; - } else if (c === 'i' || c === 'I') { - - if (plus + minus === 0) { - parser_exit(); - } - - if (tokens[i + 1] !== ' ' && !isNaN(tokens[i + 1])) { - z['im'] += parseFloat((minus % 2 ? '-' : '') + tokens[i + 1]); - i++; - } else { - z['im'] += parseFloat((minus % 2 ? '-' : '') + '1'); - } - plus = minus = 0; - - } else { - - if (plus + minus === 0 || isNaN(c)) { - parser_exit(); - } - - if (tokens[i + 1] === 'i' || tokens[i + 1] === 'I') { - z['im'] += parseFloat((minus % 2 ? '-' : '') + c); - i++; - } else { - z['re'] += parseFloat((minus % 2 ? '-' : '') + c); - } - plus = minus = 0; - } - } - - // Still something on the stack - if (plus + minus > 0) { - parser_exit(); - } - break; - - case 'number': - z['im'] = 0; - z['re'] = a; - break; - - default: - parser_exit(); - } - - return z; - }; - - /** - * @constructor - * @returns {Complex} - */ - function Complex(a, b) { - - if (!(this instanceof Complex)) { - return new Complex(a, b); - } - - var z = parse(a, b); - - this['re'] = z['re']; - this['im'] = z['im']; - } - - Complex.prototype = { - - 're': 0, - 'im': 0, - - /** - * Calculates the sign of a complex number, which is a normalized complex - * - * @returns {Complex} - */ - 'sign': function() { - - var abs = this['abs'](); - - return new Complex( - this['re'] / abs, - this['im'] / abs); - }, - - /** - * Adds two complex numbers - * - * @returns {Complex} - */ - 'add': function(a, b) { - - var z = new Complex(a, b); - - // Infinity + Infinity = NaN - if (this.isInfinite() && z.isInfinite()) { - return Complex['NAN']; - } - - // Infinity + z = Infinity { where z != Infinity } - if (this.isInfinite() || z.isInfinite()) { - return Complex['INFINITY']; - } - - return new Complex( - this['re'] + z['re'], - this['im'] + z['im']); - }, - - /** - * Subtracts two complex numbers - * - * @returns {Complex} - */ - 'sub': function(a, b) { - - var z = new Complex(a, b); - - // Infinity - Infinity = NaN - if (this.isInfinite() && z.isInfinite()) { - return Complex['NAN']; - } - - // Infinity - z = Infinity { where z != Infinity } - if (this.isInfinite() || z.isInfinite()) { - return Complex['INFINITY']; - } - - return new Complex( - this['re'] - z['re'], - this['im'] - z['im']); - }, - - /** - * Multiplies two complex numbers - * - * @returns {Complex} - */ - 'mul': function(a, b) { - - var z = new Complex(a, b); - - // Infinity * 0 = NaN - if ((this.isInfinite() && z.isZero()) || (this.isZero() && z.isInfinite())) { - return Complex['NAN']; - } - - // Infinity * z = Infinity { where z != 0 } - if (this.isInfinite() || z.isInfinite()) { - return Complex['INFINITY']; - } - - // Short circuit for real values - if (z['im'] === 0 && this['im'] === 0) { - return new Complex(this['re'] * z['re'], 0); - } - - return new Complex( - this['re'] * z['re'] - this['im'] * z['im'], - this['re'] * z['im'] + this['im'] * z['re']); - }, - - /** - * Divides two complex numbers - * - * @returns {Complex} - */ - 'div': function(a, b) { - - var z = new Complex(a, b); - - // 0 / 0 = NaN and Infinity / Infinity = NaN - if ((this.isZero() && z.isZero()) || (this.isInfinite() && z.isInfinite())) { - return Complex['NAN']; - } - - // Infinity / 0 = Infinity - if (this.isInfinite() || z.isZero()) { - return Complex['INFINITY']; - } - - // 0 / Infinity = 0 - if (this.isZero() || z.isInfinite()) { - return Complex['ZERO']; - } - - a = this['re']; - b = this['im']; - - var c = z['re']; - var d = z['im']; - var t, x; - - if (0 === d) { - // Divisor is real - return new Complex(a / c, b / c); - } - - if (Math.abs(c) < Math.abs(d)) { - - x = c / d; - t = c * x + d; - - return new Complex( - (a * x + b) / t, - (b * x - a) / t); - - } else { - - x = d / c; - t = d * x + c; - - return new Complex( - (a + b * x) / t, - (b - a * x) / t); - } - }, - - /** - * Calculate the power of two complex numbers - * - * @returns {Complex} - */ - 'pow': function(a, b) { - - var z = new Complex(a, b); - - a = this['re']; - b = this['im']; - - if (z.isZero()) { - return Complex['ONE']; - } - - // If the exponent is real - if (z['im'] === 0) { - - if (b === 0 && a >= 0) { - - return new Complex(Math.pow(a, z['re']), 0); - - } else if (a === 0) { // If base is fully imaginary - - switch ((z['re'] % 4 + 4) % 4) { - case 0: - return new Complex(Math.pow(b, z['re']), 0); - case 1: - return new Complex(0, Math.pow(b, z['re'])); - case 2: - return new Complex(-Math.pow(b, z['re']), 0); - case 3: - return new Complex(0, -Math.pow(b, z['re'])); - } - } - } - - /* I couldn't find a good formula, so here is a derivation and optimization - * - * z_1^z_2 = (a + bi)^(c + di) - * = exp((c + di) * log(a + bi) - * = pow(a^2 + b^2, (c + di) / 2) * exp(i(c + di)atan2(b, a)) - * =>... - * Re = (pow(a^2 + b^2, c / 2) * exp(-d * atan2(b, a))) * cos(d * log(a^2 + b^2) / 2 + c * atan2(b, a)) - * Im = (pow(a^2 + b^2, c / 2) * exp(-d * atan2(b, a))) * sin(d * log(a^2 + b^2) / 2 + c * atan2(b, a)) - * - * =>... - * Re = exp(c * log(sqrt(a^2 + b^2)) - d * atan2(b, a)) * cos(d * log(sqrt(a^2 + b^2)) + c * atan2(b, a)) - * Im = exp(c * log(sqrt(a^2 + b^2)) - d * atan2(b, a)) * sin(d * log(sqrt(a^2 + b^2)) + c * atan2(b, a)) - * - * => - * Re = exp(c * logsq2 - d * arg(z_1)) * cos(d * logsq2 + c * arg(z_1)) - * Im = exp(c * logsq2 - d * arg(z_1)) * sin(d * logsq2 + c * arg(z_1)) - * - */ - - if (a === 0 && b === 0 && z['re'] > 0 && z['im'] >= 0) { - return Complex['ZERO']; - } - - var arg = Math.atan2(b, a); - var loh = logHypot(a, b); - - a = Math.exp(z['re'] * loh - z['im'] * arg); - b = z['im'] * loh + z['re'] * arg; - return new Complex( - a * Math.cos(b), - a * Math.sin(b)); - }, - - /** - * Calculate the complex square root - * - * @returns {Complex} - */ - 'sqrt': function() { - - var a = this['re']; - var b = this['im']; - var r = this['abs'](); - - var re, im; - - if (a >= 0) { - - if (b === 0) { - return new Complex(Math.sqrt(a), 0); - } - - re = 0.5 * Math.sqrt(2.0 * (r + a)); - } else { - re = Math.abs(b) / Math.sqrt(2 * (r - a)); - } - - if (a <= 0) { - im = 0.5 * Math.sqrt(2.0 * (r - a)); - } else { - im = Math.abs(b) / Math.sqrt(2 * (r + a)); - } - - return new Complex(re, b < 0 ? -im : im); - }, - - /** - * Calculate the complex exponent - * - * @returns {Complex} - */ - 'exp': function() { - - var tmp = Math.exp(this['re']); - - if (this['im'] === 0) { - //return new Complex(tmp, 0); - } - return new Complex( - tmp * Math.cos(this['im']), - tmp * Math.sin(this['im'])); - }, - - /** - * Calculate the complex exponent and subtracts one. - * - * This may be more accurate than `Complex(x).exp().sub(1)` if - * `x` is small. - * - * @returns {Complex} - */ - 'expm1': function() { - - /** - * exp(a + i*b) - 1 - = exp(a) * (cos(b) + j*sin(b)) - 1 - = expm1(a)*cos(b) + cosm1(b) + j*exp(a)*sin(b) - */ - - var a = this['re']; - var b = this['im']; - - return new Complex( - Math.expm1(a) * Math.cos(b) + cosm1(b), - Math.exp(a) * Math.sin(b)); - }, - - /** - * Calculate the natural log - * - * @returns {Complex} - */ - 'log': function() { - - var a = this['re']; - var b = this['im']; - - return new Complex( - logHypot(a, b), - Math.atan2(b, a)); - }, - - /** - * Calculate the magnitude of the complex number - * - * @returns {number} - */ - 'abs': function() { - - return hypot(this['re'], this['im']); - }, - - /** - * Calculate the angle of the complex number - * - * @returns {number} - */ - 'arg': function() { - - return Math.atan2(this['im'], this['re']); - }, - - /** - * Calculate the sine of the complex number - * - * @returns {Complex} - */ - 'sin': function() { - - // sin(c) = (e^b - e^(-b)) / (2i) - - var a = this['re']; - var b = this['im']; - - return new Complex( - Math.sin(a) * cosh(b), - Math.cos(a) * sinh(b)); - }, - - /** - * Calculate the cosine - * - * @returns {Complex} - */ - 'cos': function() { - - // cos(z) = (e^b + e^(-b)) / 2 - - var a = this['re']; - var b = this['im']; - - return new Complex( - Math.cos(a) * cosh(b), - -Math.sin(a) * sinh(b)); - }, - - /** - * Calculate the tangent - * - * @returns {Complex} - */ - 'tan': function() { - - // tan(c) = (e^(ci) - e^(-ci)) / (i(e^(ci) + e^(-ci))) - - var a = 2 * this['re']; - var b = 2 * this['im']; - var d = Math.cos(a) + cosh(b); - - return new Complex( - Math.sin(a) / d, - sinh(b) / d); - }, - - /** - * Calculate the cotangent - * - * @returns {Complex} - */ - 'cot': function() { - - // cot(c) = i(e^(ci) + e^(-ci)) / (e^(ci) - e^(-ci)) - - var a = 2 * this['re']; - var b = 2 * this['im']; - var d = Math.cos(a) - cosh(b); - - return new Complex( - -Math.sin(a) / d, - sinh(b) / d); - }, - - /** - * Calculate the secant - * - * @returns {Complex} - */ - 'sec': function() { - - // sec(c) = 2 / (e^(ci) + e^(-ci)) - - var a = this['re']; - var b = this['im']; - var d = 0.5 * cosh(2 * b) + 0.5 * Math.cos(2 * a); - - return new Complex( - Math.cos(a) * cosh(b) / d, - Math.sin(a) * sinh(b) / d); - }, - - /** - * Calculate the cosecans - * - * @returns {Complex} - */ - 'csc': function() { - - // csc(c) = 2i / (e^(ci) - e^(-ci)) - - var a = this['re']; - var b = this['im']; - var d = 0.5 * cosh(2 * b) - 0.5 * Math.cos(2 * a); - - return new Complex( - Math.sin(a) * cosh(b) / d, - -Math.cos(a) * sinh(b) / d); - }, - - /** - * Calculate the complex arcus sinus - * - * @returns {Complex} - */ - 'asin': function() { - - // asin(c) = -i * log(ci + sqrt(1 - c^2)) - - var a = this['re']; - var b = this['im']; - - var t1 = new Complex( - b * b - a * a + 1, - -2 * a * b)['sqrt'](); - - var t2 = new Complex( - t1['re'] - b, - t1['im'] + a)['log'](); - - return new Complex(t2['im'], -t2['re']); - }, - - /** - * Calculate the complex arcus cosinus - * - * @returns {Complex} - */ - 'acos': function() { - - // acos(c) = i * log(c - i * sqrt(1 - c^2)) - - var a = this['re']; - var b = this['im']; - - var t1 = new Complex( - b * b - a * a + 1, - -2 * a * b)['sqrt'](); - - var t2 = new Complex( - t1['re'] - b, - t1['im'] + a)['log'](); - - return new Complex(Math.PI / 2 - t2['im'], t2['re']); - }, - - /** - * Calculate the complex arcus tangent - * - * @returns {Complex} - */ - 'atan': function() { - - // atan(c) = i / 2 log((i + x) / (i - x)) - - var a = this['re']; - var b = this['im']; - - if (a === 0) { - - if (b === 1) { - return new Complex(0, Infinity); - } - - if (b === -1) { - return new Complex(0, -Infinity); - } - } - - var d = a * a + (1.0 - b) * (1.0 - b); - - var t1 = new Complex( - (1 - b * b - a * a) / d, - -2 * a / d).log(); - - return new Complex(-0.5 * t1['im'], 0.5 * t1['re']); - }, - - /** - * Calculate the complex arcus cotangent - * - * @returns {Complex} - */ - 'acot': function() { - - // acot(c) = i / 2 log((c - i) / (c + i)) - - var a = this['re']; - var b = this['im']; - - if (b === 0) { - return new Complex(Math.atan2(1, a), 0); - } - - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).atan() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).atan(); - }, - - /** - * Calculate the complex arcus secant - * - * @returns {Complex} - */ - 'asec': function() { - - // asec(c) = -i * log(1 / c + sqrt(1 - i / c^2)) - - var a = this['re']; - var b = this['im']; - - if (a === 0 && b === 0) { - return new Complex(0, Infinity); - } - - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).acos() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).acos(); - }, - - /** - * Calculate the complex arcus cosecans - * - * @returns {Complex} - */ - 'acsc': function() { - - // acsc(c) = -i * log(i / c + sqrt(1 - 1 / c^2)) - - var a = this['re']; - var b = this['im']; - - if (a === 0 && b === 0) { - return new Complex(Math.PI / 2, Infinity); - } - - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).asin() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).asin(); - }, - - /** - * Calculate the complex sinh - * - * @returns {Complex} - */ - 'sinh': function() { - - // sinh(c) = (e^c - e^-c) / 2 - - var a = this['re']; - var b = this['im']; - - return new Complex( - sinh(a) * Math.cos(b), - cosh(a) * Math.sin(b)); - }, - - /** - * Calculate the complex cosh - * - * @returns {Complex} - */ - 'cosh': function() { - - // cosh(c) = (e^c + e^-c) / 2 - - var a = this['re']; - var b = this['im']; - - return new Complex( - cosh(a) * Math.cos(b), - sinh(a) * Math.sin(b)); - }, - - /** - * Calculate the complex tanh - * - * @returns {Complex} - */ - 'tanh': function() { - - // tanh(c) = (e^c - e^-c) / (e^c + e^-c) - - var a = 2 * this['re']; - var b = 2 * this['im']; - var d = cosh(a) + Math.cos(b); - - return new Complex( - sinh(a) / d, - Math.sin(b) / d); - }, - - /** - * Calculate the complex coth - * - * @returns {Complex} - */ - 'coth': function() { - - // coth(c) = (e^c + e^-c) / (e^c - e^-c) - - var a = 2 * this['re']; - var b = 2 * this['im']; - var d = cosh(a) - Math.cos(b); - - return new Complex( - sinh(a) / d, - -Math.sin(b) / d); - }, - - /** - * Calculate the complex coth - * - * @returns {Complex} - */ - 'csch': function() { - - // csch(c) = 2 / (e^c - e^-c) - - var a = this['re']; - var b = this['im']; - var d = Math.cos(2 * b) - cosh(2 * a); - - return new Complex( - -2 * sinh(a) * Math.cos(b) / d, - 2 * cosh(a) * Math.sin(b) / d); - }, - - /** - * Calculate the complex sech - * - * @returns {Complex} - */ - 'sech': function() { - - // sech(c) = 2 / (e^c + e^-c) - - var a = this['re']; - var b = this['im']; - var d = Math.cos(2 * b) + cosh(2 * a); - - return new Complex( - 2 * cosh(a) * Math.cos(b) / d, - -2 * sinh(a) * Math.sin(b) / d); - }, - - /** - * Calculate the complex asinh - * - * @returns {Complex} - */ - 'asinh': function() { - - // asinh(c) = log(c + sqrt(c^2 + 1)) - - var tmp = this['im']; - this['im'] = -this['re']; - this['re'] = tmp; - var res = this['asin'](); - - this['re'] = -this['im']; - this['im'] = tmp; - tmp = res['re']; - - res['re'] = -res['im']; - res['im'] = tmp; - return res; - }, - - /** - * Calculate the complex asinh - * - * @returns {Complex} - */ - 'acosh': function() { - - // acosh(c) = log(c + sqrt(c^2 - 1)) - - var res = this['acos'](); - if (res['im'] <= 0) { - var tmp = res['re']; - res['re'] = -res['im']; - res['im'] = tmp; - } else { - var tmp = res['im']; - res['im'] = -res['re']; - res['re'] = tmp; - } - return res; - }, - - /** - * Calculate the complex atanh - * - * @returns {Complex} - */ - 'atanh': function() { - - // atanh(c) = log((1+c) / (1-c)) / 2 - - var a = this['re']; - var b = this['im']; - - var noIM = a > 1 && b === 0; - var oneMinus = 1 - a; - var onePlus = 1 + a; - var d = oneMinus * oneMinus + b * b; - - var x = (d !== 0) - ? new Complex( - (onePlus * oneMinus - b * b) / d, - (b * oneMinus + onePlus * b) / d) - : new Complex( - (a !== -1) ? (a / 0) : 0, - (b !== 0) ? (b / 0) : 0); - - var temp = x['re']; - x['re'] = logHypot(x['re'], x['im']) / 2; - x['im'] = Math.atan2(x['im'], temp) / 2; - if (noIM) { - x['im'] = -x['im']; - } - return x; - }, - - /** - * Calculate the complex acoth - * - * @returns {Complex} - */ - 'acoth': function() { - - // acoth(c) = log((c+1) / (c-1)) / 2 - - var a = this['re']; - var b = this['im']; - - if (a === 0 && b === 0) { - return new Complex(0, Math.PI / 2); - } - - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).atanh() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).atanh(); - }, - - /** - * Calculate the complex acsch - * - * @returns {Complex} - */ - 'acsch': function() { - - // acsch(c) = log((1+sqrt(1+c^2))/c) - - var a = this['re']; - var b = this['im']; - - if (b === 0) { - - return new Complex( - (a !== 0) - ? Math.log(a + Math.sqrt(a * a + 1)) - : Infinity, 0); - } - - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).asinh() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).asinh(); - }, - - /** - * Calculate the complex asech - * - * @returns {Complex} - */ - 'asech': function() { - - // asech(c) = log((1+sqrt(1-c^2))/c) - - var a = this['re']; - var b = this['im']; - - if (this.isZero()) { - return Complex['INFINITY']; - } - - var d = a * a + b * b; - return (d !== 0) - ? new Complex( - a / d, - -b / d).acosh() - : new Complex( - (a !== 0) ? a / 0 : 0, - (b !== 0) ? -b / 0 : 0).acosh(); - }, - - /** - * Calculate the complex inverse 1/z - * - * @returns {Complex} - */ - 'inverse': function() { - - // 1 / 0 = Infinity and 1 / Infinity = 0 - if (this.isZero()) { - return Complex['INFINITY']; - } - - if (this.isInfinite()) { - return Complex['ZERO']; - } - - var a = this['re']; - var b = this['im']; - - var d = a * a + b * b; - - return new Complex(a / d, -b / d); - }, - - /** - * Returns the complex conjugate - * - * @returns {Complex} - */ - 'conjugate': function() { - - return new Complex(this['re'], -this['im']); - }, - - /** - * Gets the negated complex number - * - * @returns {Complex} - */ - 'neg': function() { - - return new Complex(-this['re'], -this['im']); - }, - - /** - * Ceils the actual complex number - * - * @returns {Complex} - */ - 'ceil': function(places) { - - places = Math.pow(10, places || 0); - - return new Complex( - Math.ceil(this['re'] * places) / places, - Math.ceil(this['im'] * places) / places); - }, - - /** - * Floors the actual complex number - * - * @returns {Complex} - */ - 'floor': function(places) { - - places = Math.pow(10, places || 0); - - return new Complex( - Math.floor(this['re'] * places) / places, - Math.floor(this['im'] * places) / places); - }, - - /** - * Ceils the actual complex number - * - * @returns {Complex} - */ - 'round': function(places) { - - places = Math.pow(10, places || 0); - - return new Complex( - Math.round(this['re'] * places) / places, - Math.round(this['im'] * places) / places); - }, - - /** - * Compares two complex numbers - * - * **Note:** new Complex(Infinity).equals(Infinity) === false - * - * @returns {boolean} - */ - 'equals': function(a, b) { - - var z = new Complex(a, b); - - return Math.abs(z['re'] - this['re']) <= Complex['EPSILON'] && - Math.abs(z['im'] - this['im']) <= Complex['EPSILON']; - }, - - /** - * Clones the actual object - * - * @returns {Complex} - */ - 'clone': function() { - - return new Complex(this['re'], this['im']); - }, - - /** - * Gets a string of the actual complex number - * - * @returns {string} - */ - 'toString': function() { - - var a = this['re']; - var b = this['im']; - var ret = ''; - - if (this.isNaN()) { - return 'NaN'; - } - - if (this.isZero()) { - return '0'; - } - - if (this.isInfinite()) { - return 'Infinity'; - } - - if (a !== 0) { - ret += a; - } - - if (b !== 0) { - - if (a !== 0) { - ret += b < 0 ? ' - ' : ' + '; - } else if (b < 0) { - ret += '-'; - } - - b = Math.abs(b); - - if (1 !== b) { - ret += b; - } - ret += 'i'; - } - - if (!ret) - return '0'; - - return ret; - }, - - /** - * Returns the actual number as a vector - * - * @returns {Array} - */ - 'toVector': function() { - - return [this['re'], this['im']]; - }, - - /** - * Returns the actual real value of the current object - * - * @returns {number|null} - */ - 'valueOf': function() { - - if (this['im'] === 0) { - return this['re']; - } - return null; - }, - - /** - * Determines whether a complex number is not on the Riemann sphere. - * - * @returns {boolean} - */ - 'isNaN': function() { - return isNaN(this['re']) || isNaN(this['im']); - }, - - /** - * Determines whether or not a complex number is at the zero pole of the - * Riemann sphere. - * - * @returns {boolean} - */ - 'isZero': function() { - return ( - (this['re'] === 0 || this['re'] === -0) && - (this['im'] === 0 || this['im'] === -0) - ); - }, - - /** - * Determines whether a complex number is not at the infinity pole of the - * Riemann sphere. - * - * @returns {boolean} - */ - 'isFinite': function() { - return isFinite(this['re']) && isFinite(this['im']); - }, - - /** - * Determines whether or not a complex number is at the infinity pole of the - * Riemann sphere. - * - * @returns {boolean} - */ - 'isInfinite': function() { - return !(this.isNaN() || this.isFinite()); - } - }; - - Complex['ZERO'] = new Complex(0, 0); - Complex['ONE'] = new Complex(1, 0); - Complex['I'] = new Complex(0, 1); - Complex['PI'] = new Complex(Math.PI, 0); - Complex['E'] = new Complex(Math.E, 0); - Complex['INFINITY'] = new Complex(Infinity, Infinity); - Complex['NAN'] = new Complex(NaN, NaN); - Complex['EPSILON'] = 1e-16; - - if (typeof undefined === 'function' && undefined['amd']) { - undefined([], function() { - return Complex; - }); - } else { - Object.defineProperty(exports, "__esModule", {'value': true}); - Complex['default'] = Complex; - Complex['Complex'] = Complex; - module['exports'] = Complex; - } - - })(commonjsGlobal); - }); - - unwrapExports(complex); - - var format$1 = number.format; - var isNumber = number.isNumber; - - function factory$7 (type, config, load, typed, math) { - - /** - * Attach type information - */ - complex.prototype.type = 'Complex'; - complex.prototype.isComplex = true; - - - /** - * Get a JSON representation of the complex number - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Complex", "re": 2, "im": 3}` - */ - complex.prototype.toJSON = function () { - return { - mathjs: 'Complex', - re: this.re, - im: this.im - }; - }; - - /* - * 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: this.abs(), - phi: this.arg() - }; - }; - - /** - * Get a string representation of the complex number, - * with optional formatting options. - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @return {string} str - */ - complex.prototype.format = function (options) { - var str = ''; - var im = this.im; - var re = this.re; - var strRe = format$1(this.re, options); - var strIm = format$1(this.im, options); - - // round either re or im when smaller than the configured precision - var precision = isNumber(options) ? options : options ? options.precision : null; - if (precision !== null) { - var epsilon = Math.pow(10, -precision); - if (Math.abs(re / im) < epsilon) { - re = 0; - } - if (Math.abs(im / re) < epsilon) { - im = 0; - } - } - - if (im == 0) { - // real value - str = strRe; - } else if (re == 0) { - // purely complex value - if (im == 1) { - str = 'i'; - } else if (im == -1) { - str = '-i'; - } else { - str = strIm + 'i'; - } - } else { - // complex value - if (im < 0) { - if (im == -1) { - str = strRe + ' - i'; - } else { - str = strRe + ' - ' + strIm.substring(1) + 'i'; - } - } else { - if (im == 1) { - str = strRe + ' + i'; - } else { - str = strRe + ' + ' + strIm + 'i'; - } - } - } - return str; - }; - - /** - * 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 (args) { - switch (arguments.length) { - case 1: - var arg = arguments[0]; - if (typeof arg === 'object') { - return complex(arg); - } - 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 (type.isUnit(phi) && phi.hasBase('ANGLE')) { - // convert unit to a number in radians - phi = phi.toNumber('rad'); - } - - if (isNumber(phi)) { - return new complex({r: r, phi: 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'); - } - }; - - - complex.prototype.valueOf = complex.prototype.toString; - - /** - * Create a Complex number from a JSON object - * @param {Object} json A JSON Object structured as - * {"mathjs": "Complex", "re": 2, "im": 3} - * All properties are optional, default values - * for `re` and `im` are 0. - * @return {Complex} Returns a new Complex number - */ - complex.fromJSON = function (json) { - return new complex(json); - }; - - // apply the current epsilon - complex.EPSILON = config.epsilon; - - // listen for changed in the configuration, automatically apply changed epsilon - math.on('config', function (curr, prev) { - if (curr.epsilon !== prev.epsilon) { - complex.EPSILON = curr.epsilon; - } - }); - - /** - * Compare two complex numbers, `a` and `b`: - * - * - Returns 1 when the real part of `a` is larger than the real part of `b` - * - Returns -1 when the real part of `a` is smaller than the real part of `b` - * - Returns 1 when the real parts are equal - * and the imaginary part of `a` is larger than the imaginary part of `b` - * - Returns -1 when the real parts are equal - * and the imaginary part of `a` is smaller than the imaginary part of `b` - * - Returns 0 when both real and imaginary parts are equal. - * - * @params {Complex} a - * @params {Complex} b - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ - complex.compare = function (a, b) { - if (a.re > b.re) { return 1; } - if (a.re < b.re) { return -1; } - - if (a.im > b.im) { return 1; } - if (a.im < b.im) { return -1; } - - return 0; - }; - - return complex; - } - - var name$7 = 'Complex'; - var path$2 = 'type'; - var factory_1$7 = factory$7; - var math$4 = true; // request access to the math namespace - - var Complex_1 = { - name: name$7, - path: path$2, - factory: factory_1$7, - math: math$4 - }; - - // Map the characters to escape to their escaped values. The list is derived - // from http://www.cespedes.org/blog/85/how-to-escape-latex-special-characters - - var defaultEscapes = { - "{": "\\{", - "}": "\\}", - "\\": "\\textbackslash{}", - "#": "\\#", - $: "\\$", - "%": "\\%", - "&": "\\&", - "^": "\\textasciicircum{}", - _: "\\_", - "~": "\\textasciitilde{}" - }; - var formatEscapes = { - "–": "\\--", - "—": "\\---", - " ": "~", - "\t": "\\qquad{}", - "\r\n": "\\\\newline{}", - "\n": "\\\\newline{}" - }; - - var defaultEscapeMapFn = function defaultEscapeMapFn(defaultEscapes, formatEscapes) { - return Object.assign({}, defaultEscapes, formatEscapes); - }; - - /** - * Escape a string to be used in LaTeX documents. - * @param {string} str the string to be escaped. - * @param {boolean} params.preserveFormatting whether formatting escapes should - * be performed (default: false). - * @param {function} params.escapeMapFn the function to modify the escape maps. - * @return {string} the escaped string, ready to be used in LaTeX. - */ - var dist = function (str) { - var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, - _ref$preserveFormatti = _ref.preserveFormatting, - preserveFormatting = _ref$preserveFormatti === undefined ? false : _ref$preserveFormatti, - _ref$escapeMapFn = _ref.escapeMapFn, - escapeMapFn = _ref$escapeMapFn === undefined ? defaultEscapeMapFn : _ref$escapeMapFn; - - var runningStr = String(str); - var result = ""; - - var escapes = escapeMapFn(Object.assign({}, defaultEscapes), preserveFormatting ? Object.assign({}, formatEscapes) : {}); - var escapeKeys = Object.keys(escapes); // as it is reused later on - - // Algorithm: Go through the string character by character, if it matches - // with one of the special characters then we'll replace it with the escaped - // version. - - var _loop = function _loop() { - var specialCharFound = false; - escapeKeys.forEach(function (key, index) { - if (specialCharFound) { - return; - } - if (runningStr.startsWith(key)) { - result += escapes[escapeKeys[index]]; - runningStr = runningStr.slice(key.length, runningStr.length); - specialCharFound = true; - } - }); - if (!specialCharFound) { - result += runningStr.slice(0, 1); - runningStr = runningStr.slice(1, runningStr.length); - } - }; - - while (runningStr) { - _loop(); - } - return result; - }; - - var latex = createCommonjsModule(function (module, exports) { - - - - 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', - '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 dist(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); - }; - }); - var latex_1 = latex.symbols; - var latex_2 = latex.operators; - var latex_3 = latex.defaultTemplate; - var latex_4 = latex.escape; - var latex_5 = latex.toSymbol; - - function factory$8 (type, config, load, typed) { - var latex$$1 = latex; - - /** - * Create a complex value or convert a value to a complex value. - * - * Syntax: - * - * math.complex() // creates a complex value with zero - * // as real and imaginary part. - * math.complex(re : number, im : string) // creates a complex value with provided - * // values for real and imaginary part. - * math.complex(re : number) // creates a complex value with provided - * // real value and zero imaginary part. - * math.complex(complex : Complex) // clones the provided complex value. - * math.complex(arg : string) // parses a string into a complex value. - * math.complex(array : Array) // converts the elements of the array - * // or matrix element wise into a - * // complex value. - * math.complex({re: number, im: number}) // creates a complex value with provided - * // values for real an imaginary part. - * math.complex({r: number, phi: number}) // creates a complex value with provided - * // polar coordinates - * - * Examples: - * - * var a = math.complex(3, -4); // a = Complex 3 - 4i - * a.re = 5; // a = Complex 5 - 4i - * var i = a.im; // Number -4; - * var b = math.complex('2 + 6i'); // Complex 2 + 6i - * var c = math.complex(); // Complex 0 + 0i - * var d = math.add(a, b); // Complex 5 + 2i - * - * See also: - * - * bignumber, boolean, index, matrix, number, string, unit - * - * @param {* | Array | Matrix} [args] - * Arguments specifying the real and imaginary part of the complex number - * @return {Complex | Array | Matrix} Returns a complex value - */ - var complex = typed('complex', { - '': function () { - return type.Complex.ZERO; - }, - - 'number': function (x) { - return new type.Complex(x, 0); - }, - - 'number, number': function (re, im) { - return new type.Complex(re, im); - }, - - // TODO: this signature should be redundant - 'BigNumber, BigNumber': function (re, im) { - return new type.Complex(re.toNumber(), im.toNumber()); - }, - - 'Complex': function (x) { - return x.clone(); - }, - - 'string': function (x) { - return type.Complex(x); // for example '2 + 3i' - }, - - 'null': function (x) { - return type.Complex(0); - }, - - 'Object': function (x) { - if('re' in x && 'im' in x) { - return new type.Complex(x.re, x.im); - } - - if ('r' in x && 'phi' in x) { - return new type.Complex(x); - } - - throw new Error('Expected object with either properties re and im, or properties r and phi.'); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, complex); - } - }); - - complex.toTex = { - 0: '0', - 1: '\\left(${args[0]}\\right)', - 2: '\\left(\\left(${args[0]}\\right)+' - + latex$$1.symbols['i'] + '\\cdot\\left(${args[1]}\\right)\\right)' - }; - - return complex; - } - - var name$8 = 'complex'; - var factory_1$8 = factory$8; - - var complex$2 = { - name: name$8, - factory: factory_1$8 - }; - - var complex$3 = [ - // type - Complex_1, - - // construction function - complex$2 - ]; - - var fraction = createCommonjsModule(function (module, exports) { - /** - * @license Fraction.js v4.0.8 09/09/2015 - * http://www.xarg.org/2014/03/rational-numbers-in-javascript/ - * - * Copyright (c) 2015, Robert Eisele (robert@xarg.org) - * Dual licensed under the MIT or GPL Version 2 licenses. - **/ - - - /** - * - * This class offers the possibility to calculate fractions. - * You can pass a fraction in different formats. Either as array, as double, as string or as an integer. - * - * Array/Object form - * [ 0 => , 1 => ] - * [ n => , d => ] - * - * Integer form - * - Single integer value - * - * Double form - * - Single double value - * - * String form - * 123.456 - a simple double - * 123/456 - a string fraction - * 123.'456' - a double with repeating decimal places - * 123.(456) - synonym - * 123.45'6' - a double with repeating last place - * 123.45(6) - synonym - * - * Example: - * - * var f = new Fraction("9.4'31'"); - * f.mul([-4, 3]).div(4.9); - * - */ - - (function(root) { - - // Maximum search depth for cyclic rational numbers. 2000 should be more than enough. - // Example: 1/7 = 0.(142857) has 6 repeating decimal places. - // If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits - var MAX_CYCLE_LEN = 2000; - - // Parsed data to avoid calling "new" all the time - var P = { - "s": 1, - "n": 0, - "d": 1 - }; - - function createError(name) { - - function errorConstructor() { - var temp = Error.apply(this, arguments); - temp['name'] = this['name'] = name; - this['stack'] = temp['stack']; - this['message'] = temp['message']; - } - - /** - * Error constructor - * - * @constructor - */ - function IntermediateInheritor() {} - IntermediateInheritor.prototype = Error.prototype; - errorConstructor.prototype = new IntermediateInheritor(); - - return errorConstructor; - } - - var DivisionByZero = Fraction['DivisionByZero'] = createError('DivisionByZero'); - var InvalidParameter = Fraction['InvalidParameter'] = createError('InvalidParameter'); - - function assign(n, s) { - - if (isNaN(n = parseInt(n, 10))) { - throwInvalidParam(); - } - return n * s; - } - - function throwInvalidParam() { - throw new InvalidParameter(); - } - - var parse = function(p1, p2) { - - var n = 0, d = 1, s = 1; - var v = 0, w = 0, x = 0, y = 1, z = 1; - - var A = 0, B = 1; - var C = 1, D = 1; - - var N = 10000000; - var M; - - if (p1 === undefined || p1 === null) { - /* void */ - } else if (p2 !== undefined) { - n = p1; - d = p2; - s = n * d; - } else - switch (typeof p1) { - - case "object": - { - if ("d" in p1 && "n" in p1) { - n = p1["n"]; - d = p1["d"]; - if ("s" in p1) - n *= p1["s"]; - } else if (0 in p1) { - n = p1[0]; - if (1 in p1) - d = p1[1]; - } else { - throwInvalidParam(); - } - s = n * d; - break; - } - case "number": - { - if (p1 < 0) { - s = p1; - p1 = -p1; - } - - if (p1 % 1 === 0) { - n = p1; - } else if (p1 > 0) { // check for != 0, scale would become NaN (log(0)), which converges really slow - - if (p1 >= 1) { - z = Math.pow(10, Math.floor(1 + Math.log(p1) / Math.LN10)); - p1 /= z; - } - - // Using Farey Sequences - // http://www.johndcook.com/blog/2010/10/20/best-rational-approximation/ - - while (B <= N && D <= N) { - M = (A + C) / (B + D); - - if (p1 === M) { - if (B + D <= N) { - n = A + C; - d = B + D; - } else if (D > B) { - n = C; - d = D; - } else { - n = A; - d = B; - } - break; - - } else { - - if (p1 > M) { - A += C; - B += D; - } else { - C += A; - D += B; - } - - if (B > N) { - n = C; - d = D; - } else { - n = A; - d = B; - } - } - } - n *= z; - } else if (isNaN(p1) || isNaN(p2)) { - d = n = NaN; - } - break; - } - case "string": - { - B = p1.match(/\d+|./g); - - if (B === null) - throwInvalidParam(); - - if (B[A] === '-') {// Check for minus sign at the beginning - s = -1; - A++; - } else if (B[A] === '+') {// Check for plus sign at the beginning - A++; - } - - if (B.length === A + 1) { // Check if it's just a simple number "1234" - w = assign(B[A++], s); - } else if (B[A + 1] === '.' || B[A] === '.') { // Check if it's a decimal number - - if (B[A] !== '.') { // Handle 0.5 and .5 - v = assign(B[A++], s); - } - A++; - - // Check for decimal places - if (A + 1 === B.length || B[A + 1] === '(' && B[A + 3] === ')' || B[A + 1] === "'" && B[A + 3] === "'") { - w = assign(B[A], s); - y = Math.pow(10, B[A].length); - A++; - } - - // Check for repeating places - if (B[A] === '(' && B[A + 2] === ')' || B[A] === "'" && B[A + 2] === "'") { - x = assign(B[A + 1], s); - z = Math.pow(10, B[A + 1].length) - 1; - A += 3; - } - - } else if (B[A + 1] === '/' || B[A + 1] === ':') { // Check for a simple fraction "123/456" or "123:456" - w = assign(B[A], s); - y = assign(B[A + 2], 1); - A += 3; - } else if (B[A + 3] === '/' && B[A + 1] === ' ') { // Check for a complex fraction "123 1/2" - v = assign(B[A], s); - w = assign(B[A + 2], s); - y = assign(B[A + 4], 1); - A += 5; - } - - if (B.length <= A) { // Check for more tokens on the stack - d = y * z; - s = /* void */ - n = x + d * v + z * w; - break; - } - - /* Fall through on error */ - } - default: - throwInvalidParam(); - } - - if (d === 0) { - throw new DivisionByZero(); - } - - P["s"] = s < 0 ? -1 : 1; - P["n"] = Math.abs(n); - P["d"] = Math.abs(d); - }; - - function modpow(b, e, m) { - - var r = 1; - for (; e > 0; b = (b * b) % m, e >>= 1) { - - if (e & 1) { - r = (r * b) % m; - } - } - return r; - } - - - function cycleLen(n, d) { - - for (; d % 2 === 0; - d /= 2) { - } - - for (; d % 5 === 0; - d /= 5) { - } - - if (d === 1) // Catch non-cyclic numbers - return 0; - - // If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem: - // 10^(d-1) % d == 1 - // However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone, - // as we want to translate the numbers to strings. - - var rem = 10 % d; - var t = 1; - - for (; rem !== 1; t++) { - rem = rem * 10 % d; - - if (t > MAX_CYCLE_LEN) - return 0; // Returning 0 here means that we don't print it as a cyclic number. It's likely that the answer is `d-1` - } - return t; - } - - - function cycleStart(n, d, len) { - - var rem1 = 1; - var rem2 = modpow(10, len, d); - - for (var t = 0; t < 300; t++) { // s < ~log10(Number.MAX_VALUE) - // Solve 10^s == 10^(s+t) (mod d) - - if (rem1 === rem2) - return t; - - rem1 = rem1 * 10 % d; - rem2 = rem2 * 10 % d; - } - return 0; - } - - function gcd(a, b) { - - if (!a) - return b; - if (!b) - return a; - - while (1) { - a %= b; - if (!a) - return b; - b %= a; - if (!b) - return a; - } - } - /** - * Module constructor - * - * @constructor - * @param {number|Fraction=} a - * @param {number=} b - */ - function Fraction(a, b) { - - if (!(this instanceof Fraction)) { - return new Fraction(a, b); - } - - parse(a, b); - - if (Fraction['REDUCE']) { - a = gcd(P["d"], P["n"]); // Abuse a - } else { - a = 1; - } - - this["s"] = P["s"]; - this["n"] = P["n"] / a; - this["d"] = P["d"] / a; - } - - /** - * Boolean global variable to be able to disable automatic reduction of the fraction - * - */ - Fraction['REDUCE'] = 1; - - Fraction.prototype = { - - "s": 1, - "n": 0, - "d": 1, - - /** - * Calculates the absolute value - * - * Ex: new Fraction(-4).abs() => 4 - **/ - "abs": function() { - - return new Fraction(this["n"], this["d"]); - }, - - /** - * Inverts the sign of the current fraction - * - * Ex: new Fraction(-4).neg() => 4 - **/ - "neg": function() { - - return new Fraction(-this["s"] * this["n"], this["d"]); - }, - - /** - * Adds two rational numbers - * - * Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30 - **/ - "add": function(a, b) { - - parse(a, b); - return new Fraction( - this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"], - this["d"] * P["d"] - ); - }, - - /** - * Subtracts two rational numbers - * - * Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30 - **/ - "sub": function(a, b) { - - parse(a, b); - return new Fraction( - this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"], - this["d"] * P["d"] - ); - }, - - /** - * Multiplies two rational numbers - * - * Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111 - **/ - "mul": function(a, b) { - - parse(a, b); - return new Fraction( - this["s"] * P["s"] * this["n"] * P["n"], - this["d"] * P["d"] - ); - }, - - /** - * Divides two rational numbers - * - * Ex: new Fraction("-17.(345)").inverse().div(3) - **/ - "div": function(a, b) { - - parse(a, b); - return new Fraction( - this["s"] * P["s"] * this["n"] * P["d"], - this["d"] * P["n"] - ); - }, - - /** - * Clones the actual object - * - * Ex: new Fraction("-17.(345)").clone() - **/ - "clone": function() { - return new Fraction(this); - }, - - /** - * Calculates the modulo of two rational numbers - a more precise fmod - * - * Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6) - **/ - "mod": function(a, b) { - - if (isNaN(this['n']) || isNaN(this['d'])) { - return new Fraction(NaN); - } - - if (a === undefined) { - return new Fraction(this["s"] * this["n"] % this["d"], 1); - } - - parse(a, b); - if (0 === P["n"] && 0 === this["d"]) { - Fraction(0, 0); // Throw DivisionByZero - } - - /* - * First silly attempt, kinda slow - * - return that["sub"]({ - "n": num["n"] * Math.floor((this.n / this.d) / (num.n / num.d)), - "d": num["d"], - "s": this["s"] - });*/ - - /* - * New attempt: a1 / b1 = a2 / b2 * q + r - * => b2 * a1 = a2 * b1 * q + b1 * b2 * r - * => (b2 * a1 % a2 * b1) / (b1 * b2) - */ - return new Fraction( - this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]), - P["d"] * this["d"] - ); - }, - - /** - * Calculates the fractional gcd of two rational numbers - * - * Ex: new Fraction(5,8).gcd(3,7) => 1/56 - */ - "gcd": function(a, b) { - - parse(a, b); - - // gcd(a / b, c / d) = gcd(a, c) / lcm(b, d) - - return new Fraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]); - }, - - /** - * Calculates the fractional lcm of two rational numbers - * - * Ex: new Fraction(5,8).lcm(3,7) => 15 - */ - "lcm": function(a, b) { - - parse(a, b); - - // lcm(a / b, c / d) = lcm(a, c) / gcd(b, d) - - if (P["n"] === 0 && this["n"] === 0) { - return new Fraction; - } - return new Fraction(P["n"] * this["n"], gcd(P["n"], this["n"]) * gcd(P["d"], this["d"])); - }, - - /** - * Calculates the ceil of a rational number - * - * Ex: new Fraction('4.(3)').ceil() => (5 / 1) - **/ - "ceil": function(places) { - - places = Math.pow(10, places || 0); - - if (isNaN(this["n"]) || isNaN(this["d"])) { - return new Fraction(NaN); - } - return new Fraction(Math.ceil(places * this["s"] * this["n"] / this["d"]), places); - }, - - /** - * Calculates the floor of a rational number - * - * Ex: new Fraction('4.(3)').floor() => (4 / 1) - **/ - "floor": function(places) { - - places = Math.pow(10, places || 0); - - if (isNaN(this["n"]) || isNaN(this["d"])) { - return new Fraction(NaN); - } - return new Fraction(Math.floor(places * this["s"] * this["n"] / this["d"]), places); - }, - - /** - * Rounds a rational numbers - * - * Ex: new Fraction('4.(3)').round() => (4 / 1) - **/ - "round": function(places) { - - places = Math.pow(10, places || 0); - - if (isNaN(this["n"]) || isNaN(this["d"])) { - return new Fraction(NaN); - } - return new Fraction(Math.round(places * this["s"] * this["n"] / this["d"]), places); - }, - - /** - * Gets the inverse of the fraction, means numerator and denumerator are exchanged - * - * Ex: new Fraction([-3, 4]).inverse() => -4 / 3 - **/ - "inverse": function() { - - return new Fraction(this["s"] * this["d"], this["n"]); - }, - - /** - * Calculates the fraction to some integer exponent - * - * Ex: new Fraction(-1,2).pow(-3) => -8 - */ - "pow": function(m) { - - if (m < 0) { - return new Fraction(Math.pow(this['s'] * this["d"], -m), Math.pow(this["n"], -m)); - } else { - return new Fraction(Math.pow(this['s'] * this["n"], m), Math.pow(this["d"], m)); - } - }, - - /** - * Check if two rational numbers are the same - * - * Ex: new Fraction(19.6).equals([98, 5]); - **/ - "equals": function(a, b) { - - parse(a, b); - return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"]; // Same as compare() === 0 - }, - - /** - * Check if two rational numbers are the same - * - * Ex: new Fraction(19.6).equals([98, 5]); - **/ - "compare": function(a, b) { - - parse(a, b); - var t = (this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"]); - return (0 < t) - (t < 0); - }, - - "simplify": function(eps) { - - // First naive implementation, needs improvement - - if (isNaN(this['n']) || isNaN(this['d'])) { - return this; - } - - var cont = this['abs']()['toContinued'](); - - eps = eps || 0.001; - - function rec(a) { - if (a.length === 1) - return new Fraction(a[0]); - return rec(a.slice(1))['inverse']()['add'](a[0]); - } - - for (var i = 0; i < cont.length; i++) { - var tmp = rec(cont.slice(0, i + 1)); - if (tmp['sub'](this['abs']())['abs']().valueOf() < eps) { - return tmp['mul'](this['s']); - } - } - return this; - }, - - /** - * Check if two rational numbers are divisible - * - * Ex: new Fraction(19.6).divisible(1.5); - */ - "divisible": function(a, b) { - - parse(a, b); - return !(!(P["n"] * this["d"]) || ((this["n"] * P["d"]) % (P["n"] * this["d"]))); - }, - - /** - * Returns a decimal representation of the fraction - * - * Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183 - **/ - 'valueOf': function() { - - return this["s"] * this["n"] / this["d"]; - }, - - /** - * Returns a string-fraction representation of a Fraction object - * - * Ex: new Fraction("1.'3'").toFraction() => "4 1/3" - **/ - 'toFraction': function(excludeWhole) { - - var whole, str = ""; - var n = this["n"]; - var d = this["d"]; - if (this["s"] < 0) { - str += '-'; - } - - if (d === 1) { - str += n; - } else { - - if (excludeWhole && (whole = Math.floor(n / d)) > 0) { - str += whole; - str += " "; - n %= d; - } - - str += n; - str += '/'; - str += d; - } - return str; - }, - - /** - * Returns a latex representation of a Fraction object - * - * Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}" - **/ - 'toLatex': function(excludeWhole) { - - var whole, str = ""; - var n = this["n"]; - var d = this["d"]; - if (this["s"] < 0) { - str += '-'; - } - - if (d === 1) { - str += n; - } else { - - if (excludeWhole && (whole = Math.floor(n / d)) > 0) { - str += whole; - n %= d; - } - - str += "\\frac{"; - str += n; - str += '}{'; - str += d; - str += '}'; - } - return str; - }, - - /** - * Returns an array of continued fraction elements - * - * Ex: new Fraction("7/8").toContinued() => [0,1,7] - */ - 'toContinued': function() { - - var t; - var a = this['n']; - var b = this['d']; - var res = []; - - if (isNaN(this['n']) || isNaN(this['d'])) { - return res; - } - - do { - res.push(Math.floor(a / b)); - t = a % b; - a = b; - b = t; - } while (a !== 1); - - return res; - }, - - /** - * Creates a string representation of a fraction with all digits - * - * Ex: new Fraction("100.'91823'").toString() => "100.(91823)" - **/ - 'toString': function() { - - var g; - var N = this["n"]; - var D = this["d"]; - - if (isNaN(N) || isNaN(D)) { - return "NaN"; - } - - if (!Fraction['REDUCE']) { - g = gcd(N, D); - N /= g; - D /= g; - } - - var dec = 15; // 15 = decimal places when no repitation - - var cycLen = cycleLen(N, D); // Cycle length - var cycOff = cycleStart(N, D, cycLen); // Cycle start - - var str = this['s'] === -1 ? "-" : ""; - - str += N / D | 0; - - N %= D; - N *= 10; - - if (N) - str += "."; - - if (cycLen) { - - for (var i = cycOff; i--; ) { - str += N / D | 0; - N %= D; - N *= 10; - } - str += "("; - for (var i = cycLen; i--; ) { - str += N / D | 0; - N %= D; - N *= 10; - } - str += ")"; - } else { - for (var i = dec; N && i--; ) { - str += N / D | 0; - N %= D; - N *= 10; - } - } - return str; - } - }; - - if (typeof undefined === "function" && undefined["amd"]) { - undefined([], function() { - return Fraction; - }); - } else { - Object.defineProperty(exports, "__esModule", {'value': true}); - Fraction['default'] = Fraction; - Fraction['Fraction'] = Fraction; - module['exports'] = Fraction; - } - - })(commonjsGlobal); - }); - - unwrapExports(fraction); - - /** - * Attach type information - */ - fraction.prototype.type = 'Fraction'; - fraction.prototype.isFraction = true; - - /** - * Get a JSON representation of a Fraction containing type information - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Fraction", "n": 3, "d": 8}` - */ - fraction.prototype.toJSON = function () { - return { - mathjs: 'Fraction', - n: this.s * this.n, - d: this.d - }; - }; - - /** - * Instantiate a Fraction from a JSON object - * @param {Object} json a JSON object structured as: - * `{"mathjs": "Fraction", "n": 3, "d": 8}` - * @return {BigNumber} - */ - fraction.fromJSON = function (json) { - return new fraction(json); - }; - - - function factory$9 (type, config, load, typed) { - return fraction; - } - - var name$9 = 'Fraction'; - var path$3 = 'type'; - var factory_1$9 = factory$9; - - var Fraction_1 = { - name: name$9, - path: path$3, - factory: factory_1$9 - }; - - function factory$10 (type, config, load, typed) { - /** - * Create a fraction convert a value to a fraction. - * - * Syntax: - * math.fraction(numerator, denominator) - * math.fraction({n: numerator, d: denominator}) - * math.fraction(matrix: Array | Matrix) Turn all matrix entries - * into fractions - * - * Examples: - * - * math.fraction(1, 3); - * math.fraction('2/3'); - * math.fraction({n: 2, d: 3}); - * math.fraction([0.2, 0.25, 1.25]); - * - * See also: - * - * bignumber, number, string, unit - * - * @param {number | string | Fraction | BigNumber | Array | Matrix} [args] - * Arguments specifying the numerator and denominator of - * the fraction - * @return {Fraction | Array | Matrix} Returns a fraction - */ - var fraction = typed('fraction', { - 'number': function (x) { - if (!isFinite(x) || isNaN(x)) { - throw new Error(x + ' cannot be represented as a fraction'); - } - - return new type.Fraction(x); - }, - - 'string': function (x) { - return new type.Fraction(x); - }, - - 'number, number': function (numerator, denominator) { - return new type.Fraction(numerator, denominator); - }, - - 'null': function (x) { - return new type.Fraction(0); - }, - - 'BigNumber': function (x) { - return new type.Fraction(x.toString()); - }, - - 'Fraction': function (x) { - return x; // fractions are immutable - }, - - 'Object': function (x) { - return new type.Fraction(x); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, fraction); - } - }); - - return fraction; - } - - var name$10 = 'fraction'; - var factory_1$10 = factory$10; - - var fraction$2 = { - name: name$10, - factory: factory_1$10 - }; - - var fraction$3 = [ - // type - Fraction_1, - - // construction function - fraction$2 - ]; - - /** - * Create a range error with the message: - * 'Dimension mismatch ( != )' - * @param {number | number[]} actual The actual size - * @param {number | number[]} expected The expected size - * @param {string} [relation='!='] Optional relation between actual - * and expected size: '!=', '<', etc. - * @extends RangeError - */ - function DimensionError(actual, expected, relation) { - if (!(this instanceof DimensionError)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.actual = actual; - this.expected = expected; - this.relation = relation; - - this.message = 'Dimension mismatch (' + - (Array.isArray(actual) ? ('[' + actual.join(', ') + ']') : actual) + - ' ' + (this.relation || '!=') + ' ' + - (Array.isArray(expected) ? ('[' + expected.join(', ') + ']') : expected) + - ')'; - - this.stack = (new Error()).stack; - } - - DimensionError.prototype = new RangeError(); - DimensionError.prototype.constructor = RangeError; - DimensionError.prototype.name = 'DimensionError'; - DimensionError.prototype.isDimensionError = true; - - var DimensionError_1 = DimensionError; - - /** - * Create a range error with the message: - * 'Index out of range (index < min)' - * 'Index out of range (index < max)' - * - * @param {number} index The actual index - * @param {number} [min=0] Minimum index (included) - * @param {number} [max] Maximum index (excluded) - * @extends RangeError - */ - function IndexError(index, min, max) { - if (!(this instanceof IndexError)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.index = index; - if (arguments.length < 3) { - this.min = 0; - this.max = min; - } - else { - this.min = min; - this.max = max; - } - - if (this.min !== undefined && this.index < this.min) { - this.message = 'Index out of range (' + this.index + ' < ' + this.min + ')'; - } - else if (this.max !== undefined && this.index >= this.max) { - this.message = 'Index out of range (' + this.index + ' > ' + (this.max - 1) + ')'; - } - else { - this.message = 'Index out of range (' + this.index + ')'; - } - - this.stack = (new Error()).stack; - } - - IndexError.prototype = new RangeError(); - IndexError.prototype.constructor = RangeError; - IndexError.prototype.name = 'IndexError'; - IndexError.prototype.isIndexError = true; - - var IndexError_1 = IndexError; - - var array = createCommonjsModule(function (module, exports) { - - - - - - - - /** - * 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 - */ - exports.size = function (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 DimensionError_1(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 DimensionError_1(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 DimensionError_1(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 - */ - exports.validate = function(array, size) { - var isScalar = (size.length == 0); - if (isScalar) { - // scalar - if (Array.isArray(array)) { - throw new DimensionError_1(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 - */ - exports.validateIndex = function(index, length) { - if (!number.isNumber(index) || !number.isInteger(index)) { - throw new TypeError('Index must be an integer (value: ' + index + ')'); - } - if (index < 0 || (typeof length === 'number' && index >= length)) { - throw new IndexError_1(index, length); - } - }; - - /** - * Resize a multi dimensional array. The resized array is returned. - * @param {Array} array Array to be resized - * @param {Array.} 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 - */ - exports.resize = function(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.isNumber(value) || !number.isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + string.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.} 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 - */ - exports.reshape = function(array, sizes) { - var flatArray = exports.flatten(array); - var newArray; - - var product = function (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 DimensionError_1(0, product(exports.size(array)), '!='); - } - - try { - newArray = _reshape(flatArray, sizes); - } catch (e) { - if (e instanceof DimensionError_1) { - throw new DimensionError_1( - product(sizes), - product(exports.size(array)), - '!=' - ); - } - throw e; - } - - if (flatArray.length > 0) { - throw new DimensionError_1( - product(sizes), - product(exports.size(array)), - '!=' - ); - } - - return newArray; - }; - - /** - * Recursively re-shape a multi dimensional array to fit the specified dimensions - * @param {Array} array Array to be reshaped - * @param {Array.} 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 accumulator = []; - var i; - - if (sizes.length === 0) { - if (array.length === 0) { - throw new DimensionError_1(null, null, '!='); - } - return array.shift(); - } - for (i = 0; i < sizes[0]; i += 1) { - accumulator.push(_reshape(array, sizes.slice(1))); - } - return accumulator; - } - - - /** - * Squeeze a multi dimensional array - * @param {Array} array - * @param {Array} [size] - * @returns {Array} returns the array itself - */ - exports.squeeze = function(array, size) { - var s = size || exports.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} [size] Current size of array. - * @returns {Array} returns the array itself - * @private - */ - exports.unsqueeze = function(array, dims, outer, size) { - var s = size || exports.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) - */ - exports.flatten = function(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 - */ - exports.map = function (array, callback) { - return Array.prototype.map.call(array, callback); - }; - - /** - * A safe forEach - * @param {Array} array - * @param {function} callback - */ - exports.forEach = function (array, callback) { - Array.prototype.forEach.call(array, callback); - }; - - /** - * A safe filter - * @param {Array} array - * @param {function} callback - */ - exports.filter = function (array, callback) { - if (exports.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 - */ - exports.filterRegExp = function (array, regexp) { - if (exports.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 - */ - exports.join = function (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 - */ - exports.identify = function(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'); - } - - // enlarge matrix when needed - var size = index.max().map(function (i) { - return i + 1; - }); - _fit(matrix, size, defaultValue); - - // insert the sub matrix - var dims = iSize.length, - dim = 0; - _setSubmatrix (matrix._data, index, submatrix, dims, dim); - } - - return matrix; - } - - /** - * Replace a submatrix of a multi dimensional matrix. - * @memberof DenseMatrix - * @param {Array} data - * @param {Index} index - * @param {Array} submatrix - * @param {number} dims Total number of dimensions - * @param {number} dim - * @private - */ - function _setSubmatrix (data, index, submatrix, dims, dim) { - var last = (dim === dims - 1), - range = index.dimension(dim); - - if (last) { - range.forEach(function (dataIndex, subIndex) { - validateIndex(dataIndex); - data[dataIndex] = submatrix[subIndex[0]]; - }); - } - else { - range.forEach(function (dataIndex, subIndex) { - validateIndex(dataIndex); - _setSubmatrix(data[dataIndex], index, submatrix[subIndex[0]], dims, dim + 1); - }); - } - } - - /** - * Resize the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (resize in place). - * - * @memberof DenseMatrix - * @param {number[]} size The new size the matrix should have. - * @param {*} [defaultValue=0] Default value, filled in on new entries. - * If not provided, the matrix elements will - * be filled with zeros. - * @param {boolean} [copy] Return a resized copy of the matrix - * - * @return {Matrix} The resized matrix - */ - DenseMatrix.prototype.resize = function (size, defaultValue, copy) { - // validate arguments - if (!isArray(size)) - throw new TypeError('Array expected'); - - // matrix to resize - var m = copy ? this.clone() : this; - // resize matrix - return _resize(m, size, defaultValue); - }; - - var _resize = function (matrix, size, defaultValue) { - // check size - if (size.length === 0) { - // first value in matrix - var v = matrix._data; - // go deep - while (isArray(v)) { - v = v[0]; - } - return v; - } - // resize matrix - matrix._size = size.slice(0); // copy the array - matrix._data = array$1.resize(matrix._data, matrix._size, defaultValue); - // return matrix - return matrix; - }; - - /** - * Reshape the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (reshape in place). - * - * NOTE: This might be better suited to copy by default, instead of modifying - * in place. For now, it operates in place to remain consistent with - * resize(). - * - * @memberof DenseMatrix - * @param {number[]} size The new size the matrix should have. - * @param {boolean} [copy] Return a reshaped copy of the matrix - * - * @return {Matrix} The reshaped matrix - */ - DenseMatrix.prototype.reshape = function (size, copy) { - var m = copy ? this.clone() : this; - - m._data = array$1.reshape(m._data, size); - m._size = size.slice(0); - return m; - }; - - /** - * Enlarge the matrix when it is smaller than given size. - * If the matrix is larger or equal sized, nothing is done. - * @memberof DenseMatrix - * @param {DenseMatrix} matrix The matrix to be resized - * @param {number[]} size - * @param {*} defaultValue Default value, filled in on new entries. - * @private - */ - function _fit(matrix, size, defaultValue) { - var newSize = matrix._size.slice(0), // copy the array - changed = false; - - // add dimensions when needed - while (newSize.length < size.length) { - newSize.push(0); - changed = true; - } - - // enlarge size when needed - for (var i = 0, ii = size.length; i < ii; i++) { - if (size[i] > newSize[i]) { - newSize[i] = size[i]; - changed = true; - } - } - - if (changed) { - // resize only when size is changed - _resize(matrix, newSize, defaultValue); - } - } - - /** - * Create a clone of the matrix - * @memberof DenseMatrix - * @return {DenseMatrix} clone - */ - DenseMatrix.prototype.clone = function () { - var m = new DenseMatrix({ - data: object$1.clone(this._data), - size: object$1.clone(this._size), - datatype: this._datatype - }); - return m; - }; - - /** - * Retrieve the size of the matrix. - * @memberof DenseMatrix - * @returns {number[]} size - */ - DenseMatrix.prototype.size = function() { - return this._size.slice(0); // return a clone of _size - }; - - /** - * Create a new matrix with the results of the callback function executed on - * each entry of the matrix. - * @memberof DenseMatrix - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * - * @return {DenseMatrix} matrix - */ - DenseMatrix.prototype.map = function (callback) { - // matrix instance - var me = this; - var recurse = function (value, index) { - if (isArray(value)) { - return value.map(function (child, i) { - return recurse(child, index.concat(i)); - }); - } - else { - return callback(value, index, me); - } - }; - // return dense format - return new DenseMatrix({ - data: recurse(this._data, []), - size: object$1.clone(this._size), - datatype: this._datatype - }); - }; - - /** - * Execute a callback function on each entry of the matrix. - * @memberof DenseMatrix - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - */ - DenseMatrix.prototype.forEach = function (callback) { - // matrix instance - var me = this; - var recurse = function (value, index) { - if (isArray(value)) { - value.forEach(function (child, i) { - recurse(child, index.concat(i)); - }); - } - else { - callback(value, index, me); - } - }; - recurse(this._data, []); - }; - - /** - * Create an Array with a copy of the data of the DenseMatrix - * @memberof DenseMatrix - * @returns {Array} array - */ - DenseMatrix.prototype.toArray = function () { - return object$1.clone(this._data); - }; - - /** - * Get the primitive value of the DenseMatrix: a multidimensional array - * @memberof DenseMatrix - * @returns {Array} array - */ - DenseMatrix.prototype.valueOf = function () { - return this._data; - }; - - /** - * Get a string representation of the matrix, with optional formatting options. - * @memberof DenseMatrix - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ - DenseMatrix.prototype.format = function (options) { - return string$2.format(this._data, options); - }; - - /** - * Get a string representation of the matrix - * @memberof DenseMatrix - * @returns {string} str - */ - DenseMatrix.prototype.toString = function () { - return string$2.format(this._data); - }; - - /** - * Get a JSON representation of the matrix - * @memberof DenseMatrix - * @returns {Object} - */ - DenseMatrix.prototype.toJSON = function () { - return { - mathjs: 'DenseMatrix', - data: this._data, - size: this._size, - datatype: this._datatype - }; - }; - - /** - * Get the kth Matrix diagonal. - * - * @memberof DenseMatrix - * @param {number | BigNumber} [k=0] The kth diagonal where the vector will retrieved. - * - * @returns {Array} The array vector with the diagonal values. - */ - DenseMatrix.prototype.diagonal = function(k) { - // validate k if any - if (k) { - // convert BigNumber to a number - if (type.isBigNumber(k)) - k = k.toNumber(); - // is must be an integer - if (!isNumber$1(k) || !isInteger(k)) { - throw new TypeError ('The parameter k must be an integer number'); - } - } - else { - // default value - k = 0; - } - - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // rows & columns - var rows = this._size[0]; - var columns = this._size[1]; - - // number diagonal values - var n = Math.min(rows - kSub, columns - kSuper); - - // x is a matrix get diagonal from matrix - var data = []; - - // loop rows - for (var i = 0; i < n; i++) { - data[i] = this._data[i + kSub][i + kSuper]; - } - - // create DenseMatrix - return new DenseMatrix({ - data: data, - size: [n], - datatype: this._datatype - }); - }; - - /** - * Create a diagonal matrix. - * - * @memberof DenseMatrix - * @param {Array} size The matrix size. - * @param {number | Array} value The values for the diagonal. - * @param {number | BigNumber} [k=0] The kth diagonal where the vector will be filled in. - * @param {number} [defaultValue] The default value for non-diagonal - * - * @returns {DenseMatrix} - */ - DenseMatrix.diagonal = function (size, value, k, defaultValue, datatype) { - if (!isArray(size)) - throw new TypeError('Array expected, size parameter'); - if (size.length !== 2) - throw new Error('Only two dimensions matrix are supported'); - - // map size & validate - size = size.map(function (s) { - // check it is a big number - if (type.isBigNumber(s)) { - // convert it - s = s.toNumber(); - } - // validate arguments - if (!isNumber$1(s) || !isInteger(s) || s < 1) { - throw new Error('Size values must be positive integers'); - } - return s; - }); - - // validate k if any - if (k) { - // convert BigNumber to a number - if (type.isBigNumber(k)) - k = k.toNumber(); - // is must be an integer - if (!isNumber$1(k) || !isInteger(k)) { - throw new TypeError ('The parameter k must be an integer number'); - } - } - else { - // default value - k = 0; - } - - if (defaultValue && isString$1(datatype)) { - // convert defaultValue to the same datatype - defaultValue = typed.convert(defaultValue, datatype); - } - - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // rows and columns - var rows = size[0]; - var columns = size[1]; - - // number of non-zero items - var n = Math.min(rows - kSub, columns - kSuper); - - // value extraction function - var _value; - - // check value - if (isArray(value)) { - // validate array - if (value.length !== n) { - // number of values in array must be n - throw new Error('Invalid value array length'); - } - // define function - _value = function (i) { - // return value @ i - return value[i]; - }; - } - else if (type.isMatrix(value)) { - // matrix size - var ms = value.size(); - // validate matrix - if (ms.length !== 1 || ms[0] !== n) { - // number of values in array must be n - throw new Error('Invalid matrix length'); - } - // define function - _value = function (i) { - // return value @ i - return value.get([i]); - }; - } - else { - // define function - _value = function () { - // return value - return value; - }; - } - - // discover default value if needed - if (!defaultValue) { - // check first value in array - defaultValue = type.isBigNumber(_value(0)) ? new type.BigNumber(0) : 0; - } - - // empty array - var data = []; - - // check we need to resize array - if (size.length > 0) { - // resize array - data = array$1.resize(data, size, defaultValue); - // fill diagonal - for (var d = 0; d < n; d++) { - data[d + kSub][d + kSuper] = _value(d); - } - } - - // create DenseMatrix - return new DenseMatrix({ - data: data, - size: [rows, columns] - }); - }; - - /** - * Generate a matrix from a JSON object - * @memberof DenseMatrix - * @param {Object} json An object structured like - * `{"mathjs": "DenseMatrix", data: [], size: []}`, - * where mathjs is optional - * @returns {DenseMatrix} - */ - DenseMatrix.fromJSON = function (json) { - return new DenseMatrix(json); - }; - - /** - * Swap rows i and j in Matrix. - * - * @memberof DenseMatrix - * @param {number} i Matrix row index 1 - * @param {number} j Matrix row index 2 - * - * @return {Matrix} The matrix reference - */ - DenseMatrix.prototype.swapRows = function (i, j) { - // check index - if (!isNumber$1(i) || !isInteger(i) || !isNumber$1(j) || !isInteger(j)) { - throw new Error('Row index must be positive integers'); - } - // check dimensions - if (this._size.length !== 2) { - throw new Error('Only two dimensional matrix is supported'); - } - // validate index - validateIndex(i, this._size[0]); - validateIndex(j, this._size[0]); - - // swap rows - DenseMatrix._swapRows(i, j, this._data); - // return current instance - return this; - }; - - /** - * Swap rows i and j in Dense Matrix data structure. - * - * @param {number} i Matrix row index 1 - * @param {number} j Matrix row index 2 - */ - DenseMatrix._swapRows = function (i, j, data) { - // swap values i <-> j - var vi = data[i]; - data[i] = data[j]; - data[j] = vi; - }; - - /** - * Preprocess data, which can be an Array or DenseMatrix with nested Arrays and - * Matrices. Replaces all nested Matrices with Arrays - * @memberof DenseMatrix - * @param {Array} data - * @return {Array} data - */ - function preprocess(data) { - for (var i = 0, ii = data.length; i < ii; i++) { - var elem = data[i]; - if (isArray(elem)) { - data[i] = preprocess(elem); - } - else if (elem && elem.isMatrix === true) { - data[i] = preprocess(elem.valueOf()); - } - } - - return data; - } - - // register this type in the base class Matrix - type.Matrix._storage.dense = DenseMatrix; - type.Matrix._storage['default'] = DenseMatrix; - - // exports - return DenseMatrix; - } - - var name$12 = 'DenseMatrix'; - var path$5 = 'type'; - var factory_1$12 = factory$12; - var lazy$2 = false; // no lazy loading, as we alter type.Matrix._storage - - var DenseMatrix = { - name: name$12, - path: path$5, - factory: factory_1$12, - lazy: lazy$2 - }; - - /** - * Compares two BigNumbers. - * @param {BigNumber} x First value to compare - * @param {BigNumber} 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 - */ - var nearlyEqual = function nearlyEqual(x, y, epsilon) { - // if epsilon is null or undefined, test whether x and y are exactly equal - if (epsilon == null) { - return x.eq(y); - } - - - // use "==" operator, handles infinities - if (x.eq(y)) { - return true; - } - - // NaN - if (x.isNaN() || y.isNaN()) { - return false; - } - - // at this point x and y should be finite - if(x.isFinite() && y.isFinite()) { - // check numbers are very close, needed when comparing numbers near zero - var diff = x.minus(y).abs(); - if (diff.isZero()) { - return true; - } - else { - // use relative error - var max = x.constructor.max(x.abs(), y.abs()); - return diff.lte(max.times(epsilon)); - } - } - - // Infinite and Number or negative Infinite and positive Infinite cases - return false; - }; - - var nearlyEqual$1 = number.nearlyEqual; - - - function factory$13 (type, config, load, typed) { - - /** - * Test whether two values are equal. - * - * @param {number | BigNumber | Fraction | boolean | Complex | Unit} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Complex} y Second value to compare - * @return {boolean} Returns true when the compared values are equal, else returns false - * @private - */ - var equalScalar = typed('equalScalar', { - - 'boolean, boolean': function (x, y) { - return x === y; - }, - - 'number, number': function (x, y) { - return x === y || nearlyEqual$1(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.eq(y) || nearlyEqual(x, y, config.epsilon); - }, - - 'Fraction, Fraction': function (x, y) { - return x.equals(y); - }, - - 'Complex, Complex': function (x, y) { - return x.equals(y); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return equalScalar(x.value, y.value); - } - }); - - return equalScalar; - } - - var factory_1$13 = factory$13; - - var equalScalar = { - factory: factory_1$13 - }; - - var array$2 = utils.array; - var object$2 = utils.object; - var string$3 = utils.string; - var number$2 = utils.number; - - var isArray$1 = Array.isArray; - var isNumber$2 = number$2.isNumber; - var isInteger$1 = number$2.isInteger; - var isString$2 = string$3.isString; - - var validateIndex$1 = array$2.validateIndex; - - function factory$14 (type, config, load, typed) { - var Matrix$$1 = load(Matrix); // force loading Matrix (do not use via type.Matrix) - var equalScalar$$1 = load(equalScalar); - - /** - * Sparse Matrix implementation. This type implements a Compressed Column Storage format - * for sparse matrices. - * @class SparseMatrix - */ - function SparseMatrix(data, datatype) { - if (!(this instanceof SparseMatrix)) - throw new SyntaxError('Constructor must be called with the new operator'); - if (datatype && !isString$2(datatype)) - throw new Error('Invalid datatype: ' + datatype); - - if (type.isMatrix(data)) { - // create from matrix - _createFromMatrix(this, data, datatype); - } - else if (data && isArray$1(data.index) && isArray$1(data.ptr) && isArray$1(data.size)) { - // initialize fields - this._values = data.values; - this._index = data.index; - this._ptr = data.ptr; - this._size = data.size; - this._datatype = datatype || data.datatype; - } - else if (isArray$1(data)) { - // create from array - _createFromArray(this, data, datatype); - } - else if (data) { - // unsupported type - throw new TypeError('Unsupported type of data (' + utils.types.type(data) + ')'); - } - else { - // nothing provided - this._values = []; - this._index = []; - this._ptr = [0]; - this._size = [0, 0]; - this._datatype = datatype; - } - } - - var _createFromMatrix = function (matrix, source, datatype) { - // check matrix type - if (source.type === 'SparseMatrix') { - // clone arrays - matrix._values = source._values ? object$2.clone(source._values) : undefined; - matrix._index = object$2.clone(source._index); - matrix._ptr = object$2.clone(source._ptr); - matrix._size = object$2.clone(source._size); - matrix._datatype = datatype || source._datatype; - } - else { - // build from matrix data - _createFromArray(matrix, source.valueOf(), datatype || source._datatype); - } - }; - - var _createFromArray = function (matrix, data, datatype) { - // initialize fields - matrix._values = []; - matrix._index = []; - matrix._ptr = []; - matrix._datatype = datatype; - // discover rows & columns, do not use math.size() to avoid looping array twice - var rows = data.length; - var columns = 0; - - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - if (isString$2(datatype)) { - // find signature that matches (datatype, datatype) - eq = typed.find(equalScalar$$1, [datatype, datatype]) || equalScalar$$1; - // convert 0 to the same datatype - zero = typed.convert(0, datatype); - } - - // check we have rows (empty array) - if (rows > 0) { - // column index - var j = 0; - do { - // store pointer to values index - matrix._ptr.push(matrix._index.length); - // loop rows - for (var i = 0; i < rows; i++) { - // current row - var row = data[i]; - // check row is an array - if (isArray$1(row)) { - // update columns if needed (only on first column) - if (j === 0 && columns < row.length) - columns = row.length; - // check row has column - if (j < row.length) { - // value - var v = row[j]; - // check value != 0 - if (!eq(v, zero)) { - // store value - matrix._values.push(v); - // index - matrix._index.push(i); - } - } - } - else { - // update columns if needed (only on first column) - if (j === 0 && columns < 1) - columns = 1; - // check value != 0 (row is a scalar) - if (!eq(row, zero)) { - // store value - matrix._values.push(row); - // index - matrix._index.push(i); - } - } - } - // increment index - j++; - } - while (j < columns); - } - // store number of values in ptr - matrix._ptr.push(matrix._index.length); - // size - matrix._size = [rows, columns]; - }; - - SparseMatrix.prototype = new Matrix$$1(); - - /** - * Attach type information - */ - SparseMatrix.prototype.type = 'SparseMatrix'; - SparseMatrix.prototype.isSparseMatrix = true; - - /** - * Get the storage format used by the matrix. - * - * Usage: - * var format = matrix.storage() // retrieve storage format - * - * @memberof SparseMatrix - * @return {string} The storage format. - */ - SparseMatrix.prototype.storage = function () { - return 'sparse'; - }; - - /** - * Get the datatype of the data stored in the matrix. - * - * Usage: - * var format = matrix.datatype() // retrieve matrix datatype - * - * @memberof SparseMatrix - * @return {string} The datatype. - */ - SparseMatrix.prototype.datatype = function () { - return this._datatype; - }; - - /** - * Create a new SparseMatrix - * @memberof SparseMatrix - * @param {Array} data - * @param {string} [datatype] - */ - SparseMatrix.prototype.create = function (data, datatype) { - return new SparseMatrix(data, datatype); - }; - - /** - * Get the matrix density. - * - * Usage: - * var density = matrix.density() // retrieve matrix density - * - * @memberof SparseMatrix - * @return {number} The matrix density. - */ - SparseMatrix.prototype.density = function () { - // rows & columns - var rows = this._size[0]; - var columns = this._size[1]; - // calculate density - return rows !== 0 && columns !== 0 ? (this._index.length / (rows * columns)) : 0; - }; - - /** - * 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 - * - * @memberof SparseMatrix - * @param {Index} index - * @param {Array | Maytrix | *} [replacement] - * @param {*} [defaultValue=0] Default value, filled in on new entries when - * the matrix is resized. If not provided, - * new matrix elements will be filled with zeros. - */ - SparseMatrix.prototype.subset = function (index, replacement, defaultValue) { // check it is a pattern matrix - if (!this._values) - throw new Error('Cannot invoke subset on a Pattern only matrix'); - - // check arguments - switch (arguments.length) { - case 1: - return _getsubset(this, index); - - // intentional fall through - case 2: - case 3: - return _setsubset(this, index, replacement, defaultValue); - - default: - throw new SyntaxError('Wrong number of arguments'); - } - }; - - var _getsubset = function (matrix, idx) { - // check idx - if (!type.isIndex(idx)) { - throw new TypeError('Invalid index'); - } - - var isScalar = idx.isScalar(); - if (isScalar) { - // return a scalar - return matrix.get(idx.min()); - } - // validate dimensions - var size = idx.size(); - if (size.length != matrix._size.length) { - throw new DimensionError_1(size.length, matrix._size.length); - } - - // vars - var i, ii, k, kk; - - // validate if any of the ranges in the index is out of range - var min = idx.min(); - var max = idx.max(); - for (i = 0, ii = matrix._size.length; i < ii; i++) { - validateIndex$1(min[i], matrix._size[i]); - validateIndex$1(max[i], matrix._size[i]); - } - - // matrix arrays - var mvalues = matrix._values; - var mindex = matrix._index; - var mptr = matrix._ptr; - - // rows & columns dimensions for result matrix - var rows = idx.dimension(0); - var columns = idx.dimension(1); - - // workspace & permutation vector - var w = []; - var pv = []; - - // loop rows in resulting matrix - rows.forEach(function (i, r) { - // update permutation vector - pv[i] = r[0]; - // mark i in workspace - w[i] = true; - }); - - // result matrix arrays - var values = mvalues ? [] : undefined; - var index = []; - var ptr = []; - - // loop columns in result matrix - columns.forEach(function (j) { - // update ptr - ptr.push(index.length); - // loop values in column j - for (k = mptr[j], kk = mptr[j + 1]; k < kk; k++) { - // row - i = mindex[k]; - // check row is in result matrix - if (w[i] === true) { - // push index - index.push(pv[i]); - // check we need to process values - if (values) - values.push(mvalues[k]); - } - } - }); - // update ptr - ptr.push(index.length); - - // return matrix - return new SparseMatrix({ - values: values, - index: index, - ptr: ptr, - size: size, - datatype: matrix._datatype - }); - }; - - var _setsubset = function (matrix, index, submatrix, defaultValue) { - // check index - if (!index || index.isIndex !== true) { - 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 (type.isMatrix(submatrix)) { - // submatrix size - sSize = submatrix.size(); - // use array representation - submatrix = submatrix.toArray(); - } - else { - // get submatrix size (array, scalar) - sSize = array$2.size(submatrix); - } - - // check index is a scalar - if (isScalar) { - // verify submatrix is a scalar - if (sSize.length !== 0) { - throw new TypeError('Scalar expected'); - } - // set value - matrix.set(index.min(), submatrix, defaultValue); - } - else { - // validate dimensions, index size must be one or two dimensions - if (iSize.length !== 1 && iSize.length !== 2) { - throw new DimensionError_1(iSize.length, matrix._size.length, '<'); - } - - // check submatrix and index have the same dimensions - if (sSize.length < iSize.length) { - // calculate number of missing outer dimensions - var i = 0; - var outer = 0; - while (iSize[i] === 1 && sSize[i] === 1) { - i++; - } - while (iSize[i] === 1) { - outer++; - i++; - } - // unsqueeze both outer and inner dimensions - submatrix = array$2.unsqueeze(submatrix, iSize.length, outer, sSize); - } - - // check whether the size of the submatrix matches the index size - if (!object$2.deepEqual(iSize, sSize)) { - throw new DimensionError_1(iSize, sSize, '>'); - } - - // offsets - var x0 = index.min()[0]; - var y0 = index.min()[1]; - - // submatrix rows and columns - var m = sSize[0]; - var n = sSize[1]; - - // loop submatrix - for (var x = 0; x < m; x++) { - // loop columns - for (var y = 0; y < n; y++) { - // value at i, j - var v = submatrix[x][y]; - // invoke set (zero value will remove entry from matrix) - matrix.set([x + x0, y + y0], v, defaultValue); - } - } - } - return matrix; - }; - - /** - * Get a single element from the matrix. - * @memberof SparseMatrix - * @param {number[]} index Zero-based index - * @return {*} value - */ - SparseMatrix.prototype.get = function (index) { - if (!isArray$1(index)) - throw new TypeError('Array expected'); - if (index.length != this._size.length) - throw new DimensionError_1(index.length, this._size.length); - - // check it is a pattern matrix - if (!this._values) - throw new Error('Cannot invoke get on a Pattern only matrix'); - - // row and column - var i = index[0]; - var j = index[1]; - - // check i, j are valid - validateIndex$1(i, this._size[0]); - validateIndex$1(j, this._size[1]); - - // find value index - var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index); - // check k is prior to next column k and it is in the correct row - if (k < this._ptr[j + 1] && this._index[k] === i) - return this._values[k]; - - return 0; - }; - - /** - * Replace a single element in the matrix. - * @memberof SparseMatrix - * @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 set to zero. - * @return {SparseMatrix} self - */ - SparseMatrix.prototype.set = function (index, v, defaultValue) { - if (!isArray$1(index)) - throw new TypeError('Array expected'); - if (index.length != this._size.length) - throw new DimensionError_1(index.length, this._size.length); - - // check it is a pattern matrix - if (!this._values) - throw new Error('Cannot invoke set on a Pattern only matrix'); - - // row and column - var i = index[0]; - var j = index[1]; - - // rows & columns - var rows = this._size[0]; - var columns = this._size[1]; - - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - if (isString$2(this._datatype)) { - // find signature that matches (datatype, datatype) - eq = typed.find(equalScalar$$1, [this._datatype, this._datatype]) || equalScalar$$1; - // convert 0 to the same datatype - zero = typed.convert(0, this._datatype); - } - - // check we need to resize matrix - if (i > rows - 1 || j > columns - 1) { - // resize matrix - _resize(this, Math.max(i + 1, rows), Math.max(j + 1, columns), defaultValue); - // update rows & columns - rows = this._size[0]; - columns = this._size[1]; - } - - // check i, j are valid - validateIndex$1(i, rows); - validateIndex$1(j, columns); - - // find value index - var k = _getValueIndex(i, this._ptr[j], this._ptr[j + 1], this._index); - // check k is prior to next column k and it is in the correct row - if (k < this._ptr[j + 1] && this._index[k] === i) { - // check value != 0 - if (!eq(v, zero)) { - // update value - this._values[k] = v; - } - else { - // remove value from matrix - _remove(k, j, this._values, this._index, this._ptr); - } - } - else { - // insert value @ (i, j) - _insert(k, i, j, v, this._values, this._index, this._ptr); - } - - return this; - }; - - var _getValueIndex = function(i, top, bottom, index) { - // check row is on the bottom side - if (bottom - top === 0) - return bottom; - // loop rows [top, bottom[ - for (var r = top; r < bottom; r++) { - // check we found value index - if (index[r] === i) - return r; - } - // we did not find row - return top; - }; - - var _remove = function (k, j, values, index, ptr) { - // remove value @ k - values.splice(k, 1); - index.splice(k, 1); - // update pointers - for (var x = j + 1; x < ptr.length; x++) - ptr[x]--; - }; - - var _insert = function (k, i, j, v, values, index, ptr) { - // insert value - values.splice(k, 0, v); - // update row for k - index.splice(k, 0, i); - // update column pointers - for (var x = j + 1; x < ptr.length; x++) - ptr[x]++; - }; - - /** - * Resize the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (resize in place). - * - * @memberof SparseMatrix - * @param {number[]} size The new size the matrix should have. - * @param {*} [defaultValue=0] Default value, filled in on new entries. - * If not provided, the matrix elements will - * be filled with zeros. - * @param {boolean} [copy] Return a resized copy of the matrix - * - * @return {Matrix} The resized matrix - */ - SparseMatrix.prototype.resize = function (size, defaultValue, copy) { - // validate arguments - if (!isArray$1(size)) - throw new TypeError('Array expected'); - if (size.length !== 2) - throw new Error('Only two dimensions matrix are supported'); - - // check sizes - size.forEach(function (value) { - if (!number$2.isNumber(value) || !number$2.isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + string$3.format(size) + ')'); - } - }); - - // matrix to resize - var m = copy ? this.clone() : this; - // resize matrix - return _resize(m, size[0], size[1], defaultValue); - }; - - var _resize = function (matrix, rows, columns, defaultValue) { - // value to insert at the time of growing matrix - var value = defaultValue || 0; - - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - if (isString$2(matrix._datatype)) { - // find signature that matches (datatype, datatype) - eq = typed.find(equalScalar$$1, [matrix._datatype, matrix._datatype]) || equalScalar$$1; - // convert 0 to the same datatype - zero = typed.convert(0, matrix._datatype); - // convert value to the same datatype - value = typed.convert(value, matrix._datatype); - } - - // should we insert the value? - var ins = !eq(value, zero); - - // old columns and rows - var r = matrix._size[0]; - var c = matrix._size[1]; - - var i, j, k; - - // check we need to increase columns - if (columns > c) { - // loop new columns - for (j = c; j < columns; j++) { - // update matrix._ptr for current column - matrix._ptr[j] = matrix._values.length; - // check we need to insert matrix._values - if (ins) { - // loop rows - for (i = 0; i < r; i++) { - // add new matrix._values - matrix._values.push(value); - // update matrix._index - matrix._index.push(i); - } - } - } - // store number of matrix._values in matrix._ptr - matrix._ptr[columns] = matrix._values.length; - } - else if (columns < c) { - // truncate matrix._ptr - matrix._ptr.splice(columns + 1, c - columns); - // truncate matrix._values and matrix._index - matrix._values.splice(matrix._ptr[columns], matrix._values.length); - matrix._index.splice(matrix._ptr[columns], matrix._index.length); - } - // update columns - c = columns; - - // check we need to increase rows - if (rows > r) { - // check we have to insert values - if (ins) { - // inserts - var n = 0; - // loop columns - for (j = 0; j < c; j++) { - // update matrix._ptr for current column - matrix._ptr[j] = matrix._ptr[j] + n; - // where to insert matrix._values - k = matrix._ptr[j + 1] + n; - // pointer - var p = 0; - // loop new rows, initialize pointer - for (i = r; i < rows; i++, p++) { - // add value - matrix._values.splice(k + p, 0, value); - // update matrix._index - matrix._index.splice(k + p, 0, i); - // increment inserts - n++; - } - } - // store number of matrix._values in matrix._ptr - matrix._ptr[c] = matrix._values.length; - } - } - else if (rows < r) { - // deletes - var d = 0; - // loop columns - for (j = 0; j < c; j++) { - // update matrix._ptr for current column - matrix._ptr[j] = matrix._ptr[j] - d; - // where matrix._values start for next column - var k0 = matrix._ptr[j]; - var k1 = matrix._ptr[j + 1] - d; - // loop matrix._index - for (k = k0; k < k1; k++) { - // row - i = matrix._index[k]; - // check we need to delete value and matrix._index - if (i > rows - 1) { - // remove value - matrix._values.splice(k, 1); - // remove item from matrix._index - matrix._index.splice(k, 1); - // increase deletes - d++; - } - } - } - // update matrix._ptr for current column - matrix._ptr[j] = matrix._values.length; - } - // update matrix._size - matrix._size[0] = rows; - matrix._size[1] = columns; - // return matrix - return matrix; - }; - - /** - * Reshape the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (reshape in place). - * - * NOTE: This might be better suited to copy by default, instead of modifying - * in place. For now, it operates in place to remain consistent with - * resize(). - * - * @memberof SparseMatrix - * @param {number[]} size The new size the matrix should have. - * @param {boolean} [copy] Return a reshaped copy of the matrix - * - * @return {Matrix} The reshaped matrix - */ - SparseMatrix.prototype.reshape = function (size, copy) { - - // validate arguments - if (!isArray$1(size)) - throw new TypeError('Array expected'); - if (size.length !== 2) - throw new Error('Sparse matrices can only be reshaped in two dimensions'); - - // check sizes - size.forEach(function (value) { - if (!number$2.isNumber(value) || !number$2.isInteger(value) || value < 0) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + string$3.format(size) + ')'); - } - }); - - // m * n must not change - if(this._size[0] * this._size[1] !== size[0] * size[1]) { - throw new Error('Reshaping sparse matrix will result in the wrong number of elements'); - } - - // matrix to reshape - var m = copy ? this.clone() : this; - - // return unchanged if the same shape - if(this._size[0] === size[0] && this._size[1] === size[1]) { - return m; - } - - // Convert to COO format (generate a column index) - var colIndex = []; - for(var i=0; i= minRow && i <= maxRow) { - // zero values - if (!skipZeros) { - for (var x = p; x < i; x++) - invoke(0, x - minRow, j - minColumn); - } - // value @ k - invoke(matrix._values[k], i - minRow, j - minColumn); - } - // update pointer - p = i + 1; - } - // zero values - if (!skipZeros) { - for (var y = p; y <= maxRow; y++) - invoke(0, y - minRow, j - minColumn); - } - } - // store number of values in ptr - ptr.push(values.length); - // return sparse matrix - return new SparseMatrix({ - values: values, - index: index, - ptr: ptr, - size: [maxRow - minRow + 1, maxColumn - minColumn + 1] - }); - }; - - /** - * Execute a callback function on each entry of the matrix. - * @memberof SparseMatrix - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix being traversed. - * @param {boolean} [skipZeros] Invoke callback function for non-zero values only. - */ - SparseMatrix.prototype.forEach = function (callback, skipZeros) { - // check it is a pattern matrix - if (!this._values) - throw new Error('Cannot invoke forEach on a Pattern only matrix'); - // matrix instance - var me = this; - // rows and columns - var rows = this._size[0]; - var columns = this._size[1]; - // loop columns - for (var j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = this._ptr[j]; - var k1 = this._ptr[j + 1]; - // column pointer - var p = 0; - // loop k within [k0, k1[ - for (var k = k0; k < k1; k++) { - // row index - var i = this._index[k]; - // check we need to process zeros - if (!skipZeros) { - // zero values - for (var x = p; x < i; x++) - callback(0, [x, j], me); - } - // value @ k - callback(this._values[k], [i, j], me); - // update pointer - p = i + 1; - } - // check we need to process zeros - if (!skipZeros) { - // zero values - for (var y = p; y < rows; y++) - callback(0, [y, j], me); - } - } - }; - - /** - * Create an Array with a copy of the data of the SparseMatrix - * @memberof SparseMatrix - * @returns {Array} array - */ - SparseMatrix.prototype.toArray = function () { - return _toArray(this._values, this._index, this._ptr, this._size, true); - }; - - /** - * Get the primitive value of the SparseMatrix: a two dimensions array - * @memberof SparseMatrix - * @returns {Array} array - */ - SparseMatrix.prototype.valueOf = function () { - return _toArray(this._values, this._index, this._ptr, this._size, false); - }; - - var _toArray = function (values, index, ptr, size, copy) { - // rows and columns - var rows = size[0]; - var columns = size[1]; - // result - var a = []; - // vars - var i, j; - // initialize array - for (i = 0; i < rows; i++) { - a[i] = []; - for (j = 0; j < columns; j++) - a[i][j] = 0; - } - - // loop columns - for (j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // loop k within [k0, k1[ - for (var k = k0; k < k1; k++) { - // row index - i = index[k]; - // set value (use one for pattern matrix) - a[i][j] = values ? (copy ? object$2.clone(values[k]) : values[k]) : 1; - } - } - return a; - }; - - /** - * Get a string representation of the matrix, with optional formatting options. - * @memberof SparseMatrix - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ - SparseMatrix.prototype.format = function (options) { - // rows and columns - var rows = this._size[0]; - var columns = this._size[1]; - // density - var density = this.density(); - // rows & columns - var str = 'Sparse Matrix [' + string$3.format(rows, options) + ' x ' + string$3.format(columns, options) + '] density: ' + string$3.format(density, options) + '\n'; - // loop columns - for (var j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = this._ptr[j]; - var k1 = this._ptr[j + 1]; - // loop k within [k0, k1[ - for (var k = k0; k < k1; k++) { - // row index - var i = this._index[k]; - // append value - str += '\n (' + string$3.format(i, options) + ', ' + string$3.format(j, options) + ') ==> ' + (this._values ? string$3.format(this._values[k], options) : 'X'); - } - } - return str; - }; - - /** - * Get a string representation of the matrix - * @memberof SparseMatrix - * @returns {string} str - */ - SparseMatrix.prototype.toString = function () { - return string$3.format(this.toArray()); - }; - - /** - * Get a JSON representation of the matrix - * @memberof SparseMatrix - * @returns {Object} - */ - SparseMatrix.prototype.toJSON = function () { - return { - mathjs: 'SparseMatrix', - values: this._values, - index: this._index, - ptr: this._ptr, - size: this._size, - datatype: this._datatype - }; - }; - - /** - * Get the kth Matrix diagonal. - * - * @memberof SparseMatrix - * @param {number | BigNumber} [k=0] The kth diagonal where the vector will retrieved. - * - * @returns {Matrix} The matrix vector with the diagonal values. - */ - SparseMatrix.prototype.diagonal = function(k) { - // validate k if any - if (k) { - // convert BigNumber to a number - if (type.isBigNumber(k)) - k = k.toNumber(); - // is must be an integer - if (!isNumber$2(k) || !isInteger$1(k)) { - throw new TypeError ('The parameter k must be an integer number'); - } - } - else { - // default value - k = 0; - } - - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // rows & columns - var rows = this._size[0]; - var columns = this._size[1]; - - // number diagonal values - var n = Math.min(rows - kSub, columns - kSuper); - - // diagonal arrays - var values = []; - var index = []; - var ptr = []; - // initial ptr value - ptr[0] = 0; - // loop columns - for (var j = kSuper; j < columns && values.length < n; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = this._ptr[j]; - var k1 = this._ptr[j + 1]; - // loop x within [k0, k1[ - for (var x = k0; x < k1; x++) { - // row index - var i = this._index[x]; - // check row - if (i === j - kSuper + kSub) { - // value on this column - values.push(this._values[x]); - // store row - index[values.length - 1] = i - kSub; - // exit loop - break; - } - } - } - // close ptr - ptr.push(values.length); - // return matrix - return new SparseMatrix({ - values: values, - index: index, - ptr: ptr, - size: [n, 1] - }); - }; - - /** - * Generate a matrix from a JSON object - * @memberof SparseMatrix - * @param {Object} json An object structured like - * `{"mathjs": "SparseMatrix", "values": [], "index": [], "ptr": [], "size": []}`, - * where mathjs is optional - * @returns {SparseMatrix} - */ - SparseMatrix.fromJSON = function (json) { - return new SparseMatrix(json); - }; - - /** - * Create a diagonal matrix. - * - * @memberof SparseMatrix - * @param {Array} size The matrix size. - * @param {number | Array | Matrix } value The values for the diagonal. - * @param {number | BigNumber} [k=0] The kth diagonal where the vector will be filled in. - * @param {string} [datatype] The Matrix datatype, values must be of this datatype. - * - * @returns {SparseMatrix} - */ - SparseMatrix.diagonal = function (size, value, k, defaultValue, datatype) { - if (!isArray$1(size)) - throw new TypeError('Array expected, size parameter'); - if (size.length !== 2) - throw new Error('Only two dimensions matrix are supported'); - - // map size & validate - size = size.map(function (s) { - // check it is a big number - if (type.isBigNumber(s)) { - // convert it - s = s.toNumber(); - } - // validate arguments - if (!isNumber$2(s) || !isInteger$1(s) || s < 1) { - throw new Error('Size values must be positive integers'); - } - return s; - }); - - // validate k if any - if (k) { - // convert BigNumber to a number - if (type.isBigNumber(k)) - k = k.toNumber(); - // is must be an integer - if (!isNumber$2(k) || !isInteger$1(k)) { - throw new TypeError ('The parameter k must be an integer number'); - } - } - else { - // default value - k = 0; - } - - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - if (isString$2(datatype)) { - // find signature that matches (datatype, datatype) - eq = typed.find(equalScalar$$1, [datatype, datatype]) || equalScalar$$1; - // convert 0 to the same datatype - zero = typed.convert(0, datatype); - } - - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // rows and columns - var rows = size[0]; - var columns = size[1]; - - // number of non-zero items - var n = Math.min(rows - kSub, columns - kSuper); - - // value extraction function - var _value; - - // check value - if (isArray$1(value)) { - // validate array - if (value.length !== n) { - // number of values in array must be n - throw new Error('Invalid value array length'); - } - // define function - _value = function (i) { - // return value @ i - return value[i]; - }; - } - else if (type.isMatrix(value)) { - // matrix size - var ms = value.size(); - // validate matrix - if (ms.length !== 1 || ms[0] !== n) { - // number of values in array must be n - throw new Error('Invalid matrix length'); - } - // define function - _value = function (i) { - // return value @ i - return value.get([i]); - }; - } - else { - // define function - _value = function () { - // return value - return value; - }; - } - - // create arrays - var values = []; - var index = []; - var ptr = []; - - // loop items - for (var j = 0; j < columns; j++) { - // number of rows with value - ptr.push(values.length); - // diagonal index - var i = j - kSuper; - // check we need to set diagonal value - if (i >= 0 && i < n) { - // get value @ i - var v = _value(i); - // check for zero - if (!eq(v, zero)) { - // column - index.push(i + kSub); - // add value - values.push(v); - } - } - } - // last value should be number of values - ptr.push(values.length); - // create SparseMatrix - return new SparseMatrix({ - values: values, - index: index, - ptr: ptr, - size: [rows, columns] - }); - }; - - /** - * Swap rows i and j in Matrix. - * - * @memberof SparseMatrix - * @param {number} i Matrix row index 1 - * @param {number} j Matrix row index 2 - * - * @return {Matrix} The matrix reference - */ - SparseMatrix.prototype.swapRows = function (i, j) { - // check index - if (!isNumber$2(i) || !isInteger$1(i) || !isNumber$2(j) || !isInteger$1(j)) { - throw new Error('Row index must be positive integers'); - } - // check dimensions - if (this._size.length !== 2) { - throw new Error('Only two dimensional matrix is supported'); - } - // validate index - validateIndex$1(i, this._size[0]); - validateIndex$1(j, this._size[0]); - - // swap rows - SparseMatrix._swapRows(i, j, this._size[1], this._values, this._index, this._ptr); - // return current instance - return this; - }; - - /** - * Loop rows with data in column j. - * - * @param {number} j Column - * @param {Array} values Matrix values - * @param {Array} index Matrix row indeces - * @param {Array} ptr Matrix column pointers - * @param {Function} callback Callback function invoked for every row in column j - */ - SparseMatrix._forEachRow = function (j, values, index, ptr, callback) { - // indeces for column j - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // loop - for (var k = k0; k < k1; k++) { - // invoke callback - callback(index[k], values[k]); - } - }; - - /** - * Swap rows x and y in Sparse Matrix data structures. - * - * @param {number} x Matrix row index 1 - * @param {number} y Matrix row index 2 - * @param {number} columns Number of columns in matrix - * @param {Array} values Matrix values - * @param {Array} index Matrix row indeces - * @param {Array} ptr Matrix column pointers - */ - SparseMatrix._swapRows = function (x, y, columns, values, index, ptr) { - // loop columns - for (var j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // find value index @ x - var kx = _getValueIndex(x, k0, k1, index); - // find value index @ x - var ky = _getValueIndex(y, k0, k1, index); - // check both rows exist in matrix - if (kx < k1 && ky < k1 && index[kx] === x && index[ky] === y) { - // swap values (check for pattern matrix) - if (values) { - var v = values[kx]; - values[kx] = values[ky]; - values[ky] = v; - } - // next column - continue; - } - // check x row exist & no y row - if (kx < k1 && index[kx] === x && (ky >= k1 || index[ky] !== y)) { - // value @ x (check for pattern matrix) - var vx = values ? values[kx] : undefined; - // insert value @ y - index.splice(ky, 0, y); - if (values) - values.splice(ky, 0, vx); - // remove value @ x (adjust array index if needed) - index.splice(ky <= kx ? kx + 1 : kx, 1); - if (values) - values.splice(ky <= kx ? kx + 1 : kx, 1); - // next column - continue; - } - // check y row exist & no x row - if (ky < k1 && index[ky] === y && (kx >= k1 || index[kx] !== x)) { - // value @ y (check for pattern matrix) - var vy = values ? values[ky] : undefined; - // insert value @ x - index.splice(kx, 0, x); - if (values) - values.splice(kx, 0, vy); - // remove value @ y (adjust array index if needed) - index.splice(kx <= ky ? ky + 1 : ky, 1); - if (values) - values.splice(kx <= ky ? ky + 1 : ky, 1); - } - } - }; - - // register this type in the base class Matrix - type.Matrix._storage.sparse = SparseMatrix; - - return SparseMatrix; - } - - var name$13 = 'SparseMatrix'; - var path$6 = 'type'; - var factory_1$14 = factory$14; - var lazy$3 = false; // no lazy loading, as we alter type.Matrix._storage - - var SparseMatrix = { - name: name$13, - path: path$6, - factory: factory_1$14, - lazy: lazy$3 - }; - - function factory$15 (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: - * - * var 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 (format) { - return _create([], format); - }, - - 'string, string': function (format, datatype) { - return _create([], format, datatype); - }, - - 'Array': function (data) { - return _create(data); - }, - - 'Matrix': function (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); - } - } - - var name$14 = 'matrix'; - var factory_1$15 = factory$15; - - var matrix = { - name: name$14, - factory: factory_1$15 - }; - - function factory$16(type, config, load, typed) { - - /** - * Add two scalar values, `x + y`. - * This function is meant for internal use: it is used by the public function - * `add` - * - * This function does not support collections (Array or Matrix), and does - * not validate the number of of inputs. - * - * @param {number | BigNumber | Fraction | Complex | Unit} x First value to add - * @param {number | BigNumber | Fraction | Complex} y Second value to add - * @return {number | BigNumber | Fraction | Complex | Unit} Sum of `x` and `y` - * @private - */ - var add = typed('add', { - - 'number, number': function (x, y) { - return x + y; - }, - - 'Complex, Complex': function (x, y) { - return x.add(y); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.plus(y); - }, - - 'Fraction, Fraction': function (x, y) { - return x.add(y); - }, - - 'Unit, Unit': function (x, y) { - if (x.value == null) throw new Error('Parameter x contains a unit with undefined value'); - if (y.value == null) throw new Error('Parameter y contains a unit with undefined value'); - if (!x.equalBase(y)) throw new Error('Units do not match'); - - var res = x.clone(); - res.value = add(res.value, y.value); - res.fixPrefix = false; - return res; - } - }); - - return add; - } - - var factory_1$16 = factory$16; - - var addScalar = { - factory: factory_1$16 - }; - - function factory$17 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). - * Callback function invoked NNZ times (number of nonzero items in SparseMatrix). - * - * - * ┌ f(Dij, Sij) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ Dij ; otherwise - * - * - * @param {Matrix} denseMatrix The DenseMatrix instance (D) - * @param {Matrix} sparseMatrix The SparseMatrix instance (S) - * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) - * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) - * - * @return {Matrix} DenseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 - */ - var algorithm01 = function (denseMatrix, sparseMatrix, callback, inverse) { - // dense matrix arrays - var adata = denseMatrix._data; - var asize = denseMatrix._size; - var adt = denseMatrix._datatype; - // sparse matrix arrays - var bvalues = sparseMatrix._values; - var bindex = sparseMatrix._index; - var bptr = sparseMatrix._ptr; - var bsize = sparseMatrix._size; - var bdt = sparseMatrix._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // sparse matrix cannot be a Pattern matrix - if (!bvalues) - throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // process data types - var dt = typeof adt === 'string' && adt === bdt ? adt : undefined; - // callback function - var cf = dt ? typed.find(callback, [dt, dt]) : callback; - - // vars - var i, j; - - // result (DenseMatrix) - var cdata = []; - // initialize c - for (i = 0; i < rows; i++) - cdata[i] = []; - - // workspace - var x = []; - // marks indicating we have a value in x for a given column - var w = []; - - // loop columns in b - for (j = 0; j < columns; j++) { - // column mark - var mark = j + 1; - // values in column j - for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - i = bindex[k]; - // update workspace - x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); - // mark i as updated - w[i] = mark; - } - // loop rows - for (i = 0; i < rows; i++) { - // check row is in workspace - if (w[i] === mark) { - // c[i][j] was already calculated - cdata[i][j] = x[i]; - } - else { - // item does not exist in S - cdata[i][j] = adata[i][j]; - } - } - } - - // return dense matrix - return new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); - }; - - return algorithm01; - } - - var name$15 = 'algorithm01'; - var factory_1$17 = factory$17; - - var algorithm01 = { - name: name$15, - factory: factory_1$17 - }; - - function factory$18 (type, config, load, typed) { - - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; - - /** - * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). - * Callback function invoked MAX(NNZA, NNZB) times - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 - * C(i,j) = ┤ A(i,j) ; A(i,j) !== 0 - * └ B(i,j) ; B(i,j) !== 0 - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm04 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = avalues && bvalues ? [] : undefined; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - - // workspace - var xa = avalues && bvalues ? [] : undefined; - var xb = avalues && bvalues ? [] : undefined; - // marks indicating we have a value in x for a given column - var wa = []; - var wb = []; - - // vars - var i, j, k, k0, k1; - - // loop columns - for (j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // columns mark - var mark = j + 1; - // loop A(:,j) - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // update c - cindex.push(i); - // update workspace - wa[i] = mark; - // check we need to process values - if (xa) - xa[i] = avalues[k]; - } - // loop B(:,j) - for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - i = bindex[k]; - // check row exists in A - if (wa[i] === mark) { - // update record in xa @ i - if (xa) { - // invoke callback - var v = cf(xa[i], bvalues[k]); - // check for zero - if (!eq(v, zero)) { - // update workspace - xa[i] = v; - } - else { - // remove mark (index will be removed later) - wa[i] = null; - } - } - } - else { - // update c - cindex.push(i); - // update workspace - wb[i] = mark; - // check we need to process values - if (xb) - xb[i] = bvalues[k]; - } - } - // check we need to process values (non pattern matrix) - if (xa && xb) { - // initialize first index in j - k = cptr[j]; - // loop index in j - while (k < cindex.length) { - // row - i = cindex[k]; - // check workspace has value @ i - if (wa[i] === mark) { - // push value (Aij != 0 || (Aij != 0 && Bij != 0)) - cvalues[k] = xa[i]; - // increment pointer - k++; - } - else if (wb[i] === mark) { - // push value (bij != 0) - cvalues[k] = xb[i]; - // increment pointer - k++; - } - else { - // remove index @ k - cindex.splice(k, 1); - } - } - } - } - // update cptr - cptr[columns] = cindex.length; - - // return sparse matrix - return c; - }; - - return algorithm04; - } - - var name$16 = 'algorithm04'; - var factory_1$18 = factory$18; - - var algorithm04 = { - name: name$16, - factory: factory_1$18 - }; - - function factory$19 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). - * Callback function invoked NZ times (number of nonzero items in S). - * - * - * ┌ f(Sij, b) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ b ; otherwise - * - * - * @param {Matrix} s The SparseMatrix instance (S) - * @param {Scalar} b The Scalar value - * @param {Function} callback The f(Aij,b) operation to invoke - * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) - * - * @return {Matrix} DenseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 - */ - var algorithm10 = function (s, b, callback, inverse) { - // sparse matrix arrays - var avalues = s._values; - var aindex = s._index; - var aptr = s._ptr; - var asize = s._size; - var adt = s._datatype; - - // sparse matrix cannot be a Pattern matrix - if (!avalues) - throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string') { - // datatype - dt = adt; - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cdata = []; - // matrix - var c = new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); - - // workspaces - var x = []; - // marks indicating we have a value in x for a given column - var w = []; - - // loop columns - for (var j = 0; j < columns; j++) { - // columns mark - var mark = j + 1; - // values in j - for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - var r = aindex[k]; - // update workspace - x[r] = avalues[k]; - w[r] = mark; - } - // loop rows - for (var i = 0; i < rows; i++) { - // initialize C on first column - if (j === 0) { - // create row array - cdata[i] = []; - } - // check sparse matrix has a value @ i,j - if (w[i] === mark) { - // invoke callback, update C - cdata[i][j] = inverse ? cf(b, x[i]) : cf(x[i], b); - } - else { - // dense matrix value @ i, j - cdata[i][j] = b; - } - } - } - - // return sparse matrix - return c; - }; - - return algorithm10; - } - - var name$17 = 'algorithm10'; - var factory_1$19 = factory$19; - - var algorithm10 = { - name: name$17, - factory: factory_1$19 - }; - - var string$4 = utils.string, - isString$3 = string$4.isString; - - function factory$20 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, Bij..z). - * Callback function invoked MxN times. - * - * C(i,j,...z) = f(Aij..z, Bij..z) - * - * @param {Matrix} a The DenseMatrix instance (A) - * @param {Matrix} b The DenseMatrix instance (B) - * @param {Function} callback The f(Aij..z,Bij..z) operation to invoke - * - * @return {Matrix} DenseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97658658 - */ - var algorithm13 = function (a, b, callback) { - // a arrays - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b arrays - var bdata = b._data; - var bsize = b._size; - var bdt = b._datatype; - // c arrays - var csize = []; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // validate each one of the dimension sizes - for (var s = 0; s < asize.length; s++) { - // must match - if (asize[s] !== bsize[s]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - // update dimension in c - csize[s] = asize[s]; - } - - // datatype - var dt; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // populate cdata, iterate through dimensions - var cdata = csize.length > 0 ? _iterate(cf, 0, csize, csize[0], adata, bdata) : []; - - // c matrix - return new DenseMatrix({ - data: cdata, - size: csize, - datatype: dt - }); - }; - - // recursive function - var _iterate = function (f, level, s, n, av, bv) { - // initialize array for this level - var cv = []; - // check we reach the last level - if (level === s.length - 1) { - // loop arrays in last level - for (var i = 0; i < n; i++) { - // invoke callback and store value - cv[i] = f(av[i], bv[i]); - } - } - else { - // iterate current level - for (var j = 0; j < n; j++) { - // iterate next level - cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv[j]); - } - } - return cv; - }; - - return algorithm13; - } - - var name$18 = 'algorithm13'; - var factory_1$20 = factory$20; - - var algorithm13 = { - name: name$18, - factory: factory_1$20 - }; - - var clone = object.clone; - - function factory$21 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over DenseMatrix items and invokes the callback function f(Aij..z, b). - * Callback function invoked MxN times. - * - * C(i,j,...z) = f(Aij..z, b) - * - * @param {Matrix} a The DenseMatrix instance (A) - * @param {Scalar} b The Scalar value - * @param {Function} callback The f(Aij..z,b) operation to invoke - * @param {boolean} inverse A true value indicates callback should be invoked f(b,Aij..z) - * - * @return {Matrix} DenseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97659042 - */ - var algorithm14 = function (a, b, callback, inverse) { - // a arrays - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - - // datatype - var dt; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string') { - // datatype - dt = adt; - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // populate cdata, iterate through dimensions - var cdata = asize.length > 0 ? _iterate(cf, 0, asize, asize[0], adata, b, inverse) : []; - - // c matrix - return new DenseMatrix({ - data: cdata, - size: clone(asize), - datatype: dt - }); - }; - - // recursive function - var _iterate = function (f, level, s, n, av, bv, inverse) { - // initialize array for this level - var cv = []; - // check we reach the last level - if (level === s.length - 1) { - // loop arrays in last level - for (var i = 0; i < n; i++) { - // invoke callback and store value - cv[i] = inverse ? f(bv, av[i]) : f(av[i], bv); - } - } - else { - // iterate current level - for (var j = 0; j < n; j++) { - // iterate next level - cv[j] = _iterate(f, level + 1, s, s[level + 1], av[j], bv, inverse); - } - } - return cv; - }; - - return algorithm14; - } - - var name$19 = 'algorithm14'; - var factory_1$21 = factory$21; - - var algorithm14 = { - name: name$19, - factory: factory_1$21 - }; - - var extend = object.extend; - - function factory$22 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var addScalar$$1 = load(addScalar); - var latex$$1 = latex; - - var algorithm01$$1 = load(algorithm01); - var algorithm04$$1 = load(algorithm04); - var algorithm10$$1 = load(algorithm10); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Add two or more values, `x + y`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.add(x, y) - * math.add(x, y, z, ...) - * - * Examples: - * - * math.add(2, 3); // returns number 5 - * math.add(2, 3, 4); // returns number 9 - * - * var a = math.complex(2, 3); - * var b = math.complex(-4, 1); - * math.add(a, b); // returns Complex -2 + 4i - * - * math.add([1, 2, 3], 4); // returns Array [5, 6, 7] - * - * var c = math.unit('5 cm'); - * var d = math.unit('2.1 mm'); - * math.add(c, d); // returns Unit 52.1 mm - * - * math.add("2.3", "4"); // returns number 6.3 - * - * See also: - * - * subtract, sum - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to add - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to add - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Sum of `x` and `y` - */ - var add = typed('add', extend({ - // we extend the signatures of addScalar with signatures dealing with matrices - - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, addScalar$$1); - }, - - 'DenseMatrix, SparseMatrix': function (x, y) { - return algorithm01$$1(x, y, addScalar$$1, false); - }, - - 'SparseMatrix, DenseMatrix': function (x, y) { - return algorithm01$$1(y, x, addScalar$$1, true); - }, - - 'SparseMatrix, SparseMatrix': function (x, y) { - return algorithm04$$1(x, y, addScalar$$1); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return add(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return add(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return add(x, matrix$$1(y)); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, addScalar$$1, false); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm10$$1(x, y, addScalar$$1, false); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, addScalar$$1, true); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm10$$1(y, x, addScalar$$1, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, addScalar$$1, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, addScalar$$1, true).valueOf(); - }, - - 'any, any': addScalar$$1, - - 'any, any, ...any': function (x, y, rest) { - var result = add(x, y); - - for (var i = 0; i < rest.length; i++) { - result = add(result, rest[i]); - } - - return result; - } - }, addScalar$$1.signatures)); - - add.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['add'] + '${args[1]}\\right)' - }; - - return add; - } - - var name$20 = 'add'; - var factory_1$22 = factory$22; - - var add = { - name: name$20, - factory: factory_1$22 - }; - - function factory$23 (type, config, load) { - - var add$$1 = load(add); - var equalScalar$$1 = load(equalScalar); - - /** - * An ordered Sparse Accumulator is a representation for a sparse vector that includes a dense array - * of the vector elements and an ordered list of non-zero elements. - */ - function Spa() { - if (!(this instanceof Spa)) - throw new SyntaxError('Constructor must be called with the new operator'); - - // allocate vector, TODO use typed arrays - this._values = []; - this._heap = new type.FibonacciHeap(); - } - - /** - * Attach type information - */ - Spa.prototype.type = 'Spa'; - Spa.prototype.isSpa = true; - - /** - * Set the value for index i. - * - * @param {number} i The index - * @param {number | BigNumber | Complex} The value at index i - */ - Spa.prototype.set = function (i, v) { - // check we have a value @ i - if (!this._values[i]) { - // insert in heap - var node = this._heap.insert(i, v); - // set the value @ i - this._values[i] = node; - } - else { - // update the value @ i - this._values[i].value = v; - } - }; - - Spa.prototype.get = function (i) { - var node = this._values[i]; - if (node) - return node.value; - return 0; - }; - - Spa.prototype.accumulate = function (i, v) { - // node @ i - var node = this._values[i]; - if (!node) { - // insert in heap - node = this._heap.insert(i, v); - // initialize value - this._values[i] = node; - } - else { - // accumulate value - node.value = add$$1(node.value, v); - } - }; - - Spa.prototype.forEach = function (from, to, callback) { - // references - var heap = this._heap; - var values = this._values; - // nodes - var nodes = []; - // node with minimum key, save it - var node = heap.extractMinimum(); - if (node) - nodes.push(node); - // extract nodes from heap (ordered) - while (node && node.key <= to) { - // check it is in range - if (node.key >= from) { - // check value is not zero - if (!equalScalar$$1(node.value, 0)) { - // invoke callback - callback(node.key, node.value, this); - } - } - // extract next node, save it - node = heap.extractMinimum(); - if (node) - nodes.push(node); - } - // reinsert all nodes in heap - for (var i = 0; i < nodes.length; i++) { - // current node - var n = nodes[i]; - // insert node in heap - node = heap.insert(n.key, n.value); - // update values - values[node.key] = node; - } - }; - - Spa.prototype.swap = function (i, j) { - // node @ i and j - var nodei = this._values[i]; - var nodej = this._values[j]; - // check we need to insert indeces - if (!nodei && nodej) { - // insert in heap - nodei = this._heap.insert(i, nodej.value); - // remove from heap - this._heap.remove(nodej); - // set values - this._values[i] = nodei; - this._values[j] = undefined; - } - else if (nodei && !nodej) { - // insert in heap - nodej = this._heap.insert(j, nodei.value); - // remove from heap - this._heap.remove(nodei); - // set values - this._values[j] = nodej; - this._values[i] = undefined; - } - else if (nodei && nodej) { - // swap values - var v = nodei.value; - nodei.value = nodej.value; - nodej.value = v; - } - }; - - return Spa; - } - - var name$21 = 'Spa'; - var path$7 = 'type'; - var factory_1$23 = factory$23; - - var Spa = { - name: name$21, - path: path$7, - factory: factory_1$23 - }; - - function factory$24 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over SparseMatrix items and invokes the callback function f(Dij, Sij). - * Callback function invoked M*N times. - * - * - * ┌ f(Dij, Sij) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ f(Dij, 0) ; otherwise - * - * - * @param {Matrix} denseMatrix The DenseMatrix instance (D) - * @param {Matrix} sparseMatrix The SparseMatrix instance (C) - * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) - * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) - * - * @return {Matrix} DenseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 - */ - var algorithm03 = function (denseMatrix, sparseMatrix, callback, inverse) { - // dense matrix arrays - var adata = denseMatrix._data; - var asize = denseMatrix._size; - var adt = denseMatrix._datatype; - // sparse matrix arrays - var bvalues = sparseMatrix._values; - var bindex = sparseMatrix._index; - var bptr = sparseMatrix._ptr; - var bsize = sparseMatrix._size; - var bdt = sparseMatrix._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // sparse matrix cannot be a Pattern matrix - if (!bvalues) - throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result (DenseMatrix) - var cdata = []; - - // initialize dense matrix - for (var z = 0; z < rows; z++) { - // initialize row - cdata[z] = []; - } - - // workspace - var x = []; - // marks indicating we have a value in x for a given column - var w = []; - - // loop columns in b - for (var j = 0; j < columns; j++) { - // column mark - var mark = j + 1; - // values in column j - for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - var i = bindex[k]; - // update workspace - x[i] = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); - w[i] = mark; - } - // process workspace - for (var y = 0; y < rows; y++) { - // check we have a calculated value for current row - if (w[y] === mark) { - // use calculated value - cdata[y][j] = x[y]; - } - else { - // calculate value - cdata[y][j] = inverse ? cf(zero, adata[y][j]) : cf(adata[y][j], zero); - } - } - } - - // return dense matrix - return new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); - }; - - return algorithm03; - } - - var name$22 = 'algorithm03'; - var factory_1$24 = factory$24; - - var algorithm03 = { - name: name$22, - factory: factory_1$24 - }; - - function factory$25 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over SparseMatrix A and SparseMatrix B items (zero and nonzero) and invokes the callback function f(Aij, Bij). - * Callback function invoked MxN times. - * - * C(i,j) = f(Aij, Bij) - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} DenseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm07 = function (a, b, callback) { - // sparse matrix arrays - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // vars - var i, j; - - // result arrays - var cdata = []; - // initialize c - for (i = 0; i < rows; i++) - cdata[i] = []; - - // matrix - var c = new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); - - // workspaces - var xa = []; - var xb = []; - // marks indicating we have a value in x for a given column - var wa = []; - var wb = []; - - // loop columns - for (j = 0; j < columns; j++) { - // columns mark - var mark = j + 1; - // scatter the values of A(:,j) into workspace - _scatter(a, j, wa, xa, mark); - // scatter the values of B(:,j) into workspace - _scatter(b, j, wb, xb, mark); - // loop rows - for (i = 0; i < rows; i++) { - // matrix values @ i,j - var va = wa[i] === mark ? xa[i] : zero; - var vb = wb[i] === mark ? xb[i] : zero; - // invoke callback - cdata[i][j] = cf(va, vb); - } - } - - // return sparse matrix - return c; - }; - - var _scatter = function (m, j, w, x, mark) { - // a arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // loop values in column j - for (var k = ptr[j], k1 = ptr[j + 1]; k < k1; k++) { - // row - var i = index[k]; - // update workspace - w[i] = mark; - x[i] = values[k]; - } - }; - - return algorithm07; - } - - var name$23 = 'algorithm07'; - var factory_1$25 = factory$25; - - var algorithm07 = { - name: name$23, - factory: factory_1$25 - }; - - function factory$26 (type, config, load, typed) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). - * Callback function invoked MxN times. - * - * - * ┌ f(Sij, b) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ f(0, b) ; otherwise - * - * - * @param {Matrix} s The SparseMatrix instance (S) - * @param {Scalar} b The Scalar value - * @param {Function} callback The f(Aij,b) operation to invoke - * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) - * - * @return {Matrix} DenseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 - */ - var algorithm12 = function (s, b, callback, inverse) { - // sparse matrix arrays - var avalues = s._values; - var aindex = s._index; - var aptr = s._ptr; - var asize = s._size; - var adt = s._datatype; - - // sparse matrix cannot be a Pattern matrix - if (!avalues) - throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string') { - // datatype - dt = adt; - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cdata = []; - // matrix - var c = new DenseMatrix({ - data: cdata, - size: [rows, columns], - datatype: dt - }); - - // workspaces - var x = []; - // marks indicating we have a value in x for a given column - var w = []; - - // loop columns - for (var j = 0; j < columns; j++) { - // columns mark - var mark = j + 1; - // values in j - for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - var r = aindex[k]; - // update workspace - x[r] = avalues[k]; - w[r] = mark; - } - // loop rows - for (var i = 0; i < rows; i++) { - // initialize C on first column - if (j === 0) { - // create row array - cdata[i] = []; - } - // check sparse matrix has a value @ i,j - if (w[i] === mark) { - // invoke callback, update C - cdata[i][j] = inverse ? cf(b, x[i]) : cf(x[i], b); - } - else { - // dense matrix value @ i, j - cdata[i][j] = inverse ? cf(b, 0) : cf(0, b); - } - } - } - - // return sparse matrix - return c; - }; - - return algorithm12; - } - - var name$24 = 'algorithm12'; - var factory_1$26 = factory$26; - - var algorithm12 = { - name: name$24, - factory: factory_1$26 - }; - - var nearlyEqual$2 = number.nearlyEqual; - - - function factory$27 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - var latex$$1 = latex; - - /** - * Test whether value x is smaller than y. - * - * The function returns true when x is smaller than y and the relative - * difference between x and y is smaller than the configured epsilon. The - * function cannot be used to compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.smaller(x, y) - * - * Examples: - * - * math.smaller(2, 3); // returns true - * math.smaller(5, 2 * 2); // returns false - * - * var a = math.unit('5 cm'); - * var b = math.unit('2 inch'); - * math.smaller(a, b); // returns true - * - * See also: - * - * equal, unequal, smallerEq, smaller, smallerEq, compare - * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false - */ - var smaller = typed('smaller', { - - 'boolean, boolean': function (x, y) { - return x < y; - }, - - 'number, number': function (x, y) { - return x < y && !nearlyEqual$2(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.lt(y) && !nearlyEqual(x, y, config.epsilon); - }, - - 'Fraction, Fraction': function (x, y) { - return x.compare(y) === -1; - }, - - 'Complex, Complex': function (x, y) { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return smaller(x.value, y.value); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, smaller); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, smaller, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, smaller, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, smaller); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return smaller(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return smaller(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return smaller(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, smaller, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, smaller, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, smaller, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, smaller, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, smaller, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, smaller, true).valueOf(); - } - }); - - smaller.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['smaller'] + '${args[1]}\\right)' - }; - - return smaller; - } - - var name$25 = 'smaller'; - var factory_1$27 = factory$27; - - var smaller = { - name: name$25, - factory: factory_1$27 - }; - - var nearlyEqual$3 = number.nearlyEqual; - - - function factory$28 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - var latex$$1 = latex; - - /** - * Test whether value x is larger than y. - * - * The function returns true when x is larger than y and the relative - * difference between x and y is larger than the configured epsilon. The - * function cannot be used to compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.larger(x, y) - * - * Examples: - * - * math.larger(2, 3); // returns false - * math.larger(5, 2 + 2); // returns true - * - * var a = math.unit('5 cm'); - * var b = math.unit('2 inch'); - * math.larger(a, b); // returns false - * - * See also: - * - * equal, unequal, smaller, smallerEq, largerEq, compare - * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the x is larger than y, else returns false - */ - var larger = typed('larger', { - - 'boolean, boolean': function (x, y) { - return x > y; - }, - - 'number, number': function (x, y) { - return x > y && !nearlyEqual$3(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.gt(y) && !nearlyEqual(x, y, config.epsilon); - }, - - 'Fraction, Fraction': function (x, y) { - return x.compare(y) === 1; - }, - - 'Complex, Complex': function () { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return larger(x.value, y.value); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, larger); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, larger, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, larger, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, larger); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return larger(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return larger(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return larger(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, larger, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, larger, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, larger, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, larger, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, larger, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, larger, true).valueOf(); - } - }); - - larger.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['larger'] + '${args[1]}\\right)' - }; - - return larger; - } - - var name$26 = 'larger'; - var factory_1$28 = factory$28; - - var larger = { - name: name$26, - factory: factory_1$28 - }; - - function factory$29 (type, config, load, typed) { - - var smaller$$1 = load(smaller); - var larger$$1 = load(larger); - - var oneOverLogPhi = 1.0 / Math.log((1.0 + Math.sqrt(5.0)) / 2.0); - - /** - * Fibonacci Heap implementation, used interally for Matrix math. - * @class FibonacciHeap - * @constructor FibonacciHeap - */ - function FibonacciHeap() { - if (!(this instanceof FibonacciHeap)) - throw new SyntaxError('Constructor must be called with the new operator'); - - // initialize fields - this._minimum = null; - this._size = 0; - } - - /** - * Attach type information - */ - FibonacciHeap.prototype.type = 'FibonacciHeap'; - FibonacciHeap.prototype.isFibonacciHeap = true; - - /** - * Inserts a new data element into the heap. No heap consolidation is - * performed at this time, the new node is simply inserted into the root - * list of this heap. Running time: O(1) actual. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.insert = function (key, value) { - // create node - var node = { - key: key, - value: value, - degree: 0 - }; - // check we have a node in the minimum - if (this._minimum) { - // minimum node - var minimum = this._minimum; - // update left & right of node - node.left = minimum; - node.right = minimum.right; - minimum.right = node; - node.right.left = node; - // update minimum node in heap if needed - if (smaller$$1(key, minimum.key)) { - // node has a smaller key, use it as minimum - this._minimum = node; - } - } - else { - // set left & right - node.left = node; - node.right = node; - // this is the first node - this._minimum = node; - } - // increment number of nodes in heap - this._size++; - // return node - return node; - }; - - /** - * Returns the number of nodes in heap. Running time: O(1) actual. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.size = function () { - return this._size; - }; - - /** - * Removes all elements from this heap. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.clear = function () { - this._minimum = null; - this._size = 0; - }; - - /** - * Returns true if the heap is empty, otherwise false. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.isEmpty = function () { - return this._size === 0; - }; - - /** - * Extracts the node with minimum key from heap. Amortized running - * time: O(log n). - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.extractMinimum = function () { - // node to remove - var node = this._minimum; - // check we have a minimum - if (node === null) - return node; - // current minimum - var minimum = this._minimum; - // get number of children - var numberOfChildren = node.degree; - // pointer to the first child - var x = node.child; - // for each child of node do... - while (numberOfChildren > 0) { - // store node in right side - var tempRight = x.right; - // remove x from child list - x.left.right = x.right; - x.right.left = x.left; - // add x to root list of heap - x.left = minimum; - x.right = minimum.right; - minimum.right = x; - x.right.left = x; - // set Parent[x] to null - x.parent = null; - x = tempRight; - numberOfChildren--; - } - // remove node from root list of heap - node.left.right = node.right; - node.right.left = node.left; - // update minimum - if (node == node.right) { - // empty - minimum = null; - } - else { - // update minimum - minimum = node.right; - // we need to update the pointer to the root with minimum key - minimum = _findMinimumNode(minimum, this._size); - } - // decrement size of heap - this._size--; - // update minimum - this._minimum = minimum; - // return node - return node; - }; - - /** - * Removes a node from the heap given the reference to the node. The trees - * in the heap will be consolidated, if necessary. This operation may fail - * to remove the correct element if there are nodes with key value -Infinity. - * Running time: O(log n) amortized. - * @memberof FibonacciHeap - */ - FibonacciHeap.prototype.remove = function (node) { - // decrease key value - this._minimum = _decreaseKey(this._minimum, node, -1); - // remove the smallest - this.extractMinimum(); - }; - - /** - * Decreases the key value for a heap node, given the new value to take on. - * The structure of the heap may be changed and will not be consolidated. - * Running time: O(1) amortized. - * @memberof FibonacciHeap - */ - var _decreaseKey = function (minimum, node, key) { - // set node key - node.key = key; - // get parent node - var parent = node.parent; - if (parent && smaller$$1(node.key, parent.key)) { - // remove node from parent - _cut(minimum, node, parent); - // remove all nodes from parent to the root parent - _cascadingCut(minimum, parent); - } - // update minimum node if needed - if (smaller$$1(node.key, minimum.key)) - minimum = node; - // return minimum - return minimum; - }; - - /** - * The reverse of the link operation: removes node from the child list of parent. - * This method assumes that min is non-null. Running time: O(1). - * @memberof FibonacciHeap - */ - var _cut = function (minimum, node, parent) { - // remove node from parent children and decrement Degree[parent] - node.left.right = node.right; - node.right.left = node.left; - parent.degree--; - // reset y.child if necessary - if (parent.child == node) - parent.child = node.right; - // remove child if degree is 0 - if (parent.degree === 0) - parent.child = null; - // add node to root list of heap - node.left = minimum; - node.right = minimum.right; - minimum.right = node; - node.right.left = node; - // set parent[node] to null - node.parent = null; - // set mark[node] to false - node.mark = false; - }; - - /** - * Performs a cascading cut operation. This cuts node from its parent and then - * does the same for its parent, and so on up the tree. - * Running time: O(log n); O(1) excluding the recursion. - * @memberof FibonacciHeap - */ - var _cascadingCut= function (minimum, node) { - // store parent node - var parent = node.parent; - // if there's a parent... - if (!parent) - return; - // if node is unmarked, set it marked - if (!node.mark) { - node.mark = true; - } - else { - // it's marked, cut it from parent - _cut(minimum, node, parent); - // cut its parent as well - _cascadingCut(parent); - } - }; - - /** - * Make the first node a child of the second one. Running time: O(1) actual. - * @memberof FibonacciHeap - */ - var _linkNodes = function (node, parent) { - // remove node from root list of heap - node.left.right = node.right; - node.right.left = node.left; - // make node a Child of parent - node.parent = parent; - if (!parent.child) { - parent.child = node; - node.right = node; - node.left = node; - } - else { - node.left = parent.child; - node.right = parent.child.right; - parent.child.right = node; - node.right.left = node; - } - // increase degree[parent] - parent.degree++; - // set mark[node] false - node.mark = false; - }; - - var _findMinimumNode = function (minimum, size) { - // to find trees of the same degree efficiently we use an array of length O(log n) in which we keep a pointer to one root of each degree - var arraySize = Math.floor(Math.log(size) * oneOverLogPhi) + 1; - // create list with initial capacity - var array = new Array(arraySize); - // find the number of root nodes. - var numRoots = 0; - var x = minimum; - if (x) { - numRoots++; - x = x.right; - while (x !== minimum) { - numRoots++; - x = x.right; - } - } - // vars - var y; - // For each node in root list do... - while (numRoots > 0) { - // access this node's degree.. - var d = x.degree; - // get next node - var next = x.right; - // check if there is a node already in array with the same degree - while (true) { - // get node with the same degree is any - y = array[d]; - if (!y) - break; - // make one node with the same degree a child of the other, do this based on the key value. - if (larger$$1(x.key, y.key)) { - var temp = y; - y = x; - x = temp; - } - // make y a child of x - _linkNodes(y, x); - // we have handled this degree, go to next one. - array[d] = null; - d++; - } - // save this node for later when we might encounter another of the same degree. - array[d] = x; - // move forward through list. - x = next; - numRoots--; - } - // Set min to null (effectively losing the root list) and reconstruct the root list from the array entries in array[]. - minimum = null; - // loop nodes in array - for (var i = 0; i < arraySize; i++) { - // get current node - y = array[i]; - if (!y) - continue; - // check if we have a linked list - if (minimum) { - // First remove node from root list. - y.left.right = y.right; - y.right.left = y.left; - // now add to root list, again. - y.left = minimum; - y.right = minimum.right; - minimum.right = y; - y.right.left = y; - // check if this is a new min. - if (smaller$$1(y.key, minimum.key)) - minimum = y; - } - else - minimum = y; - } - return minimum; - }; - - return FibonacciHeap; - } - - var name$27 = 'FibonacciHeap'; - var path$8 = 'type'; - var factory_1$29 = factory$29; - - var FibonacciHeap = { - name: name$27, - path: path$8, - factory: factory_1$29 - }; - - var string$5 = utils.string; - var object$3 = utils.object; - - var isArray$2 = Array.isArray; - var isString$4 = string$5.isString; - - function factory$30 (type, config, load) { - - var DenseMatrix$$1 = load(DenseMatrix); - - var smaller$$1 = load(smaller); - - function ImmutableDenseMatrix(data, datatype) { - if (!(this instanceof ImmutableDenseMatrix)) - throw new SyntaxError('Constructor must be called with the new operator'); - if (datatype && !isString$4(datatype)) - throw new Error('Invalid datatype: ' + datatype); - - if (type.isMatrix(data) || isArray$2(data)) { - // use DenseMatrix implementation - var matrix = new DenseMatrix$$1(data, datatype); - // internal structures - this._data = matrix._data; - this._size = matrix._size; - this._datatype = matrix._datatype; - this._min = null; - this._max = null; - } - else if (data && isArray$2(data.data) && isArray$2(data.size)) { - // initialize fields from JSON representation - this._data = data.data; - this._size = data.size; - this._datatype = data.datatype; - this._min = typeof data.min !== 'undefined' ? data.min : null; - this._max = typeof data.max !== 'undefined' ? data.max : null; - } - else if (data) { - // unsupported type - throw new TypeError('Unsupported type of data (' + utils.types.type(data) + ')'); - } - else { - // nothing provided - this._data = []; - this._size = [0]; - this._datatype = datatype; - this._min = null; - this._max = null; - } - } - - ImmutableDenseMatrix.prototype = new DenseMatrix$$1(); - - /** - * Attach type information - */ - ImmutableDenseMatrix.prototype.type = 'ImmutableDenseMatrix'; - ImmutableDenseMatrix.prototype.isImmutableDenseMatrix = true; - - /** - * 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 | ImmutableDenseMatrix | *} [replacement] - * @param {*} [defaultValue=0] Default value, filled in on new entries when - * the matrix is resized. If not provided, - * new matrix elements will be filled with zeros. - */ - ImmutableDenseMatrix.prototype.subset = function (index) { - switch (arguments.length) { - case 1: - // use base implementation - var m = DenseMatrix$$1.prototype.subset.call(this, index); - // check result is a matrix - if (type.isMatrix(m)) { - // return immutable matrix - return new ImmutableDenseMatrix({ - data: m._data, - size: m._size, - datatype: m._datatype - }); - } - return m; - - // intentional fall through - case 2: - case 3: - throw new Error('Cannot invoke set subset on an Immutable Matrix instance'); - - default: - throw new SyntaxError('Wrong number of arguments'); - } - }; - - /** - * 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 {ImmutableDenseMatrix} self - */ - ImmutableDenseMatrix.prototype.set = function () { - throw new Error('Cannot invoke set on an Immutable Matrix instance'); - }; - - /** - * Resize the matrix to the given size. Returns a copy of the matrix when - * `copy=true`, otherwise return the matrix itself (resize in place). - * - * @param {Number[]} size The new size the matrix should have. - * @param {*} [defaultValue=0] Default value, filled in on new entries. - * If not provided, the matrix elements will - * be filled with zeros. - * @param {boolean} [copy] Return a resized copy of the matrix - * - * @return {Matrix} The resized matrix - */ - ImmutableDenseMatrix.prototype.resize = function () { - throw new Error('Cannot invoke resize on an Immutable Matrix instance'); - }; - - /** - * Disallows reshaping in favor of immutability. - * - * @throws {Error} Operation not allowed - */ - ImmutableDenseMatrix.prototype.reshape = function () { - throw new Error('Cannot invoke reshape on an Immutable Matrix instance'); - }; - - /** - * Create a clone of the matrix - * @return {ImmutableDenseMatrix} clone - */ - ImmutableDenseMatrix.prototype.clone = function () { - var m = new ImmutableDenseMatrix({ - data: object$3.clone(this._data), - size: object$3.clone(this._size), - datatype: this._datatype - }); - return m; - }; - - /** - * Get a JSON representation of the matrix - * @returns {Object} - */ - ImmutableDenseMatrix.prototype.toJSON = function () { - return { - mathjs: 'ImmutableDenseMatrix', - data: this._data, - size: this._size, - datatype: this._datatype - }; - }; - - /** - * Generate a matrix from a JSON object - * @param {Object} json An object structured like - * `{"mathjs": "ImmutableDenseMatrix", data: [], size: []}`, - * where mathjs is optional - * @returns {ImmutableDenseMatrix} - */ - ImmutableDenseMatrix.fromJSON = function (json) { - return new ImmutableDenseMatrix(json); - }; - - /** - * Swap rows i and j in Matrix. - * - * @param {Number} i Matrix row index 1 - * @param {Number} j Matrix row index 2 - * - * @return {Matrix} The matrix reference - */ - ImmutableDenseMatrix.prototype.swapRows = function () { - throw new Error('Cannot invoke swapRows on an Immutable Matrix instance'); - }; - - /** - * Calculate the minimum value in the set - * @return {Number | undefined} min - */ - ImmutableDenseMatrix.prototype.min = function () { - // check min has been calculated before - if (this._min === null) { - // minimum - var m = null; - // compute min - this.forEach(function (v) { - if (m === null || smaller$$1(v, m)) - m = v; - }); - this._min = m !== null ? m : undefined; - } - return this._min; - }; - - /** - * Calculate the maximum value in the set - * @return {Number | undefined} max - */ - ImmutableDenseMatrix.prototype.max = function () { - // check max has been calculated before - if (this._max === null) { - // maximum - var m = null; - // compute max - this.forEach(function (v) { - if (m === null || smaller$$1(m, v)) - m = v; - }); - this._max = m !== null ? m : undefined; - } - return this._max; - }; - - // exports - return ImmutableDenseMatrix; - } - - var name$28 = 'ImmutableDenseMatrix'; - var path$9 = 'type'; - var factory_1$30 = factory$30; - - var ImmutableDenseMatrix = { - name: name$28, - path: path$9, - factory: factory_1$30 - }; - - var clone$1 = object.clone; - var isInteger$2 = number.isInteger; - - function factory$31 (type) { - - /** - * Create an index. An Index can store ranges and sets for multiple dimensions. - * Matrix.get, Matrix.set, and math.subset accept an Index as input. - * - * Usage: - * var index = new Index(range1, range2, matrix1, array1, ...); - * - * Where each parameter can be any of: - * A number - * A string (containing a name of an object property) - * An instance of Range - * An Array with the Set values - * A Matrix with the Set values - * - * The parameters start, end, and step must be integer numbers. - * - * @class Index - * @Constructor Index - * @param {...*} ranges - */ - function Index(ranges) { - if (!(this instanceof Index)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this._dimensions = []; - this._isScalar = true; - - for (var i = 0, ii = arguments.length; i < ii; i++) { - var arg = arguments[i]; - - if (type.isRange(arg)) { - this._dimensions.push(arg); - this._isScalar = false; - } - else if (Array.isArray(arg) || type.isMatrix(arg)) { - // create matrix - var m = _createImmutableMatrix(arg.valueOf()); - this._dimensions.push(m); - // size - var size = m.size(); - // scalar - if (size.length !== 1 || size[0] !== 1) { - this._isScalar = false; - } - } - else if (typeof arg === 'number') { - this._dimensions.push(_createImmutableMatrix([arg])); - } - else if (typeof arg === 'string') { - // object property (arguments.count should be 1) - this._dimensions.push(arg); - } - // TODO: implement support for wildcard '*' - else { - throw new TypeError('Dimension must be an Array, Matrix, number, string, or Range'); - } - } - } - - /** - * Attach type information - */ - Index.prototype.type = 'Index'; - Index.prototype.isIndex = true; - - function _createImmutableMatrix(arg) { - // loop array elements - for (var i = 0, l = arg.length; i < l; i++) { - if (typeof arg[i] !== 'number' || !isInteger$2(arg[i])) { - throw new TypeError('Index parameters must be positive integer numbers'); - } - } - // create matrix - return new type.ImmutableDenseMatrix(arg); - } - - /** - * Create a clone of the index - * @memberof Index - * @return {Index} clone - */ - Index.prototype.clone = function () { - var index = new Index(); - index._dimensions = clone$1(this._dimensions); - index._isScalar = this._isScalar; - return index; - }; - - /** - * Create an index from an array with ranges/numbers - * @memberof Index - * @param {Array.} ranges - * @return {Index} index - * @private - */ - Index.create = function (ranges) { - var index = new Index(); - Index.apply(index, ranges); - return index; - }; - - /** - * Retrieve the size of the index, the number of elements for each dimension. - * @memberof Index - * @returns {number[]} size - */ - Index.prototype.size = function () { - var size = []; - - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var d = this._dimensions[i]; - size[i] = (typeof d === 'string') ? 1 : d.size()[0]; - } - - return size; - }; - - /** - * Get the maximum value for each of the indexes ranges. - * @memberof Index - * @returns {number[]} max - */ - Index.prototype.max = function () { - var values = []; - - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var range = this._dimensions[i]; - values[i] = (typeof range === 'string') ? range : range.max(); - } - - return values; - }; - - /** - * Get the minimum value for each of the indexes ranges. - * @memberof Index - * @returns {number[]} min - */ - Index.prototype.min = function () { - var values = []; - - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var range = this._dimensions[i]; - values[i] = (typeof range === 'string') ? range : range.min(); - } - - return values; - }; - - /** - * Loop over each of the ranges of the index - * @memberof 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 (callback) { - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - callback(this._dimensions[i], i, this); - } - }; - - /** - * Retrieve the dimension for the given index - * @memberof Index - * @param {Number} dim Number of the dimension - * @returns {Range | null} range - */ - Index.prototype.dimension = function (dim) { - return this._dimensions[dim] || null; - }; - - /** - * Test whether this index contains an object property - * @returns {boolean} Returns true if the index is an object property - */ - Index.prototype.isObjectProperty = function () { - return this._dimensions.length === 1 && typeof this._dimensions[0] === 'string'; - }; - - /** - * Returns the object property name when the Index holds a single object property, - * else returns null - * @returns {string | null} - */ - Index.prototype.getObjectProperty = function () { - return this.isObjectProperty() ? this._dimensions[0] : null; - }; - - /** - * Test whether this index contains only a single value. - * - * This is the case when the index is created with only scalar values as ranges, - * not for ranges resolving into a single value. - * @memberof Index - * @return {boolean} isScalar - */ - Index.prototype.isScalar = function () { - return this._isScalar; - }; - - /** - * Expand the Index into an array. - * For example new Index([0,3], [2,7]) returns [[0,1,2], [2,3,4,5,6]] - * @memberof Index - * @returns {Array} array - */ - Index.prototype.toArray = function () { - var array = []; - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var dimension = this._dimensions[i]; - array.push((typeof dimension === 'string') ? dimension : dimension.toArray()); - } - return array; - }; - - /** - * Get the primitive value of the Index, a two dimensional array. - * Equivalent to Index.toArray(). - * @memberof Index - * @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, [1,2,3]]' - * @memberof Index - * @returns {String} str - */ - Index.prototype.toString = function () { - var strings = []; - - for (var i = 0, ii = this._dimensions.length; i < ii; i++) { - var dimension = this._dimensions[i]; - if (typeof dimension === 'string') { - strings.push(JSON.stringify(dimension)); - } - else { - strings.push(dimension.toString()); - } - } - - return '[' + strings.join(', ') + ']'; - }; - - /** - * Get a JSON representation of the Index - * @memberof Index - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Index", "ranges": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}` - */ - Index.prototype.toJSON = function () { - return { - mathjs: 'Index', - dimensions: this._dimensions - }; - }; - - /** - * Instantiate an Index from a JSON object - * @memberof Index - * @param {Object} json A JSON object structured as: - * `{"mathjs": "Index", "dimensions": [{"mathjs": "Range", start: 0, end: 10, step:1}, ...]}` - * @return {Index} - */ - Index.fromJSON = function (json) { - return Index.create(json.dimensions); - }; - - return Index; - } - - var name$29 = 'Index'; - var path$10 = 'type'; - var factory_1$31 = factory$31; - - var MatrixIndex = { - name: name$29, - path: path$10, - factory: factory_1$31 - }; - - function factory$32 (type, config, load, typed) { - /** - * 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] - * - * @class Range - * @constructor Range - * @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) { - if (type.isBigNumber(start)) - start = start.toNumber(); - else if (typeof start !== 'number') - throw new TypeError('Parameter start must be a number'); - } - if (end != null) { - if (type.isBigNumber(end)) - end = end.toNumber(); - else if (typeof end !== 'number') - throw new TypeError('Parameter end must be a number'); - } - if (step != null) { - if (type.isBigNumber(step)) - step = step.toNumber(); - else if (typeof step !== 'number') - 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; - } - - /** - * Attach type information - */ - Range.prototype.type = 'Range'; - Range.prototype.isRange = true; - - /** - * 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'. - * @memberof Range - * @param {string} str - * @return {Range | null} range - */ - Range.parse = function (str) { - if (typeof str !== 'string') { - 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 () { - return new Range(this.start, this.end, this.step); - }; - - /** - * Retrieve the size of the range. - * Returns an array containing one number, the number of elements in the range. - * @memberof Range - * @returns {number[]} size - */ - Range.prototype.size = function () { - 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 - * @memberof Range - * @return {number | undefined} min - */ - Range.prototype.min = function () { - 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 - * @memberof Range - * @return {number | undefined} max - */ - Range.prototype.max = function () { - 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. - * @memberof Range - * @param {function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the Range being traversed. - */ - Range.prototype.forEach = function (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 - * @memberof 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. - * @returns {Array} array - */ - Range.prototype.map = function (callback) { - var array = []; - this.forEach(function (value, index, obj) { - array[index[0]] = callback(value, index, obj); - }); - return array; - }; - - /** - * Create an Array with a copy of the Ranges data - * @memberof Range - * @returns {Array} array - */ - Range.prototype.toArray = function () { - var array = []; - this.forEach(function (value, index) { - array[index[0]] = value; - }); - return array; - }; - - /** - * Get the primitive value of the Range, a one dimensional array - * @memberof Range - * @returns {Array} array - */ - Range.prototype.valueOf = function () { - // 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' - * @memberof Range - * @param {Object | number | function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @returns {string} str - */ - Range.prototype.format = function (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. - * @memberof Range - * @returns {string} - */ - Range.prototype.toString = function () { - return this.format(); - }; - - /** - * Get a JSON representation of the range - * @memberof Range - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}` - */ - Range.prototype.toJSON = function () { - return { - mathjs: 'Range', - start: this.start, - end: this.end, - step: this.step - }; - }; - - /** - * Instantiate a Range from a JSON object - * @memberof Range - * @param {Object} json A JSON object structured as: - * `{"mathjs": "Range", "start": 2, "end": 4, "step": 1}` - * @return {Range} - */ - Range.fromJSON = function (json) { - return new Range(json.start, json.end, json.step); - }; - - return Range; - } - - var name$30 = 'Range'; - var path$11 = 'type'; - var factory_1$32 = factory$32; - - var Range = { - name: name$30, - path: path$11, - factory: factory_1$32 - }; - - function factory$33 (type, config, load, typed) { - /** - * 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. - * - * Syntax: - * - * math.index(range1, range2, ...) - * - * Where each range can be any of: - * - * - A number - * - A string for getting/setting an object property - * - An instance of `Range` - * - A one-dimensional Array or a Matrix with numbers - * - * Indexes must be zero-based, integer numbers. - * - * Examples: - * - * var math = math.js - * - * var b = [1, 2, 3, 4, 5]; - * math.subset(b, math.index([1, 2, 3])); // returns [2, 3, 4] - * - * var a = math.matrix([[1, 2], [3, 4]]); - * a.subset(math.index(0, 1)); // returns 2 - * - * See also: - * - * bignumber, boolean, complex, matrix, number, string, unit - * - * @param {...*} ranges Zero or more ranges or numbers. - * @return {Index} Returns the created index - */ - return typed('index', { - '...number | string | BigNumber | Range | Array | Matrix': function (args) { - var ranges = args.map(function (arg) { - if (type.isBigNumber(arg)) { - return arg.toNumber(); // convert BigNumber to Number - } - else if (Array.isArray(arg) || type.isMatrix(arg)) { - return arg.map(function (elem) { - // convert BigNumber to Number - return type.isBigNumber(elem) ? elem.toNumber() : elem; - }); - } - else { - return arg; - } - }); - - var res = new type.Index(); - type.Index.apply(res, ranges); - return res; - } - }); - } - - var name$31 = 'index'; - var factory_1$33 = factory$33; - - var _function$1 = { - name: name$31, - factory: factory_1$33 - }; - - function factory$34 (type, config, load, typed) { - - var SparseMatrix = type.SparseMatrix; - - /** - * Create a Sparse 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. - * - * Syntax: - * - * math.sparse() // creates an empty sparse matrix. - * math.sparse(data) // creates a sparse matrix with initial data. - * math.sparse(data, 'number') // creates a sparse matrix with initial data, number datatype. - * - * Examples: - * - * var m = math.sparse([[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, matrix - * - * @param {Array | Matrix} [data] A two dimensional array - * - * @return {Matrix} The created matrix - */ - var sparse = typed('sparse', { - '': function () { - return new SparseMatrix([]); - }, - - 'string': function (datatype) { - return new SparseMatrix([], datatype); - }, - - 'Array | Matrix': function (data) { - return new SparseMatrix(data); - }, - - 'Array | Matrix, string': function (data, datatype) { - return new SparseMatrix(data, datatype); - } - }); - - sparse.toTex = { - 0: '\\begin{bsparse}\\end{bsparse}', - 1: '\\left(${args[0]}\\right)' - }; - - return sparse; - } - - var name$32 = 'sparse'; - var factory_1$34 = factory$34; - - var sparse = { - name: name$32, - factory: factory_1$34 - }; - - var matrix$1 = [ - // types - Matrix, - DenseMatrix, - SparseMatrix, - Spa, - FibonacciHeap, - ImmutableDenseMatrix, - MatrixIndex, - Range, - - // construction functions - _function$1, - matrix, - sparse - ]; - - function factory$35 (type, config, load, typed) { - /** - * Create a number or convert a string, boolean, or unit to a number. - * When value is a matrix, all elements will be converted to number. - * - * Syntax: - * - * math.number(value) - * math.number(unit, valuelessUnit) - * - * Examples: - * - * math.number(2); // returns number 2 - * math.number('7.2'); // returns number 7.2 - * math.number(true); // returns number 1 - * math.number([true, false, true, true]); // returns [1, 0, 1, 1] - * math.number(math.unit('52cm'), 'm'); // returns 0.52 - * - * See also: - * - * bignumber, boolean, complex, index, matrix, string, unit - * - * @param {string | number | BigNumber | Fraction | boolean | Array | Matrix | Unit | null} [value] Value to be converted - * @param {Unit | string} [valuelessUnit] A valueless unit, used to convert a unit to a number - * @return {number | Array | Matrix} The created number - */ - var number = typed('number', { - '': function () { - return 0; - }, - - 'number': function (x) { - return x; - }, - - 'string': function (x) { - var num = Number(x); - if (isNaN(num)) { - throw new SyntaxError('String "' + x + '" is no valid number'); - } - return num; - }, - - 'BigNumber': function (x) { - return x.toNumber(); - }, - - 'Fraction': function (x) { - return x.valueOf(); - }, - - 'Unit': function (x) { - throw new Error('Second argument with valueless unit expected'); - }, - - 'null': function (x) { - return 0; - }, - - 'Unit, string | Unit': function (unit, valuelessUnit) { - return unit.toNumber(valuelessUnit); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, number); - } - }); - - number.toTex = { - 0: '0', - 1: '\\left(${args[0]}\\right)', - 2: '\\left(\\left(${args[0]}\\right)${args[1]}\\right)' - }; - - return number; - } - - var name$33 = 'number'; - var factory_1$35 = factory$35; - - var number$3 = { - name: name$33, - factory: factory_1$35 - }; - - function factory$36 (type, config, load, typed) { - /** - * A ResultSet contains a list or results - * @class ResultSet - * @param {Array} entries - * @constructor ResultSet - */ - function ResultSet(entries) { - if (!(this instanceof ResultSet)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.entries = entries || []; - } - - /** - * Attach type information - */ - ResultSet.prototype.type = 'ResultSet'; - ResultSet.prototype.isResultSet = true; - - /** - * Returns the array with results hold by this ResultSet - * @memberof ResultSet - * @returns {Array} entries - */ - ResultSet.prototype.valueOf = function () { - return this.entries; - }; - - /** - * Returns the stringified results of the ResultSet - * @memberof ResultSet - * @returns {string} string - */ - ResultSet.prototype.toString = function () { - return '[' + this.entries.join(', ') + ']'; - }; - - /** - * Get a JSON representation of the ResultSet - * @memberof ResultSet - * @returns {Object} Returns a JSON object structured as: - * `{"mathjs": "ResultSet", "entries": [...]}` - */ - ResultSet.prototype.toJSON = function () { - return { - mathjs: 'ResultSet', - entries: this.entries - }; - }; - - /** - * Instantiate a ResultSet from a JSON object - * @memberof ResultSet - * @param {Object} json A JSON object structured as: - * `{"mathjs": "ResultSet", "entries": [...]}` - * @return {ResultSet} - */ - ResultSet.fromJSON = function (json) { - return new ResultSet(json.entries); - }; - - return ResultSet; - } - - var name$34 = 'ResultSet'; - var path$12 = 'type'; - var factory_1$36 = factory$36; - - var ResultSet = { - name: name$34, - path: path$12, - factory: factory_1$36 - }; - - var resultset = [ - // type - ResultSet - ]; - - function factory$37 (type, config, load, typed) { - /** - * Create a string or convert any object into a string. - * Elements of Arrays and Matrices are processed element wise. - * - * Syntax: - * - * math.string(value) - * - * Examples: - * - * math.string(4.2); // returns string '4.2' - * math.string(math.complex(3, 2); // returns string '3 + 2i' - * - * var u = math.unit(5, 'km'); - * math.string(u.to('m')); // returns string '5000 m' - * - * math.string([true, false]); // returns ['true', 'false'] - * - * See also: - * - * bignumber, boolean, complex, index, matrix, number, unit - * - * @param {* | Array | Matrix | null} [value] A value to convert to a string - * @return {string | Array | Matrix} The created string - */ - var string = typed('string', { - '': function () { - return ''; - }, - - 'number': number.format, - - 'null': function (x) { - return 'null'; - }, - - 'boolean': function (x) { - return x + ''; - }, - - 'string': function (x) { - return x; - }, - - 'Array | Matrix': function (x) { - return deepMap(x, string); - }, - - 'any': function (x) { - return String(x); - } - }); - - string.toTex = { - 0: '\\mathtt{""}', - 1: '\\mathrm{string}\\left(${args[0]}\\right)' - }; - - return string; - } - - var name$35 = 'string'; - var factory_1$37 = factory$37; - - var string$6 = { - name: name$35, - factory: factory_1$37 - }; - - var type = [ - bignumber$1, - boolean_1, - chain$1, - complex$3, - fraction$3, - matrix$1, - number$3, - resultset, - string$6, - ]; - - var constants = createCommonjsModule(function (module, exports) { - var memoize = _function.memoize; - - /** - * Calculate BigNumber e - * @param {function} BigNumber BigNumber constructor - * @returns {BigNumber} Returns e - */ - exports.e = memoize(function (BigNumber) { - return new BigNumber(1).exp(); - }, hasher); - - /** - * Calculate BigNumber golden ratio, phi = (1+sqrt(5))/2 - * @param {function} BigNumber BigNumber constructor - * @returns {BigNumber} Returns phi - */ - exports.phi = memoize(function (BigNumber) { - return new BigNumber(1).plus(new BigNumber(5).sqrt()).div(2); - }, hasher); - - /** - * Calculate BigNumber pi. - * @param {function} BigNumber BigNumber constructor - * @returns {BigNumber} Returns pi - */ - exports.pi = memoize(function (BigNumber) { - return BigNumber.acos(-1); - }, hasher); - - /** - * Calculate BigNumber tau, tau = 2 * pi - * @param {function} BigNumber BigNumber constructor - * @returns {BigNumber} Returns tau - */ - exports.tau = memoize(function (BigNumber) { - return exports.pi(BigNumber).times(2); - }, hasher); - - /** - * Create a hash for a BigNumber constructor function. The created has is - * the configured precision - * @param {Array} args Supposed to contain a single entry with - * a BigNumber constructor - * @return {number} precision - * @private - */ - function hasher (args) { - return args[0].precision; - } - }); - var constants_1 = constants.e; - var constants_2 = constants.phi; - var constants_3 = constants.pi; - var constants_4 = constants.tau; - - function factory$38 (type, config, load, typed, math) { - // listen for changed in the configuration, automatically reload - // constants when needed - math.on('config', function (curr, prev) { - if (curr.number !== prev.number || curr.define_pi !== prev.define_pi - || curr.define_e !== prev.define_e || curr.define_i !== prev.define_i) { - factory$38(type, config, load, typed, math); - } - }); - - setConstant(math, 'true', true); - setConstant(math, 'false', false); - setConstant(math, 'null', null); - setConstant(math, 'uninitialized', 'Error: Constant uninitialized is removed since v4.0.0. Use null instead'); - - if (config.number === 'BigNumber') { - setConstant(math, 'Infinity', new type.BigNumber(Infinity)); - setConstant(math, 'NaN', new type.BigNumber(NaN)); - - if(config.define_pi === false) - deleteConstant(math, 'pi'); - else - setLazyConstant(math, 'pi', function () {return constants.pi(type.BigNumber)}); - if(config.define_e === false) - deleteConstant(math, 'e'); - else - setLazyConstant(math, 'e', function () {return constants.e(type.BigNumber)}); - } - else { - setConstant(math, 'Infinity', Infinity); - setConstant(math, 'NaN', NaN); - - if(config.define_pi === false) - deleteConstant(math, 'pi'); - else - setConstant(math, 'pi', Math.PI); - if(config.define_e === false) - deleteConstant(math, 'e'); - else - setConstant(math, 'e', Math.E); - } - - if(config.define_i===false) - deleteConstant(math, 'i'); - else - // complex i - setConstant(math, 'i', type.Complex.I); - - } - - // delete a constant in both math and mathWithTransform - function deleteConstant(math, name) { - delete math[name]; - delete math.expression.mathWithTransform[name]; - } - - // create a constant in both math and mathWithTransform - function setConstant(math, name, value) { - math[name] = value; - math.expression.mathWithTransform[name] = value; - } - - // create a lazy constant in both math and mathWithTransform - function setLazyConstant (math, name, resolver) { - object.lazy(math, name, resolver); - object.lazy(math.expression.mathWithTransform, name, resolver); - } - - const lazy$4 = false; // no lazy loading of constants, the constants themselves are lazy when needed - const math$5 = true; // request access to the math namespace - - var constants$1 = { factory: factory$38, lazy: lazy$4, math: math$5 }; - - var bignumber$2 = { - 'name': 'bignumber', - 'category': 'Construction', - 'syntax': [ - 'bignumber(x)' - ], - 'description': - 'Create a big number from a number or string.', - 'examples': [ - '0.1 + 0.2', - 'bignumber(0.1) + bignumber(0.2)', - 'bignumber("7.2")', - 'bignumber("7.2e500")', - 'bignumber([0.1, 0.2, 0.3])' - ], - 'seealso': [ - 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' - ] - }; - - var boolean_1$2 = { - 'name': 'boolean', - 'category': 'Construction', - 'syntax': [ - 'x', - 'boolean(x)' - ], - 'description': - 'Convert a string or number into a boolean.', - 'examples': [ - 'boolean(0)', - 'boolean(1)', - 'boolean(3)', - 'boolean("true")', - 'boolean("false")', - 'boolean([1, 0, 1, 1])' - ], - 'seealso': [ - 'bignumber', 'complex', 'index', 'matrix', 'number', 'string', 'unit' - ] - }; - - var complex$4 = { - 'name': 'complex', - 'category': 'Construction', - 'syntax': [ - 'complex()', - 'complex(re, im)', - 'complex(string)' - ], - 'description': - 'Create a complex number.', - 'examples': [ - 'complex()', - 'complex(2, 3)', - 'complex("7 - 2i")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'index', 'matrix', 'number', 'string', 'unit' - ] - }; - - var createUnit = { - 'name': 'createUnit', - 'category': 'Construction', - 'syntax': [ - 'createUnit(definitions)', - 'createUnit(name, definition)' - ], - 'description': - 'Create a user-defined unit and register it with the Unit type.', - 'examples': [ - 'createUnit("foo")', - 'createUnit("knot", {definition: "0.514444444 m/s", aliases: ["knots", "kt", "kts"]})', - 'createUnit("mph", "1 mile/hour")' - ], - 'seealso': [ - 'unit', 'splitUnit' - ] - }; - - var fraction$4 = { - 'name': 'fraction', - 'category': 'Construction', - 'syntax': [ - 'fraction(num)', - 'fraction(num,den)' - ], - 'description': - 'Create a fraction from a number or from a numerator and denominator.', - 'examples': [ - 'fraction(0.125)', - 'fraction(1, 3) + fraction(2, 5)' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'string', 'unit' - ] - }; - - var construction = { - 'name': 'index', - 'category': 'Construction', - 'syntax': [ - '[start]', - '[start:end]', - '[start:step:end]', - '[start1, start 2, ...]', - '[start1:end1, start2:end2, ...]', - '[start1:step1:end1, start2:step2:end2, ...]' - ], - 'description': - 'Create an index to get or replace a subset of a matrix', - 'examples': [ - '[]', - '[1, 2, 3]', - 'A = [1, 2, 3; 4, 5, 6]', - 'A[1, :]', - 'A[1, 2] = 50', - 'A[0:2, 0:2] = ones(2, 2)' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'matrix,', 'number', 'range', 'string', 'unit' - ] - }; - - var matrix$2 = { - 'name': 'matrix', - 'category': 'Construction', - 'syntax': [ - '[]', - '[a1, b1, ...; a2, b2, ...]', - 'matrix()', - 'matrix("dense")', - 'matrix([...])' - ], - 'description': - 'Create a matrix.', - 'examples': [ - '[]', - '[1, 2, 3]', - '[1, 2, 3; 4, 5, 6]', - 'matrix()', - 'matrix([3, 4])', - 'matrix([3, 4; 5, 6], "sparse")', - 'matrix([3, 4; 5, 6], "sparse", "number")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit', 'sparse' - ] - }; - - var number$4 = { - 'name': 'number', - 'category': 'Construction', - 'syntax': [ - 'x', - 'number(x)', - 'number(unit, valuelessUnit)' - ], - 'description': - 'Create a number or convert a string or boolean into a number.', - 'examples': [ - '2', - '2e3', - '4.05', - 'number(2)', - 'number("7.2")', - 'number(true)', - 'number([true, false, true, true])', - 'number(unit("52cm"), "m")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'fraction', 'index', 'matrix', 'string', 'unit' - ] - }; - - var sparse$1 = { - 'name': 'sparse', - 'category': 'Construction', - 'syntax': [ - 'sparse()', - 'sparse([a1, b1, ...; a1, b2, ...])', - 'sparse([a1, b1, ...; a1, b2, ...], "number")' - ], - 'description': - 'Create a sparse matrix.', - 'examples': [ - 'sparse()', - 'sparse([3, 4; 5, 6])', - 'sparse([3, 0; 5, 0], "number")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'number', 'string', 'unit', 'matrix' - ] - }; - - var splitUnit = { - 'name': 'splitUnit', - 'category': 'Construction', - 'syntax': [ - 'splitUnit(unit: Unit, parts: Unit[])' - ], - 'description': - 'Split a unit in an array of units whose sum is equal to the original unit.', - 'examples': [ - 'splitUnit(1 m, ["feet", "inch"])' - ], - 'seealso': [ - 'unit', 'createUnit' - ] - }; - - var string$7 = { - 'name': 'string', - 'category': 'Construction', - 'syntax': [ - '"text"', - 'string(x)' - ], - 'description': - 'Create a string or convert a value to a string', - 'examples': [ - '"Hello World!"', - 'string(4.2)', - 'string(3 + 2i)' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'number', 'unit' - ] - }; - - var unit = { - 'name': 'unit', - 'category': 'Construction', - 'syntax': [ - 'value unit', - 'unit(value, unit)', - 'unit(string)' - ], - 'description': - 'Create a unit.', - 'examples': [ - '5.5 mm', - '3 inch', - 'unit(7.1, "kilogram")', - 'unit("23 deg")' - ], - 'seealso': [ - 'bignumber', 'boolean', 'complex', 'index', 'matrix', 'number', 'string' - ] - }; - - var e = { - 'name': 'e', - 'category': 'Constants', - 'syntax': [ - 'e' - ], - 'description': 'Euler\'s number, the base of the natural logarithm. Approximately equal to 2.71828', - 'examples': [ - 'e', - 'e ^ 2', - 'exp(2)', - 'log(e)' - ], - 'seealso': ['exp'] - }; - - var _false = { - 'name': 'false', - 'category': 'Constants', - 'syntax': [ - 'false' - ], - 'description': 'Boolean value false', - 'examples': [ - 'false' - ], - 'seealso': ['true'] - }; - - var i = { - 'name': 'i', - 'category': 'Constants', - 'syntax': [ - 'i' - ], - 'description': 'Imaginary unit, defined as i*i=-1. A complex number is described as a + b*i, where a is the real part, and b is the imaginary part.', - 'examples': [ - 'i', - 'i * i', - 'sqrt(-1)' - ], - 'seealso': [] - }; - - var _Infinity = { - 'name': 'Infinity', - 'category': 'Constants', - 'syntax': [ - 'Infinity' - ], - 'description': 'Infinity, a number which is larger than the maximum number that can be handled by a floating point number.', - 'examples': [ - 'Infinity', - '1 / 0' - ], - 'seealso': [] - }; - - var LN2 = { - 'name': 'LN2', - 'category': 'Constants', - 'syntax': [ - 'LN2' - ], - 'description': 'Returns the natural logarithm of 2, approximately equal to 0.693', - 'examples': [ - 'LN2', - 'log(2)' - ], - 'seealso': [] - }; - - var LN10 = { - 'name': 'LN10', - 'category': 'Constants', - 'syntax': [ - 'LN10' - ], - 'description': 'Returns the natural logarithm of 10, approximately equal to 2.302', - 'examples': [ - 'LN10', - 'log(10)' - ], - 'seealso': [] - }; - - var LOG2E = { - 'name': 'LOG2E', - 'category': 'Constants', - 'syntax': [ - 'LOG2E' - ], - 'description': 'Returns the base-2 logarithm of E, approximately equal to 1.442', - 'examples': [ - 'LOG2E', - 'log(e, 2)' - ], - 'seealso': [] - }; - - var LOG10E = { - 'name': 'LOG10E', - 'category': 'Constants', - 'syntax': [ - 'LOG10E' - ], - 'description': 'Returns the base-10 logarithm of E, approximately equal to 0.434', - 'examples': [ - 'LOG10E', - 'log(e, 10)' - ], - 'seealso': [] - }; - - var _NaN = { - 'name': 'NaN', - 'category': 'Constants', - 'syntax': [ - 'NaN' - ], - 'description': 'Not a number', - 'examples': [ - 'NaN', - '0 / 0' - ], - 'seealso': [] - }; - - var _null = { - 'name': 'null', - 'category': 'Constants', - 'syntax': [ - 'null' - ], - 'description': 'Value null', - 'examples': [ - 'null' - ], - 'seealso': ['true', 'false'] - }; - - var pi = { - 'name': 'pi', - 'category': 'Constants', - 'syntax': [ - 'pi' - ], - 'description': 'The number pi is a mathematical constant that is the ratio of a circle\'s circumference to its diameter, and is approximately equal to 3.14159', - 'examples': [ - 'pi', - 'sin(pi/2)' - ], - 'seealso': ['tau'] - }; - - var phi = { - 'name': 'phi', - 'category': 'Constants', - 'syntax': [ - 'phi' - ], - 'description': 'Phi is the golden ratio. Two quantities are in the golden ratio if their ratio is the same as the ratio of their sum to the larger of the two quantities. Phi is defined as `(1 + sqrt(5)) / 2` and is approximately 1.618034...', - 'examples': [ - 'phi' - ], - 'seealso': [] - }; - - var SQRT1_2 = { - 'name': 'SQRT1_2', - 'category': 'Constants', - 'syntax': [ - 'SQRT1_2' - ], - 'description': 'Returns the square root of 1/2, approximately equal to 0.707', - 'examples': [ - 'SQRT1_2', - 'sqrt(1/2)' - ], - 'seealso': [] - }; - - var SQRT2 = { - 'name': 'SQRT2', - 'category': 'Constants', - 'syntax': [ - 'SQRT2' - ], - 'description': 'Returns the square root of 2, approximately equal to 1.414', - 'examples': [ - 'SQRT2', - 'sqrt(2)' - ], - 'seealso': [] - }; - - var tau = { - 'name': 'tau', - 'category': 'Constants', - 'syntax': [ - 'tau' - ], - 'description': 'Tau is the ratio constant of a circle\'s circumference to radius, equal to 2 * pi, approximately 6.2832.', - 'examples': [ - 'tau', - '2 * pi' - ], - 'seealso': ['pi'] - }; - - var _true = { - 'name': 'true', - 'category': 'Constants', - 'syntax': [ - 'true' - ], - 'description': 'Boolean value true', - 'examples': [ - 'true' - ], - 'seealso': ['false'] - }; - - var version = { - 'name': 'version', - 'category': 'Constants', - 'syntax': [ - 'version' - ], - 'description': 'A string with the version number of math.js', - 'examples': [ - 'version' - ], - 'seealso': [] - }; - - var derivative = { - 'name': 'derivative', - 'category': 'Algebra', - 'syntax': [ - 'derivative(expr, variable)', - 'derivative(expr, variable, {simplify: boolean})' - ], - 'description': 'Takes the derivative of an expression expressed in parser Nodes. The derivative will be taken over the supplied variable in the second parameter. If there are multiple variables in the expression, it will return a partial derivative.', - 'examples': [ - 'derivative("2x^3", "x")', - 'derivative("2x^3", "x", {simplify: false})', - 'derivative("2x^2 + 3x + 4", "x")', - 'derivative("sin(2x)", "x")', - 'f = parse("x^2 + x")', - 'x = parse("x")', - 'df = derivative(f, x)', - 'df.eval({x: 3})' - ], - 'seealso': [ - 'simplify', 'parse', 'eval' - ] - }; - - var lsolve = { - 'name': 'lsolve', - 'category': 'Algebra', - 'syntax': [ - 'x=lsolve(L, b)' - ], - 'description': - 'Solves the linear system L * x = b where L is an [n x n] lower triangular matrix and b is a [n] column vector.', - 'examples': [ - 'a = [-2, 3; 2, 1]', - 'b = [11, 9]', - 'x = lsolve(a, b)' - ], - 'seealso': [ - 'lup', 'lusolve', 'usolve', 'matrix', 'sparse' - ] - }; - - var lup = { - 'name': 'lup', - 'category': 'Algebra', - 'syntax': [ - 'lup(m)' - ], - 'description': - 'Calculate the Matrix LU decomposition with partial pivoting. Matrix A is decomposed in three matrices (L, U, P) where P * A = L * U', - 'examples': [ - 'lup([[2, 1], [1, 4]])', - 'lup(matrix([[2, 1], [1, 4]]))', - 'lup(sparse([[2, 1], [1, 4]]))' - ], - 'seealso': [ - 'lusolve', 'lsolve', 'usolve', 'matrix', 'sparse', 'slu', 'qr' - ] - }; - - var lusolve = { - 'name': 'lusolve', - 'category': 'Algebra', - 'syntax': [ - 'x=lusolve(A, b)', - 'x=lusolve(lu, b)' - ], - 'description': 'Solves the linear system A * x = b where A is an [n x n] matrix and b is a [n] column vector.', - 'examples': [ - 'a = [-2, 3; 2, 1]', - 'b = [11, 9]', - 'x = lusolve(a, b)' - ], - 'seealso': [ - 'lup', 'slu', 'lsolve', 'usolve', 'matrix', 'sparse' - ] - }; - - var simplify = { - 'name': 'simplify', - 'category': 'Algebra', - 'syntax': [ - 'simplify(expr)', - 'simplify(expr, rules)' - ], - 'description': 'Simplify an expression tree.', - 'examples': [ - 'simplify("3 + 2 / 4")', - 'simplify("2x + x")', - 'f = parse("x * (x + 2 + x)")', - 'simplified = simplify(f)', - 'simplified.eval({x: 2})' - ], - 'seealso': [ - 'derivative', 'parse', 'eval' - ] - }; - - var rationalize = { - 'name': 'rationalize', - 'category': 'Algebra', - 'syntax': [ - 'rationalize(expr)', - 'rationalize(expr, scope)', - 'rationalize(expr, scope, detailed)' - ], - 'description': 'Transform a rationalizable expression in a rational fraction. If rational fraction is one variable polynomial then converts the numerator and denominator in canonical form, with decreasing exponents, returning the coefficients of numerator.', - 'examples': [ - 'rationalize("2x/y - y/(x+1)")', - 'rationalize("2x/y - y/(x+1)", true)', - ], - 'seealso': [ - 'simplify' - ] - }; - - var slu = { - 'name': 'slu', - 'category': 'Algebra', - 'syntax': [ - 'slu(A, order, threshold)' - ], - 'description': 'Calculate the Matrix LU decomposition with full pivoting. Matrix A is decomposed in two matrices (L, U) and two permutation vectors (pinv, q) where P * A * Q = L * U', - 'examples': [ - 'slu(sparse([4.5, 0, 3.2, 0; 3.1, 2.9, 0, 0.9; 0, 1.7, 3, 0; 3.5, 0.4, 0, 1]), 1, 0.001)' - ], - 'seealso': [ - 'lusolve', 'lsolve', 'usolve', 'matrix', 'sparse', 'lup', 'qr' - ] - }; - - var usolve = { - 'name': 'usolve', - 'category': 'Algebra', - 'syntax': [ - 'x=usolve(U, b)' - ], - 'description': - 'Solves the linear system U * x = b where U is an [n x n] upper triangular matrix and b is a [n] column vector.', - 'examples': [ - 'x=usolve(sparse([1, 1, 1, 1; 0, 1, 1, 1; 0, 0, 1, 1; 0, 0, 0, 1]), [1; 2; 3; 4])' - ], - 'seealso': [ - 'lup', 'lusolve', 'lsolve', 'matrix', 'sparse' - ] - }; - - var qr = { - 'name': 'qr', - 'category': 'Algebra', - 'syntax': [ - 'qr(A)' - ], - 'description': - 'Calculates the Matrix QR decomposition. Matrix `A` is decomposed in two matrices (`Q`, `R`) where `Q` is an orthogonal matrix and `R` is an upper triangular matrix.', - 'examples': [ - 'qr([[1, -1, 4], [1, 4, -2], [1, 4, 2], [1, -1, 0]])' - ], - 'seealso': [ - 'lup', 'slu', 'matrix' - ] - }; - - var abs = { - 'name': 'abs', - 'category': 'Arithmetic', - 'syntax': [ - 'abs(x)' - ], - 'description': 'Compute the absolute value.', - 'examples': [ - 'abs(3.5)', - 'abs(-4.2)' - ], - 'seealso': ['sign'] - }; - - var add$1 = { - 'name': 'add', - 'category': 'Operators', - 'syntax': [ - 'x + y', - 'add(x, y)' - ], - 'description': 'Add two values.', - 'examples': [ - 'a = 2.1 + 3.6', - 'a - 3.6', - '3 + 2i', - '3 cm + 2 inch', - '"2.3" + "4"' - ], - 'seealso': [ - 'subtract' - ] - }; - - var cbrt = { - 'name': 'cbrt', - 'category': 'Arithmetic', - 'syntax': [ - 'cbrt(x)', - 'cbrt(x, allRoots)' - ], - 'description': - 'Compute the cubic root value. If x = y * y * y, then y is the cubic root of x. When `x` is a number or complex number, an optional second argument `allRoots` can be provided to return all three cubic roots. If not provided, the principal root is returned', - 'examples': [ - 'cbrt(64)', - 'cube(4)', - 'cbrt(-8)', - 'cbrt(2 + 3i)', - 'cbrt(8i)', - 'cbrt(8i, true)', - 'cbrt(27 m^3)' - ], - 'seealso': [ - 'square', - 'sqrt', - 'cube', - 'multiply' - ] - }; - - var ceil = { - 'name': 'ceil', - 'category': 'Arithmetic', - 'syntax': [ - 'ceil(x)' - ], - 'description': - 'Round a value towards plus infinity. If x is complex, both real and imaginary part are rounded towards plus infinity.', - 'examples': [ - 'ceil(3.2)', - 'ceil(3.8)', - 'ceil(-4.2)' - ], - 'seealso': ['floor', 'fix', 'round'] - }; - - var cube = { - 'name': 'cube', - 'category': 'Arithmetic', - 'syntax': [ - 'cube(x)' - ], - 'description': 'Compute the cube of a value. The cube of x is x * x * x.', - 'examples': [ - 'cube(2)', - '2^3', - '2 * 2 * 2' - ], - 'seealso': [ - 'multiply', - 'square', - 'pow' - ] - }; - - var divide = { - 'name': 'divide', - 'category': 'Operators', - 'syntax': [ - 'x / y', - 'divide(x, y)' - ], - 'description': 'Divide two values.', - 'examples': [ - 'a = 2 / 3', - 'a * 3', - '4.5 / 2', - '3 + 4 / 2', - '(3 + 4) / 2', - '18 km / 4.5' - ], - 'seealso': [ - 'multiply' - ] - }; - - var dotDivide = { - 'name': 'dotDivide', - 'category': 'Operators', - 'syntax': [ - 'x ./ y', - 'dotDivide(x, y)' - ], - 'description': 'Divide two values element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'b = [2, 1, 1; 3, 2, 5]', - 'a ./ b' - ], - 'seealso': [ - 'multiply', - 'dotMultiply', - 'divide' - ] - }; - - var dotMultiply = { - 'name': 'dotMultiply', - 'category': 'Operators', - 'syntax': [ - 'x .* y', - 'dotMultiply(x, y)' - ], - 'description': 'Multiply two values element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'b = [2, 1, 1; 3, 2, 5]', - 'a .* b' - ], - 'seealso': [ - 'multiply', - 'divide', - 'dotDivide' - ] - }; - - var dotPow = { - 'name': 'dotpow', - 'category': 'Operators', - 'syntax': [ - 'x .^ y', - 'dotpow(x, y)' - ], - 'description': - 'Calculates the power of x to y element wise.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'a .^ 2' - ], - 'seealso': [ - 'pow' - ] - }; - - var exp = { - 'name': 'exp', - 'category': 'Arithmetic', - 'syntax': [ - 'exp(x)' - ], - 'description': 'Calculate the exponent of a value.', - 'examples': [ - 'exp(1.3)', - 'e ^ 1.3', - 'log(exp(1.3))', - 'x = 2.4', - '(exp(i*x) == cos(x) + i*sin(x)) # Euler\'s formula' - ], - 'seealso': [ - 'expm', - 'expm1', - 'pow', - 'log' - ] - }; - - var expm = { - 'name': 'expm', - 'category': 'Arithmetic', - 'syntax': [ - 'exp(x)' - ], - 'description': 'Compute the matrix exponential, expm(A) = e^A. ' + - 'The matrix must be square. ' + - 'Not to be confused with exp(a), which performs element-wise exponentiation.', - 'examples': [ - 'expm([[0,2],[0,0]])' - ], - 'seealso': [ - 'exp' - ] - }; - - var expm1 = { - 'name': 'expm1', - 'category': 'Arithmetic', - 'syntax': [ - 'expm1(x)' - ], - 'description': 'Calculate the value of subtracting 1 from the exponential value.', - 'examples': [ - 'expm1(2)', - 'pow(e, 2) - 1', - 'log(expm1(2) + 1)' - ], - 'seealso': [ - 'exp', - 'pow', - 'log' - ] - }; - - var fix = { - 'name': 'fix', - 'category': 'Arithmetic', - 'syntax': [ - 'fix(x)' - ], - 'description': - 'Round a value towards zero. If x is complex, both real and imaginary part are rounded towards zero.', - 'examples': [ - 'fix(3.2)', - 'fix(3.8)', - 'fix(-4.2)', - 'fix(-4.8)' - ], - 'seealso': ['ceil', 'floor', 'round'] - }; - - var floor = { - 'name': 'floor', - 'category': 'Arithmetic', - 'syntax': [ - 'floor(x)' - ], - 'description': - 'Round a value towards minus infinity.If x is complex, both real and imaginary part are rounded towards minus infinity.', - 'examples': [ - 'floor(3.2)', - 'floor(3.8)', - 'floor(-4.2)' - ], - 'seealso': ['ceil', 'fix', 'round'] - }; - - var gcd = { - 'name': 'gcd', - 'category': 'Arithmetic', - 'syntax': [ - 'gcd(a, b)', - 'gcd(a, b, c, ...)' - ], - 'description': 'Compute the greatest common divisor.', - 'examples': [ - 'gcd(8, 12)', - 'gcd(-4, 6)', - 'gcd(25, 15, -10)' - ], - 'seealso': [ 'lcm', 'xgcd' ] - }; - - var hypot = { - 'name': 'hypot', - 'category': 'Arithmetic', - 'syntax': [ - 'hypot(a, b, c, ...)', - 'hypot([a, b, c, ...])' - ], - 'description': 'Calculate the hypotenusa of a list with values. ', - 'examples': [ - 'hypot(3, 4)', - 'sqrt(3^2 + 4^2)', - 'hypot(-2)', - 'hypot([3, 4, 5])' - ], - 'seealso': [ 'abs', 'norm' ] - }; - - var lcm = { - 'name': 'lcm', - 'category': 'Arithmetic', - 'syntax': [ - 'lcm(x, y)' - ], - 'description': 'Compute the least common multiple.', - 'examples': [ - 'lcm(4, 6)', - 'lcm(6, 21)', - 'lcm(6, 21, 5)' - ], - 'seealso': [ 'gcd' ] - }; - - var log = { - 'name': 'log', - 'category': 'Arithmetic', - 'syntax': [ - 'log(x)', - 'log(x, base)' - ], - 'description': 'Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).', - 'examples': [ - 'log(3.5)', - 'a = log(2.4)', - 'exp(a)', - '10 ^ 4', - 'log(10000, 10)', - 'log(10000) / log(10)', - 'b = log(1024, 2)', - '2 ^ b' - ], - 'seealso': [ - 'exp', - 'log1p', - 'log2', - 'log10' - ] - }; - - var log2 = { - 'name': 'log2', - 'category': 'Arithmetic', - 'syntax': [ - 'log2(x)' - ], - 'description': 'Calculate the 2-base of a value. This is the same as calculating `log(x, 2)`.', - 'examples': [ - 'log2(0.03125)', - 'log2(16)', - 'log2(16) / log2(2)', - 'pow(2, 4)' - ], - 'seealso': [ - 'exp', - 'log1p', - 'log', - 'log10' - ] - }; - - var log1p = { - 'name': 'log1p', - 'category': 'Arithmetic', - 'syntax': [ - 'log1p(x)', - 'log1p(x, base)' - ], - 'description': 'Calculate the logarithm of a `value+1`', - 'examples': [ - 'log1p(2.5)', - 'exp(log1p(1.4))', - 'pow(10, 4)', - 'log1p(9999, 10)', - 'log1p(9999) / log(10)' - ], - 'seealso': [ - 'exp', - 'log', - 'log2', - 'log10' - ] - }; - - var log10 = { - 'name': 'log10', - 'category': 'Arithmetic', - 'syntax': [ - 'log10(x)' - ], - 'description': 'Compute the 10-base logarithm of a value.', - 'examples': [ - 'log10(0.00001)', - 'log10(10000)', - '10 ^ 4', - 'log(10000) / log(10)', - 'log(10000, 10)' - ], - 'seealso': [ - 'exp', - 'log' - ] - }; - - var mod = { - 'name': 'mod', - 'category': 'Operators', - 'syntax': [ - 'x % y', - 'x mod y', - 'mod(x, y)' - ], - 'description': - 'Calculates the modulus, the remainder of an integer division.', - 'examples': [ - '7 % 3', - '11 % 2', - '10 mod 4', - 'isOdd(x) = x % 2', - 'isOdd(2)', - 'isOdd(3)' - ], - 'seealso': ['divide'] - }; - - var multiply = { - 'name': 'multiply', - 'category': 'Operators', - 'syntax': [ - 'x * y', - 'multiply(x, y)' - ], - 'description': 'multiply two values.', - 'examples': [ - 'a = 2.1 * 3.4', - 'a / 3.4', - '2 * 3 + 4', - '2 * (3 + 4)', - '3 * 2.1 km' - ], - 'seealso': [ - 'divide' - ] - }; - - var norm = { - 'name': 'norm', - 'category': 'Arithmetic', - 'syntax': [ - 'norm(x)', - 'norm(x, p)' - ], - 'description': 'Calculate the norm of a number, vector or matrix.', - 'examples': [ - 'abs(-3.5)', - 'norm(-3.5)', - 'norm(3 - 4i)', - 'norm([1, 2, -3], Infinity)', - 'norm([1, 2, -3], -Infinity)', - 'norm([3, 4], 2)', - 'norm([[1, 2], [3, 4]], 1)', - 'norm([[1, 2], [3, 4]], "inf")', - 'norm([[1, 2], [3, 4]], "fro")' - ] - }; - - var nthRoot = { - 'name': 'nthRoot', - 'category': 'Arithmetic', - 'syntax': [ - 'nthRoot(a)', - 'nthRoot(a, root)' - ], - 'description': 'Calculate the nth root of a value. ' + - 'The principal nth root of a positive real number A, ' + - 'is the positive real solution of the equation "x^root = A".', - 'examples': [ - '4 ^ 3', - 'nthRoot(64, 3)', - 'nthRoot(9, 2)', - 'sqrt(9)' - ], - 'seealso': [ - 'sqrt', - 'pow' - ] - }; - - var pow = { - 'name': 'pow', - 'category': 'Operators', - 'syntax': [ - 'x ^ y', - 'pow(x, y)' - ], - 'description': - 'Calculates the power of x to y, x^y.', - 'examples': [ - '2^3', - '2*2*2', - '1 + e ^ (pi * i)' - ], - 'seealso': [ 'multiply' ] - }; - - var round = { - 'name': 'round', - 'category': 'Arithmetic', - 'syntax': [ - 'round(x)', - 'round(x, n)' - ], - 'description': - 'round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.', - 'examples': [ - 'round(3.2)', - 'round(3.8)', - 'round(-4.2)', - 'round(-4.8)', - 'round(pi, 3)', - 'round(123.45678, 2)' - ], - 'seealso': ['ceil', 'floor', 'fix'] - }; - - var sign = { - 'name': 'sign', - 'category': 'Arithmetic', - 'syntax': [ - 'sign(x)' - ], - 'description': - 'Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.', - 'examples': [ - 'sign(3.5)', - 'sign(-4.2)', - 'sign(0)' - ], - 'seealso': [ - 'abs' - ] - }; - - var sqrt = { - 'name': 'sqrt', - 'category': 'Arithmetic', - 'syntax': [ - 'sqrt(x)' - ], - 'description': - 'Compute the square root value. If x = y * y, then y is the square root of x.', - 'examples': [ - 'sqrt(25)', - '5 * 5', - 'sqrt(-1)' - ], - 'seealso': [ - 'square', - 'sqrtm', - 'multiply' - ] - }; - - var sqrtm = { - 'name': 'sqrtm', - 'category': 'Arithmetic', - 'syntax': [ - 'sqrtm(x)' - ], - 'description': - 'Calculate the principal square root of a square matrix. The principal square root matrix `X` of another matrix `A` is such that `X * X = A`.', - 'examples': [ - 'sqrtm([[1, 2], [3, 4]])' - ], - 'seealso': [ - 'sqrt', - 'abs', - 'square', - 'multiply' - ] - }; - - var square = { - 'name': 'square', - 'category': 'Arithmetic', - 'syntax': [ - 'square(x)' - ], - 'description': - 'Compute the square of a value. The square of x is x * x.', - 'examples': [ - 'square(3)', - 'sqrt(9)', - '3^2', - '3 * 3' - ], - 'seealso': [ - 'multiply', - 'pow', - 'sqrt', - 'cube' - ] - }; - - var subtract = { - 'name': 'subtract', - 'category': 'Operators', - 'syntax': [ - 'x - y', - 'subtract(x, y)' - ], - 'description': 'subtract two values.', - 'examples': [ - 'a = 5.3 - 2', - 'a + 2', - '2/3 - 1/6', - '2 * 3 - 3', - '2.1 km - 500m' - ], - 'seealso': [ - 'add' - ] - }; - - var unaryMinus = { - 'name': 'unaryMinus', - 'category': 'Operators', - 'syntax': [ - '-x', - 'unaryMinus(x)' - ], - 'description': - 'Inverse the sign of a value. Converts booleans and strings to numbers.', - 'examples': [ - '-4.5', - '-(-5.6)', - '-"22"' - ], - 'seealso': [ - 'add', 'subtract', 'unaryPlus' - ] - }; - - var unaryPlus = { - 'name': 'unaryPlus', - 'category': 'Operators', - 'syntax': [ - '+x', - 'unaryPlus(x)' - ], - 'description': - 'Converts booleans and strings to numbers.', - 'examples': [ - '+true', - '+"2"' - ], - 'seealso': [ - 'add', 'subtract', 'unaryMinus' - ] - }; - - var xgcd = { - 'name': 'xgcd', - 'category': 'Arithmetic', - 'syntax': [ - 'xgcd(a, b)' - ], - 'description': 'Calculate the extended greatest common divisor for two values. The result is an array [d, x, y] with 3 entries, where d is the greatest common divisor, and d = x * a + y * b.', - 'examples': [ - 'xgcd(8, 12)', - 'gcd(8, 12)', - 'xgcd(36163, 21199)' - ], - 'seealso': [ 'gcd', 'lcm' ] - }; - - var bitAnd = { - 'name': 'bitAnd', - 'category': 'Bitwise', - 'syntax': [ - 'x & y', - 'bitAnd(x, y)' - ], - 'description': 'Bitwise AND operation. Performs the logical AND operation on each pair of the corresponding bits of the two given values by multiplying them. If both bits in the compared position are 1, the bit in the resulting binary representation is 1, otherwise, the result is 0', - 'examples': [ - '5 & 3', - 'bitAnd(53, 131)', - '[1, 12, 31] & 42' - ], - 'seealso': [ - 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' - ] - }; - - var bitNot = { - 'name': 'bitNot', - 'category': 'Bitwise', - 'syntax': [ - '~x', - 'bitNot(x)' - ], - 'description': 'Bitwise NOT operation. Performs a logical negation on each bit of the given value. Bits that are 0 become 1, and those that are 1 become 0.', - 'examples': [ - '~1', - '~2', - 'bitNot([2, -3, 4])' - ], - 'seealso': [ - 'bitAnd', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' - ] - }; - - var bitOr = { - 'name': 'bitOr', - 'category': 'Bitwise', - 'syntax': [ - 'x | y', - 'bitOr(x, y)' - ], - 'description': 'Bitwise OR operation. Performs the logical inclusive OR operation on each pair of corresponding bits of the two given values. The result in each position is 1 if the first bit is 1 or the second bit is 1 or both bits are 1, otherwise, the result is 0.', - 'examples': [ - '5 | 3', - 'bitOr([1, 2, 3], 4)' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitXor', 'leftShift', 'rightArithShift', 'rightLogShift' - ] - }; - - var bitXor = { - 'name': 'bitXor', - 'category': 'Bitwise', - 'syntax': [ - 'bitXor(x, y)' - ], - 'description': 'Bitwise XOR operation, exclusive OR. Performs the logical exclusive OR operation on each pair of corresponding bits of the two given values. The result in each position is 1 if only the first bit is 1 or only the second bit is 1, but will be 0 if both are 0 or both are 1.', - 'examples': [ - 'bitOr(1, 2)', - 'bitXor([2, 3, 4], 4)' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitOr', 'leftShift', 'rightArithShift', 'rightLogShift' - ] - }; - - var leftShift = { - 'name': 'leftShift', - 'category': 'Bitwise', - 'syntax': [ - 'x << y', - 'leftShift(x, y)' - ], - 'description': 'Bitwise left logical shift of a value x by y number of bits.', - 'examples': [ - '4 << 1', - '8 >> 1' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'rightArithShift', 'rightLogShift' - ] - }; - - var rightArithShift = { - 'name': 'rightArithShift', - 'category': 'Bitwise', - 'syntax': [ - 'x >> y', - 'rightArithShift(x, y)' - ], - 'description': 'Bitwise right arithmetic shift of a value x by y number of bits.', - 'examples': [ - '8 >> 1', - '4 << 1', - '-12 >> 2' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightLogShift' - ] - }; - - var rightLogShift = { - 'name': 'rightLogShift', - 'category': 'Bitwise', - 'syntax': [ - 'x >>> y', - 'rightLogShift(x, y)' - ], - 'description': 'Bitwise right logical shift of a value x by y number of bits.', - 'examples': [ - '8 >>> 1', - '4 << 1', - '-12 >>> 2' - ], - 'seealso': [ - 'bitAnd', 'bitNot', 'bitOr', 'bitXor', 'leftShift', 'rightArithShift' - ] - }; - - var bellNumbers = { - 'name': 'bellNumbers', - 'category': 'Combinatorics', - 'syntax': [ - 'bellNumbers(n)' - ], - 'description': 'The Bell Numbers count the number of partitions of a set. A partition is a pairwise disjoint subset of S whose union is S. `bellNumbers` only takes integer arguments. The following condition must be enforced: n >= 0.', - 'examples': [ - 'bellNumbers(3)', - 'bellNumbers(8)' - ], - 'seealso': ['stirlingS2'] - }; - - var catalan = { - 'name': 'catalan', - 'category': 'Combinatorics', - 'syntax': [ - 'catalan(n)' - ], - 'description': 'The Catalan Numbers enumerate combinatorial structures of many different types. catalan only takes integer arguments. The following condition must be enforced: n >= 0.', - 'examples': [ - 'catalan(3)', - 'catalan(8)' - ], - 'seealso': ['bellNumbers'] - }; - - var composition = { - 'name': 'composition', - 'category': 'Combinatorics', - 'syntax': [ - 'composition(n, k)' - ], - 'description': 'The composition counts of n into k parts. composition only takes integer arguments. The following condition must be enforced: k <= n.', - 'examples': [ - 'composition(5, 3)' - ], - 'seealso': ['combinations'] - }; - - var stirlingS2 = { - 'name': 'stirlingS2', - 'category': 'Combinatorics', - 'syntax': [ - 'stirlingS2(n, k)' - ], - 'description': 'he Stirling numbers of the second kind, counts the number of ways to partition a set of n labelled objects into k nonempty unlabelled subsets. `stirlingS2` only takes integer arguments. The following condition must be enforced: k <= n. If n = k or k = 1, then s(n,k) = 1.', - 'examples': [ - 'stirlingS2(5, 3)' - ], - 'seealso': ['bellNumbers'] - }; - - var config$1 = { - 'name': 'config', - 'category': 'Core', - 'syntax': [ - 'config()', - 'config(options)' - ], - 'description': 'Get configuration or change configuration.', - 'examples': [ - 'config()', - '1/3 + 1/4', - 'config({number: "Fraction"})', - '1/3 + 1/4' - ], - 'seealso': [] - }; - - var _import$1 = { - 'name': 'import', - 'category': 'Core', - 'syntax': [ - 'import(functions)', - 'import(functions, options)' - ], - 'description': 'Import functions or constants from an object.', - 'examples': [ - 'import({myFn: f(x)=x^2, myConstant: 32 })', - 'myFn(2)', - 'myConstant' - ], - 'seealso': [] - }; - - var typed$1 = { - 'name': 'typed', - 'category': 'Core', - 'syntax': [ - 'typed(signatures)', - 'typed(name, signatures)' - ], - 'description': 'Create a typed function.', - 'examples': [ - 'double = typed({ "number, number": f(x)=x+x })', - 'double(2)', - 'double("hello")' - ], - 'seealso': [] - }; - - var arg = { - 'name': 'arg', - 'category': 'Complex', - 'syntax': [ - 'arg(x)' - ], - 'description': - 'Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).', - 'examples': [ - 'arg(2 + 2i)', - 'atan2(3, 2)', - 'arg(2 + 3i)' - ], - 'seealso': [ - 're', - 'im', - 'conj', - 'abs' - ] - }; - - var conj = { - 'name': 'conj', - 'category': 'Complex', - 'syntax': [ - 'conj(x)' - ], - 'description': - 'Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.', - 'examples': [ - 'conj(2 + 3i)', - 'conj(2 - 3i)', - 'conj(-5.2i)' - ], - 'seealso': [ - 're', - 'im', - 'abs', - 'arg' - ] - }; - - var re = { - 'name': 're', - 'category': 'Complex', - 'syntax': [ - 're(x)' - ], - 'description': 'Get the real part of a complex number.', - 'examples': [ - 're(2 + 3i)', - 'im(2 + 3i)', - 're(-5.2i)', - 're(2.4)' - ], - 'seealso': [ - 'im', - 'conj', - 'abs', - 'arg' - ] - }; - - var im = { - 'name': 'im', - 'category': 'Complex', - 'syntax': [ - 'im(x)' - ], - 'description': 'Get the imaginary part of a complex number.', - 'examples': [ - 'im(2 + 3i)', - 're(2 + 3i)', - 'im(-5.2i)', - 'im(2.4)' - ], - 'seealso': [ - 're', - 'conj', - 'abs', - 'arg' - ] - }; - - var _eval = { - 'name': 'eval', - 'category': 'Expression', - 'syntax': [ - 'eval(expression)', - 'eval([expr1, expr2, expr3, ...])' - ], - 'description': 'Evaluate an expression or an array with expressions.', - 'examples': [ - 'eval("2 + 3")', - 'eval("sqrt(" + 4 + ")")' - ], - 'seealso': [] - }; - - var help = { - 'name': 'help', - 'category': 'Expression', - 'syntax': [ - 'help(object)', - 'help(string)' - ], - 'description': 'Display documentation on a function or data type.', - 'examples': [ - 'help(sqrt)', - 'help("complex")' - ], - 'seealso': [] - }; - - var distance = { - 'name': 'distance', - 'category': 'Geometry', - 'syntax': [ - 'distance([x1, y1], [x2, y2])', - 'distance([[x1, y1], [x2, y2])' - ], - 'description': 'Calculates the Euclidean distance between two points.', - 'examples': [ - 'distance([0,0], [4,4])', - 'distance([[0,0], [4,4]])' - ], - 'seealso': [] - }; - - var intersect = { - 'name': 'intersect', - 'category': 'Geometry', - 'syntax': [ - 'intersect(expr1, expr2, expr3, expr4)', - 'intersect(expr1, expr2, expr3)' - ], - 'description': 'Computes the intersection point of lines and/or planes.', - 'examples': [ - 'intersect([0, 0], [10, 10], [10, 0], [0, 10])', - 'intersect([1, 0, 1], [4, -2, 2], [1, 1, 1, 6])' - ], - 'seealso': [] - }; - - var and = { - 'name': 'and', - 'category': 'Logical', - 'syntax': [ - 'x and y', - 'and(x, y)' - ], - 'description': 'Logical and. Test whether two values are both defined with a nonzero/nonempty value.', - 'examples': [ - 'true and false', - 'true and true', - '2 and 4' - ], - 'seealso': [ - 'not', 'or', 'xor' - ] - }; - - var not = { - 'name': 'not', - 'category': 'Logical', - 'syntax': [ - 'not x', - 'not(x)' - ], - 'description': 'Logical not. Flips the boolean value of given argument.', - 'examples': [ - 'not true', - 'not false', - 'not 2', - 'not 0' - ], - 'seealso': [ - 'and', 'or', 'xor' - ] - }; - - var or = { - 'name': 'or', - 'category': 'Logical', - 'syntax': [ - 'x or y', - 'or(x, y)' - ], - 'description': 'Logical or. Test if at least one value is defined with a nonzero/nonempty value.', - 'examples': [ - 'true or false', - 'false or false', - '0 or 4' - ], - 'seealso': [ - 'not', 'and', 'xor' - ] - }; - - var xor = { - 'name': 'xor', - 'category': 'Logical', - 'syntax': [ - 'x xor y', - 'xor(x, y)' - ], - 'description': 'Logical exclusive or, xor. Test whether one and only one value is defined with a nonzero/nonempty value.', - 'examples': [ - 'true xor false', - 'false xor false', - 'true xor true', - '0 xor 4' - ], - 'seealso': [ - 'not', 'and', 'or' - ] - }; - - var concat = { - 'name': 'concat', - 'category': 'Matrix', - 'syntax': [ - 'concat(A, B, C, ...)', - 'concat(A, B, C, ..., dim)' - ], - 'description': 'Concatenate matrices. By default, the matrices are concatenated by the last dimension. The dimension on which to concatenate can be provided as last argument.', - 'examples': [ - 'A = [1, 2; 5, 6]', - 'B = [3, 4; 7, 8]', - 'concat(A, B)', - 'concat(A, B, 1)', - 'concat(A, B, 2)' - ], - 'seealso': [ - 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var cross = { - 'name': 'cross', - 'category': 'Matrix', - 'syntax': [ - 'cross(A, B)' - ], - 'description': 'Calculate the cross product for two vectors in three dimensional space.', - 'examples': [ - 'cross([1, 1, 0], [0, 1, 1])', - 'cross([3, -3, 1], [4, 9, 2])', - 'cross([2, 3, 4], [5, 6, 7])' - ], - 'seealso': [ - 'multiply', - 'dot' - ] - }; - - var det = { - 'name': 'det', - 'category': 'Matrix', - 'syntax': [ - 'det(x)' - ], - 'description': 'Calculate the determinant of a matrix', - 'examples': [ - 'det([1, 2; 3, 4])', - 'det([-2, 2, 3; -1, 1, 3; 2, 0, -1])' - ], - 'seealso': [ - 'concat', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var diag = { - 'name': 'diag', - 'category': 'Matrix', - 'syntax': [ - 'diag(x)', - 'diag(x, k)' - ], - 'description': 'Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned. When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.', - 'examples': [ - 'diag(1:3)', - 'diag(1:3, 1)', - 'a = [1, 2, 3; 4, 5, 6; 7, 8, 9]', - 'diag(a)' - ], - 'seealso': [ - 'concat', 'det', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var dot = { - 'name': 'dot', - 'category': 'Matrix', - 'syntax': [ - 'dot(A, B)', - 'A * B' - ], - 'description': 'Calculate the dot product of two vectors. ' + - 'The dot product of A = [a1, a2, a3, ..., an] and B = [b1, b2, b3, ..., bn] ' + - 'is defined as dot(A, B) = a1 * b1 + a2 * b2 + a3 * b3 + ... + an * bn', - 'examples': [ - 'dot([2, 4, 1], [2, 2, 3])', - '[2, 4, 1] * [2, 2, 3]' - ], - 'seealso': [ - 'multiply', - 'cross' - ] - }; - - var eye = { - 'name': 'eye', - 'category': 'Matrix', - 'syntax': [ - 'eye(n)', - 'eye(m, n)', - 'eye([m, n])' - ], - 'description': 'Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.', - 'examples': [ - 'eye(3)', - 'eye(3, 5)', - 'a = [1, 2, 3; 4, 5, 6]', - 'eye(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var filter = { - 'name': 'filter', - 'category': 'Matrix', - 'syntax': [ - 'filter(x, test)' - ], - 'description': 'Filter items in a matrix.', - 'examples': [ - 'isPositive(x) = x > 0', - 'filter([6, -2, -1, 4, 3], isPositive)', - 'filter([6, -2, 0, 1, 0], x != 0)' - ], - 'seealso': ['sort', 'map', 'forEach'] - }; - - var flatten$1 = { - 'name': 'flatten', - 'category': 'Matrix', - 'syntax': [ - 'flatten(x)' - ], - 'description': 'Flatten a multi dimensional matrix into a single dimensional matrix.', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'size(a)', - 'b = flatten(a)', - 'size(b)' - ], - 'seealso': [ - 'concat', 'resize', 'size', 'squeeze' - ] - }; - - var forEach = { - 'name': 'forEach', - 'category': 'Matrix', - 'syntax': [ - 'forEach(x, callback)' - ], - 'description': 'Iterates over all elements of a matrix/array, and executes the given callback function.', - 'examples': [ - 'forEach([1, 2, 3], function(val) { console.log(val) })' - ], - 'seealso': ['map', 'sort', 'filter'] - }; - - var inv = { - 'name': 'inv', - 'category': 'Matrix', - 'syntax': [ - 'inv(x)' - ], - 'description': 'Calculate the inverse of a matrix', - 'examples': [ - 'inv([1, 2; 3, 4])', - 'inv(4)', - '1 / 4' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var kron = { - 'name': 'kron', - 'category': 'Matrix', - 'syntax': [ - 'kron(x, y)' - ], - 'description': 'Calculates the kronecker product of 2 matrices or vectors.', - 'examples': [ - 'kron([[1, 0], [0, 1]], [[1, 2], [3, 4]])', - 'kron([1,1], [2,3,4])' - ], - 'seealso': [ - 'multiply', 'dot', 'cross' - ] - }; - - var map = { - 'name': 'map', - 'category': 'Matrix', - 'syntax': [ - 'map(x, callback)' - ], - 'description': 'Create a new matrix or array with the results of the callback function executed on each entry of the matrix/array.', - 'examples': [ - 'map([1, 2, 3], square)' - ], - 'seealso': ['filter', 'forEach'] - }; - - var ones = { - 'name': 'ones', - 'category': 'Matrix', - 'syntax': [ - 'ones(m)', - 'ones(m, n)', - 'ones(m, n, p, ...)', - 'ones([m])', - 'ones([m, n])', - 'ones([m, n, p, ...])' - ], - 'description': 'Create a matrix containing ones.', - 'examples': [ - 'ones(3)', - 'ones(3, 5)', - 'ones([2,3]) * 4.5', - 'a = [1, 2, 3; 4, 5, 6]', - 'ones(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var partitionSelect = { - 'name': 'partitionSelect', - 'category': 'Matrix', - 'syntax': [ - 'partitionSelect(x, k)', - 'partitionSelect(x, k, compare)' - ], - 'description': 'Partition-based selection of an array or 1D matrix. Will find the kth smallest value, and mutates the input array. Uses Quickselect.', - 'examples': [ - 'partitionSelect([5, 10, 1], 2)', - 'partitionSelect(["C", "B", "A", "D"], 1)' - ], - 'seealso': ['sort'] - }; - - var range = { - 'name': 'range', - 'category': 'Type', - 'syntax': [ - 'start:end', - 'start:step:end', - 'range(start, end)', - 'range(start, end, step)', - 'range(string)' - ], - 'description': - 'Create a range. Lower bound of the range is included, upper bound is excluded.', - 'examples': [ - '1:5', - '3:-1:-3', - 'range(3, 7)', - 'range(0, 12, 2)', - 'range("4:10")', - 'a = [1, 2, 3, 4; 5, 6, 7, 8]', - 'a[1:2, 1:2]' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'size', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var resize = { - 'name': 'resize', - 'category': 'Matrix', - 'syntax': [ - 'resize(x, size)', - 'resize(x, size, defaultValue)' - ], - 'description': 'Resize a matrix.', - 'examples': [ - 'resize([1,2,3,4,5], [3])', - 'resize([1,2,3], [5])', - 'resize([1,2,3], [5], -1)', - 'resize(2, [2, 3])', - 'resize("hello", [8], "!")' - ], - 'seealso': [ - 'size', 'subset', 'squeeze', 'reshape' - ] - }; - - var reshape = { - 'name': 'reshape', - 'category': 'Matrix', - 'syntax': [ - 'reshape(x, sizes)' - ], - 'description': 'Reshape a multi dimensional array to fit the specified dimensions.', - 'examples': [ - 'reshape([1, 2, 3, 4, 5, 6], [2, 3])', - 'reshape([[1, 2], [3, 4]], [1, 4])', - 'reshape([[1, 2], [3, 4]], [4])' - ], - 'seealso': [ - 'size', 'squeeze', 'resize' - ] - }; - - var size = { - 'name': 'size', - 'category': 'Matrix', - 'syntax': [ - 'size(x)' - ], - 'description': 'Calculate the size of a matrix.', - 'examples': [ - 'size(2.3)', - 'size("hello world")', - 'a = [1, 2; 3, 4; 5, 6]', - 'size(a)', - 'size(1:6)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'squeeze', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var sort = { - 'name': 'sort', - 'category': 'Matrix', - 'syntax': [ - 'sort(x)', - 'sort(x, compare)' - ], - 'description': 'Sort the items in a matrix. Compare can be a string "asc", "desc", "natural", or a custom sort function.', - 'examples': [ - 'sort([5, 10, 1])', - 'sort(["C", "B", "A", "D"])', - 'sortByLength(a, b) = size(a)[1] - size(b)[1]', - 'sort(["Langdon", "Tom", "Sara"], sortByLength)', - 'sort(["10", "1", "2"], "natural")' - ], - 'seealso': ['map', 'filter', 'forEach'] - }; - - var squeeze = { - 'name': 'squeeze', - 'category': 'Matrix', - 'syntax': [ - 'squeeze(x)' - ], - 'description': 'Remove inner and outer singleton dimensions from a matrix.', - 'examples': [ - 'a = zeros(3,2,1)', - 'size(squeeze(a))', - 'b = zeros(1,1,3)', - 'size(squeeze(b))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'subset', 'trace', 'transpose', 'zeros' - ] - }; - - var subset = { - 'name': 'subset', - 'category': 'Matrix', - 'syntax': [ - 'value(index)', - 'value(index) = replacement', - 'subset(value, [index])', - 'subset(value, [index], replacement)' - ], - 'description': 'Get or set a subset of a matrix or string. ' + - 'Indexes are one-based. ' + - 'Both the ranges lower-bound and upper-bound are included.', - 'examples': [ - 'd = [1, 2; 3, 4]', - 'e = []', - 'e[1, 1:2] = [5, 6]', - 'e[2, :] = [7, 8]', - 'f = d * e', - 'f[2, 1]', - 'f[:, 1]' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'trace', 'transpose', 'zeros' - ] - }; - - var trace = { - 'name': 'trace', - 'category': 'Matrix', - 'syntax': [ - 'trace(A)' - ], - 'description': 'Calculate the trace of a matrix: the sum of the elements on the main diagonal of a square matrix.', - 'examples': [ - 'A = [1, 2, 3; -1, 2, 3; 2, 0, 3]', - 'trace(A)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros' - ] - }; - - var transpose = { - 'name': 'transpose', - 'category': 'Matrix', - 'syntax': [ - 'x\'', - 'transpose(x)' - ], - 'description': 'Transpose a matrix', - 'examples': [ - 'a = [1, 2, 3; 4, 5, 6]', - 'a\'', - 'transpose(a)' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'zeros' - ] - }; - - var zeros = { - 'name': 'zeros', - 'category': 'Matrix', - 'syntax': [ - 'zeros(m)', - 'zeros(m, n)', - 'zeros(m, n, p, ...)', - 'zeros([m])', - 'zeros([m, n])', - 'zeros([m, n, p, ...])' - ], - 'description': 'Create a matrix containing zeros.', - 'examples': [ - 'zeros(3)', - 'zeros(3, 5)', - 'a = [1, 2, 3; 4, 5, 6]', - 'zeros(size(a))' - ], - 'seealso': [ - 'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'trace', 'transpose' - ] - }; - - var combinations = { - 'name': 'combinations', - 'category': 'Probability', - 'syntax': [ - 'combinations(n, k)' - ], - 'description': 'Compute the number of combinations of n items taken k at a time', - 'examples': [ - 'combinations(7, 5)' - ], - 'seealso': ['permutations', 'factorial'] - }; - - var factorial = { - 'name': 'factorial', - 'category': 'Probability', - 'syntax': [ - 'n!', - 'factorial(n)' - ], - 'description': 'Compute the factorial of a value', - 'examples': [ - '5!', - '5 * 4 * 3 * 2 * 1', - '3!' - ], - 'seealso': ['combinations', 'permutations', 'gamma'] - }; - - var gamma = { - 'name': 'gamma', - 'category': 'Probability', - 'syntax': [ - 'gamma(n)' - ], - 'description': 'Compute the gamma function. For small values, the Lanczos approximation is used, and for large values the extended Stirling approximation.', - 'examples': [ - 'gamma(4)', - '3!', - 'gamma(1/2)', - 'sqrt(pi)' - ], - 'seealso': ['factorial'] - }; - - var kldivergence = { - 'name': 'kldivergence', - 'category': 'Probability', - 'syntax': [ - 'kldivergence(x, y)' - ], - 'description': 'Calculate the Kullback-Leibler (KL) divergence between two distributions.', - 'examples': [ - 'kldivergence([0.7,0.5,0.4], [0.2,0.9,0.5])' - ], - 'seealso': [] - }; - - var multinomial = { - 'name': 'multinomial', - 'category': 'Probability', - 'syntax': [ - 'multinomial(A)' - ], - 'description': 'Multinomial Coefficients compute the number of ways of picking a1, a2, ..., ai unordered outcomes from `n` possibilities. multinomial takes one array of integers as an argument. The following condition must be enforced: every ai > 0.', - 'examples': [ - 'multinomial([1, 2, 1])' - ], - 'seealso': ['combinations', 'factorial'] - }; - - var permutations = { - 'name': 'permutations', - 'category': 'Probability', - 'syntax': [ - 'permutations(n)', - 'permutations(n, k)' - ], - 'description': 'Compute the number of permutations of n items taken k at a time', - 'examples': [ - 'permutations(5)', - 'permutations(5, 3)' - ], - 'seealso': ['combinations', 'factorial'] - }; - - var pickRandom = { - 'name': 'pickRandom', - 'category': 'Probability', - 'syntax': [ - 'pickRandom(array)', - 'pickRandom(array, number)', - 'pickRandom(array, weights)', - 'pickRandom(array, number, weights)', - 'pickRandom(array, weights, number)' - ], - 'description': - 'Pick a random entry from a given array.', - 'examples': [ - 'pickRandom(0:10)', - 'pickRandom([1, 3, 1, 6])', - 'pickRandom([1, 3, 1, 6], 2)', - 'pickRandom([1, 3, 1, 6], [2, 3, 2, 1])', - 'pickRandom([1, 3, 1, 6], 2, [2, 3, 2, 1])', - 'pickRandom([1, 3, 1, 6], [2, 3, 2, 1], 2)' - ], - 'seealso': ['random', 'randomInt'] - }; - - var random = { - 'name': 'random', - 'category': 'Probability', - 'syntax': [ - 'random()', - 'random(max)', - 'random(min, max)', - 'random(size)', - 'random(size, max)', - 'random(size, min, max)' - ], - 'description': - 'Return a random number.', - 'examples': [ - 'random()', - 'random(10, 20)', - 'random([2, 3])' - ], - 'seealso': ['pickRandom', 'randomInt'] - }; - - var randomInt = { - 'name': 'randomInt', - 'category': 'Probability', - 'syntax': [ - 'randomInt(max)', - 'randomInt(min, max)', - 'randomInt(size)', - 'randomInt(size, max)', - 'randomInt(size, min, max)' - ], - 'description': - 'Return a random integer number', - 'examples': [ - 'randomInt(10, 20)', - 'randomInt([2, 3], 10)' - ], - 'seealso': ['pickRandom', 'random'] - }; - - var compare = { - 'name': 'compare', - 'category': 'Relational', - 'syntax': [ - 'compare(x, y)' - ], - 'description': - 'Compare two values. ' + - 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', - 'examples': [ - 'compare(2, 3)', - 'compare(3, 2)', - 'compare(2, 2)', - 'compare(5cm, 40mm)', - 'compare(2, [1, 2, 3])' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compareNatural', 'compareText' - ] - }; - - var compareNatural = { - 'name': 'compareNatural', - 'category': 'Relational', - 'syntax': [ - 'compareNatural(x, y)' - ], - 'description': - 'Compare two values of any type in a deterministic, natural way. ' + - 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', - 'examples': [ - 'compareNatural(2, 3)', - 'compareNatural(3, 2)', - 'compareNatural(2, 2)', - 'compareNatural(5cm, 40mm)', - 'compareNatural("2", "10")', - 'compareNatural(2 + 3i, 2 + 4i)', - 'compareNatural([1, 2, 4], [1, 2, 3])', - 'compareNatural([1, 5], [1, 2, 3])', - 'compareNatural([1, 2], [1, 2])', - 'compareNatural({a: 2}, {a: 4})' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compare', 'compareText' - ] - }; - - var compareText = { - 'name': 'compareText', - 'category': 'Relational', - 'syntax': [ - 'compareText(x, y)' - ], - 'description': - 'Compare two strings lexically. Comparison is case sensitive. ' + - 'Returns 1 when x > y, -1 when x < y, and 0 when x == y.', - 'examples': [ - 'compareText("B", "A")', - 'compareText("A", "B")', - 'compareText("A", "A")', - 'compareText("2", "10")', - 'compare("2", "10")', - 'compare(2, 10)', - 'compareNatural("2", "10")', - 'compareText("B", ["A", "B", "C"])' - ], - 'seealso': [ - 'compare', 'compareNatural' - ] - }; - - var deepEqual = { - 'name': 'deepEqual', - 'category': 'Relational', - 'syntax': [ - 'deepEqual(x, y)' - ], - 'description': - 'Check equality of two matrices element wise. Returns true if the size of both matrices is equal and when and each of the elements are equal.', - 'examples': [ - 'deepEqual([1,3,4], [1,3,4])', - 'deepEqual([1,3,4], [1,3])' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare' - ] - }; - - var equal = { - 'name': 'equal', - 'category': 'Relational', - 'syntax': [ - 'x == y', - 'equal(x, y)' - ], - 'description': - 'Check equality of two values. Returns true if the values are equal, and false if not.', - 'examples': [ - '2+2 == 3', - '2+2 == 4', - 'a = 3.2', - 'b = 6-2.8', - 'a == b', - '50cm == 0.5m' - ], - 'seealso': [ - 'unequal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare', 'deepEqual', 'equalText' - ] - }; - - var equalText = { - 'name': 'equalText', - 'category': 'Relational', - 'syntax': [ - 'equalText(x, y)' - ], - 'description': - 'Check equality of two strings. Comparison is case sensitive. Returns true if the values are equal, and false if not.', - 'examples': [ - 'equalText("Hello", "Hello")', - 'equalText("a", "A")', - 'equal("2e3", "2000")', - 'equalText("2e3", "2000")', - 'equalText("B", ["A", "B", "C"])' - ], - 'seealso': [ - 'compare', 'compareNatural', 'compareText', 'equal' - ] - }; - - var larger$1 = { - 'name': 'larger', - 'category': 'Relational', - 'syntax': [ - 'x > y', - 'larger(x, y)' - ], - 'description': - 'Check if value x is larger than y. Returns true if x is larger than y, and false if not.', - 'examples': [ - '2 > 3', - '5 > 2*2', - 'a = 3.3', - 'b = 6-2.8', - '(a > b)', - '(b < a)', - '5 cm > 2 inch' - ], - 'seealso': [ - 'equal', 'unequal', 'smaller', 'smallerEq', 'largerEq', 'compare' - ] - }; - - var largerEq = { - 'name': 'largerEq', - 'category': 'Relational', - 'syntax': [ - 'x >= y', - 'largerEq(x, y)' - ], - 'description': - 'Check if value x is larger or equal to y. Returns true if x is larger or equal to y, and false if not.', - 'examples': [ - '2 >= 1+1', - '2 > 1+1', - 'a = 3.2', - 'b = 6-2.8', - '(a >= b)' - ], - 'seealso': [ - 'equal', 'unequal', 'smallerEq', 'smaller', 'compare' - ] - }; - - var smaller$1 = { - 'name': 'smaller', - 'category': 'Relational', - 'syntax': [ - 'x < y', - 'smaller(x, y)' - ], - 'description': - 'Check if value x is smaller than value y. Returns true if x is smaller than y, and false if not.', - 'examples': [ - '2 < 3', - '5 < 2*2', - 'a = 3.3', - 'b = 6-2.8', - '(a < b)', - '5 cm < 2 inch' - ], - 'seealso': [ - 'equal', 'unequal', 'larger', 'smallerEq', 'largerEq', 'compare' - ] - }; - - var smallerEq = { - 'name': 'smallerEq', - 'category': 'Relational', - 'syntax': [ - 'x <= y', - 'smallerEq(x, y)' - ], - 'description': - 'Check if value x is smaller or equal to value y. Returns true if x is smaller than y, and false if not.', - 'examples': [ - '2 <= 1+1', - '2 < 1+1', - 'a = 3.2', - 'b = 6-2.8', - '(a <= b)' - ], - 'seealso': [ - 'equal', 'unequal', 'larger', 'smaller', 'largerEq', 'compare' - ] - }; - - var unequal = { - 'name': 'unequal', - 'category': 'Relational', - 'syntax': [ - 'x != y', - 'unequal(x, y)' - ], - 'description': - 'Check unequality of two values. Returns true if the values are unequal, and false if they are equal.', - 'examples': [ - '2+2 != 3', - '2+2 != 4', - 'a = 3.2', - 'b = 6-2.8', - 'a != b', - '50cm != 0.5m', - '5 cm != 2 inch' - ], - 'seealso': [ - 'equal', 'smaller', 'larger', 'smallerEq', 'largerEq', 'compare', 'deepEqual' - ] - }; - - var setCartesian = { - 'name': 'setCartesian', - 'category': 'Set', - 'syntax': [ - 'setCartesian(set1, set2)' - ], - 'description': - 'Create the cartesian product of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setCartesian([1, 2], [3, 4])' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setDifference', 'setPowerset' - ] - }; - - var setDifference = { - 'name': 'setDifference', - 'category': 'Set', - 'syntax': [ - 'setDifference(set1, set2)' - ], - 'description': - 'Create the difference of two (multi)sets: every element of set1, that is not the element of set2. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setDifference([1, 2, 3, 4], [3, 4, 5, 6])', - 'setDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]])' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setSymDifference' - ] - }; - - var setDistinct = { - 'name': 'setDistinct', - 'category': 'Set', - 'syntax': [ - 'setDistinct(set)' - ], - 'description': - 'Collect the distinct elements of a multiset. A multi-dimension array will be converted to a single-dimension array before the operation.', - 'examples': [ - 'setDistinct([1, 1, 1, 2, 2, 3])' - ], - 'seealso': [ - 'setMultiplicity' - ] - }; - - var setIntersect = { - 'name': 'setIntersect', - 'category': 'Set', - 'syntax': [ - 'setIntersect(set1, set2)' - ], - 'description': - 'Create the intersection of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setIntersect([1, 2, 3, 4], [3, 4, 5, 6])', - 'setIntersect([[1, 2], [3, 4]], [[3, 4], [5, 6]])' - ], - 'seealso': [ - 'setUnion', 'setDifference' - ] - }; - - var setIsSubset = { - 'name': 'setIsSubset', - 'category': 'Set', - 'syntax': [ - 'setIsSubset(set1, set2)' - ], - 'description': - 'Check whether a (multi)set is a subset of another (multi)set: every element of set1 is the element of set2. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setIsSubset([1, 2], [3, 4, 5, 6])', - 'setIsSubset([3, 4], [3, 4, 5, 6])' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setDifference' - ] - }; - - var setMultiplicity = { - 'name': 'setMultiplicity', - 'category': 'Set', - 'syntax': [ - 'setMultiplicity(element, set)' - ], - 'description': - 'Count the multiplicity of an element in a multiset. A multi-dimension array will be converted to a single-dimension array before the operation.', - 'examples': [ - 'setMultiplicity(1, [1, 2, 2, 4])', - 'setMultiplicity(2, [1, 2, 2, 4])' - ], - 'seealso': [ - 'setDistinct', 'setSize' - ] - }; - - var setPowerset = { - 'name': 'setPowerset', - 'category': 'Set', - 'syntax': [ - 'setPowerset(set)' - ], - 'description': - 'Create the powerset of a (multi)set: the powerset contains very possible subsets of a (multi)set. A multi-dimension array will be converted to a single-dimension array before the operation.', - 'examples': [ - 'setPowerset([1, 2, 3])' - ], - 'seealso': [ - 'setCartesian' - ] - }; - - var setSize = { - 'name': 'setSize', - 'category': 'Set', - 'syntax': [ - 'setSize(set)', - 'setSize(set, unique)' - ], - 'description': - 'Count the number of elements of a (multi)set. When the second parameter "unique" is true, count only the unique values. A multi-dimension array will be converted to a single-dimension array before the operation.', - 'examples': [ - 'setSize([1, 2, 2, 4])', - 'setSize([1, 2, 2, 4], true)' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setDifference' - ] - }; - - var setSymDifference = { - 'name': 'setSymDifference', - 'category': 'Set', - 'syntax': [ - 'setSymDifference(set1, set2)' - ], - 'description': - 'Create the symmetric difference of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setSymDifference([1, 2, 3, 4], [3, 4, 5, 6])', - 'setSymDifference([[1, 2], [3, 4]], [[3, 4], [5, 6]])' - ], - 'seealso': [ - 'setUnion', 'setIntersect', 'setDifference' - ] - }; - - var setUnion = { - 'name': 'setUnion', - 'category': 'Set', - 'syntax': [ - 'setUnion(set1, set2)' - ], - 'description': - 'Create the union of two (multi)sets. Multi-dimension arrays will be converted to single-dimension arrays before the operation.', - 'examples': [ - 'setUnion([1, 2, 3, 4], [3, 4, 5, 6])', - 'setUnion([[1, 2], [3, 4]], [[3, 4], [5, 6]])' - ], - 'seealso': [ - 'setIntersect', 'setDifference' - ] - }; - - var erf = { - 'name': 'erf', - 'category': 'Special', - 'syntax': [ - 'erf(x)' - ], - 'description': 'Compute the erf function of a value using a rational Chebyshev approximations for different intervals of x', - 'examples': [ - 'erf(0.2)', - 'erf(-0.5)', - 'erf(4)' - ], - 'seealso': [] - }; - - var mad = { - 'name': 'mad', - 'category': 'Statistics', - 'syntax': [ - 'mad(a, b, c, ...)', - 'mad(A)' - ], - 'description': 'Compute the median absolute deviation of a matrix or a list with values. The median absolute deviation is defined as the median of the absolute deviations from the median.', - 'examples': [ - 'mad(10, 20, 30)', - 'mad([1, 2, 3])' - ], - 'seealso': [ - 'mean', - 'median', - 'std', - 'abs' - ] - }; - - var max = { - 'name': 'max', - 'category': 'Statistics', - 'syntax': [ - 'max(a, b, c, ...)', - 'max(A)', - 'max(A, dim)' - ], - 'description': 'Compute the maximum value of a list of values.', - 'examples': [ - 'max(2, 3, 4, 1)', - 'max([2, 3, 4, 1])', - 'max([2, 5; 4, 3])', - 'max([2, 5; 4, 3], 1)', - 'max([2, 5; 4, 3], 2)', - 'max(2.7, 7.1, -4.5, 2.0, 4.1)', - 'min(2.7, 7.1, -4.5, 2.0, 4.1)' - ], - 'seealso': [ - 'mean', - 'median', - 'min', - 'prod', - 'std', - 'sum', - 'var' - ] - }; - - var mean = { - 'name': 'mean', - 'category': 'Statistics', - 'syntax': [ - 'mean(a, b, c, ...)', - 'mean(A)', - 'mean(A, dim)' - ], - 'description': 'Compute the arithmetic mean of a list of values.', - 'examples': [ - 'mean(2, 3, 4, 1)', - 'mean([2, 3, 4, 1])', - 'mean([2, 5; 4, 3])', - 'mean([2, 5; 4, 3], 1)', - 'mean([2, 5; 4, 3], 2)', - 'mean([1.0, 2.7, 3.2, 4.0])' - ], - 'seealso': [ - 'max', - 'median', - 'min', - 'prod', - 'std', - 'sum', - 'var' - ] - }; - - var median = { - 'name': 'median', - 'category': 'Statistics', - 'syntax': [ - 'median(a, b, c, ...)', - 'median(A)' - ], - 'description': 'Compute the median of all values. The values are sorted and the middle value is returned. In case of an even number of values, the average of the two middle values is returned.', - 'examples': [ - 'median(5, 2, 7)', - 'median([3, -1, 5, 7])' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'prod', - 'std', - 'sum', - 'var', - 'quantileSeq' - ] - }; - - var min = { - 'name': 'min', - 'category': 'Statistics', - 'syntax': [ - 'min(a, b, c, ...)', - 'min(A)', - 'min(A, dim)' - ], - 'description': 'Compute the minimum value of a list of values.', - 'examples': [ - 'min(2, 3, 4, 1)', - 'min([2, 3, 4, 1])', - 'min([2, 5; 4, 3])', - 'min([2, 5; 4, 3], 1)', - 'min([2, 5; 4, 3], 2)', - 'min(2.7, 7.1, -4.5, 2.0, 4.1)', - 'max(2.7, 7.1, -4.5, 2.0, 4.1)' - ], - 'seealso': [ - 'max', - 'mean', - 'median', - 'prod', - 'std', - 'sum', - 'var' - ] - }; - - var mode = { - 'name': 'mode', - 'category': 'Statistics', - 'syntax': [ - 'mode(a, b, c, ...)', - 'mode(A)', - 'mode(A, a, b, B, c, ...)' - ], - 'description': 'Computes the mode of all values as an array. In case mode being more than one, multiple values are returned in an array.', - 'examples': [ - 'mode(2, 1, 4, 3, 1)', - 'mode([1, 2.7, 3.2, 4, 2.7])', - 'mode(1, 4, 6, 1, 6)' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'median', - 'prod', - 'std', - 'sum', - 'var' - ] - }; - - var prod = { - 'name': 'prod', - 'category': 'Statistics', - 'syntax': [ - 'prod(a, b, c, ...)', - 'prod(A)' - ], - 'description': 'Compute the product of all values.', - 'examples': [ - 'prod(2, 3, 4)', - 'prod([2, 3, 4])', - 'prod([2, 5; 4, 3])' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'median', - 'min', - 'std', - 'sum', - 'var' - ] - }; - - var quantileSeq = { - 'name': 'quantileSeq', - 'category': 'Statistics', - 'syntax': [ - 'quantileSeq(A, prob[, sorted])', - 'quantileSeq(A, [prob1, prob2, ...][, sorted])', - 'quantileSeq(A, N[, sorted])' - ], - 'description': 'Compute the prob order quantile of a matrix or a list with values. The sequence is sorted and the middle value is returned. Supported types of sequence values are: Number, BigNumber, Unit Supported types of probablity are: Number, BigNumber. \n\nIn case of a (multi dimensional) array or matrix, the prob order quantile of all elements will be calculated.', - 'examples': [ - 'quantileSeq([3, -1, 5, 7], 0.5)', - 'quantileSeq([3, -1, 5, 7], [1/3, 2/3])', - 'quantileSeq([3, -1, 5, 7], 2)', - 'quantileSeq([-1, 3, 5, 7], 0.5, true)' - ], - 'seealso': [ - 'mean', - 'median', - 'min', - 'max', - 'prod', - 'std', - 'sum', - 'var' - ] - }; - - var std = { - 'name': 'std', - 'category': 'Statistics', - 'syntax': [ - 'std(a, b, c, ...)', - 'std(A)', - 'std(A, normalization)' - ], - 'description': 'Compute the standard deviation of all values, defined as std(A) = sqrt(var(A)). Optional parameter normalization can be "unbiased" (default), "uncorrected", or "biased".', - 'examples': [ - 'std(2, 4, 6)', - 'std([2, 4, 6, 8])', - 'std([2, 4, 6, 8], "uncorrected")', - 'std([2, 4, 6, 8], "biased")', - 'std([1, 2, 3; 4, 5, 6])' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'median', - 'min', - 'prod', - 'sum', - 'var' - ] - }; - - var sum = { - 'name': 'sum', - 'category': 'Statistics', - 'syntax': [ - 'sum(a, b, c, ...)', - 'sum(A)' - ], - 'description': 'Compute the sum of all values.', - 'examples': [ - 'sum(2, 3, 4, 1)', - 'sum([2, 3, 4, 1])', - 'sum([2, 5; 4, 3])' - ], - 'seealso': [ - 'max', - 'mean', - 'median', - 'min', - 'prod', - 'std', - 'sum', - 'var' - ] - }; - - var _var = { - 'name': 'var', - 'category': 'Statistics', - 'syntax': [ - 'var(a, b, c, ...)', - 'var(A)', - 'var(A, normalization)' - ], - 'description': 'Compute the variance of all values. Optional parameter normalization can be "unbiased" (default), "uncorrected", or "biased".', - 'examples': [ - 'var(2, 4, 6)', - 'var([2, 4, 6, 8])', - 'var([2, 4, 6, 8], "uncorrected")', - 'var([2, 4, 6, 8], "biased")', - 'var([1, 2, 3; 4, 5, 6])' - ], - 'seealso': [ - 'max', - 'mean', - 'min', - 'median', - 'min', - 'prod', - 'std', - 'sum' - ] - }; - - var acos = { - 'name': 'acos', - 'category': 'Trigonometry', - 'syntax': [ - 'acos(x)' - ], - 'description': 'Compute the inverse cosine of a value in radians.', - 'examples': [ - 'acos(0.5)', - 'acos(cos(2.3))' - ], - 'seealso': [ - 'cos', - 'atan', - 'asin' - ] - }; - - var acosh = { - 'name': 'acosh', - 'category': 'Trigonometry', - 'syntax': [ - 'acosh(x)' - ], - 'description': 'Calculate the hyperbolic arccos of a value, defined as `acosh(x) = ln(sqrt(x^2 - 1) + x)`.', - 'examples': [ - 'acosh(1.5)' - ], - 'seealso': [ - 'cosh', - 'asinh', - 'atanh' - ] - }; - - var acot = { - 'name': 'acot', - 'category': 'Trigonometry', - 'syntax': [ - 'acot(x)' - ], - 'description': 'Calculate the inverse cotangent of a value.', - 'examples': [ - 'acot(0.5)', - 'acot(cot(0.5))', - 'acot(2)' - ], - 'seealso': [ - 'cot', - 'atan' - ] - }; - - var acoth = { - 'name': 'acoth', - 'category': 'Trigonometry', - 'syntax': [ - 'acoth(x)' - ], - 'description': 'Calculate the hyperbolic arccotangent of a value, defined as `acoth(x) = (ln((x+1)/x) + ln(x/(x-1))) / 2`.', - 'examples': [ - 'acoth(2)', - 'acoth(0.5)' - ], - 'seealso': [ - 'acsch', - 'asech' - ] - }; - - var acsc = { - 'name': 'acsc', - 'category': 'Trigonometry', - 'syntax': [ - 'acsc(x)' - ], - 'description': 'Calculate the inverse cotangent of a value.', - 'examples': [ - 'acsc(2)', - 'acsc(csc(0.5))', - 'acsc(0.5)' - ], - 'seealso': [ - 'csc', - 'asin', - 'asec' - ] - }; - - var acsch = { - 'name': 'acsch', - 'category': 'Trigonometry', - 'syntax': [ - 'acsch(x)' - ], - 'description': 'Calculate the hyperbolic arccosecant of a value, defined as `acsch(x) = ln(1/x + sqrt(1/x^2 + 1))`.', - 'examples': [ - 'acsch(0.5)' - ], - 'seealso': [ - 'asech', - 'acoth' - ] - }; - - var asec = { - 'name': 'asec', - 'category': 'Trigonometry', - 'syntax': [ - 'asec(x)' - ], - 'description': 'Calculate the inverse secant of a value.', - 'examples': [ - 'asec(0.5)', - 'asec(sec(0.5))', - 'asec(2)' - ], - 'seealso': [ - 'acos', - 'acot', - 'acsc' - ] - }; - - var asech = { - 'name': 'asech', - 'category': 'Trigonometry', - 'syntax': [ - 'asech(x)' - ], - 'description': 'Calculate the inverse secant of a value.', - 'examples': [ - 'asech(0.5)' - ], - 'seealso': [ - 'acsch', - 'acoth' - ] - }; - - var asin = { - 'name': 'asin', - 'category': 'Trigonometry', - 'syntax': [ - 'asin(x)' - ], - 'description': 'Compute the inverse sine of a value in radians.', - 'examples': [ - 'asin(0.5)', - 'asin(sin(0.5))' - ], - 'seealso': [ - 'sin', - 'acos', - 'atan' - ] - }; - - var asinh = { - 'name': 'asinh', - 'category': 'Trigonometry', - 'syntax': [ - 'asinh(x)' - ], - 'description': 'Calculate the hyperbolic arcsine of a value, defined as `asinh(x) = ln(x + sqrt(x^2 + 1))`.', - 'examples': [ - 'asinh(0.5)' - ], - 'seealso': [ - 'acosh', - 'atanh' - ] - }; - - var atan = { - 'name': 'atan', - 'category': 'Trigonometry', - 'syntax': [ - 'atan(x)' - ], - 'description': 'Compute the inverse tangent of a value in radians.', - 'examples': [ - 'atan(0.5)', - 'atan(tan(0.5))' - ], - 'seealso': [ - 'tan', - 'acos', - 'asin' - ] - }; - - var atanh = { - 'name': 'atanh', - 'category': 'Trigonometry', - 'syntax': [ - 'atanh(x)' - ], - 'description': 'Calculate the hyperbolic arctangent of a value, defined as `atanh(x) = ln((1 + x)/(1 - x)) / 2`.', - 'examples': [ - 'atanh(0.5)' - ], - 'seealso': [ - 'acosh', - 'asinh' - ] - }; - - var atan2 = { - 'name': 'atan2', - 'category': 'Trigonometry', - 'syntax': [ - 'atan2(y, x)' - ], - 'description': - 'Computes the principal value of the arc tangent of y/x in radians.', - 'examples': [ - 'atan2(2, 2) / pi', - 'angle = 60 deg in rad', - 'x = cos(angle)', - 'y = sin(angle)', - 'atan2(y, x)' - ], - 'seealso': [ - 'sin', - 'cos', - 'tan' - ] - }; - - var cos = { - 'name': 'cos', - 'category': 'Trigonometry', - 'syntax': [ - 'cos(x)' - ], - 'description': 'Compute the cosine of x in radians.', - 'examples': [ - 'cos(2)', - 'cos(pi / 4) ^ 2', - 'cos(180 deg)', - 'cos(60 deg)', - 'sin(0.2)^2 + cos(0.2)^2' - ], - 'seealso': [ - 'acos', - 'sin', - 'tan' - ] - }; - - var cosh = { - 'name': 'cosh', - 'category': 'Trigonometry', - 'syntax': [ - 'cosh(x)' - ], - 'description': 'Compute the hyperbolic cosine of x in radians.', - 'examples': [ - 'cosh(0.5)' - ], - 'seealso': [ - 'sinh', - 'tanh', - 'coth' - ] - }; - - var cot = { - 'name': 'cot', - 'category': 'Trigonometry', - 'syntax': [ - 'cot(x)' - ], - 'description': 'Compute the cotangent of x in radians. Defined as 1/tan(x)', - 'examples': [ - 'cot(2)', - '1 / tan(2)' - ], - 'seealso': [ - 'sec', - 'csc', - 'tan' - ] - }; - - var coth = { - 'name': 'coth', - 'category': 'Trigonometry', - 'syntax': [ - 'coth(x)' - ], - 'description': 'Compute the hyperbolic cotangent of x in radians.', - 'examples': [ - 'coth(2)', - '1 / tanh(2)' - ], - 'seealso': [ - 'sech', - 'csch', - 'tanh' - ] - }; - - var csc = { - 'name': 'csc', - 'category': 'Trigonometry', - 'syntax': [ - 'csc(x)' - ], - 'description': 'Compute the cosecant of x in radians. Defined as 1/sin(x)', - 'examples': [ - 'csc(2)', - '1 / sin(2)' - ], - 'seealso': [ - 'sec', - 'cot', - 'sin' - ] - }; - - var csch = { - 'name': 'csch', - 'category': 'Trigonometry', - 'syntax': [ - 'csch(x)' - ], - 'description': 'Compute the hyperbolic cosecant of x in radians. Defined as 1/sinh(x)', - 'examples': [ - 'csch(2)', - '1 / sinh(2)' - ], - 'seealso': [ - 'sech', - 'coth', - 'sinh' - ] - }; - - var sec = { - 'name': 'sec', - 'category': 'Trigonometry', - 'syntax': [ - 'sec(x)' - ], - 'description': 'Compute the secant of x in radians. Defined as 1/cos(x)', - 'examples': [ - 'sec(2)', - '1 / cos(2)' - ], - 'seealso': [ - 'cot', - 'csc', - 'cos' - ] - }; - - var sech = { - 'name': 'sech', - 'category': 'Trigonometry', - 'syntax': [ - 'sech(x)' - ], - 'description': 'Compute the hyperbolic secant of x in radians. Defined as 1/cosh(x)', - 'examples': [ - 'sech(2)', - '1 / cosh(2)' - ], - 'seealso': [ - 'coth', - 'csch', - 'cosh' - ] - }; - - var sin = { - 'name': 'sin', - 'category': 'Trigonometry', - 'syntax': [ - 'sin(x)' - ], - 'description': 'Compute the sine of x in radians.', - 'examples': [ - 'sin(2)', - 'sin(pi / 4) ^ 2', - 'sin(90 deg)', - 'sin(30 deg)', - 'sin(0.2)^2 + cos(0.2)^2' - ], - 'seealso': [ - 'asin', - 'cos', - 'tan' - ] - }; - - var sinh = { - 'name': 'sinh', - 'category': 'Trigonometry', - 'syntax': [ - 'sinh(x)' - ], - 'description': 'Compute the hyperbolic sine of x in radians.', - 'examples': [ - 'sinh(0.5)' - ], - 'seealso': [ - 'cosh', - 'tanh' - ] - }; - - var tan = { - 'name': 'tan', - 'category': 'Trigonometry', - 'syntax': [ - 'tan(x)' - ], - 'description': 'Compute the tangent of x in radians.', - 'examples': [ - 'tan(0.5)', - 'sin(0.5) / cos(0.5)', - 'tan(pi / 4)', - 'tan(45 deg)' - ], - 'seealso': [ - 'atan', - 'sin', - 'cos' - ] - }; - - var tanh = { - 'name': 'tanh', - 'category': 'Trigonometry', - 'syntax': [ - 'tanh(x)' - ], - 'description': 'Compute the hyperbolic tangent of x in radians.', - 'examples': [ - 'tanh(0.5)', - 'sinh(0.5) / cosh(0.5)' - ], - 'seealso': [ - 'sinh', - 'cosh' - ] - }; - - var to = { - 'name': 'to', - 'category': 'Units', - 'syntax': [ - 'x to unit', - 'to(x, unit)' - ], - 'description': 'Change the unit of a value.', - 'examples': [ - '5 inch to cm', - '3.2kg to g', - '16 bytes in bits' - ], - 'seealso': [] - }; - - var clone$2 = { - 'name': 'clone', - 'category': 'Utils', - 'syntax': [ - 'clone(x)' - ], - 'description': 'Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices', - 'examples': [ - 'clone(3.5)', - 'clone(2 - 4i)', - 'clone(45 deg)', - 'clone([1, 2; 3, 4])', - 'clone("hello world")' - ], - 'seealso': [] - }; - - var format$2 = { - 'name': 'format', - 'category': 'Utils', - 'syntax': [ - 'format(value)', - 'format(value, precision)' - ], - 'description': 'Format a value of any type as string.', - 'examples': [ - 'format(2.3)', - 'format(3 - 4i)', - 'format([])', - 'format(pi, 3)' - ], - 'seealso': ['print'] - }; - - var _isNaN = { - 'name': 'isNaN', - 'category': 'Utils', - 'syntax': [ - 'isNaN(x)' - ], - 'description': 'Test whether a value is NaN (not a number)', - 'examples': [ - 'isNaN(2)', - 'isNaN(0 / 0)', - 'isNaN(NaN)', - 'isNaN(Infinity)' - ], - 'seealso': ['isNegative', 'isNumeric', 'isPositive', 'isZero'] - }; - - var isInteger$3 = { - 'name': 'isInteger', - 'category': 'Utils', - 'syntax': [ - 'isInteger(x)' - ], - 'description': 'Test whether a value is an integer number.', - 'examples': [ - 'isInteger(2)', - 'isInteger(3.5)', - 'isInteger([3, 0.5, -2])' - ], - 'seealso': ['isNegative', 'isNumeric', 'isPositive', 'isZero'] - }; - - var isNegative = { - 'name': 'isNegative', - 'category': 'Utils', - 'syntax': [ - 'isNegative(x)' - ], - 'description': 'Test whether a value is negative: smaller than zero.', - 'examples': [ - 'isNegative(2)', - 'isNegative(0)', - 'isNegative(-4)', - 'isNegative([3, 0.5, -2])' - ], - 'seealso': ['isInteger', 'isNumeric', 'isPositive', 'isZero'] - }; - - var isNumeric = { - 'name': 'isNumeric', - 'category': 'Utils', - 'syntax': [ - 'isNumeric(x)' - ], - 'description': 'Test whether a value is a numeric value. ' + - 'Returns true when the input is a number, BigNumber, Fraction, or boolean.', - 'examples': [ - 'isNumeric(2)', - 'isNumeric(0)', - 'isNumeric(bignumber(500))', - 'isNumeric(fraction(0.125))', - 'isNumeric("3")', - 'isNumeric(2 + 3i)', - 'isNumeric([2.3, "foo", false])' - ], - 'seealso': ['isInteger', 'isZero', 'isNegative', 'isPositive', 'isNaN'] - }; - - var isPositive = { - 'name': 'isPositive', - 'category': 'Utils', - 'syntax': [ - 'isPositive(x)' - ], - 'description': 'Test whether a value is positive: larger than zero.', - 'examples': [ - 'isPositive(2)', - 'isPositive(0)', - 'isPositive(-4)', - 'isPositive([3, 0.5, -2])' - ], - 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isZero'] - }; - - var isPrime = { - 'name': 'isPrime', - 'category': 'Utils', - 'syntax': [ - 'isPrime(x)' - ], - 'description': 'Test whether a value is prime: has no divisors other than itself and one.', - 'examples': [ - 'isPrime(3)', - 'isPrime(-2)', - 'isPrime([2, 17, 100])' - ], - 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isZero'] - }; - - var isZero = { - 'name': 'isZero', - 'category': 'Utils', - 'syntax': [ - 'isZero(x)' - ], - 'description': 'Test whether a value is zero.', - 'examples': [ - 'isZero(2)', - 'isZero(0)', - 'isZero(-4)', - 'isZero([3, 0, -2, 0])' - ], - 'seealso': ['isInteger', 'isNumeric', 'isNegative', 'isPositive'] - }; - - var _typeof = { - 'name': 'typeof', - 'category': 'Utils', - 'syntax': [ - 'typeof(x)' - ], - 'description': 'Get the type of a variable.', - 'examples': [ - 'typeof(3.5)', - 'typeof(2 - 4i)', - 'typeof(45 deg)', - 'typeof("hello world")' - ], - 'seealso': [] - }; - - function factory$39 (construction$$1, config, load, typed) { - var docs = {}; - - - // construction functions - docs.bignumber = bignumber$2; - docs['boolean'] = boolean_1$2; - docs.complex = complex$4; - docs.createUnit = createUnit; - docs.fraction = fraction$4; - docs.index = construction; - docs.matrix = matrix$2; - docs.number = number$4; - docs.sparse = sparse$1; - docs.splitUnit = splitUnit; - docs.string = string$7; - docs.unit = unit; - - // constants - docs.e = e; - docs.E = e; - docs['false'] = _false; - docs.i = i; - docs['Infinity'] = _Infinity; - docs.LN2 = LN2; - docs.LN10 = LN10; - docs.LOG2E = LOG2E; - docs.LOG10E = LOG10E; - docs.NaN = _NaN; - docs['null'] = _null; - docs.pi = pi; - docs.PI = pi; - docs.phi = phi; - docs.SQRT1_2 = SQRT1_2; - docs.SQRT2 = SQRT2; - docs.tau = tau; - docs['true'] = _true; - docs.version = version; - - // physical constants - // TODO: more detailed docs for physical constants - docs.speedOfLight = {description: 'Speed of light in vacuum', examples: ['speedOfLight']}; - docs.gravitationConstant = {description: 'Newtonian constant of gravitation', examples: ['gravitationConstant']}; - docs.planckConstant = {description: 'Planck constant', examples: ['planckConstant']}; - docs.reducedPlanckConstant = {description: 'Reduced Planck constant', examples: ['reducedPlanckConstant']}; - - docs.magneticConstant = {description: 'Magnetic constant (vacuum permeability)', examples: ['magneticConstant']}; - docs.electricConstant = {description: 'Electric constant (vacuum permeability)', examples: ['electricConstant']}; - docs.vacuumImpedance = {description: 'Characteristic impedance of vacuum', examples: ['vacuumImpedance']}; - docs.coulomb = {description: 'Coulomb\'s constant', examples: ['coulomb']}; - docs.elementaryCharge = {description: 'Elementary charge', examples: ['elementaryCharge']}; - docs.bohrMagneton = {description: 'Borh magneton', examples: ['bohrMagneton']}; - docs.conductanceQuantum = {description: 'Conductance quantum', examples: ['conductanceQuantum']}; - docs.inverseConductanceQuantum = {description: 'Inverse conductance quantum', examples: ['inverseConductanceQuantum']}; - //docs.josephson = {description: 'Josephson constant', examples: ['josephson']}; - docs.magneticFluxQuantum = {description: 'Magnetic flux quantum', examples: ['magneticFluxQuantum']}; - docs.nuclearMagneton = {description: 'Nuclear magneton', examples: ['nuclearMagneton']}; - docs.klitzing = {description: 'Von Klitzing constant', examples: ['klitzing']}; - - docs.bohrRadius = {description: 'Borh radius', examples: ['bohrRadius']}; - docs.classicalElectronRadius = {description: 'Classical electron radius', examples: ['classicalElectronRadius']}; - docs.electronMass = {description: 'Electron mass', examples: ['electronMass']}; - docs.fermiCoupling = {description: 'Fermi coupling constant', examples: ['fermiCoupling']}; - docs.fineStructure = {description: 'Fine-structure constant', examples: ['fineStructure']}; - docs.hartreeEnergy = {description: 'Hartree energy', examples: ['hartreeEnergy']}; - docs.protonMass = {description: 'Proton mass', examples: ['protonMass']}; - docs.deuteronMass = {description: 'Deuteron Mass', examples: ['deuteronMass']}; - docs.neutronMass = {description: 'Neutron mass', examples: ['neutronMass']}; - docs.quantumOfCirculation = {description: 'Quantum of circulation', examples: ['quantumOfCirculation']}; - docs.rydberg = {description: 'Rydberg constant', examples: ['rydberg']}; - docs.thomsonCrossSection = {description: 'Thomson cross section', examples: ['thomsonCrossSection']}; - docs.weakMixingAngle = {description: 'Weak mixing angle', examples: ['weakMixingAngle']}; - docs.efimovFactor = {description: 'Efimov factor', examples: ['efimovFactor']}; - - docs.atomicMass = {description: 'Atomic mass constant', examples: ['atomicMass']}; - docs.avogadro = {description: 'Avogadro\'s number', examples: ['avogadro']}; - docs.boltzmann = {description: 'Boltzmann constant', examples: ['boltzmann']}; - docs.faraday = {description: 'Faraday constant', examples: ['faraday']}; - docs.firstRadiation = {description: 'First radiation constant', examples: ['firstRadiation']}; - docs.loschmidt = {description: 'Loschmidt constant at T=273.15 K and p=101.325 kPa', examples: ['loschmidt']}; - docs.gasConstant = {description: 'Gas constant', examples: ['gasConstant']}; - docs.molarPlanckConstant = {description: 'Molar Planck constant', examples: ['molarPlanckConstant']}; - docs.molarVolume = {description: 'Molar volume of an ideal gas at T=273.15 K and p=101.325 kPa', examples: ['molarVolume']}; - docs.sackurTetrode = {description: 'Sackur-Tetrode constant at T=1 K and p=101.325 kPa', examples: ['sackurTetrode']}; - docs.secondRadiation = {description: 'Second radiation constant', examples: ['secondRadiation']}; - docs.stefanBoltzmann = {description: 'Stefan-Boltzmann constant', examples: ['stefanBoltzmann']}; - docs.wienDisplacement = {description: 'Wien displacement law constant', examples: ['wienDisplacement']}; - //docs.spectralRadiance = {description: 'First radiation constant for spectral radiance', examples: ['spectralRadiance']}; - - docs.molarMass = {description: 'Molar mass constant', examples: ['molarMass']}; - docs.molarMassC12 = {description: 'Molar mass constant of carbon-12', examples: ['molarMassC12']}; - docs.gravity = {description: 'Standard acceleration of gravity (standard acceleration of free-fall on Earth)', examples: ['gravity']}; - - docs.planckLength = {description: 'Planck length', examples: ['planckLength']}; - docs.planckMass = {description: 'Planck mass', examples: ['planckMass']}; - docs.planckTime = {description: 'Planck time', examples: ['planckTime']}; - docs.planckCharge = {description: 'Planck charge', examples: ['planckCharge']}; - docs.planckTemperature = {description: 'Planck temperature', examples: ['planckTemperature']}; - - // functions - algebra - docs.derivative = derivative; - docs.lsolve = lsolve; - docs.lup = lup; - docs.lusolve = lusolve; - docs.simplify = simplify; - docs.rationalize = rationalize; - docs.slu = slu; - docs.usolve = usolve; - docs.qr = qr; - - // functions - arithmetic - docs.abs = abs; - docs.add = add$1; - docs.cbrt = cbrt; - docs.ceil = ceil; - docs.cube = cube; - docs.divide = divide; - docs.dotDivide = dotDivide; - docs.dotMultiply = dotMultiply; - docs.dotPow = dotPow; - docs.exp = exp; - docs.expm = expm; - docs.expm1 = expm1; - docs.fix = fix; - docs.floor = floor; - docs.gcd = gcd; - docs.hypot = hypot; - docs.lcm = lcm; - docs.log = log; - docs.log2 = log2; - docs.log1p = log1p; - docs.log10 = log10; - docs.mod = mod; - docs.multiply = multiply; - docs.norm = norm; - docs.nthRoot = nthRoot; - docs.pow = pow; - docs.round = round; - docs.sign = sign; - docs.sqrt = sqrt; - docs.sqrtm = sqrtm; - docs.square = square; - docs.subtract = subtract; - docs.unaryMinus = unaryMinus; - docs.unaryPlus = unaryPlus; - docs.xgcd = xgcd; - - // functions - bitwise - docs.bitAnd = bitAnd; - docs.bitNot = bitNot; - docs.bitOr = bitOr; - docs.bitXor = bitXor; - docs.leftShift = leftShift; - docs.rightArithShift = rightArithShift; - docs.rightLogShift = rightLogShift; - - // functions - combinatorics - docs.bellNumbers = bellNumbers; - docs.catalan = catalan; - docs.composition = composition; - docs.stirlingS2 = stirlingS2; - - // functions - core - docs['config'] = config$1; - docs['import'] = _import$1; - docs['typed'] = typed$1; - - // functions - complex - docs.arg = arg; - docs.conj = conj; - docs.re = re; - docs.im = im; - - // functions - expression - docs['eval'] = _eval; - docs.help = help; - - // functions - geometry - docs.distance = distance; - docs.intersect = intersect; - - // functions - logical - docs['and'] = and; - docs['not'] = not; - docs['or'] = or; - docs['xor'] = xor; - - // functions - matrix - docs['concat'] = concat; - docs.cross = cross; - docs.det = det; - docs.diag = diag; - docs.dot = dot; - docs.eye = eye; - docs.filter = filter; - docs.flatten = flatten$1; - docs.forEach = forEach; - docs.inv = inv; - docs.kron = kron; - docs.map = map; - docs.ones = ones; - docs.partitionSelect = partitionSelect; - docs.range = range; - docs.resize = resize; - docs.reshape = reshape; - docs.size = size; - docs.sort = sort; - docs.squeeze = squeeze; - docs.subset = subset; - docs.trace = trace; - docs.transpose = transpose; - docs.zeros = zeros; - - // functions - probability - docs.combinations = combinations; - //docs.distribution = require('./function/probability/distribution'); - docs.factorial = factorial; - docs.gamma = gamma; - docs.kldivergence = kldivergence; - docs.multinomial = multinomial; - docs.permutations = permutations; - docs.pickRandom = pickRandom; - docs.random = random; - docs.randomInt = randomInt; - - // functions - relational - docs.compare = compare; - docs.compareNatural = compareNatural; - docs.compareText = compareText; - docs.deepEqual = deepEqual; - docs['equal'] = equal; - docs.equalText = equalText; - docs.larger = larger$1; - docs.largerEq = largerEq; - docs.smaller = smaller$1; - docs.smallerEq = smallerEq; - docs.unequal = unequal; - - // functions - set - docs.setCartesian = setCartesian; - docs.setDifference = setDifference; - docs.setDistinct = setDistinct; - docs.setIntersect = setIntersect; - docs.setIsSubset = setIsSubset; - docs.setMultiplicity = setMultiplicity; - docs.setPowerset = setPowerset; - docs.setSize = setSize; - docs.setSymDifference = setSymDifference; - docs.setUnion = setUnion; - - // functions - special - docs.erf = erf; - - // functions - statistics - docs.mad = mad; - docs.max = max; - docs.mean = mean; - docs.median = median; - docs.min = min; - docs.mode = mode; - docs.prod = prod; - docs.quantileSeq = quantileSeq; - docs.std = std; - docs.sum = sum; - docs['var'] = _var; - - // functions - trigonometry - docs.acos = acos; - docs.acosh = acosh; - docs.acot = acot; - docs.acoth = acoth; - docs.acsc = acsc; - docs.acsch = acsch; - docs.asec = asec; - docs.asech = asech; - docs.asin = asin; - docs.asinh = asinh; - docs.atan = atan; - docs.atanh = atanh; - docs.atan2 = atan2; - docs.cos = cos; - docs.cosh = cosh; - docs.cot = cot; - docs.coth = coth; - docs.csc = csc; - docs.csch = csch; - docs.sec = sec; - docs.sech = sech; - docs.sin = sin; - docs.sinh = sinh; - docs.tan = tan; - docs.tanh = tanh; - - // functions - units - docs.to = to; - - // functions - utils - docs.clone = clone$2; - docs.format = format$2; - docs.isNaN = _isNaN; - docs.isInteger = isInteger$3; - docs.isNegative = isNegative; - docs.isNumeric = isNumeric; - docs.isPositive = isPositive; - docs.isPrime = isPrime; - docs.isZero = isZero; - // docs.print = require('./function/utils/print'); // TODO: add documentation for print as soon as the parser supports objects. - docs['typeof'] = _typeof; - - return docs; - } - - var name$36 = 'docs'; - var path$13 = 'expression'; - var factory_1$38 = factory$39; - - var embeddedDocs = { - name: name$36, - path: path$13, - factory: factory_1$38 - }; - - function factory$40(type, config, load, typed) { - - // TODO: expose this function to mathjs, add documentation - - /** - * Create a numeric value with a specific type: number, BigNumber, or Fraction - * - * @param {string | number} value - * @param {'number' | 'BigNumber' | 'Fraction'} - * @return {number | BigNumber | Fraction} Returns an instance of the - * numeric requested type - */ - return function numeric (value, valueType) { - if (valueType === 'BigNumber') { - return new type.BigNumber(value); - } - else if (valueType === 'Fraction') { - return new type.Fraction(value); - } - else { - // valueType === 'number' or undefined // TODO: check this - if (typeof value === 'number') { - return value; - } - else { - if (value === 'Infinity') { - return Infinity; - } - - if (value === 'NaN') { - return NaN; - } - - // The following regexp is relatively permissive - if (!/^[\-+]?((\d+\.?\d*)|(\d*\.?\d+))([eE][+\-]?\d+)?$/.test(value)) { - throw new Error('Invalid numeric value "' + value + '"'); - } - - // remove leading zeros like '003.2' which are not allowed by JavaScript - return parseFloat(value.replace(/^(0*)[0-9]/, function (match, zeros) { - return match.substring(zeros.length); - })); - } - } - } - } - - var factory_1$39 = factory$40; - - var numeric = { - factory: factory_1$39 - }; - - var hasOwnProperty = object.hasOwnProperty; - - /** - * Get a property of a plain object - * Throws an error in case the object is not a plain object or the - * property is not defined on the object itself - * @param {Object} object - * @param {string} prop - * @return {*} Returns the property value when safe - */ - function getSafeProperty (object$$1, prop) { - // only allow getting safe properties of a plain object - if (isPlainObject(object$$1) && isSafeProperty(object$$1, prop)) { - return object$$1[prop]; - } - - if (typeof object$$1[prop] === 'function' && isSafeMethod(object$$1, prop)) { - throw new Error('Cannot access method "' + prop + '" as a property'); - } - - throw new Error('No access to property "' + prop + '"'); - } - - /** - * Set a property on a plain object. - * Throws an error in case the object is not a plain object or the - * property would override an inherited property like .constructor or .toString - * @param {Object} object - * @param {string} prop - * @param {*} value - * @return {*} Returns the value - */ - // TODO: merge this function into access.js? - function setSafeProperty (object$$1, prop, value) { - // only allow setting safe properties of a plain object - if (isPlainObject(object$$1) && isSafeProperty(object$$1, prop)) { - return object$$1[prop] = value; - } - - throw new Error('No access to property "' + prop + '"'); - } - - /** - * Test whether a property is safe to use for an object. - * For example .toString and .constructor are not safe - * @param {string} prop - * @return {boolean} Returns true when safe - */ - function isSafeProperty (object$$1, prop) { - if (!object$$1 || typeof object$$1 !== 'object') { - return false; - } - // SAFE: whitelisted - // e.g length - if (hasOwnProperty(safeNativeProperties, prop)) { - return true; - } - // UNSAFE: inherited from Object prototype - // e.g constructor - if (prop in Object.prototype) { - // 'in' is used instead of hasOwnProperty for nodejs v0.10 - // which is inconsistent on root prototypes. It is safe - // here because Object.prototype is a root object - return false; - } - // UNSAFE: inherited from Function prototype - // e.g call, apply - if (prop in Function.prototype) { - // 'in' is used instead of hasOwnProperty for nodejs v0.10 - // which is inconsistent on root prototypes. It is safe - // here because Function.prototype is a root object - return false; - } - return true; - } - - /** - * Validate whether a method is safe. - * Throws an error when that's not the case. - * @param {Object} object - * @param {string} method - */ - // TODO: merge this function into assign.js? - function validateSafeMethod (object$$1, method) { - if (!isSafeMethod(object$$1, method)) { - throw new Error('No access to method "' + method + '"'); - } - } - - /** - * Check whether a method is safe. - * Throws an error when that's not the case (for example for `constructor`). - * @param {Object} object - * @param {string} method - * @return {boolean} Returns true when safe, false otherwise - */ - function isSafeMethod (object$$1, method) { - if (!object$$1 || typeof object$$1[method] !== 'function') { - return false; - } - // UNSAFE: ghosted - // e.g overridden toString - // Note that IE10 doesn't support __proto__ and we can't do this check there. - if (hasOwnProperty(object$$1, method) && - (object$$1.__proto__ && (method in object$$1.__proto__))) { - return false; - } - // SAFE: whitelisted - // e.g toString - if (hasOwnProperty(safeNativeMethods, method)) { - return true; - } - // UNSAFE: inherited from Object prototype - // e.g constructor - if (method in Object.prototype) { - // 'in' is used instead of hasOwnProperty for nodejs v0.10 - // which is inconsistent on root prototypes. It is safe - // here because Object.prototype is a root object - return false; - } - // UNSAFE: inherited from Function prototype - // e.g call, apply - if (method in Function.prototype) { - // 'in' is used instead of hasOwnProperty for nodejs v0.10 - // which is inconsistent on root prototypes. It is safe - // here because Function.prototype is a root object - return false; - } - return true; - } - - function isPlainObject (object$$1) { - return typeof object$$1 === 'object' && object$$1 && object$$1.constructor === Object; - } - - var safeNativeProperties = { - length: true, - name: true - }; - - var safeNativeMethods = { - toString: true, - valueOf: true, - toLocaleString: true - }; - - var getSafeProperty_1 = getSafeProperty; - var setSafeProperty_1 = setSafeProperty; - var isSafeProperty_1 = isSafeProperty; - var validateSafeMethod_1 = validateSafeMethod; - var isSafeMethod_1 = isSafeMethod; - var isPlainObject_1 = isPlainObject; - - var customs = { - getSafeProperty: getSafeProperty_1, - setSafeProperty: setSafeProperty_1, - isSafeProperty: isSafeProperty_1, - validateSafeMethod: validateSafeMethod_1, - isSafeMethod: isSafeMethod_1, - isPlainObject: isPlainObject_1 - }; - - // Reserved keywords not allowed to use in the parser - var keywords = { - end: true - }; - - var deepEqual$1= object.deepEqual; - var hasOwnProperty$1 = object.hasOwnProperty; - - function factory$41 (type, config, load, typed, math) { - - /** - * Node - */ - function Node() { - if (!(this instanceof Node)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - } - - /** - * Evaluate the node - * @param {Object} [scope] Scope to read/write variables - * @return {*} Returns the result - */ - Node.prototype.eval = function(scope) { - return this.compile().eval(scope); - }; - - Node.prototype.type = 'Node'; - - Node.prototype.isNode = true; - - Node.prototype.comment = ''; - - /** - * Compile the node into an optimized, evauatable JavaScript function - * @return {{eval: function([Object])}} expr Returns an object with a function 'eval', - * which can be invoked as expr.eval([scope: Object]), - * where scope is an optional object with - * variables. - */ - Node.prototype.compile = function () { - var expr = this._compile(math.expression.mathWithTransform, {}); - var args = {}; - var context = null; - return { - eval: function evalNode(scope) { - var s = scope ? scope : {}; - _validateScope(s); - return expr(s, args, context); - } - } - }; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - Node.prototype._compile = function (math, argNames) { - throw new Error('Method _compile should be implemented by type ' + this.type); - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - Node.prototype.forEach = function (callback) { - // must be implemented by each of the Node implementations - throw new Error('Cannot run forEach on a Node interface'); - }; - - /** - * Create a new Node having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {OperatorNode} Returns a transformed copy of the node - */ - Node.prototype.map = function (callback) { - // must be implemented by each of the Node implementations - throw new Error('Cannot run map on a Node interface'); - }; - - /** - * Validate whether an object is a Node, for use with map - * @param {Node} node - * @returns {Node} Returns the input if it's a node, else throws an Error - * @protected - */ - Node.prototype._ifNode = function (node) { - if (!type.isNode(node)) { - throw new TypeError('Callback function must return a Node'); - } - - return node; - }; - - /** - * Recursively traverse all nodes in a node tree. Executes given callback for - * this node and each of its child nodes. - * @param {function(node: Node, path: string, parent: Node)} callback - * A callback called for every node in the node tree. - */ - Node.prototype.traverse = function (callback) { - // execute callback for itself - callback(this, null, null); - - // recursively traverse over all childs of a node - function _traverse(node, callback) { - node.forEach(function (child, path, parent) { - callback(child, path, parent); - _traverse(child, callback); - }); - } - - _traverse(this, callback); - }; - - /** - * Recursively transform a node tree via a transform function. - * - * For example, to replace all nodes of type SymbolNode having name 'x' with a - * ConstantNode with value 2: - * - * var res = Node.transform(function (node, path, parent) { - * if (node && node.isSymbolNode) && (node.name == 'x')) { - * return new ConstantNode(2); - * } - * else { - * return node; - * } - * }); - * - * @param {function(node: Node, path: string, parent: Node) : Node} callback - * A mapping function accepting a node, and returning - * a replacement for the node or the original node. - * Signature: callback(node: Node, index: string, parent: Node) : Node - * @return {Node} Returns the original node or its replacement - */ - Node.prototype.transform = function (callback) { - // traverse over all childs - function _transform (node, callback) { - return node.map(function(child, path, parent) { - var replacement = callback(child, path, parent); - return _transform(replacement, callback); - }); - } - - var replacement = callback(this, null, null); - return _transform(replacement, callback); - }; - - /** - * Find any node in the node tree matching given filter function. For example, to - * find all nodes of type SymbolNode having name 'x': - * - * var results = Node.filter(function (node) { - * return (node && node.isSymbolNode) && (node.name == 'x'); - * }); - * - * @param {function(node: Node, path: string, parent: Node) : Node} callback - * A test function returning true when a node matches, and false - * otherwise. Function signature: - * callback(node: Node, index: string, parent: Node) : boolean - * @return {Node[]} nodes An array with nodes matching given filter criteria - */ - Node.prototype.filter = function (callback) { - var nodes = []; - - this.traverse(function (node, path, parent) { - if (callback(node, path, parent)) { - nodes.push(node); - } - }); - - return nodes; - }; - - // TODO: deprecated since version 1.1.0, remove this some day - Node.prototype.find = function () { - throw new Error('Function Node.find is deprecated. Use Node.filter instead.'); - }; - - // TODO: deprecated since version 1.1.0, remove this some day - Node.prototype.match = function () { - throw new Error('Function Node.match is deprecated. See functions Node.filter, Node.transform, Node.traverse.'); - }; - - /** - * Create a shallow clone of this node - * @return {Node} - */ - Node.prototype.clone = function () { - // must be implemented by each of the Node implementations - throw new Error('Cannot clone a Node interface'); - }; - - /** - * Create a deep clone of this node - * @return {Node} - */ - Node.prototype.cloneDeep = function () { - return this.map(function (node) { - return node.cloneDeep(); - }); - }; - - /** - * Deep compare this node with another node. - * @param {Node} other - * @return {boolean} Returns true when both nodes are of the same type and - * contain the same values (as do their childs) - */ - Node.prototype.equals = function (other) { - return other - ? deepEqual$1(this, other) - : false - }; - - /** - * Get string representation. (wrapper function) - * - * This function can get an object of the following form: - * { - * handler: //This can be a callback function of the form - * // "function callback(node, options)"or - * // a map that maps function names (used in FunctionNodes) - * // to callbacks - * parenthesis: "keep" //the parenthesis option (This is optional) - * } - * - * @param {Object} [options] - * @return {string} - */ - Node.prototype.toString = function (options) { - var customString; - if (options && typeof options === 'object') { - switch (typeof options.handler) { - case 'object': - case 'undefined': - break; - case 'function': - customString = options.handler(this, options); - break; - default: - throw new TypeError('Object or function expected as callback'); - } - } - - if (typeof customString !== 'undefined') { - return customString; - } - - return this._toString(options); - }; - - /** - * Get a JSON representation of the node - * Both .toJSON() and the static .fromJSON(json) should be implemented by all - * implementations of Node - * @returns {Object} - */ - Node.prototype.toJSON = function () { - throw new Error('Cannot serialize object: toJSON not implemented by ' + this.type); - }; - - /** - * Get HTML representation. (wrapper function) - * - * This function can get an object of the following form: - * { - * handler: //This can be a callback function of the form - * // "function callback(node, options)" or - * // a map that maps function names (used in FunctionNodes) - * // to callbacks - * parenthesis: "keep" //the parenthesis option (This is optional) - * } - * - * @param {Object} [options] - * @return {string} - */ - Node.prototype.toHTML = function (options) { - var customString; - if (options && typeof options === 'object') { - switch (typeof options.handler) { - case 'object': - case 'undefined': - break; - case 'function': - customString = options.handler(this, options); - break; - default: - throw new TypeError('Object or function expected as callback'); - } - } - - if (typeof customString !== 'undefined') { - return customString; - } - - return this.toHTML(options); - }; - - /** - * Internal function to generate the string output. - * This has to be implemented by every Node - * - * @throws {Error} - */ - Node.prototype._toString = function () { - //must be implemented by each of the Node implementations - throw new Error('_toString not implemented for ' + this.type); - }; - - /** - * Get LaTeX representation. (wrapper function) - * - * This function can get an object of the following form: - * { - * handler: //This can be a callback function of the form - * // "function callback(node, options)"or - * // a map that maps function names (used in FunctionNodes) - * // to callbacks - * parenthesis: "keep" //the parenthesis option (This is optional) - * } - * - * @param {Object} [options] - * @return {string} - */ - Node.prototype.toTex = function (options) { - var customTex; - if (options && typeof options == 'object') { - switch (typeof options.handler) { - case 'object': - case 'undefined': - break; - case 'function': - customTex = options.handler(this, options); - break; - default: - throw new TypeError('Object or function expected as callback'); - } - } - - if (typeof customTex !== 'undefined') { - return customTex; - } - - return this._toTex(options); - }; - - /** - * Internal function to generate the LaTeX output. - * This has to be implemented by every Node - * - * @param {Object} [options] - * @throws {Error} - */ - Node.prototype._toTex = function (options) { - //must be implemented by each of the Node implementations - throw new Error('_toTex not implemented for ' + this.type); - }; - - /** - * Get identifier. - * @return {string} - */ - Node.prototype.getIdentifier = function () { - return this.type; - }; - - /** - * Get the content of the current Node. - * @return {Node} node - **/ - Node.prototype.getContent = function () { - return this; - }; - - /** - * Validate the symbol names of a scope. - * Throws an error when the scope contains an illegal symbol. - * @param {Object} scope - */ - function _validateScope(scope) { - for (var symbol in scope) { - if (hasOwnProperty$1(scope, symbol)) { - if (symbol in keywords) { - throw new Error('Scope contains an illegal symbol, "' + symbol + '" is a reserved keyword'); - } - } - } - } - - return Node; - } - - var name$37 = 'Node'; - var path$14 = 'expression.node'; - var math$6 = true; // request access to the math namespace as 5th argument of the factory function - var factory_1$40 = factory$41; - - var Node = { - name: name$37, - path: path$14, - math: math$6, - factory: factory_1$40 - }; - - var map$1 = array.map; - var escape = string.escape; - - function factory$42 (type, config, load, typed) { - var Node$$1 = load(Node); - var Range$$1 = load(Range); - - var isArray = Array.isArray; - - /** - * @constructor IndexNode - * @extends Node - * - * Describes a subset of a matrix or an object property. - * Cannot be used on its own, needs to be used within an AccessorNode or - * AssignmentNode. - * - * @param {Node[]} dimensions - * @param {boolean} [dotNotation=false] Optional property describing whether - * this index was written using dot - * notation like `a.b`, or using bracket - * notation like `a["b"]` (default). - * Used to stringify an IndexNode. - */ - function IndexNode(dimensions, dotNotation) { - if (!(this instanceof IndexNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.dimensions = dimensions; - this.dotNotation = dotNotation || false; - - // validate input - if (!isArray(dimensions) || !dimensions.every(type.isNode)) { - throw new TypeError('Array containing Nodes expected for parameter "dimensions"'); - } - if (this.dotNotation && !this.isObjectProperty()) { - throw new Error('dotNotation only applicable for object properties'); - } - - // TODO: deprecated since v3, remove some day - var deprecated = function () { - throw new Error('Property `IndexNode.object` is deprecated, use `IndexNode.fn` instead'); - }; - Object.defineProperty(this, 'object', { get: deprecated, set: deprecated }); - } - - IndexNode.prototype = new Node$$1(); - - IndexNode.prototype.type = 'IndexNode'; - - IndexNode.prototype.isIndexNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - IndexNode.prototype._compile = function (math, argNames) { - // TODO: implement support for bignumber (currently bignumbers are silently - // reduced to numbers when changing the value to zero-based) - - // TODO: Optimization: when the range values are ConstantNodes, - // we can beforehand resolve the zero-based value - - // optimization for a simple object property - var evalDimensions = map$1(this.dimensions, function (range, i) { - if (type.isRangeNode(range)) { - if (range.needsEnd()) { - // create a range containing end (like '4:end') - var childArgNames = Object.create(argNames); - childArgNames['end'] = true; - - var evalStart = range.start._compile(math, childArgNames); - var evalEnd = range.end._compile(math, childArgNames); - var evalStep = range.step - ? range.step._compile(math, childArgNames) - : function () { return 1 }; - - return function evalDimension(scope, args, context) { - var size = math.size(context).valueOf(); - var childArgs = Object.create(args); - childArgs['end'] = size[i]; - - return createRange( - evalStart(scope, childArgs, context), - evalEnd(scope, childArgs, context), - evalStep(scope, childArgs, context) - ); - }; - } - else { - // create range - var evalStart = range.start._compile(math, argNames); - var evalEnd = range.end._compile(math, argNames); - var evalStep = range.step - ? range.step._compile(math, argNames) - : function () { return 1 }; - - return function evalDimension(scope, args, context) { - return createRange( - evalStart(scope, args, context), - evalEnd(scope, args, context), - evalStep(scope, args, context) - ); - }; - } - } - else if (type.isSymbolNode(range) && range.name === 'end') { - // SymbolNode 'end' - var childArgNames = Object.create(argNames); - childArgNames['end'] = true; - - var evalRange = range._compile(math, childArgNames); - - return function evalDimension(scope, args, context) { - var size = math.size(context).valueOf(); - var childArgs = Object.create(args); - childArgs['end'] = size[i]; - - return evalRange(scope, childArgs, context); - }; - } - else { - // ConstantNode - var evalRange = range._compile(math, argNames); - return function evalDimension(scope, args, context) { - return evalRange(scope, args, context); - }; - } - }); - - return function evalIndexNode (scope, args, context) { - var dimensions = map$1(evalDimensions, function (evalDimension) { - return evalDimension(scope, args, context); - }); - return math.index.apply(math, dimensions); - }; - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - IndexNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.dimensions.length; i++) { - callback(this.dimensions[i], 'dimensions[' + i + ']', this); - } - }; - - /** - * Create a new IndexNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {IndexNode} Returns a transformed copy of the node - */ - IndexNode.prototype.map = function (callback) { - var dimensions = []; - for (var i = 0; i < this.dimensions.length; i++) { - dimensions[i] = this._ifNode(callback(this.dimensions[i], 'dimensions[' + i + ']', this)); - } - - return new IndexNode(dimensions); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {IndexNode} - */ - IndexNode.prototype.clone = function () { - return new IndexNode(this.dimensions.slice(0)); - }; - - /** - * Test whether this IndexNode contains a single property name - * @return {boolean} - */ - IndexNode.prototype.isObjectProperty = function () { - return this.dimensions.length === 1 && - type.isConstantNode(this.dimensions[0]) && - typeof this.dimensions[0].value === 'string'; - }; - - /** - * Returns the property name if IndexNode contains a property. - * If not, returns null. - * @return {string | null} - */ - IndexNode.prototype.getObjectProperty = function () { - return this.isObjectProperty() ? this.dimensions[0].value : null; - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - IndexNode.prototype._toString = function (options) { - // format the parameters like "[1, 0:5]" - return this.dotNotation - ? ('.' + this.getObjectProperty()) - : ('[' + this.dimensions.join(', ') + ']'); - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - IndexNode.prototype.toJSON = function () { - return { - mathjs: 'IndexNode', - dimensions: this.dimensions, - dotNotation: this.dotNotation - }; - }; - - /** - * Instantiate an IndexNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "IndexNode", dimensions: [...], dotNotation: false}`, - * where mathjs is optional - * @returns {IndexNode} - */ - IndexNode.fromJSON = function (json) { - return new IndexNode(json.dimensions, json.dotNotation); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - IndexNode.prototype.toHTML = function (options) { - // format the parameters like "[1, 0:5]" - var dimensions = []; - for (var i=0; i.' + '' + escape(this.getObjectProperty()) + '';} - else { - return '[' + dimensions.join(',') + ']'} - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - IndexNode.prototype._toTex = function (options) { - var dimensions = this.dimensions.map(function (range) { - return range.toTex(options); - }); - - return this.dotNotation - ? ('.' + this.getObjectProperty() + '') - : ('_{' + dimensions.join(',') + '}'); - }; - - // helper function to create a Range from start, step and end - function createRange(start, end, step) { - return new Range$$1( - type.isBigNumber(start) ? start.toNumber() : start, - type.isBigNumber(end) ? end.toNumber() : end, - type.isBigNumber(step) ? step.toNumber() : step - ); - } - return IndexNode; - } - - var name$38 = 'IndexNode'; - var path$15 = 'expression.node'; - var factory_1$41 = factory$42; - - var IndexNode = { - name: name$38, - path: path$15, - factory: factory_1$41 - }; - - /** - * Transform zero-based indices to one-based indices in errors - * @param {Error} err - * @returns {Error} Returns the transformed error - */ - var transform = function (err) { - if (err && err.isIndexError) { - return new IndexError_1( - err.index + 1, - err.min + 1, - err.max !== undefined ? err.max + 1 : undefined); - } - - return err; - }; - - var error_transform = { - transform: transform - }; - - var clone$3 = object.clone; - var validateIndex$2 = array.validateIndex; - var getSafeProperty$1 = customs.getSafeProperty; - var setSafeProperty$1 = customs.setSafeProperty; - - - function factory$43 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Get or set a subset of a matrix or string. - * - * Syntax: - * math.subset(value, index) // retrieve a subset - * math.subset(value, index, replacement [, defaultValue]) // replace a subset - * - * Examples: - * - * // get a subset - * var d = [[1, 2], [3, 4]]; - * math.subset(d, math.index(1, 0)); // returns 3 - * math.subset(d, math.index([0, 2], 1)); // returns [[2], [4]] - * - * // replace a subset - * var e = []; - * var f = math.subset(e, math.index(0, [0, 2]), [5, 6]); // f = [[5, 6]] - * var g = math.subset(f, math.index(1, 1), 7, 0); // g = [[5, 6], [0, 7]] - * - * See also: - * - * size, resize, squeeze, index - * - * @param {Array | Matrix | string} matrix An array, matrix, or string - * @param {Index} index An index containing ranges for each - * dimension - * @param {*} [replacement] An array, matrix, or scalar. - * If provided, the subset is replaced with replacement. - * If not provided, the subset is returned - * @param {*} [defaultValue=undefined] Default value, filled in on new entries when - * the matrix is resized. If not provided, - * math.matrix elements will be left undefined. - * @return {Array | Matrix | string} Either the retrieved subset or the updated matrix. - */ - var subset = typed('subset', { - // get subset - 'Array, Index': function (value, index) { - var m = matrix$$1(value); - var subset = m.subset(index); // returns a Matrix - return index.isScalar() - ? subset - : subset.valueOf(); // return an Array (like the input) - }, - - 'Matrix, Index': function (value, index) { - return value.subset(index); - }, - - 'Object, Index': _getObjectProperty, - - 'string, Index': _getSubstring, - - // set subset - 'Array, Index, any': function (value, index, replacement) { - return matrix$$1(clone$3(value)) - .subset(index, replacement, undefined) - .valueOf(); - }, - - 'Array, Index, any, any': function (value, index, replacement, defaultValue) { - return matrix$$1(clone$3(value)) - .subset(index, replacement, defaultValue) - .valueOf(); - }, - - 'Matrix, Index, any': function (value, index, replacement) { - return value.clone().subset(index, replacement); - }, - - 'Matrix, Index, any, any': function (value, index, replacement, defaultValue) { - return value.clone().subset(index, replacement, defaultValue); - }, - - 'string, Index, string': _setSubstring, - 'string, Index, string, string': _setSubstring, - 'Object, Index, any': _setObjectProperty - }); - - subset.toTex = undefined; // use default template - - return subset; - - /** - * Retrieve a subset of a string - * @param {string} str string from which to get a substring - * @param {Index} index An index containing ranges for each dimension - * @returns {string} substring - * @private - */ - function _getSubstring(str, index) { - if (!type.isIndex(index)) { - // TODO: better error message - throw new TypeError('Index expected'); - } - if (index.size().length != 1) { - throw new DimensionError_1(index.size().length, 1); - } - - // validate whether the range is out of range - var strLen = str.length; - validateIndex$2(index.min()[0], strLen); - validateIndex$2(index.max()[0], strLen); - - var range = index.dimension(0); - - var substr = ''; - range.forEach(function (v) { - substr += str.charAt(v); - }); - - return substr; - } - - /** - * Replace a substring in a string - * @param {string} str string to be replaced - * @param {Index} index An index containing ranges for each dimension - * @param {string} replacement Replacement string - * @param {string} [defaultValue] Default value to be uses when resizing - * the string. is ' ' by default - * @returns {string} result - * @private - */ - function _setSubstring(str, index, replacement, defaultValue) { - if (!index || index.isIndex !== true) { - // TODO: better error message - throw new TypeError('Index expected'); - } - if (index.size().length != 1) { - throw new DimensionError_1(index.size().length, 1); - } - if (defaultValue !== undefined) { - if (typeof defaultValue !== 'string' || defaultValue.length !== 1) { - throw new TypeError('Single character expected as defaultValue'); - } - } - else { - defaultValue = ' '; - } - - var range = index.dimension(0); - var len = range.size()[0]; - - if (len != replacement.length) { - throw new DimensionError_1(range.size()[0], replacement.length); - } - - // validate whether the range is out of range - var strLen = str.length; - validateIndex$2(index.min()[0]); - validateIndex$2(index.max()[0]); - - // copy the string into an array with characters - var chars = []; - for (var i = 0; i < strLen; i++) { - chars[i] = str.charAt(i); - } - - range.forEach(function (v, i) { - chars[v] = replacement.charAt(i[0]); - }); - - // initialize undefined characters with a space - if (chars.length > strLen) { - for (i = strLen - 1, len = chars.length; i < len; i++) { - if (!chars[i]) { - chars[i] = defaultValue; - } - } - } - - return chars.join(''); - } - } - - /** - * Retrieve a property from an object - * @param {Object} object - * @param {Index} index - * @return {*} Returns the value of the property - * @private - */ - function _getObjectProperty (object$$1, index) { - if (index.size().length !== 1) { - throw new DimensionError_1(index.size(), 1); - } - - var key = index.dimension(0); - if (typeof key !== 'string') { - throw new TypeError('String expected as index to retrieve an object property'); - } - - return getSafeProperty$1(object$$1, key); - } - - /** - * Set a property on an object - * @param {Object} object - * @param {Index} index - * @param {*} replacement - * @return {*} Returns the updated object - * @private - */ - function _setObjectProperty (object$$1, index, replacement) { - if (index.size().length !== 1) { - throw new DimensionError_1(index.size(), 1); - } - - var key = index.dimension(0); - if (typeof key !== 'string') { - throw new TypeError('String expected as index to retrieve an object property'); - } - - // clone the object, and apply the property to the clone - var updated = clone$3(object$$1); - setSafeProperty$1(updated, key, replacement); - - return updated; - } - - var name$39 = 'subset'; - var factory_1$42 = factory$43; - - var subset$1 = { - name: name$39, - factory: factory_1$42 - }; - - var errorTransform = error_transform.transform; - var getSafeProperty$2 = customs.getSafeProperty; - - function factory$44 (type, config, load, typed) { - var subset = load(subset$1); - - /** - * Retrieve part of an object: - * - * - Retrieve a property from an object - * - Retrieve a part of a string - * - Retrieve a matrix subset - * - * @param {Object | Array | Matrix | string} object - * @param {Index} index - * @return {Object | Array | Matrix | string} Returns the subset - */ - return function access(object, index) { - try { - if (Array.isArray(object)) { - return subset(object, index); - } - else if (object && typeof object.subset === 'function') { // Matrix - return object.subset(index); - } - else if (typeof object === 'string') { - // TODO: move getStringSubset into a separate util file, use that - return subset(object, index); - } - else if (typeof object === 'object') { - if (!index.isObjectProperty()) { - throw new TypeError('Cannot apply a numeric index as object property'); - } - - return getSafeProperty$2(object, index.getObjectProperty()); - } - else { - throw new TypeError('Cannot apply index: unsupported type of object'); - } - } - catch (err) { - throw errorTransform(err); - } - } - } - - var factory_1$43 = factory$44; - - var access = { - factory: factory_1$43 - }; - - var getSafeProperty$3 = customs.getSafeProperty; - - function factory$45 (type, config, load, typed) { - var Node$$1 = load(Node); - var IndexNode$$1 = load(IndexNode); - var access$$1 = load(access); - - /** - * @constructor AccessorNode - * @extends {Node} - * Access an object property or get a matrix subset - * - * @param {Node} object The object from which to retrieve - * a property or subset. - * @param {IndexNode} index IndexNode containing ranges - */ - function AccessorNode(object, index) { - if (!(this instanceof AccessorNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - if (!type.isNode(object)) { - throw new TypeError('Node expected for parameter "object"'); - } - if (!type.isIndexNode(index)) { - throw new TypeError('IndexNode expected for parameter "index"'); - } - - this.object = object || null; - this.index = index; - - // readonly property name - Object.defineProperty(this, 'name', { - get: function () { - if (this.index) { - return (this.index.isObjectProperty()) - ? this.index.getObjectProperty() - : ''; - } - else { - return this.object.name || ''; - } - }.bind(this), - set: function () { - throw new Error('Cannot assign a new name, name is read-only'); - } - }); - } - - AccessorNode.prototype = new Node$$1(); - - AccessorNode.prototype.type = 'AccessorNode'; - - AccessorNode.prototype.isAccessorNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - AccessorNode.prototype._compile = function (math, argNames) { - var evalObject = this.object._compile(math, argNames); - var evalIndex = this.index._compile(math, argNames); - - if (this.index.isObjectProperty()) { - var prop = this.index.getObjectProperty(); - return function evalAccessorNode(scope, args, context) { - return getSafeProperty$3(evalObject(scope, args, context), prop); - }; - } - else { - return function evalAccessorNode (scope, args, context) { - var object = evalObject(scope, args, context); - var index = evalIndex(scope, args, object); // we pass object here instead of context - return access$$1(object, index); - }; - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - AccessorNode.prototype.forEach = function (callback) { - callback(this.object, 'object', this); - callback(this.index, 'index', this); - }; - - /** - * Create a new AccessorNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {AccessorNode} Returns a transformed copy of the node - */ - AccessorNode.prototype.map = function (callback) { - return new AccessorNode( - this._ifNode(callback(this.object, 'object', this)), - this._ifNode(callback(this.index, 'index', this)) - ); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {AccessorNode} - */ - AccessorNode.prototype.clone = function () { - return new AccessorNode(this.object, this.index); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} - */ - AccessorNode.prototype._toString = function (options) { - var object = this.object.toString(options); - if (needParenthesis(this.object)) { - object = '(' + object + ')'; - } - - return object + this.index.toString(options); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} - */ - AccessorNode.prototype.toHTML = function (options) { - var object = this.object.toHTML(options); - if (needParenthesis(this.object)) { - object = '(' + object + ')'; - } - - return object + this.index.toHTML(options); - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} - */ - AccessorNode.prototype._toTex = function (options) { - var object = this.object.toTex(options); - if (needParenthesis(this.object)) { - object = '\\left(' + object + '\\right)'; - } - - return object + this.index.toTex(options); - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - AccessorNode.prototype.toJSON = function () { - return { - mathjs: 'AccessorNode', - object: this.object, - index: this.index - }; - }; - - /** - * Instantiate an AccessorNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "AccessorNode", object: ..., index: ...}`, - * where mathjs is optional - * @returns {AccessorNode} - */ - AccessorNode.fromJSON = function (json) { - return new AccessorNode(json.object, json.index); - }; - - /** - * Are parenthesis needed? - * @private - */ - function needParenthesis(node) { - // TODO: maybe make a method on the nodes which tells whether they need parenthesis? - return !( - type.isAccessorNode(node) || - type.isArrayNode(node) || - type.isConstantNode(node) || - type.isFunctionNode(node) || - type.isObjectNode(node) || - type.isParenthesisNode(node) || - type.isSymbolNode(node)); - } - - return AccessorNode; - } - - var name$40 = 'AccessorNode'; - var path$16 = 'expression.node'; - var factory_1$44 = factory$45; - - var AccessorNode = { - name: name$40, - path: path$16, - factory: factory_1$44 - }; - - var map$2 = array.map; - - function factory$46 (type, config, load, typed) { - var Node$$1 = load(Node); - - /** - * @constructor ArrayNode - * @extends {Node} - * Holds an 1-dimensional array with items - * @param {Node[]} [items] 1 dimensional array with items - */ - function ArrayNode(items) { - if (!(this instanceof ArrayNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.items = items || []; - - // validate input - if (!Array.isArray(this.items) || !this.items.every(type.isNode)) { - throw new TypeError('Array containing Nodes expected'); - } - - // TODO: deprecated since v3, remove some day - var deprecated = function () { - throw new Error('Property `ArrayNode.nodes` is deprecated, use `ArrayNode.items` instead'); - }; - Object.defineProperty(this, 'nodes', { get: deprecated, set: deprecated }); - } - - ArrayNode.prototype = new Node$$1(); - - ArrayNode.prototype.type = 'ArrayNode'; - - ArrayNode.prototype.isArrayNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ArrayNode.prototype._compile = function (math, argNames) { - var evalItems = map$2(this.items, function (item) { - return item._compile(math, argNames); - }); - - var asMatrix = (math.config().matrix !== 'Array'); - if (asMatrix) { - var matrix = math.matrix; - return function evalArrayNode (scope, args, context) { - return matrix(map$2(evalItems, function (evalItem) { - return evalItem(scope, args, context); - })); - }; - } - else { - return function evalArrayNode (scope, args, context) { - return map$2(evalItems, function (evalItem) { - return evalItem(scope, args, context); - }); - }; - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ArrayNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.items.length; i++) { - var node = this.items[i]; - callback(node, 'items[' + i + ']', this); - } - }; - - /** - * Create a new ArrayNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {ArrayNode} Returns a transformed copy of the node - */ - ArrayNode.prototype.map = function (callback) { - var items = []; - for (var i = 0; i < this.items.length; i++) { - items[i] = this._ifNode(callback(this.items[i], 'items[' + i + ']', this)); - } - return new ArrayNode(items); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {ArrayNode} - */ - ArrayNode.prototype.clone = function() { - return new ArrayNode(this.items.slice(0)); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - ArrayNode.prototype._toString = function(options) { - var items = this.items.map(function (node) { - return node.toString(options); - }); - return '[' + items.join(', ') + ']'; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ArrayNode.prototype.toJSON = function () { - return { - mathjs: 'ArrayNode', - items: this.items - }; - }; - - /** - * Instantiate an ArrayNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "ArrayNode", items: [...]}`, - * where mathjs is optional - * @returns {ArrayNode} - */ - ArrayNode.fromJSON = function (json) { - return new ArrayNode(json.items); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - ArrayNode.prototype.toHTML = function(options) { - var items = this.items.map(function (node) { - return node.toHTML(options); - }); - return '[' + items.join(',') + ']'; - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - ArrayNode.prototype._toTex = function(options) { - var s = '\\begin{bmatrix}'; - - this.items.forEach(function(node) { - if (node.items) { - s += node.items.map(function(childNode) { - return childNode.toTex(options); - }).join('&'); - } - else { - s += node.toTex(options); - } - - // new line - s += '\\\\'; - }); - s += '\\end{bmatrix}'; - return s; - }; - - return ArrayNode; - } - - var name$41 = 'ArrayNode'; - var path$17 = 'expression.node'; - var factory_1$45 = factory$46; - - var ArrayNode = { - name: name$41, - path: path$17, - factory: factory_1$45 - }; - - var errorTransform$1 = error_transform.transform; - var setSafeProperty$2 = customs.setSafeProperty; - - function factory$47 (type, config, load, typed) { - var subset = load(subset$1); - var matrix$$1 = load(matrix); - - /** - * Replace part of an object: - * - * - Assign a property to an object - * - Replace a part of a string - * - Replace a matrix subset - * - * @param {Object | Array | Matrix | string} object - * @param {Index} index - * @param {*} value - * @return {Object | Array | Matrix | string} Returns the original object - * except in case of a string - */ - // TODO: change assign to return the value instead of the object - return function assign(object, index, value) { - try { - if (Array.isArray(object)) { - return matrix$$1(object).subset(index, value).valueOf(); - } - else if (object && typeof object.subset === 'function') { // Matrix - return object.subset(index, value); - } - else if (typeof object === 'string') { - // TODO: move setStringSubset into a separate util file, use that - return subset(object, index, value); - } - else if (typeof object === 'object') { - if (!index.isObjectProperty()) { - throw TypeError('Cannot apply a numeric index as object property'); - } - setSafeProperty$2(object, index.getObjectProperty(), value); - return object; - } - else { - throw new TypeError('Cannot apply index: unsupported type of object'); - } - } - catch (err) { - throw errorTransform$1(err); - } - } - } - - var factory_1$46 = factory$47; - - var assign = { - factory: factory_1$46 - }; - - //list of identifiers of nodes in order of their precedence - //also contains information about left/right associativity - //and which other operator the operator is associative with - //Example: - // addition is associative with addition and subtraction, because: - // (a+b)+c=a+(b+c) - // (a+b)-c=a+(b-c) - // - // postfix operators are left associative, prefix operators - // are right associative - // - //It's also possible to set the following properties: - // latexParens: if set to false, this node doesn't need to be enclosed - // in parentheses when using LaTeX - // latexLeftParens: if set to false, this !OperatorNode's! - // left argument doesn't need to be enclosed - // in parentheses - // latexRightParens: the same for the right argument - var properties = [ - { //assignment - 'AssignmentNode': {}, - 'FunctionAssignmentNode': {} - }, - { //conditional expression - 'ConditionalNode': { - latexLeftParens: false, - latexRightParens: false, - latexParens: false - //conditionals don't need parentheses in LaTeX because - //they are 2 dimensional - } - }, - { //logical or - 'OperatorNode:or': { - associativity: 'left', - associativeWith: [] - } - - }, - { //logical xor - 'OperatorNode:xor': { - associativity: 'left', - associativeWith: [] - } - }, - { //logical and - 'OperatorNode:and': { - associativity: 'left', - associativeWith: [] - } - }, - { //bitwise or - 'OperatorNode:bitOr': { - associativity: 'left', - associativeWith: [] - } - }, - { //bitwise xor - 'OperatorNode:bitXor': { - associativity: 'left', - associativeWith: [] - } - }, - { //bitwise and - 'OperatorNode:bitAnd': { - associativity: 'left', - associativeWith: [] - } - }, - { //relational operators - 'OperatorNode:equal': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:unequal': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:smaller': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:larger': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:smallerEq': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:largerEq': { - associativity: 'left', - associativeWith: [] - } - }, - { //bitshift operators - 'OperatorNode:leftShift': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:rightArithShift': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:rightLogShift': { - associativity: 'left', - associativeWith: [] - } - }, - { //unit conversion - 'OperatorNode:to': { - associativity: 'left', - associativeWith: [] - } - }, - { //range - 'RangeNode': {} - }, - { //addition, subtraction - 'OperatorNode:add': { - associativity: 'left', - associativeWith: ['OperatorNode:add', 'OperatorNode:subtract'] - }, - 'OperatorNode:subtract': { - associativity: 'left', - associativeWith: [] - } - }, - { //multiply, divide, modulus - 'OperatorNode:multiply': { - associativity: 'left', - associativeWith: [ - 'OperatorNode:multiply', - 'OperatorNode:divide', - 'Operator:dotMultiply', - 'Operator:dotDivide' - ] - }, - 'OperatorNode:divide': { - associativity: 'left', - associativeWith: [], - latexLeftParens: false, - latexRightParens: false, - latexParens: false - //fractions don't require parentheses because - //they're 2 dimensional, so parens aren't needed - //in LaTeX - }, - 'OperatorNode:dotMultiply': { - associativity: 'left', - associativeWith: [ - 'OperatorNode:multiply', - 'OperatorNode:divide', - 'OperatorNode:dotMultiply', - 'OperatorNode:doDivide' - ] - }, - 'OperatorNode:dotDivide': { - associativity: 'left', - associativeWith: [] - }, - 'OperatorNode:mod': { - associativity: 'left', - associativeWith: [] - } - }, - { //unary prefix operators - 'OperatorNode:unaryPlus': { - associativity: 'right' - }, - 'OperatorNode:unaryMinus': { - associativity: 'right' - }, - 'OperatorNode:bitNot': { - associativity: 'right' - }, - 'OperatorNode:not': { - associativity: 'right' - } - }, - { //exponentiation - 'OperatorNode:pow': { - associativity: 'right', - associativeWith: [], - latexRightParens: false - //the exponent doesn't need parentheses in - //LaTeX because it's 2 dimensional - //(it's on top) - }, - 'OperatorNode:dotPow': { - associativity: 'right', - associativeWith: [] - } - }, - { //factorial - 'OperatorNode:factorial': { - associativity: 'left' - } - }, - { //matrix transpose - 'OperatorNode:transpose': { - associativity: 'left' - } - } - ]; - - /** - * Get the precedence of a Node. - * Higher number for higher precedence, starting with 0. - * Returns null if the precedence is undefined. - * - * @param {Node} - * @param {string} parenthesis - * @return {number|null} - */ - function getPrecedence (_node, parenthesis) { - var node = _node; - if (parenthesis !== 'keep') { - //ParenthesisNodes are only ignored when not in 'keep' mode - node = _node.getContent(); - } - var identifier = node.getIdentifier(); - for (var i = 0; i < properties.length; i++) { - if (identifier in properties[i]) { - return i; - } - } - return null; - } - - /** - * Get the associativity of an operator (left or right). - * Returns a string containing 'left' or 'right' or null if - * the associativity is not defined. - * - * @param {Node} - * @param {string} parenthesis - * @return {string|null} - * @throws {Error} - */ - function getAssociativity (_node, parenthesis) { - var node = _node; - if (parenthesis !== 'keep') { - //ParenthesisNodes are only ignored when not in 'keep' mode - node = _node.getContent(); - } - var identifier = node.getIdentifier(); - var index = getPrecedence(node, parenthesis); - if (index === null) { - //node isn't in the list - return null; - } - var property = properties[index][identifier]; - - if (property.hasOwnProperty('associativity')) { - if (property.associativity === 'left') { - return 'left'; - } - if (property.associativity === 'right') { - return 'right'; - } - //associativity is invalid - throw Error('\'' + identifier + '\' has the invalid associativity \'' - + property.associativity + '\'.'); - } - - //associativity is undefined - return null; - } - - /** - * Check if an operator is associative with another operator. - * Returns either true or false or null if not defined. - * - * @param {Node} nodeA - * @param {Node} nodeB - * @param {string} parenthesis - * @return {bool|null} - */ - function isAssociativeWith (nodeA, nodeB, parenthesis) { - var a = nodeA; - var b = nodeB; - if (parenthesis !== 'keep') { - //ParenthesisNodes are only ignored when not in 'keep' mode - var a = nodeA.getContent(); - var b = nodeB.getContent(); - } - var identifierA = a.getIdentifier(); - var identifierB = b.getIdentifier(); - var index = getPrecedence(a, parenthesis); - if (index === null) { - //node isn't in the list - return null; - } - var property = properties[index][identifierA]; - - if (property.hasOwnProperty('associativeWith') - && (property.associativeWith instanceof Array)) { - for (var i = 0; i < property.associativeWith.length; i++) { - if (property.associativeWith[i] === identifierB) { - return true; - } - } - return false; - } - - //associativeWith is not defined - return null; - } - - var properties_1 = properties; - var getPrecedence_1 = getPrecedence; - var getAssociativity_1 = getAssociativity; - var isAssociativeWith_1 = isAssociativeWith; - - var operators = { - properties: properties_1, - getPrecedence: getPrecedence_1, - getAssociativity: getAssociativity_1, - isAssociativeWith: isAssociativeWith_1 - }; - - var getSafeProperty$4 = customs.getSafeProperty; - var setSafeProperty$3 = customs.setSafeProperty; - - function factory$48 (type, config, load, typed) { - var Node$$1 = load(Node); - var assign$$1 = load(assign); - var access$$1 = load(access); - - var operators$$1 = operators; - - /** - * @constructor AssignmentNode - * @extends {Node} - * - * Define a symbol, like `a=3.2`, update a property like `a.b=3.2`, or - * replace a subset of a matrix like `A[2,2]=42`. - * - * Syntax: - * - * new AssignmentNode(symbol, value) - * new AssignmentNode(object, index, value) - * - * Usage: - * - * new AssignmentNode(new SymbolNode('a'), new ConstantNode(2)); // a=2 - * new AssignmentNode(new SymbolNode('a'), new IndexNode('b'), new ConstantNode(2)) // a.b=2 - * new AssignmentNode(new SymbolNode('a'), new IndexNode(1, 2), new ConstantNode(3)) // a[1,2]=3 - * - * @param {SymbolNode | AccessorNode} object Object on which to assign a value - * @param {IndexNode} [index=null] Index, property name or matrix - * index. Optional. If not provided - * and `object` is a SymbolNode, - * the property is assigned to the - * global scope. - * @param {Node} value The value to be assigned - */ - function AssignmentNode(object, index, value) { - if (!(this instanceof AssignmentNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.object = object; - this.index = value ? index : null; - this.value = value ? value : index; - - // validate input - if (!type.isSymbolNode(object) && !type.isAccessorNode(object)) { - throw new TypeError('SymbolNode or AccessorNode expected as "object"'); - } - if (type.isSymbolNode(object) && object.name === 'end') { - throw new Error('Cannot assign to symbol "end"'); - } - if (this.index && !type.isIndexNode(this.index)) { // index is optional - throw new TypeError('IndexNode expected as "index"'); - } - if (!type.isNode(this.value)) { - throw new TypeError('Node expected as "value"'); - } - - // readonly property name - Object.defineProperty(this, 'name', { - get: function () { - if (this.index) { - return (this.index.isObjectProperty()) - ? this.index.getObjectProperty() - : ''; - } - else { - return this.object.name || ''; - } - }.bind(this), - set: function () { - throw new Error('Cannot assign a new name, name is read-only'); - } - }); - } - - AssignmentNode.prototype = new Node$$1(); - - AssignmentNode.prototype.type = 'AssignmentNode'; - - AssignmentNode.prototype.isAssignmentNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - AssignmentNode.prototype._compile = function (math, argNames) { - var evalObject = this.object._compile(math, argNames); - var evalIndex = this.index ? this.index._compile(math, argNames) : null; - var evalValue = this.value._compile(math, argNames); - var name = this.object.name; - - if (!this.index) { - // apply a variable to the scope, for example `a=2` - if (!type.isSymbolNode(this.object)) { - throw new TypeError('SymbolNode expected as object'); - } - - return function evalAssignmentNode (scope, args, context) { - return setSafeProperty$3(scope, name, evalValue(scope, args, context)); - }; - } - else if (this.index.isObjectProperty()) { - // apply an object property for example `a.b=2` - var prop = this.index.getObjectProperty(); - - return function evalAssignmentNode (scope, args, context) { - var object = evalObject(scope, args, context); - var value = evalValue(scope, args, context); - return setSafeProperty$3(object, prop, value); - }; - } - else if (type.isSymbolNode(this.object)) { - // update a matrix subset, for example `a[2]=3` - return function evalAssignmentNode(scope, args, context) { - var childObject = evalObject(scope, args, context); - var value = evalValue(scope, args, context); - var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context - setSafeProperty$3(scope, name, assign$$1(childObject, index, value)); - return value; - } - } - else { // type.isAccessorNode(node.object) === true - // update a matrix subset, for example `a.b[2]=3` - - // we will not use the compile function of the AccessorNode, but compile it - // ourselves here as we need the parent object of the AccessorNode: - // wee need to apply the updated object to parent object - var evalParentObject = this.object.object._compile(math, argNames); - - if (this.object.index.isObjectProperty()) { - var parentProp = this.object.index.getObjectProperty(); - - return function evalAssignmentNode(scope, args, context) { - var parent = evalParentObject(scope, args, context); - var childObject = getSafeProperty$4(parent, parentProp); - var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context - var value = evalValue(scope, args, context); - setSafeProperty$3(parent, parentProp, assign$$1(childObject, index, value)); - return value; - } - } - else { - // if some parameters use the 'end' parameter, we need to calculate the size - var evalParentIndex = this.object.index._compile(math, argNames); - - return function evalAssignmentNode(scope, args, context) { - var parent = evalParentObject(scope, args, context); - var parentIndex = evalParentIndex(scope, args, parent); // Important: we pass parent instead of context - var childObject = access$$1(parent, parentIndex); - var index = evalIndex(scope, args, childObject); // Important: we pass childObject instead of context - var value = evalValue(scope, args, context); - - assign$$1(parent, parentIndex, assign$$1(childObject, index, value)); - - return value; - } - } - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - AssignmentNode.prototype.forEach = function (callback) { - callback(this.object, 'object', this); - if (this.index) { - callback(this.index, 'index', this); - } - callback(this.value, 'value', this); - }; - - /** - * Create a new AssignmentNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {AssignmentNode} Returns a transformed copy of the node - */ - AssignmentNode.prototype.map = function (callback) { - var object = this._ifNode(callback(this.object, 'object', this)); - var index = this.index - ? this._ifNode(callback(this.index, 'index', this)) - : null; - var value = this._ifNode(callback(this.value, 'value', this)); - - return new AssignmentNode(object, index, value); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {AssignmentNode} - */ - AssignmentNode.prototype.clone = function() { - return new AssignmentNode(this.object, this.index, this.value); - }; - - /* - * Is parenthesis needed? - * @param {node} node - * @param {string} [parenthesis='keep'] - * @private - */ - function needParenthesis(node, parenthesis) { - if (!parenthesis) { - parenthesis = 'keep'; - } - - var precedence = operators$$1.getPrecedence(node, parenthesis); - var exprPrecedence = operators$$1.getPrecedence(node.value, parenthesis); - return (parenthesis === 'all') - || ((exprPrecedence !== null) && (exprPrecedence <= precedence)); - } - - /** - * Get string representation - * @param {Object} options - * @return {string} - */ - AssignmentNode.prototype._toString = function(options) { - var object = this.object.toString(options); - var index = this.index ? this.index.toString(options) : ''; - var value = this.value.toString(options); - if (needParenthesis(this, options && options.parenthesis)) { - value = '(' + value + ')'; - } - - return object + index + ' = ' + value; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - AssignmentNode.prototype.toJSON = function () { - return { - mathjs: 'AssignmentNode', - object: this.object, - index: this.index, - value: this.value - }; - }; - - /** - * Instantiate an AssignmentNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "AssignmentNode", object: ..., index: ..., value: ...}`, - * where mathjs is optional - * @returns {AssignmentNode} - */ - AssignmentNode.fromJSON = function (json) { - return new AssignmentNode(json.object, json.index, json.value); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} - */ - AssignmentNode.prototype.toHTML = function(options) { - var object = this.object.toHTML(options); - var index = this.index ? this.index.toHTML(options) : ''; - var value = this.value.toHTML(options); - if (needParenthesis(this, options && options.parenthesis)) { - value = '(' + value + ')'; - } - - return object + index + '=' + value; - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} - */ - AssignmentNode.prototype._toTex = function(options) { - var object = this.object.toTex(options); - var index = this.index ? this.index.toTex(options) : ''; - var value = this.value.toTex(options); - if (needParenthesis(this, options && options.parenthesis)) { - value = '\\left(' + value + '\\right)'; - } - - return object + index + ':=' + value; - }; - - return AssignmentNode; - } - - var name$42 = 'AssignmentNode'; - var path$18 = 'expression.node'; - var factory_1$47 = factory$48; - - var AssignmentNode = { - name: name$42, - path: path$18, - factory: factory_1$47 - }; - - var forEach$1 = array.forEach; - var map$3 = array.map; - - function factory$49 (type, config, load, typed) { - var Node$$1 = load(Node); - var ResultSet$$1 = load(ResultSet); - - /** - * @constructor BlockNode - * @extends {Node} - * Holds a set with blocks - * @param {Array.<{node: Node} | {node: Node, visible: boolean}>} blocks - * An array with blocks, where a block is constructed as an Object - * with properties block, which is a Node, and visible, which is - * a boolean. The property visible is optional and is true by default - */ - function BlockNode(blocks) { - if (!(this instanceof BlockNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - // validate input, copy blocks - if (!Array.isArray(blocks)) throw new Error('Array expected'); - this.blocks = blocks.map(function (block) { - var node = block && block.node; - var visible = block && block.visible !== undefined ? block.visible : true; - - if (!type.isNode(node)) throw new TypeError('Property "node" must be a Node'); - if (typeof visible !== 'boolean') throw new TypeError('Property "visible" must be a boolean'); - - return { - node: node, - visible: visible - } - }); - } - - BlockNode.prototype = new Node$$1(); - - BlockNode.prototype.type = 'BlockNode'; - - BlockNode.prototype.isBlockNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - BlockNode.prototype._compile = function (math, argNames) { - var evalBlocks = map$3(this.blocks, function (block) { - return { - eval: block.node._compile(math, argNames), - visible: block.visible - }; - }); - - return function evalBlockNodes (scope, args, context) { - var results = []; - - forEach$1(evalBlocks, function evalBlockNode(block) { - var result = block.eval(scope, args, context); - if (block.visible) { - results.push(result); - } - }); - - return new ResultSet$$1(results); - } - }; - - /** - * Execute a callback for each of the child blocks of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - BlockNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.blocks.length; i++) { - callback(this.blocks[i].node, 'blocks[' + i + '].node', this); - } - }; - - /** - * Create a new BlockNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {BlockNode} Returns a transformed copy of the node - */ - BlockNode.prototype.map = function (callback) { - var blocks = []; - for (var i = 0; i < this.blocks.length; i++) { - var block = this.blocks[i]; - var node = this._ifNode(callback(block.node, 'blocks[' + i + '].node', this)); - blocks[i] = { - node: node, - visible: block.visible - }; - } - return new BlockNode(blocks); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {BlockNode} - */ - BlockNode.prototype.clone = function () { - var blocks = this.blocks.map(function (block) { - return { - node: block.node, - visible: block.visible - }; - }); - - return new BlockNode(blocks); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - BlockNode.prototype._toString = function (options) { - return this.blocks.map(function (param) { - return param.node.toString(options) + (param.visible ? '' : ';'); - }).join('\n'); - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - BlockNode.prototype.toJSON = function () { - return { - mathjs: 'BlockNode', - blocks: this.blocks - }; - }; - - /** - * Instantiate an BlockNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "BlockNode", blocks: [{node: ..., visible: false}, ...]}`, - * where mathjs is optional - * @returns {BlockNode} - */ - BlockNode.fromJSON = function (json) { - return new BlockNode(json.blocks); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - BlockNode.prototype.toHTML = function (options) { - return this.blocks.map(function (param) { - return param.node.toHTML(options) + (param.visible ? '' : ';'); - }).join('
'); - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - BlockNode.prototype._toTex = function (options) { - return this.blocks.map(function (param) { - return param.node.toTex(options) + (param.visible ? '' : ';'); - }).join('\\;\\;\n'); - }; - - return BlockNode; - } - - var name$43 = 'BlockNode'; - var path$19 = 'expression.node'; - var factory_1$48 = factory$49; - - var BlockNode = { - name: name$43, - path: path$19, - factory: factory_1$48 - }; - - function factory$50 (type, config, load, typed) { - /** - * Determine the type of a variable. - * - * Function `typeof` recognizes the following types of objects: - * - * Object | Returns | Example - * ---------------------- | ------------- | ------------------------------------------ - * null | `'null'` | `math.typeof(null)` - * number | `'number'` | `math.typeof(3.5)` - * boolean | `'boolean'` | `math.typeof(true)` - * string | `'string'` | `math.typeof('hello world')` - * Array | `'Array'` | `math.typeof([1, 2, 3])` - * Date | `'Date'` | `math.typeof(new Date())` - * Function | `'Function'` | `math.typeof(function () {})` - * Object | `'Object'` | `math.typeof({a: 2, b: 3})` - * RegExp | `'RegExp'` | `math.typeof(/a regexp/)` - * undefined | `'undefined'` | `math.typeof(undefined)` - * math.type.BigNumber | `'BigNumber'` | `math.typeof(math.bignumber('2.3e500'))` - * math.type.Chain | `'Chain'` | `math.typeof(math.chain(2))` - * math.type.Complex | `'Complex'` | `math.typeof(math.complex(2, 3))` - * math.type.Fraction | `'Fraction'` | `math.typeof(math.fraction(1, 3))` - * math.type.Help | `'Help'` | `math.typeof(math.help('sqrt'))` - * math.type.Help | `'Help'` | `math.typeof(math.help('sqrt'))` - * math.type.Index | `'Index'` | `math.typeof(math.index(1, 3))` - * math.type.Matrix | `'Matrix'` | `math.typeof(math.matrix([[1,2], [3, 4]]))` - * math.type.Range | `'Range'` | `math.typeof(math.range(0, 10))` - * math.type.ResultSet | `'ResultSet'` | `math.typeof(math.eval('a=2\nb=3'))` - * math.type.Unit | `'Unit'` | `math.typeof(math.unit('45 deg'))` - * math.expression.node.AccessorNode | `'AccessorNode'` | `math.typeof(math.parse('A[2]'))` - * math.expression.node.ArrayNode | `'ArrayNode'` | `math.typeof(math.parse('[1,2,3]'))` - * math.expression.node.AssignmentNode | `'AssignmentNode'` | `math.typeof(math.parse('x=2'))` - * math.expression.node.BlockNode | `'BlockNode'` | `math.typeof(math.parse('a=2; b=3'))` - * math.expression.node.ConditionalNode | `'ConditionalNode'` | `math.typeof(math.parse('x<0 ? -x : x'))` - * math.expression.node.ConstantNode | `'ConstantNode'` | `math.typeof(math.parse('2.3'))` - * math.expression.node.FunctionAssignmentNode | `'FunctionAssignmentNode'` | `math.typeof(math.parse('f(x)=x^2'))` - * math.expression.node.FunctionNode | `'FunctionNode'` | `math.typeof(math.parse('sqrt(4)'))` - * math.expression.node.IndexNode | `'IndexNode'` | `math.typeof(math.parse('A[2]').index)` - * math.expression.node.ObjectNode | `'ObjectNode'` | `math.typeof(math.parse('{a:2}'))` - * math.expression.node.ParenthesisNode | `'ParenthesisNode'` | `math.typeof(math.parse('(2+3)'))` - * math.expression.node.RangeNode | `'RangeNode'` | `math.typeof(math.parse('1:10'))` - * math.expression.node.SymbolNode | `'SymbolNode'` | `math.typeof(math.parse('x'))` - * - * Syntax: - * - * math.typeof(x) - * - * Examples: - * - * math.typeof(3.5); // returns 'number' - * math.typeof(math.complex('2-4i')); // returns 'Complex' - * math.typeof(math.unit('45 deg')); // returns 'Unit' - * math.typeof('hello world'); // returns 'string' - * - * @param {*} x The variable for which to test the type. - * @return {string} Returns the name of the type. Primitive types are lower case, - * non-primitive types are upper-camel-case. - * For example 'number', 'string', 'Array', 'Date'. - */ - var _typeof = typed('_typeof', { - 'any': function (x) { - var t = typeof x; - - if (t === 'object') { - // JavaScript types - if (x === null) return 'null'; - if (Array.isArray(x)) return 'Array'; - if (x instanceof Date) return 'Date'; - if (x instanceof RegExp) return 'RegExp'; - if (x instanceof Boolean) return 'boolean'; - if (x instanceof Number) return 'number'; - if (x instanceof String) return 'string'; - - // math.js types - if (type.isBigNumber(x)) return 'BigNumber'; - if (type.isComplex(x)) return 'Complex'; - if (type.isFraction(x)) return 'Fraction'; - if (type.isMatrix(x)) return 'Matrix'; - if (type.isUnit(x)) return 'Unit'; - if (type.isIndex(x)) return 'Index'; - if (type.isRange(x)) return 'Range'; - if (type.isResultSet(x)) return 'ResultSet'; - if (type.isNode(x)) return x.type; - if (type.isChain(x)) return 'Chain'; - if (type.isHelp(x)) return 'Help'; - - return 'Object'; - } - - if (t === 'function') return 'Function'; - - return t; // can be 'string', 'number', 'boolean', ... - } - }); - - _typeof.toTex = undefined; // use default template - - return _typeof; - } - - var name$44 = 'typeof'; - var factory_1$49 = factory$50; - - var _typeof$1 = { - name: name$44, - factory: factory_1$49 - }; - - function factory$51 (type, config, load, typed) { - var Node$$1 = load(Node); - var mathTypeOf = load(_typeof$1); - - /** - * A lazy evaluating conditional operator: 'condition ? trueExpr : falseExpr' - * - * @param {Node} condition Condition, must result in a boolean - * @param {Node} trueExpr Expression evaluated when condition is true - * @param {Node} falseExpr Expression evaluated when condition is true - * - * @constructor ConditionalNode - * @extends {Node} - */ - function ConditionalNode(condition, trueExpr, falseExpr) { - if (!(this instanceof ConditionalNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - if (!type.isNode(condition)) throw new TypeError('Parameter condition must be a Node'); - if (!type.isNode(trueExpr)) throw new TypeError('Parameter trueExpr must be a Node'); - if (!type.isNode(falseExpr)) throw new TypeError('Parameter falseExpr must be a Node'); - - this.condition = condition; - this.trueExpr = trueExpr; - this.falseExpr = falseExpr; - } - - ConditionalNode.prototype = new Node$$1(); - - ConditionalNode.prototype.type = 'ConditionalNode'; - - ConditionalNode.prototype.isConditionalNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ConditionalNode.prototype._compile = function (math, argNames) { - var evalCondition = this.condition._compile(math, argNames); - var evalTrueExpr = this.trueExpr._compile(math, argNames); - var evalFalseExpr = this.falseExpr._compile(math, argNames); - - return function evalConditionalNode(scope, args, context) { - return testCondition(evalCondition(scope, args, context)) - ? evalTrueExpr(scope, args, context) - : evalFalseExpr(scope, args, context); - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ConditionalNode.prototype.forEach = function (callback) { - callback(this.condition, 'condition', this); - callback(this.trueExpr, 'trueExpr', this); - callback(this.falseExpr, 'falseExpr', this); - }; - - /** - * Create a new ConditionalNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {ConditionalNode} Returns a transformed copy of the node - */ - ConditionalNode.prototype.map = function (callback) { - return new ConditionalNode( - this._ifNode(callback(this.condition, 'condition', this)), - this._ifNode(callback(this.trueExpr, 'trueExpr', this)), - this._ifNode(callback(this.falseExpr, 'falseExpr', this)) - ); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {ConditionalNode} - */ - ConditionalNode.prototype.clone = function () { - return new ConditionalNode(this.condition, this.trueExpr, this.falseExpr); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - ConditionalNode.prototype._toString = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var precedence = operators.getPrecedence(this, parenthesis); - - //Enclose Arguments in parentheses if they are an OperatorNode - //or have lower or equal precedence - //NOTE: enclosing all OperatorNodes in parentheses is a decision - //purely based on aesthetics and readability - var condition = this.condition.toString(options); - var conditionPrecedence = operators.getPrecedence(this.condition, parenthesis); - if ((parenthesis === 'all') - || (this.condition.type === 'OperatorNode') - || ((conditionPrecedence !== null) && (conditionPrecedence <= precedence))) { - condition = '(' + condition + ')'; - } - - var trueExpr = this.trueExpr.toString(options); - var truePrecedence = operators.getPrecedence(this.trueExpr, parenthesis); - if ((parenthesis === 'all') - || (this.trueExpr.type === 'OperatorNode') - || ((truePrecedence !== null) && (truePrecedence <= precedence))) { - trueExpr = '(' + trueExpr + ')'; - } - - var falseExpr = this.falseExpr.toString(options); - var falsePrecedence = operators.getPrecedence(this.falseExpr, parenthesis); - if ((parenthesis === 'all') - || (this.falseExpr.type === 'OperatorNode') - || ((falsePrecedence !== null) && (falsePrecedence <= precedence))) { - falseExpr = '(' + falseExpr + ')'; - } - return condition + ' ? ' + trueExpr + ' : ' + falseExpr; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ConditionalNode.prototype.toJSON = function () { - return { - mathjs: 'ConditionalNode', - condition: this.condition, - trueExpr: this.trueExpr, - falseExpr: this.falseExpr - }; - }; - - /** - * Instantiate an ConditionalNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "ConditionalNode", "condition": ..., "trueExpr": ..., "falseExpr": ...}`, - * where mathjs is optional - * @returns {ConditionalNode} - */ - ConditionalNode.fromJSON = function (json) { - return new ConditionalNode(json.condition, json.trueExpr, json.falseExpr); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - ConditionalNode.prototype.toHTML = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var precedence = operators.getPrecedence(this, parenthesis); - - //Enclose Arguments in parentheses if they are an OperatorNode - //or have lower or equal precedence - //NOTE: enclosing all OperatorNodes in parentheses is a decision - //purely based on aesthetics and readability - var condition = this.condition.toHTML(options); - var conditionPrecedence = operators.getPrecedence(this.condition, parenthesis); - if ((parenthesis === 'all') - || (this.condition.type === 'OperatorNode') - || ((conditionPrecedence !== null) && (conditionPrecedence <= precedence))) { - condition = '(' + condition + ')'; - } - - var trueExpr = this.trueExpr.toHTML(options); - var truePrecedence = operators.getPrecedence(this.trueExpr, parenthesis); - if ((parenthesis === 'all') - || (this.trueExpr.type === 'OperatorNode') - || ((truePrecedence !== null) && (truePrecedence <= precedence))) { - trueExpr = '(' + trueExpr + ')'; - } - - var falseExpr = this.falseExpr.toHTML(options); - var falsePrecedence = operators.getPrecedence(this.falseExpr, parenthesis); - if ((parenthesis === 'all') - || (this.falseExpr.type === 'OperatorNode') - || ((falsePrecedence !== null) && (falsePrecedence <= precedence))) { - falseExpr = '(' + falseExpr + ')'; - } - return condition + '?' + trueExpr + ':' + falseExpr; - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - ConditionalNode.prototype._toTex = function (options) { - return '\\begin{cases} {' - + this.trueExpr.toTex(options) + '}, &\\quad{\\text{if }\\;' - + this.condition.toTex(options) - + '}\\\\{' + this.falseExpr.toTex(options) - + '}, &\\quad{\\text{otherwise}}\\end{cases}'; - }; - - /** - * Test whether a condition is met - * @param {*} condition - * @returns {boolean} true if condition is true or non-zero, else false - */ - function testCondition (condition) { - if (typeof condition === 'number' - || typeof condition === 'boolean' - || typeof condition === 'string') { - return condition ? true : false; - } - - if (condition) { - if (type.isBigNumber(condition)) { - return condition.isZero() ? false : true; - } - - if (type.isComplex(condition)) { - return (condition.re || condition.im) ? true : false; - } - - if (type.isUnit(condition)) { - return condition.value ? true : false; - } - } - - if (condition === null || condition === undefined) { - return false; - } - - throw new TypeError('Unsupported type of condition "' + mathTypeOf(condition) + '"'); - } - return ConditionalNode; - } - - var name$45 = 'ConditionalNode'; - var path$20 = 'expression.node'; - var factory_1$50 = factory$51; - - var ConditionalNode = { - name: name$45, - path: path$20, - factory: factory_1$50 - }; - - var format$3 = string.format; - var escapeLatex = latex.escape; - - function factory$52 (type, config, load, typed) { - var Node$$1 = load(Node); - var getType = load(_typeof$1); - - /** - * A ConstantNode holds a constant value like a number or string. - * - * Usage: - * - * new ConstantNode(2.3); - * new ConstantNode('hello'); - * - * @param {*} value Value can be any type (number, BigNumber, string, ...) - * @constructor ConstantNode - * @extends {Node} - */ - function ConstantNode(value) { - if (!(this instanceof ConstantNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - if (arguments.length === 2) { - // TODO: remove deprecation error some day (created 2018-01-23) - throw new SyntaxError('new ConstantNode(valueStr, valueType) is not supported anymore since math v4.0.0. Use new ConstantNode(value) instead, where value is a non-stringified value.'); - } - - this.value = value; - } - - ConstantNode.prototype = new Node$$1(); - - ConstantNode.prototype.type = 'ConstantNode'; - - ConstantNode.prototype.isConstantNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ConstantNode.prototype._compile = function (math, argNames) { - var value = this.value; - - return function evalConstantNode() { - return value; - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ConstantNode.prototype.forEach = function (callback) { - // nothing to do, we don't have childs - }; - - /** - * Create a new ConstantNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node) : Node} callback - * @returns {ConstantNode} Returns a clone of the node - */ - ConstantNode.prototype.map = function (callback) { - return this.clone(); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {ConstantNode} - */ - ConstantNode.prototype.clone = function () { - return new ConstantNode(this.value); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - ConstantNode.prototype._toString = function (options) { - return format$3 (this.value, options); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - ConstantNode.prototype.toHTML = function (options) { - var value = this._toString(options); - - switch (getType(this.value)) { - case 'number': - case 'BigNumber': - case 'Fraction': - return '' + value + ''; - case 'string': - return '' + value + ''; - case 'boolean': - return '' + value + ''; - case 'null': - return '' + value + ''; - case 'undefined': - return '' + value + ''; - - default: - return '' + value + ''; - } - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ConstantNode.prototype.toJSON = function () { - return { - mathjs: 'ConstantNode', - value: this.value - }; - }; - - /** - * Instantiate a ConstantNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "SymbolNode", value: 2.3}`, - * where mathjs is optional - * @returns {ConstantNode} - */ - ConstantNode.fromJSON = function (json) { - return new ConstantNode(json.value); - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - ConstantNode.prototype._toTex = function (options) { - var value = this._toString(options); - - switch (getType(this.value)) { - case 'string': - return '\\mathtt{' + escapeLatex(value) + '}'; - - case 'number': - case 'BigNumber': - var index = value.toLowerCase().indexOf('e'); - if (index !== -1) { - return value.substring(0, index) + '\\cdot10^{' + - value.substring(index + 1) + '}'; - } - return value; - - case 'Fraction': - return this.value.toLatex(); - - default: - return value; - } - }; - - return ConstantNode; - } - - var name$46 = 'ConstantNode'; - var path$21 = 'expression.node'; - var factory_1$51 = factory$52; - - var ConstantNode = { - name: name$46, - path: path$21, - factory: factory_1$51 - }; - - var escape$1 = string.escape; - var forEach$2 = array.forEach; - var join = array.join; - - - var setSafeProperty$4 = customs.setSafeProperty; - - function factory$53 (type, config, load, typed) { - var Node$$1 = load(Node); - - /** - * @constructor FunctionAssignmentNode - * @extends {Node} - * Function assignment - * - * @param {string} name Function name - * @param {string[] | Array.<{name: string, type: string}>} params - * Array with function parameter names, or an - * array with objects containing the name - * and type of the parameter - * @param {Node} expr The function expression - */ - function FunctionAssignmentNode(name, params, expr) { - if (!(this instanceof FunctionAssignmentNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - // validate input - if (typeof name !== 'string') throw new TypeError('String expected for parameter "name"'); - if (!Array.isArray(params)) throw new TypeError('Array containing strings or objects expected for parameter "params"'); - if (!type.isNode(expr)) throw new TypeError('Node expected for parameter "expr"'); - if (name in keywords) throw new Error('Illegal function name, "' + name + '" is a reserved keyword'); - - this.name = name; - this.params = params.map(function (param) { - return param && param.name || param; - }); - this.types = params.map(function (param) { - return param && param.type || 'any' - }); - this.expr = expr; - } - - FunctionAssignmentNode.prototype = new Node$$1(); - - FunctionAssignmentNode.prototype.type = 'FunctionAssignmentNode'; - - FunctionAssignmentNode.prototype.isFunctionAssignmentNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - FunctionAssignmentNode.prototype._compile = function (math, argNames) { - var childArgNames = Object.create(argNames); - forEach$2(this.params, function (param) { - childArgNames[param] = true; - }); - - // compile the function expression with the child args - var evalExpr = this.expr._compile(math, childArgNames); - var name = this.name; - var params = this.params; - var signature = join(this.types, ','); - var syntax = name + '(' + join(this.params, ', ') + ')'; - - return function evalFunctionAssignmentNode(scope, args, context) { - var signatures = {}; - signatures[signature] = function () { - var childArgs = Object.create(args); - - for (var i = 0; i < params.length; i++) { - childArgs[params[i]] = arguments[i]; - } - - return evalExpr(scope, childArgs, context); - }; - var fn = typed(name, signatures); - fn.syntax = syntax; - - setSafeProperty$4(scope, name, fn); - - return fn; - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - FunctionAssignmentNode.prototype.forEach = function (callback) { - callback(this.expr, 'expr', this); - }; - - /** - * Create a new FunctionAssignmentNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {FunctionAssignmentNode} Returns a transformed copy of the node - */ - FunctionAssignmentNode.prototype.map = function (callback) { - var expr = this._ifNode(callback(this.expr, 'expr', this)); - - return new FunctionAssignmentNode(this.name, this.params.slice(0), expr); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {FunctionAssignmentNode} - */ - FunctionAssignmentNode.prototype.clone = function () { - return new FunctionAssignmentNode(this.name, this.params.slice(0), this.expr); - }; - - /** - * Is parenthesis needed? - * @param {Node} node - * @param {Object} parenthesis - * @private - */ - function needParenthesis(node, parenthesis) { - var precedence = operators.getPrecedence(node, parenthesis); - var exprPrecedence = operators.getPrecedence(node.expr, parenthesis); - - return (parenthesis === 'all') - || ((exprPrecedence !== null) && (exprPrecedence <= precedence)); - } - - /** - * get string representation - * @param {Object} options - * @return {string} str - */ - FunctionAssignmentNode.prototype._toString = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var expr = this.expr.toString(options); - if (needParenthesis(this, parenthesis)) { - expr = '(' + expr + ')'; - } - return this.name + '(' + this.params.join(', ') + ') = ' + expr; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - FunctionAssignmentNode.prototype.toJSON = function () { - var types = this.types; - - return { - mathjs: 'FunctionAssignmentNode', - name: this.name, - params: this.params.map(function(param, index) { - return { - name: param, - type: types[index] - } - }), - expr: this.expr - }; - }; - - /** - * Instantiate an FunctionAssignmentNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "FunctionAssignmentNode", name: ..., params: ..., expr: ...}`, - * where mathjs is optional - * @returns {FunctionAssignmentNode} - */ - FunctionAssignmentNode.fromJSON = function (json) { - return new FunctionAssignmentNode(json.name, json.params, json.expr); - }; - - /** - * get HTML representation - * @param {Object} options - * @return {string} str - */ - FunctionAssignmentNode.prototype.toHTML = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var params = []; - for (var i=0; i' + escape$1(this.params[i]) + ''); - } - var expr = this.expr.toHTML(options); - if (needParenthesis(this, parenthesis)) { - expr = '(' + expr + ')'; - } - return '' + escape$1(this.name) + '' + '(' + params.join(',') + ')=' + expr; - }; - - /** - * get LaTeX representation - * @param {Object} options - * @return {string} str - */ - FunctionAssignmentNode.prototype._toTex = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var expr = this.expr.toTex(options); - if (needParenthesis(this, parenthesis)) { - expr = '\\left(' + expr + '\\right)'; - } - - return '\\mathrm{' + this.name - + '}\\left(' + this.params.map(latex.toSymbol).join(',') + '\\right):=' + expr; - }; - - return FunctionAssignmentNode; - } - var name$47 = 'FunctionAssignmentNode'; - var path$22 = 'expression.node'; - var factory_1$52 = factory$53; - - var FunctionAssignmentNode = { - name: name$47, - path: path$22, - factory: factory_1$52 - }; - - var stringify = string.stringify; - var escape$2 = string.escape; - var isSafeProperty$1 = customs.isSafeProperty; - var hasOwnProperty$2 = object.hasOwnProperty; - - function factory$54 (type, config, load, typed) { - var Node$$1 = load(Node); - - /** - * @constructor ObjectNode - * @extends {Node} - * Holds an object with keys/values - * @param {Object.} [properties] object with key/value pairs - */ - function ObjectNode(properties) { - if (!(this instanceof ObjectNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - this.properties = properties || {}; - - // validate input - if (properties) { - if (!(typeof properties === 'object') || !Object.keys(properties).every(function (key) { - return type.isNode(properties[key]); - })) { - throw new TypeError('Object containing Nodes expected'); - } - } - } - - ObjectNode.prototype = new Node$$1(); - - ObjectNode.prototype.type = 'ObjectNode'; - - ObjectNode.prototype.isObjectNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ObjectNode.prototype._compile = function (math, argNames) { - var evalEntries = {}; - - for (var key in this.properties) { - if (hasOwnProperty$2(this.properties, key)) { - // we stringify/parse the key here to resolve unicode characters, - // so you cannot create a key like {"co\\u006Estructor": null} - var stringifiedKey = stringify(key); - var parsedKey = JSON.parse(stringifiedKey); - if (!isSafeProperty$1(this.properties, parsedKey)) { - throw new Error('No access to property "' + parsedKey + '"'); - } - - evalEntries[parsedKey]= this.properties[key]._compile(math, argNames); - } - } - - return function evalObjectNode (scope, args, context) { - var obj = {}; - - for (var key in evalEntries) { - if (hasOwnProperty$2(evalEntries, key)) { - obj[key] = evalEntries[key](scope, args, context); - } - } - - return obj; - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ObjectNode.prototype.forEach = function (callback) { - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - callback(this.properties[key], 'properties[' + stringify(key) + ']', this); - } - } - }; - - /** - * Create a new ObjectNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {ObjectNode} Returns a transformed copy of the node - */ - ObjectNode.prototype.map = function (callback) { - var properties = {}; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - properties[key] = this._ifNode(callback(this.properties[key], - 'properties[' + stringify(key) + ']', this)); - } - } - return new ObjectNode(properties); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {ObjectNode} - */ - ObjectNode.prototype.clone = function() { - var properties = {}; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - properties[key] = this.properties[key]; - } - } - return new ObjectNode(properties); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - ObjectNode.prototype._toString = function(options) { - var entries = []; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - entries.push(stringify(key) + ': ' + this.properties[key].toString(options)); - } - } - return '{' + entries.join(', ') + '}'; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ObjectNode.prototype.toJSON = function () { - return { - mathjs: 'ObjectNode', - properties: this.properties - }; - }; - - /** - * Instantiate an OperatorNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "ObjectNode", "properties": {...}}`, - * where mathjs is optional - * @returns {ObjectNode} - */ - ObjectNode.fromJSON = function (json) { - return new ObjectNode(json.properties); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - ObjectNode.prototype.toHTML = function(options) { - var entries = []; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - entries.push('' + escape$2(key) + '' + ':' + this.properties[key].toHTML(options)); - } - } - return '{' + entries.join(',') + '}'; - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - ObjectNode.prototype._toTex = function(options) { - var entries = []; - for (var key in this.properties) { - if (this.properties.hasOwnProperty(key)) { - entries.push("\\mathbf{" + key + ':} & ' + this.properties[key].toTex(options) + "\\\\"); - } - } - return '\\left\\{\\begin{array}{ll}' + entries.join('\n') + '\\end{array}\\right\\}'; - }; - - return ObjectNode; - } - - var name$48 = 'ObjectNode'; - var path$23 = 'expression.node'; - var factory_1$53 = factory$54; - - var ObjectNode = { - name: name$48, - path: path$23, - factory: factory_1$53 - }; - - var map$4 = array.map; - var escape$3 = string.escape; - var isSafeMethod$1 = customs.isSafeMethod; - var getSafeProperty$5 = customs.getSafeProperty; - - - function factory$55 (type, config, load, typed) { - var Node$$1 = load(Node); - - /** - * @constructor OperatorNode - * @extends {Node} - * An operator with two arguments, like 2+3 - * - * @param {string} op Operator name, for example '+' - * @param {string} fn Function name, for example 'add' - * @param {Node[]} args Operator arguments - * @param {boolean} [implicit] Is this an implicit multiplication? - */ - function OperatorNode(op, fn, args, implicit) { - if (!(this instanceof OperatorNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - //validate input - if (typeof op !== 'string') { - throw new TypeError('string expected for parameter "op"'); - } - if (typeof fn !== 'string') { - throw new TypeError('string expected for parameter "fn"'); - } - if (!Array.isArray(args) || !args.every(type.isNode)) { - throw new TypeError('Array containing Nodes expected for parameter "args"'); - } - - this.implicit = (implicit === true); - this.op = op; - this.fn = fn; - this.args = args || []; - } - - OperatorNode.prototype = new Node$$1(); - - OperatorNode.prototype.type = 'OperatorNode'; - - OperatorNode.prototype.isOperatorNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - OperatorNode.prototype._compile = function (math, argNames) { - // validate fn - if (typeof this.fn !== 'string' || !isSafeMethod$1(math, this.fn)) { - if (!math[this.fn]) { - throw new Error('Function ' + this.fn + ' missing in provided namespace "math"'); - } - else { - throw new Error('No access to function "' + this.fn + '"'); - } - } - - var fn = getSafeProperty$5(math, this.fn); - var evalArgs = map$4(this.args, function (arg) { - return arg._compile(math, argNames); - }); - - if (evalArgs.length === 1) { - var evalArg0 = evalArgs[0]; - return function evalOperatorNode(scope, args, context) { - return fn(evalArg0(scope, args, context)); - }; - } - else if (evalArgs.length === 2) { - var evalArg0 = evalArgs[0]; - var evalArg1 = evalArgs[1]; - return function evalOperatorNode(scope, args, context) { - return fn(evalArg0(scope, args, context), evalArg1(scope, args, context)) - }; - } - else { - return function evalOperatorNode(scope, args, context) { - return fn.apply(null, map$4(evalArgs, function (evalArg) { - return evalArg(scope, args, context) - })); - }; - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - OperatorNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.args.length; i++) { - callback(this.args[i], 'args[' + i + ']', this); - } - }; - - /** - * Create a new OperatorNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {OperatorNode} Returns a transformed copy of the node - */ - OperatorNode.prototype.map = function (callback) { - var args = []; - for (var i = 0; i < this.args.length; i++) { - args[i] = this._ifNode(callback(this.args[i], 'args[' + i + ']', this)); - } - return new OperatorNode(this.op, this.fn, args, this.implicit); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {OperatorNode} - */ - OperatorNode.prototype.clone = function () { - return new OperatorNode(this.op, this.fn, this.args.slice(0), this.implicit); - }; - - /** - * Check whether this is an unary OperatorNode: - * has exactly one argument, like `-a`. - * @return {boolean} Returns true when an unary operator node, false otherwise. - */ - OperatorNode.prototype.isUnary = function () { - return this.args.length === 1; - }; - - /** - * Check whether this is a binary OperatorNode: - * has exactly two arguments, like `a + b`. - * @return {boolean} Returns true when a binary operator node, false otherwise. - */ - OperatorNode.prototype.isBinary = function () { - return this.args.length === 2; - }; - - /** - * Calculate which parentheses are necessary. Gets an OperatorNode - * (which is the root of the tree) and an Array of Nodes - * (this.args) and returns an array where 'true' means that an argument - * has to be enclosed in parentheses whereas 'false' means the opposite. - * - * @param {OperatorNode} root - * @param {string} parenthesis - * @param {Node[]} args - * @param {boolean} latex - * @return {boolean[]} - * @private - */ - function calculateNecessaryParentheses(root, parenthesis, implicit, args, latex$$1) { - //precedence of the root OperatorNode - var precedence = operators.getPrecedence(root, parenthesis); - var associativity = operators.getAssociativity(root, parenthesis); - - if ((parenthesis === 'all') || ((args.length > 2) && (root.getIdentifier() !== 'OperatorNode:add') && (root.getIdentifier() !== 'OperatorNode:multiply'))) { - var parens = args.map(function (arg) { - switch (arg.getContent().type) { //Nodes that don't need extra parentheses - case 'ArrayNode': - case 'ConstantNode': - case 'SymbolNode': - case 'ParenthesisNode': - return false; - break; - default: - return true; - } - }); - return parens; - } - - var result = undefined; - switch (args.length) { - case 0: - result = []; - break; - - case 1: //unary operators - //precedence of the operand - var operandPrecedence = operators.getPrecedence(args[0], parenthesis); - - //handle special cases for LaTeX, where some of the parentheses aren't needed - if (latex$$1 && (operandPrecedence !== null)) { - var operandIdentifier; - var rootIdentifier; - if (parenthesis === 'keep') { - operandIdentifier = args[0].getIdentifier(); - rootIdentifier = root.getIdentifier(); - } - else { - //Ignore Parenthesis Nodes when not in 'keep' mode - operandIdentifier = args[0].getContent().getIdentifier(); - rootIdentifier = root.getContent().getIdentifier(); - } - if (operators.properties[precedence][rootIdentifier].latexLeftParens === false) { - result = [false]; - break; - } - - if (operators.properties[operandPrecedence][operandIdentifier].latexParens === false) { - result = [false]; - break; - } - } - - if (operandPrecedence === null) { - //if the operand has no defined precedence, no parens are needed - result = [false]; - break; - } - - if (operandPrecedence <= precedence) { - //if the operands precedence is lower, parens are needed - result = [true]; - break; - } - - //otherwise, no parens needed - result = [false]; - break; - - case 2: //binary operators - var lhsParens; //left hand side needs parenthesis? - //precedence of the left hand side - var lhsPrecedence = operators.getPrecedence(args[0], parenthesis); - //is the root node associative with the left hand side - var assocWithLhs = operators.isAssociativeWith(root, args[0], parenthesis); - - if (lhsPrecedence === null) { - //if the left hand side has no defined precedence, no parens are needed - //FunctionNode for example - lhsParens = false; - } - else if ((lhsPrecedence === precedence) && (associativity === 'right') && !assocWithLhs) { - //In case of equal precedence, if the root node is left associative - // parens are **never** necessary for the left hand side. - //If it is right associative however, parens are necessary - //if the root node isn't associative with the left hand side - lhsParens = true; - } - else if (lhsPrecedence < precedence) { - lhsParens = true; - } - else { - lhsParens = false; - } - - var rhsParens; //right hand side needs parenthesis? - //precedence of the right hand side - var rhsPrecedence = operators.getPrecedence(args[1], parenthesis); - //is the root node associative with the right hand side? - var assocWithRhs = operators.isAssociativeWith(root, args[1], parenthesis); - - if (rhsPrecedence === null) { - //if the right hand side has no defined precedence, no parens are needed - //FunctionNode for example - rhsParens = false; - } - else if ((rhsPrecedence === precedence) && (associativity === 'left') && !assocWithRhs) { - //In case of equal precedence, if the root node is right associative - // parens are **never** necessary for the right hand side. - //If it is left associative however, parens are necessary - //if the root node isn't associative with the right hand side - rhsParens = true; - } - else if (rhsPrecedence < precedence) { - rhsParens = true; - } - else { - rhsParens = false; - } - - //handle special cases for LaTeX, where some of the parentheses aren't needed - if (latex$$1) { - var rootIdentifier; - var lhsIdentifier; - var rhsIdentifier; - if (parenthesis === 'keep') { - rootIdentifier = root.getIdentifier(); - lhsIdentifier = root.args[0].getIdentifier(); - rhsIdentifier = root.args[1].getIdentifier(); - } - else { - //Ignore ParenthesisNodes when not in 'keep' mode - rootIdentifier = root.getContent().getIdentifier(); - lhsIdentifier = root.args[0].getContent().getIdentifier(); - rhsIdentifier = root.args[1].getContent().getIdentifier(); - } - - if (lhsPrecedence !== null) { - if (operators.properties[precedence][rootIdentifier].latexLeftParens === false) { - lhsParens = false; - } - - if (operators.properties[lhsPrecedence][lhsIdentifier].latexParens === false) { - lhsParens = false; - } - } - - if (rhsPrecedence !== null) { - if (operators.properties[precedence][rootIdentifier].latexRightParens === false) { - rhsParens = false; - } - - if (operators.properties[rhsPrecedence][rhsIdentifier].latexParens === false) { - rhsParens = false; - } - } - } - - result = [lhsParens, rhsParens]; - break; - - default: - if ((root.getIdentifier() === 'OperatorNode:add') || (root.getIdentifier() === 'OperatorNode:multiply')) { - var result = args.map(function (arg) { - var argPrecedence = operators.getPrecedence(arg, parenthesis); - var assocWithArg = operators.isAssociativeWith(root, arg, parenthesis); - var argAssociativity = operators.getAssociativity(arg, parenthesis); - if (argPrecedence === null) { - //if the argument has no defined precedence, no parens are needed - return false; - } else if ((precedence === argPrecedence) && (associativity === argAssociativity) && !assocWithArg) { - return true; - } else if (argPrecedence < precedence) { - return true; - } - - return false; - }); - } - break; - } - - //handles an edge case of 'auto' parentheses with implicit multiplication of ConstantNode - //In that case print parentheses for ParenthesisNodes even though they normally wouldn't be - //printed. - if ((args.length >= 2) && (root.getIdentifier() === 'OperatorNode:multiply') && root.implicit && (parenthesis === 'auto') && (implicit === 'hide')) { - result = args.map(function (arg, index) { - var isParenthesisNode = (arg.getIdentifier() === 'ParenthesisNode'); - if (result[index] || isParenthesisNode) { //put in parenthesis? - return true; - } - - return false; - }); - } - - return result; - } - - /** - * Get string representation. - * @param {Object} options - * @return {string} str - */ - OperatorNode.prototype._toString = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var implicit = (options && options.implicit) ? options.implicit : 'hide'; - var args = this.args; - var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, false); - - if (args.length === 1) { //unary operators - var assoc = operators.getAssociativity(this, parenthesis); - - var operand = args[0].toString(options); - if (parens[0]) { - operand = '(' + operand + ')'; - } - - if (assoc === 'right') { //prefix operator - return this.op + operand; - } - else if (assoc === 'left') { //postfix - return operand + this.op; - } - - //fall back to postfix - return operand + this.op; - } else if (args.length == 2) { - var lhs = args[0].toString(options); //left hand side - var rhs = args[1].toString(options); //right hand side - if (parens[0]) { //left hand side in parenthesis? - lhs = '(' + lhs + ')'; - } - if (parens[1]) { //right hand side in parenthesis? - rhs = '(' + rhs + ')'; - } - - if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit == 'hide')) { - return lhs + ' ' + rhs; - } - - return lhs + ' ' + this.op + ' ' + rhs; - } else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { - var stringifiedArgs = args.map(function (arg, index) { - arg = arg.toString(options); - if (parens[index]) { //put in parenthesis? - arg = '(' + arg + ')'; - } - - return arg; - }); - - if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit === 'hide')) { - return stringifiedArgs.join(' '); - } - - return stringifiedArgs.join(' ' + this.op + ' '); - } else { - //fallback to formatting as a function call - return this.fn + '(' + this.args.join(', ') + ')'; - } - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - OperatorNode.prototype.toJSON = function () { - return { - mathjs: 'OperatorNode', - op: this.op, - fn: this.fn, - args: this.args, - implicit: this.implicit - }; - }; - - /** - * Instantiate an OperatorNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "OperatorNode", "op": "+", "fn": "add", "args": [...], "implicit": false}`, - * where mathjs is optional - * @returns {OperatorNode} - */ - OperatorNode.fromJSON = function (json) { - return new OperatorNode(json.op, json.fn, json.args, json.implicit); - }; - - /** - * Get HTML representation. - * @param {Object} options - * @return {string} str - */ - OperatorNode.prototype.toHTML = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var implicit = (options && options.implicit) ? options.implicit : 'hide'; - var args = this.args; - var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, false); - - if (args.length === 1) { //unary operators - var assoc = operators.getAssociativity(this, parenthesis); - - var operand = args[0].toHTML(options); - if (parens[0]) { - operand = '(' + operand + ')'; - } - - if (assoc === 'right') { //prefix operator - return '' + escape$3(this.op) + '' + operand; - } - else if (assoc === 'left') { //postfix - return '' + escape$3(this.op) + '' + operand; - } - - //fall back to postfix - return '' + escape$3(this.op) + '' + operand; - } - else if (args.length == 2) { // binary operatoes - var lhs = args[0].toHTML(options); //left hand side - var rhs = args[1].toHTML(options); //right hand side - if (parens[0]) { //left hand side in parenthesis? - lhs = '(' + lhs + ')'; - } - if (parens[1]) { //right hand side in parenthesis? - rhs = '(' + rhs + ')'; - } - - if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit == 'hide')) { - return lhs + '' + rhs; - } - - return lhs + '' + escape$3(this.op) + '' + rhs; - } - else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { - var stringifiedArgs = args.map(function (arg, index) { - arg = arg.toHTML(options); - if (parens[index]) { //put in parenthesis? - arg = '(' + arg + ')'; - } - - return arg; - }); - - if (this.implicit && (this.getIdentifier() === 'OperatorNode:multiply') && (implicit === 'hide')) { - return stringifiedArgs.join(''); - } - - return stringifiedArgs.join('' + escape$3(this.op) + ''); - } else { - //fallback to formatting as a function call - return '' + escape$3(this.fn) + '(' + stringifiedArgs.join(',') + ')'; - } - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - OperatorNode.prototype._toTex = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var implicit = (options && options.implicit) ? options.implicit : 'hide'; - var args = this.args; - var parens = calculateNecessaryParentheses(this, parenthesis, implicit, args, true); - var op = latex.operators[this.fn]; - op = typeof op === 'undefined' ? this.op : op; //fall back to using this.op - - if (args.length === 1) { //unary operators - var assoc = operators.getAssociativity(this, parenthesis); - - var operand = args[0].toTex(options); - if (parens[0]) { - operand = '\\left(' + operand + '\\right)'; - } - - if (assoc === 'right') { //prefix operator - return op + operand; - } - else if (assoc === 'left') { //postfix operator - return operand + op; - } - - //fall back to postfix - return operand + op; - } else if (args.length === 2) { //binary operators - var lhs = args[0]; //left hand side - var lhsTex = lhs.toTex(options); - if (parens[0]) { - lhsTex = '\\left(' + lhsTex + '\\right)'; - } - - var rhs = args[1]; //right hand side - var rhsTex = rhs.toTex(options); - if (parens[1]) { - rhsTex = '\\left(' + rhsTex + '\\right)'; - } - - //handle some exceptions (due to the way LaTeX works) - var lhsIdentifier; - if (parenthesis === 'keep') { - lhsIdentifier = lhs.getIdentifier(); - } - else { - //Ignore ParenthesisNodes if in 'keep' mode - lhsIdentifier = lhs.getContent().getIdentifier(); - } - switch (this.getIdentifier()) { - case 'OperatorNode:divide': - //op contains '\\frac' at this point - return op + '{' + lhsTex + '}' + '{' + rhsTex + '}'; - case 'OperatorNode:pow': - lhsTex = '{' + lhsTex + '}'; - rhsTex = '{' + rhsTex + '}'; - switch (lhsIdentifier) { - case 'ConditionalNode': // - case 'OperatorNode:divide': - lhsTex = '\\left(' + lhsTex + '\\right)'; - } - case 'OperatorNode:multiply': - if (this.implicit && (implicit === 'hide')) { - return lhsTex + '~' + rhsTex; - } - } - return lhsTex + op + rhsTex; - } else if ((args.length > 2) && ((this.getIdentifier() === 'OperatorNode:add') || (this.getIdentifier() === 'OperatorNode:multiply'))) { - var texifiedArgs = args.map(function (arg, index) { - arg = arg.toTex(options); - if (parens[index]) { - arg = '\\left(' + arg + '\\right)'; - } - return arg; - }); - - if ((this.getIdentifier() === 'OperatorNode:multiply') && this.implicit) { - return texifiedArgs.join('~'); - } - - return texifiedArgs.join(op) - } else { - //fall back to formatting as a function call - //as this is a fallback, it doesn't use - //fancy function names - return '\\mathrm{' + this.fn + '}\\left(' - + args.map(function (arg) { - return arg.toTex(options); - }).join(',') + '\\right)'; - } - }; - - /** - * Get identifier. - * @return {string} - */ - OperatorNode.prototype.getIdentifier = function () { - return this.type + ':' + this.fn; - }; - - return OperatorNode; - } - - var name$49 = 'OperatorNode'; - var path$24 = 'expression.node'; - var factory_1$54 = factory$55; - - var OperatorNode = { - name: name$49, - path: path$24, - factory: factory_1$54 - }; - - function factory$56 (type, config, load, typed) { - var Node$$1 = load(Node); - - /** - * @constructor ParenthesisNode - * @extends {Node} - * A parenthesis node describes manual parenthesis from the user input - * @param {Node} content - * @extends {Node} - */ - function ParenthesisNode(content) { - if (!(this instanceof ParenthesisNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - // validate input - if (!type.isNode(content)) { - throw new TypeError('Node expected for parameter "content"'); - } - - this.content = content; - } - - ParenthesisNode.prototype = new Node$$1(); - - ParenthesisNode.prototype.type = 'ParenthesisNode'; - - ParenthesisNode.prototype.isParenthesisNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - ParenthesisNode.prototype._compile = function (math, argNames) { - return this.content._compile(math, argNames); - }; - - /** - * Get the content of the current Node. - * @return {Node} content - * @override - **/ - ParenthesisNode.prototype.getContent = function () { - return this.content.getContent(); - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - ParenthesisNode.prototype.forEach = function (callback) { - callback(this.content, 'content', this); - }; - - /** - * Create a new ParenthesisNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node) : Node} callback - * @returns {ParenthesisNode} Returns a clone of the node - */ - ParenthesisNode.prototype.map = function (callback) { - var content = callback(this.content, 'content', this); - return new ParenthesisNode(content); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {ParenthesisNode} - */ - ParenthesisNode.prototype.clone = function() { - return new ParenthesisNode(this.content); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - ParenthesisNode.prototype._toString = function(options) { - if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { - return '(' + this.content.toString(options) + ')'; - } - return this.content.toString(options); - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - ParenthesisNode.prototype.toJSON = function () { - return { - mathjs: 'ParenthesisNode', - content: this.content - }; - }; - - /** - * Instantiate an ParenthesisNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "ParenthesisNode", "content": ...}`, - * where mathjs is optional - * @returns {ParenthesisNode} - */ - ParenthesisNode.fromJSON = function (json) { - return new ParenthesisNode(json.content); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - ParenthesisNode.prototype.toHTML = function(options) { - if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { - return '(' + this.content.toHTML(options) + ')'; - } - return this.content.toHTML(options); - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - * @override - */ - ParenthesisNode.prototype._toTex = function(options) { - if ((!options) || (options && !options.parenthesis) || (options && options.parenthesis === 'keep')) { - return '\\left(' + this.content.toTex(options) + '\\right)'; - } - return this.content.toTex(options); - }; - - return ParenthesisNode; - } - - var name$50 = 'ParenthesisNode'; - var path$25 = 'expression.node'; - var factory_1$55 = factory$56; - - var ParenthesisNode = { - name: name$50, - path: path$25, - factory: factory_1$55 - }; - - var escape$4 = string.escape; - var hasOwnProperty$3 = object.hasOwnProperty; - var getSafeProperty$6 = customs.getSafeProperty; - - function factory$57 (type, config, load, typed, math) { - var Node$$1 = load(Node); - - /** - * Check whether some name is a valueless unit like "inch". - * @param {string} name - * @return {boolean} - */ - function isValuelessUnit (name) { - return type.Unit ? type.Unit.isValuelessUnit(name) : false; - } - - /** - * @constructor SymbolNode - * @extends {Node} - * A symbol node can hold and resolve a symbol - * @param {string} name - * @extends {Node} - */ - function SymbolNode(name) { - if (!(this instanceof SymbolNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - // validate input - if (typeof name !== 'string') throw new TypeError('String expected for parameter "name"'); - - this.name = name; - } - - SymbolNode.prototype = new Node$$1(); - - SymbolNode.prototype.type = 'SymbolNode'; - - SymbolNode.prototype.isSymbolNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - SymbolNode.prototype._compile = function (math, argNames) { - var name = this.name; - - if (hasOwnProperty$3(argNames, name)) { - // this is a FunctionAssignment argument - // (like an x when inside the expression of a function assignment `f(x) = ...`) - return function (scope, args, context) { - return args[name]; - } - } - else if (name in math) { - return function (scope, args, context) { - return name in scope - ? getSafeProperty$6(scope, name) - : getSafeProperty$6(math, name); - } - } - else { - var isUnit = isValuelessUnit(name); - - return function (scope, args, context) { - return name in scope - ? getSafeProperty$6(scope, name) - : isUnit - ? new type.Unit(null, name) - : undef(name); - } - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - SymbolNode.prototype.forEach = function (callback) { - // nothing to do, we don't have childs - }; - - /** - * Create a new SymbolNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node) : Node} callback - * @returns {SymbolNode} Returns a clone of the node - */ - SymbolNode.prototype.map = function (callback) { - return this.clone(); - }; - - /** - * Throws an error 'Undefined symbol {name}' - * @param {string} name - */ - function undef (name) { - throw new Error('Undefined symbol ' + name); - } - - /** - * Create a clone of this node, a shallow copy - * @return {SymbolNode} - */ - SymbolNode.prototype.clone = function() { - return new SymbolNode(this.name); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - * @override - */ - SymbolNode.prototype._toString = function(options) { - return this.name; - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - * @override - */ - SymbolNode.prototype.toHTML = function(options) { - var name = escape$4(this.name); - - if (name == "true" || name == "false") { - return '' + name + ''; - } - else if (name == "i") { - return '' + name + ''; - } - else if (name == "Infinity") { - return '' + name + ''; - } - else if (name == "NaN") { - return '' + name + ''; - } - else if (name == "null") { - return '' + name + ''; - } - else if (name == "undefined") { - return '' + name + ''; - } - - return '' + name + ''; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - SymbolNode.prototype.toJSON = function () { - return { - mathjs: 'SymbolNode', - name: this.name - }; - }; - - /** - * Instantiate a SymbolNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "SymbolNode", name: "x"}`, - * where mathjs is optional - * @returns {SymbolNode} - */ - SymbolNode.fromJSON = function (json) { - return new SymbolNode(json.name); - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - * @override - */ - SymbolNode.prototype._toTex = function(options) { - var isUnit = false; - if ((typeof math[this.name] === 'undefined') && isValuelessUnit(this.name)) { - isUnit = true; - } - var symbol = latex.toSymbol(this.name, isUnit); - if (symbol[0] === '\\') { - //no space needed if the symbol starts with '\' - return symbol; - } - //the space prevents symbols from breaking stuff like '\cdot' if it's written right before the symbol - return ' ' + symbol; - }; - - return SymbolNode; - } - - var name$51 = 'SymbolNode'; - var path$26 = 'expression.node'; - var math$7 = true; // request access to the math namespace as 5th argument of the factory function - var factory_1$56 = factory$57; - - var SymbolNode = { - name: name$51, - path: path$26, - math: math$7, - factory: factory_1$56 - }; - - var latex$1 = latex; - var escape$5 = string.escape; - var hasOwnProperty$4 = object.hasOwnProperty; - var map$5 = array.map; - var validateSafeMethod$1 = customs.validateSafeMethod; - var getSafeProperty$7 = customs.getSafeProperty; - - function factory$58 (type, config, load, typed, math) { - var Node$$1 = load(Node); - var SymbolNode$$1 = load(SymbolNode); - - /** - * @constructor FunctionNode - * @extends {./Node} - * invoke a list with arguments on a node - * @param {./Node | string} fn Node resolving with a function on which to invoke - * the arguments, typically a SymboNode or AccessorNode - * @param {./Node[]} args - */ - function FunctionNode(fn, args) { - if (!(this instanceof FunctionNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - if (typeof fn === 'string') { - fn = new SymbolNode$$1(fn); - } - - // validate input - if (!type.isNode(fn)) throw new TypeError('Node expected as parameter "fn"'); - if (!Array.isArray(args) || !args.every(type.isNode)) { - throw new TypeError('Array containing Nodes expected for parameter "args"'); - } - - this.fn = fn; - this.args = args || []; - - // readonly property name - Object.defineProperty(this, 'name', { - get: function () { - return this.fn.name || ''; - }.bind(this), - set: function () { - throw new Error('Cannot assign a new name, name is read-only'); - } - }); - - // TODO: deprecated since v3, remove some day - var deprecated = function () { - throw new Error('Property `FunctionNode.object` is deprecated, use `FunctionNode.fn` instead'); - }; - Object.defineProperty(this, 'object', { get: deprecated, set: deprecated }); - } - - FunctionNode.prototype = new Node$$1(); - - FunctionNode.prototype.type = 'FunctionNode'; - - FunctionNode.prototype.isFunctionNode = true; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - FunctionNode.prototype._compile = function (math, argNames) { - if (!(this instanceof FunctionNode)) { - throw new TypeError('No valid FunctionNode') - } - - // compile arguments - var evalArgs = map$5(this.args, function (arg) { - return arg._compile(math, argNames); - }); - - if (type.isSymbolNode(this.fn)) { - // we can statically determine whether the function has an rawArgs property - var name = this.fn.name; - var fn = name in math ? getSafeProperty$7(math, name) : undefined; - var isRaw = (typeof fn === 'function') && (fn.rawArgs == true); - - if (isRaw) { - // pass unevaluated parameters (nodes) to the function - // "raw" evaluation - var rawArgs = this.args; - return function evalFunctionNode(scope, args, context) { - return (name in scope ? getSafeProperty$7(scope, name) : fn)(rawArgs, math, scope); - }; - } - else { - // "regular" evaluation - if (evalArgs.length === 1) { - var evalArg0 = evalArgs[0]; - return function evalFunctionNode(scope, args, context) { - return (name in scope ? getSafeProperty$7(scope, name) : fn)(evalArg0(scope, args, context)); - }; - } - else if (evalArgs.length === 2) { - var evalArg0 = evalArgs[0]; - var evalArg1 = evalArgs[1]; - return function evalFunctionNode(scope, args, context) { - return (name in scope ? getSafeProperty$7(scope, name) : fn)(evalArg0(scope, args, context), evalArg1(scope, args, context)); - }; - } - else { - return function evalFunctionNode(scope, args, context) { - return (name in scope ? getSafeProperty$7(scope, name) : fn).apply(null, map$5(evalArgs, function (evalArg) { - return evalArg(scope, args, context); - })); - } - } - } - } - else if (type.isAccessorNode(this.fn) && - type.isIndexNode(this.fn.index) && this.fn.index.isObjectProperty()) { - // execute the function with the right context: the object of the AccessorNode - - var evalObject = this.fn.object._compile(math, argNames); - var prop = this.fn.index.getObjectProperty(); - var rawArgs = this.args; - - return function evalFunctionNode (scope, args, context) { - var object$$1 = evalObject(scope, args, context); - validateSafeMethod$1(object$$1, prop); - var isRaw = object$$1[prop] && object$$1[prop].rawArgs; - - return isRaw - ? object$$1[prop](rawArgs, math, scope) // "raw" evaluation - : object$$1[prop].apply(object$$1, map$5(evalArgs, function (evalArg) { // "regular" evaluation - return evalArg(scope, args, context); - })); - } - } - else { // node.fn.isAccessorNode && !node.fn.index.isObjectProperty() - // we have to dynamically determine whether the function has a rawArgs property - var evalFn = this.fn._compile(math, argNames); - - return function evalFunctionNode (scope, args, context) { - var fn = evalFn(scope, args, context); - var isRaw = fn && fn.rawArgs; - - return isRaw - ? fn(rawArgs, math, scope) // "raw" evaluation - : fn.apply(fn, map$5(evalArgs, function (evalArg) { // "regular" evaluation - return evalArg(scope, args, context); - })); - }; - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - FunctionNode.prototype.forEach = function (callback) { - for (var i = 0; i < this.args.length; i++) { - callback(this.args[i], 'args[' + i + ']', this); - } - }; - - /** - * Create a new FunctionNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {FunctionNode} Returns a transformed copy of the node - */ - FunctionNode.prototype.map = function (callback) { - var fn = this.fn.map(callback); - var args = []; - for (var i = 0; i < this.args.length; i++) { - args[i] = this._ifNode(callback(this.args[i], 'args[' + i + ']', this)); - } - return new FunctionNode(fn, args); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {FunctionNode} - */ - FunctionNode.prototype.clone = function () { - return new FunctionNode(this.fn, this.args.slice(0)); - }; - - //backup Node's toString function - //@private - var nodeToString = FunctionNode.prototype.toString; - - /** - * Get string representation. (wrapper function) - * This overrides parts of Node's toString function. - * If callback is an object containing callbacks, it - * calls the correct callback for the current node, - * otherwise it falls back to calling Node's toString - * function. - * - * @param {Object} options - * @return {string} str - * @override - */ - FunctionNode.prototype.toString = function (options) { - var customString; - var name = this.fn.toString(options); - if (options && (typeof options.handler === 'object') && hasOwnProperty$4(options.handler, name)) { - //callback is a map of callback functions - customString = options.handler[name](this, options); - } - - if (typeof customString !== 'undefined') { - return customString; - } - - //fall back to Node's toString - return nodeToString.call(this, options); - }; - - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - FunctionNode.prototype._toString = function (options) { - var args = this.args.map(function (arg) { - return arg.toString(options); - }); - - var fn = type.isFunctionAssignmentNode(this.fn) - ? ('(' + this.fn.toString(options) + ')') - : this.fn.toString(options); - - // format the arguments like "add(2, 4.2)" - return fn + '(' + args.join(', ') + ')'; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - FunctionNode.prototype.toJSON = function () { - return { - mathjs: 'FunctionNode', - fn: this.fn, - args: this.args - }; - }; - - /** - * Instantiate an AssignmentNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "FunctionNode", fn: ..., args: ...}`, - * where mathjs is optional - * @returns {FunctionNode} - */ - FunctionNode.fromJSON = function (json) { - return new FunctionNode(json.fn, json.args); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - FunctionNode.prototype.toHTML = function (options) { - var args = this.args.map(function (arg) { - return arg.toHTML(options); - }); - - // format the arguments like "add(2, 4.2)" - return '' + escape$5(this.fn) + '(' + args.join(',') + ')'; - }; - - /* - * Expand a LaTeX template - * - * @param {string} template - * @param {Node} node - * @param {Object} options - * @private - **/ - function expandTemplate(template, node, options) { - var latex$$1 = ''; - - // Match everything of the form ${identifier} or ${identifier[2]} or $$ - // while submatching identifier and 2 (in the second case) - var regex = new RegExp('\\$(?:\\{([a-z_][a-z_0-9]*)(?:\\[([0-9]+)\\])?\\}|\\$)', 'ig'); - - var inputPos = 0; //position in the input string - var match; - while ((match = regex.exec(template)) !== null) { //go through all matches - // add everything in front of the match to the LaTeX string - latex$$1 += template.substring(inputPos, match.index); - inputPos = match.index; - - if (match[0] === '$$') { // escaped dollar sign - latex$$1 += '$'; - inputPos++; - } - else { // template parameter - inputPos += match[0].length; - var property = node[match[1]]; - if (!property) { - throw new ReferenceError('Template: Property ' + match[1] + ' does not exist.'); - } - if (match[2] === undefined) { //no square brackets - switch (typeof property) { - case 'string': - latex$$1 += property; - break; - case 'object': - if (type.isNode(property)) { - latex$$1 += property.toTex(options); - } - else if (Array.isArray(property)) { - //make array of Nodes into comma separated list - latex$$1 += property.map(function (arg, index) { - if (type.isNode(arg)) { - return arg.toTex(options); - } - throw new TypeError('Template: ' + match[1] + '[' + index + '] is not a Node.'); - }).join(','); - } - else { - throw new TypeError('Template: ' + match[1] + ' has to be a Node, String or array of Nodes'); - } - break; - default: - throw new TypeError('Template: ' + match[1] + ' has to be a Node, String or array of Nodes'); - } - } - else { //with square brackets - if (type.isNode(property[match[2]] && property[match[2]])) { - latex$$1 += property[match[2]].toTex(options); - } - else { - throw new TypeError('Template: ' + match[1] + '[' + match[2] + '] is not a Node.'); - } - } - } - } - latex$$1 += template.slice(inputPos); //append rest of the template - - return latex$$1; - } - - //backup Node's toTex function - //@private - var nodeToTex = FunctionNode.prototype.toTex; - - /** - * Get LaTeX representation. (wrapper function) - * This overrides parts of Node's toTex function. - * If callback is an object containing callbacks, it - * calls the correct callback for the current node, - * otherwise it falls back to calling Node's toTex - * function. - * - * @param {Object} options - * @return {string} - */ - FunctionNode.prototype.toTex = function (options) { - var customTex; - if (options && (typeof options.handler === 'object') && hasOwnProperty$4(options.handler, this.name)) { - //callback is a map of callback functions - customTex = options.handler[this.name](this, options); - } - - if (typeof customTex !== 'undefined') { - return customTex; - } - - //fall back to Node's toTex - return nodeToTex.call(this, options); - }; - - /** - * Get LaTeX representation - * @param {Object} options - * @return {string} str - */ - FunctionNode.prototype._toTex = function (options) { - var args = this.args.map(function (arg) { //get LaTeX of the arguments - return arg.toTex(options); - }); - - var latexConverter; - - if (math[this.name] && ((typeof math[this.name].toTex === 'function') || (typeof math[this.name].toTex === 'object') || (typeof math[this.name].toTex === 'string'))) { - //.toTex is a callback function - latexConverter = math[this.name].toTex; - } - - var customToTex; - switch (typeof latexConverter) { - case 'function': //a callback function - customToTex = latexConverter(this, options); - break; - case 'string': //a template string - customToTex = expandTemplate(latexConverter, this, options); - break; - case 'object': //an object with different "converters" for different numbers of arguments - switch (typeof latexConverter[args.length]) { - case 'function': - customToTex = latexConverter[args.length](this, options); - break; - case 'string': - customToTex = expandTemplate(latexConverter[args.length], this, options); - break; - } - } - - if (typeof customToTex !== 'undefined') { - return customToTex; - } - - return expandTemplate(latex$1.defaultTemplate, this, options); - }; - - /** - * Get identifier. - * @return {string} - */ - FunctionNode.prototype.getIdentifier = function () { - return this.type + ':' + this.name; - }; - - return FunctionNode; - } - - var name$52 = 'FunctionNode'; - var path$27 = 'expression.node'; - var math$8 = true; // request access to the math namespace as 5th argument of the factory function - var factory_1$57 = factory$58; - - var FunctionNode = { - name: name$52, - path: path$27, - math: math$8, - factory: factory_1$57 - }; - - function factory$59 (type, config, load, typed) { - var Node$$1 = load(Node); - - /** - * @constructor RangeNode - * @extends {Node} - * create a range - * @param {Node} start included lower-bound - * @param {Node} end included upper-bound - * @param {Node} [step] optional step - */ - function RangeNode(start, end, step) { - if (!(this instanceof RangeNode)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - // validate inputs - if (!type.isNode(start)) throw new TypeError('Node expected'); - if (!type.isNode(end)) throw new TypeError('Node expected'); - if (step && !type.isNode(step)) throw new TypeError('Node expected'); - if (arguments.length > 3) throw new Error('Too many arguments'); - - this.start = start; // included lower-bound - this.end = end; // included upper-bound - this.step = step || null; // optional step - } - - RangeNode.prototype = new Node$$1(); - - RangeNode.prototype.type = 'RangeNode'; - - RangeNode.prototype.isRangeNode = true; - - /** - * Check whether the RangeNode needs the `end` symbol to be defined. - * This end is the size of the Matrix in current dimension. - * @return {boolean} - */ - RangeNode.prototype.needsEnd = function () { - // find all `end` symbols in this RangeNode - var endSymbols = this.filter(function (node) { - return type.isSymbolNode(node) && (node.name === 'end'); - }); - - return endSymbols.length > 0; - }; - - /** - * Compile a node into a JavaScript function. - * This basically pre-calculates as much as possible and only leaves open - * calculations which depend on a dynamic scope with variables. - * @param {Object} math Math.js namespace with functions and constants. - * @param {Object} argNames An object with argument names as key and `true` - * as value. Used in the SymbolNode to optimize - * for arguments from user assigned functions - * (see FunctionAssignmentNode) or special symbols - * like `end` (see IndexNode). - * @return {function} Returns a function which can be called like: - * evalNode(scope: Object, args: Object, context: *) - */ - RangeNode.prototype._compile = function (math, argNames) { - var range = math.range; - var evalStart = this.start._compile(math, argNames); - var evalEnd = this.end._compile(math, argNames); - - if (this.step) { - var evalStep = this.step._compile(math, argNames); - - return function evalRangeNode(scope, args, context) { - return range( - evalStart(scope, args, context), - evalEnd(scope, args, context), - evalStep(scope, args, context) - ); - } - } - else { - return function evalRangeNode(scope, args, context) { - return range( - evalStart(scope, args, context), - evalEnd(scope, args, context) - ); - } - } - }; - - /** - * Execute a callback for each of the child nodes of this node - * @param {function(child: Node, path: string, parent: Node)} callback - */ - RangeNode.prototype.forEach = function (callback) { - callback(this.start, 'start', this); - callback(this.end, 'end', this); - if (this.step) { - callback(this.step, 'step', this); - } - }; - - /** - * Create a new RangeNode having it's childs be the results of calling - * the provided callback function for each of the childs of the original node. - * @param {function(child: Node, path: string, parent: Node): Node} callback - * @returns {RangeNode} Returns a transformed copy of the node - */ - RangeNode.prototype.map = function (callback) { - return new RangeNode( - this._ifNode(callback(this.start, 'start', this)), - this._ifNode(callback(this.end, 'end', this)), - this.step && this._ifNode(callback(this.step, 'step', this)) - ); - }; - - /** - * Create a clone of this node, a shallow copy - * @return {RangeNode} - */ - RangeNode.prototype.clone = function () { - return new RangeNode(this.start, this.end, this.step && this.step); - }; - - /** - * Calculate the necessary parentheses - * @param {Node} node - * @param {string} parenthesis - * @return {Object} parentheses - * @private - */ - function calculateNecessaryParentheses(node, parenthesis) { - var precedence = operators.getPrecedence(node, parenthesis); - var parens = {}; - - var startPrecedence = operators.getPrecedence(node.start, parenthesis); - parens.start = ((startPrecedence !== null) && (startPrecedence <= precedence)) - || (parenthesis === 'all'); - - if (node.step) { - var stepPrecedence = operators.getPrecedence(node.step, parenthesis); - parens.step = ((stepPrecedence !== null) && (stepPrecedence <= precedence)) - || (parenthesis === 'all'); - } - - var endPrecedence = operators.getPrecedence(node.end, parenthesis); - parens.end = ((endPrecedence !== null) && (endPrecedence <= precedence)) - || (parenthesis === 'all'); - - return parens; - } - - /** - * Get string representation - * @param {Object} options - * @return {string} str - */ - RangeNode.prototype._toString = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var parens = calculateNecessaryParentheses(this, parenthesis); - - //format string as start:step:stop - var str; - - var start = this.start.toString(options); - if (parens.start) { - start = '(' + start + ')'; - } - str = start; - - if (this.step) { - var step = this.step.toString(options); - if (parens.step) { - step = '(' + step + ')'; - } - str += ':' + step; - } - - var end = this.end.toString(options); - if (parens.end) { - end = '(' + end + ')'; - } - str += ':' + end; - - return str; - }; - - /** - * Get a JSON representation of the node - * @returns {Object} - */ - RangeNode.prototype.toJSON = function () { - return { - mathjs: 'RangeNode', - start: this.start, - end: this.end, - step: this.step - }; - }; - - /** - * Instantiate an RangeNode from its JSON representation - * @param {Object} json An object structured like - * `{"mathjs": "RangeNode", "start": ..., "end": ..., "step": ...}`, - * where mathjs is optional - * @returns {RangeNode} - */ - RangeNode.fromJSON = function (json) { - return new RangeNode(json.start, json.end, json.step); - }; - - /** - * Get HTML representation - * @param {Object} options - * @return {string} str - */ - RangeNode.prototype.toHTML = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var parens = calculateNecessaryParentheses(this, parenthesis); - - //format string as start:step:stop - var str; - - var start = this.start.toHTML(options); - if (parens.start) { - start = '(' + start + ')'; - } - str = start; - - if (this.step) { - var step = this.step.toHTML(options); - if (parens.step) { - step = '(' + step + ')'; - } - str += ':' + step; - } - - var end = this.end.toHTML(options); - if (parens.end) { - end = '(' + end + ')'; - } - str += ':' + end; - - return str; - }; - - /** - * Get LaTeX representation - * @params {Object} options - * @return {string} str - */ - RangeNode.prototype._toTex = function (options) { - var parenthesis = (options && options.parenthesis) ? options.parenthesis : 'keep'; - var parens = calculateNecessaryParentheses(this, parenthesis); - - var str = this.start.toTex(options); - if (parens.start) { - str = '\\left(' + str + '\\right)'; - } - - if (this.step) { - var step = this.step.toTex(options); - if (parens.step) { - step = '\\left(' + step + '\\right)'; - } - str += ':' + step; - } - - var end = this.end.toTex(options); - if (parens.end) { - end = '\\left(' + end + '\\right)'; - } - str += ':' + end; - - return str; - }; - - return RangeNode; - } - - var name$53 = 'RangeNode'; - var path$28 = 'expression.node'; - var factory_1$58 = factory$59; - - var RangeNode = { - name: name$53, - path: path$28, - factory: factory_1$58 - }; - - function factory$60 (type, config, load, typed) { - var numeric$$1 = load(numeric); - - var AccessorNode$$1 = load(AccessorNode); - var ArrayNode$$1 = load(ArrayNode); - var AssignmentNode$$1 = load(AssignmentNode); - var BlockNode$$1 = load(BlockNode); - var ConditionalNode$$1 = load(ConditionalNode); - var ConstantNode$$1 = load(ConstantNode); - var FunctionAssignmentNode$$1 = load(FunctionAssignmentNode); - var IndexNode$$1 = load(IndexNode); - var ObjectNode$$1 = load(ObjectNode); - var OperatorNode$$1 = load(OperatorNode); - var ParenthesisNode$$1 = load(ParenthesisNode); - var FunctionNode$$1 = load(FunctionNode); - var RangeNode$$1 = load(RangeNode); - var SymbolNode$$1 = load(SymbolNode); - - /** - * Parse an expression. Returns a node tree, which can be evaluated by - * invoking node.eval(); - * - * Syntax: - * - * parse(expr) - * parse(expr, options) - * parse([expr1, expr2, expr3, ...]) - * parse([expr1, expr2, expr3, ...], options) - * - * Example: - * - * var node = parse('sqrt(3^2 + 4^2)'); - * node.compile(math).eval(); // 5 - * - * var scope = {a:3, b:4} - * var node = parse('a * b'); // 12 - * var code = node.compile(math); - * code.eval(scope); // 12 - * scope.a = 5; - * code.eval(scope); // 20 - * - * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); - * nodes[2].compile(math).eval(); // 12 - * - * @param {string | string[] | Matrix} expr - * @param {{nodes: Object}} [options] Available options: - * - `nodes` a set of custom nodes - * @return {Node | Node[]} node - * @throws {Error} - */ - function parse (expr, options) { - if (arguments.length !== 1 && arguments.length !== 2) { - throw new ArgumentsError_1('parse', arguments.length, 1, 2); - } - - // pass extra nodes - extra_nodes = (options && options.nodes) ? options.nodes : {}; - - if (typeof expr === 'string') { - // parse a single expression - expression = expr; - return parseStart(); - } - else if (Array.isArray(expr) || expr instanceof type.Matrix) { - // parse an array or matrix with expressions - return deepMap(expr, function (elem) { - if (typeof elem !== 'string') throw new TypeError('String expected'); - - expression = elem; - return parseStart(); - }); - } - else { - // oops - throw new TypeError('String or matrix expected'); - } - } - - // token types enumeration - var TOKENTYPE = { - NULL : 0, - DELIMITER : 1, - NUMBER : 2, - SYMBOL : 3, - UNKNOWN : 4 - }; - - // map with all delimiters - var DELIMITERS = { - ',': true, - '(': true, - ')': true, - '[': true, - ']': true, - '{': true, - '}': true, - '\"': true, - ';': true, - - '+': true, - '-': true, - '*': true, - '.*': true, - '/': true, - './': true, - '%': true, - '^': true, - '.^': true, - '~': true, - '!': true, - '&': true, - '|': true, - '^|': true, - '\'': true, - '=': true, - ':': true, - '?': true, - - '==': true, - '!=': true, - '<': true, - '>': true, - '<=': true, - '>=': true, - - '<<': true, - '>>': true, - '>>>': true - }; - - // map with all named delimiters - var NAMED_DELIMITERS = { - 'mod': true, - 'to': true, - 'in': true, - 'and': true, - 'xor': true, - 'or': true, - 'not': true - }; - - var CONSTANTS = { - 'true': true, - 'false': false, - 'null': null, - 'undefined': undefined - }; - - var NUMERIC_CONSTANTS = [ - 'NaN', - 'Infinity' - ]; - - var extra_nodes = {}; // current extra nodes - var expression = ''; // current expression - var comment = ''; // last parsed comment - var index = 0; // current index in expr - var c = ''; // current token character in expr - var token = ''; // current token - var token_type = TOKENTYPE.NULL; // type of the token - var nesting_level = 0; // level of nesting inside parameters, used to ignore newline characters - var conditional_level = null; // when a conditional is being parsed, the level of the conditional is stored here - var tokenStates = []; // holds saved token states - - /** - * Get the first character from the expression. - * The character is stored into the char c. If the end of the expression is - * reached, the function puts an empty string in c. - * @private - */ - function first() { - index = 0; - c = expression.charAt(0); - nesting_level = 0; - conditional_level = null; - } - - /** - * Get the next character from the expression. - * The character is stored into the char c. If the end of the expression is - * reached, the function puts an empty string in c. - * @private - */ - function next() { - index++; - c = expression.charAt(index); - } - - /** - * Preview the previous character from the expression. - * @return {string} cNext - * @private - */ - function prevPreview() { - return expression.charAt(index - 1); - } - - /** - * Preview the next character from the expression. - * @return {string} cNext - * @private - */ - function nextPreview() { - return expression.charAt(index + 1); - } - - /** - * Preview the second next character from the expression. - * @return {string} cNext - * @private - */ - function nextNextPreview() { - return expression.charAt(index + 2); - } - - /** - * Save the current token state so we can rewind later if necessary. - * @private - */ - function pushTokenState() { - tokenStates.push({ - token_type: token_type, - token: token, - comment: comment, - index: index, - c: c - }); - } - - /** - * Rewind the parser by one token by restoring the last saved token state - * @private - */ - function popTokenState() { - var restoredState = tokenStates.pop(); - token_type = restoredState.token_type; - token = restoredState.token; - comment = restoredState.comment; - index = restoredState.index; - c = restoredState.c; - } - - /** - * Discard the most recent token state without restoring it - * @private - */ - function discardTokenState() { - tokenStates.pop(); - } - - /** - * Get next token in the current string expr. - * The token and token type are available as token and token_type - * @private - */ - function getToken() { - token_type = TOKENTYPE.NULL; - token = ''; - comment = ''; - - // skip over whitespaces - // space, tab, and newline when inside parameters - while (parse.isWhitespace(c, nesting_level)) { - next(); - } - - // skip comment - if (c === '#') { - while (c !== '\n' && c !== '') { - comment += c; - next(); - } - } - - // check for end of expression - if (c === '') { - // token is still empty - token_type = TOKENTYPE.DELIMITER; - return; - } - - // check for new line character - if (c === '\n' && !nesting_level) { - token_type = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } - - // check for delimiters consisting of 3 characters - var c2 = c + nextPreview(); - var c3 = c2 + nextNextPreview(); - if (c3.length === 3 && DELIMITERS[c3]) { - token_type = TOKENTYPE.DELIMITER; - token = c3; - next(); - next(); - next(); - return; - } - - // check for delimiters consisting of 2 characters - if (c2.length === 2 && DELIMITERS[c2]) { - token_type = TOKENTYPE.DELIMITER; - token = c2; - next(); - next(); - return; - } - - // check for delimiters consisting of 1 character - if (DELIMITERS[c]) { - token_type = TOKENTYPE.DELIMITER; - token = c; - next(); - return; - } - - // check for a number - if (parse.isDigitDot(c)) { - token_type = TOKENTYPE.NUMBER; - - // get number, can have a single dot - if (c === '.') { - token += c; - next(); - - if (!parse.isDigit(c)) { - // this is no number, it is just a dot (can be dot notation) - token_type = TOKENTYPE.DELIMITER; - } - } - else { - while (parse.isDigit(c)) { - token += c; - next(); - } - if (parse.isDecimalMark(c, nextPreview())) { - token += c; - next(); - } - } - while (parse.isDigit(c)) { - token += c; - next(); - } - - // check for exponential notation like "2.3e-4", "1.23e50" or "2e+4" - c2 = nextPreview(); - if (c === 'E' || c === 'e') { - if (parse.isDigit(c2) || c2 === '-' || c2 === '+') { - token += c; - next(); - - if (c === '+' || c === '-') { - token += c; - next(); - } - - // Scientific notation MUST be followed by an exponent - if (!parse.isDigit(c)) { - throw createSyntaxError('Digit expected, got "' + c + '"'); - } - - while (parse.isDigit(c)) { - token += c; - next(); - } - - if (parse.isDecimalMark(c, nextPreview())) { - throw createSyntaxError('Digit expected, got "' + c + '"'); - } - } - else if (c2 === '.') { - next(); - throw createSyntaxError('Digit expected, got "' + c + '"'); - } - } - - return; - } - - // check for variables, functions, named operators - if (parse.isAlpha(c, prevPreview(), nextPreview())) { - while (parse.isAlpha(c, prevPreview(), nextPreview()) || parse.isDigit(c)) { - token += c; - next(); - } - - if (NAMED_DELIMITERS.hasOwnProperty(token)) { - token_type = TOKENTYPE.DELIMITER; - } - else { - token_type = TOKENTYPE.SYMBOL; - } - - return; - } - - // something unknown is found, wrong characters -> a syntax error - token_type = TOKENTYPE.UNKNOWN; - while (c !== '') { - token += c; - next(); - } - throw createSyntaxError('Syntax error in part "' + token + '"'); - } - - /** - * Get next token and skip newline tokens - */ - function getTokenSkipNewline () { - do { - getToken(); - } - while (token === '\n'); - } - - /** - * Open parameters. - * New line characters will be ignored until closeParams() is called - */ - function openParams() { - nesting_level++; - } - - /** - * Close parameters. - * New line characters will no longer be ignored - */ - function closeParams() { - nesting_level--; - } - - /** - * Checks whether the current character `c` is a valid alpha character: - * - * - A latin letter (upper or lower case) Ascii: a-z, A-Z - * - An underscore Ascii: _ - * - A dollar sign Ascii: $ - * - A latin letter with accents Unicode: \u00C0 - \u02AF - * - A greek letter Unicode: \u0370 - \u03FF - * - A mathematical alphanumeric symbol Unicode: \u{1D400} - \u{1D7FF} excluding invalid code points - * - * The previous and next characters are needed to determine whether - * this character is part of a unicode surrogate pair. - * - * @param {string} c Current character in the expression - * @param {string} cPrev Previous character - * @param {string} cNext Next character - * @return {boolean} - */ - parse.isAlpha = function isAlpha (c, cPrev, cNext) { - return parse.isValidLatinOrGreek(c) - || parse.isValidMathSymbol(c, cNext) - || parse.isValidMathSymbol(cPrev, c); - }; - - /** - * Test whether a character is a valid latin, greek, or letter-like character - * @param {string} c - * @return {boolean} - */ - parse.isValidLatinOrGreek = function isValidLatinOrGreek (c) { - return /^[a-zA-Z_$\u00C0-\u02AF\u0370-\u03FF\u2100-\u214F]$/.test(c); - }; - - /** - * Test whether two given 16 bit characters form a surrogate pair of a - * unicode math symbol. - * - * http://unicode-table.com/en/ - * http://www.wikiwand.com/en/Mathematical_operators_and_symbols_in_Unicode - * - * Note: In ES6 will be unicode aware: - * http://stackoverflow.com/questions/280712/javascript-unicode-regexes - * https://mathiasbynens.be/notes/es6-unicode-regex - * - * @param {string} high - * @param {string} low - * @return {boolean} - */ - parse.isValidMathSymbol = function isValidMathSymbol (high, low) { - return /^[\uD835]$/.test(high) && - /^[\uDC00-\uDFFF]$/.test(low) && - /^[^\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]$/.test(low); - }; - - /** - * Check whether given character c is a white space character: space, tab, or enter - * @param {string} c - * @param {number} nestingLevel - * @return {boolean} - */ - parse.isWhitespace = function isWhitespace (c, nestingLevel) { - // TODO: also take '\r' carriage return as newline? Or does that give problems on mac? - return c === ' ' || c === '\t' || (c === '\n' && nestingLevel > 0); - }; - - /** - * Test whether the character c is a decimal mark (dot). - * This is the case when it's not the start of a delimiter '.*', './', or '.^' - * @param {string} c - * @param {string} cNext - * @return {boolean} - */ - parse.isDecimalMark = function isDecimalMark (c, cNext) { - return c === '.' && cNext !== '/' && cNext !== '*' && cNext !== '^'; - }; - - /** - * checks if the given char c is a digit or dot - * @param {string} c a string with one character - * @return {boolean} - */ - parse.isDigitDot = function isDigitDot (c) { - return ((c >= '0' && c <= '9') || c === '.'); - }; - - /** - * checks if the given char c is a digit - * @param {string} c a string with one character - * @return {boolean} - */ - parse.isDigit = function isDigit (c) { - return (c >= '0' && c <= '9'); - }; - - /** - * Start of the parse levels below, in order of precedence - * @return {Node} node - * @private - */ - function parseStart () { - // get the first character in expression - first(); - - getToken(); - - var node = parseBlock(); - - // check for garbage at the end of the expression - // an expression ends with a empty character '' and token_type DELIMITER - if (token !== '') { - if (token_type === TOKENTYPE.DELIMITER) { - // user entered a not existing operator like "//" - - // TODO: give hints for aliases, for example with "<>" give as hint " did you mean !== ?" - throw createError('Unexpected operator ' + token); - } - else { - throw createSyntaxError('Unexpected part "' + token + '"'); - } - } - - return node; - } - - /** - * Parse a block with expressions. Expressions can be separated by a newline - * character '\n', or by a semicolon ';'. In case of a semicolon, no output - * of the preceding line is returned. - * @return {Node} node - * @private - */ - function parseBlock () { - var node; - var blocks = []; - var visible; - - if (token !== '' && token !== '\n' && token !== ';') { - node = parseAssignment(); - node.comment = comment; - } - - // TODO: simplify this loop - while (token === '\n' || token === ';') { - if (blocks.length === 0 && node) { - visible = (token !== ';'); - blocks.push({ - node: node, - visible: visible - }); - } - - getToken(); - if (token !== '\n' && token !== ';' && token !== '') { - node = parseAssignment(); - node.comment = comment; - - visible = (token !== ';'); - blocks.push({ - node: node, - visible: visible - }); - } - } - - if (blocks.length > 0) { - return new BlockNode$$1(blocks); - } - else { - if (!node) { - node = new ConstantNode$$1(undefined); - node.comment = comment; - } - - return node - } - } - - /** - * Assignment of a function or variable, - * - can be a variable like 'a=2.3' - * - or a updating an existing variable like 'matrix(2,3:5)=[6,7,8]' - * - defining a function like 'f(x) = x^2' - * @return {Node} node - * @private - */ - function parseAssignment () { - var name, args, value, valid; - - var node = parseConditional(); - - if (token === '=') { - if (type.isSymbolNode(node)) { - // parse a variable assignment like 'a = 2/3' - name = node.name; - getTokenSkipNewline(); - value = parseAssignment(); - return new AssignmentNode$$1(new SymbolNode$$1(name), value); - } - else if (type.isAccessorNode(node)) { - // parse a matrix subset assignment like 'A[1,2] = 4' - getTokenSkipNewline(); - value = parseAssignment(); - return new AssignmentNode$$1(node.object, node.index, value); - } - else if (type.isFunctionNode(node) && type.isSymbolNode(node.fn)) { - // parse function assignment like 'f(x) = x^2' - valid = true; - args = []; - - name = node.name; - node.args.forEach(function (arg, index) { - if (type.isSymbolNode(arg)) { - args[index] = arg.name; - } - else { - valid = false; - } - }); - - if (valid) { - getTokenSkipNewline(); - value = parseAssignment(); - return new FunctionAssignmentNode$$1(name, args, value); - } - } - - throw createSyntaxError('Invalid left hand side of assignment operator ='); - } - - return node; - } - - /** - * conditional operation - * - * condition ? truePart : falsePart - * - * Note: conditional operator is right-associative - * - * @return {Node} node - * @private - */ - function parseConditional () { - var node = parseLogicalOr(); - - while (token === '?') { - // set a conditional level, the range operator will be ignored as long - // as conditional_level === nesting_level. - var prev = conditional_level; - conditional_level = nesting_level; - getTokenSkipNewline(); - - var condition = node; - var trueExpr = parseAssignment(); - - if (token !== ':') throw createSyntaxError('False part of conditional expression expected'); - - conditional_level = null; - getTokenSkipNewline(); - - var falseExpr = parseAssignment(); // Note: check for conditional operator again, right associativity - - node = new ConditionalNode$$1(condition, trueExpr, falseExpr); - - // restore the previous conditional level - conditional_level = prev; - } - - return node; - } - - /** - * logical or, 'x or y' - * @return {Node} node - * @private - */ - function parseLogicalOr() { - var node = parseLogicalXor(); - - while (token === 'or') { - getTokenSkipNewline(); - node = new OperatorNode$$1('or', 'or', [node, parseLogicalXor()]); - } - - return node; - } - - /** - * logical exclusive or, 'x xor y' - * @return {Node} node - * @private - */ - function parseLogicalXor() { - var node = parseLogicalAnd(); - - while (token === 'xor') { - getTokenSkipNewline(); - node = new OperatorNode$$1('xor', 'xor', [node, parseLogicalAnd()]); - } - - return node; - } - - /** - * logical and, 'x and y' - * @return {Node} node - * @private - */ - function parseLogicalAnd() { - var node = parseBitwiseOr(); - - while (token === 'and') { - getTokenSkipNewline(); - node = new OperatorNode$$1('and', 'and', [node, parseBitwiseOr()]); - } - - return node; - } - - /** - * bitwise or, 'x | y' - * @return {Node} node - * @private - */ - function parseBitwiseOr() { - var node = parseBitwiseXor(); - - while (token === '|') { - getTokenSkipNewline(); - node = new OperatorNode$$1('|', 'bitOr', [node, parseBitwiseXor()]); - } - - return node; - } - - /** - * bitwise exclusive or (xor), 'x ^| y' - * @return {Node} node - * @private - */ - function parseBitwiseXor() { - var node = parseBitwiseAnd(); - - while (token === '^|') { - getTokenSkipNewline(); - node = new OperatorNode$$1('^|', 'bitXor', [node, parseBitwiseAnd()]); - } - - return node; - } - - /** - * bitwise and, 'x & y' - * @return {Node} node - * @private - */ - function parseBitwiseAnd () { - var node = parseRelational(); - - while (token === '&') { - getTokenSkipNewline(); - node = new OperatorNode$$1('&', 'bitAnd', [node, parseRelational()]); - } - - return node; - } - - /** - * relational operators - * @return {Node} node - * @private - */ - function parseRelational () { - var node, operators, name, fn, params; - - node = parseShift(); - - operators = { - '==': 'equal', - '!=': 'unequal', - '<': 'smaller', - '>': 'larger', - '<=': 'smallerEq', - '>=': 'largerEq' - }; - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; - - getTokenSkipNewline(); - params = [node, parseShift()]; - node = new OperatorNode$$1(name, fn, params); - } - - return node; - } - - /** - * Bitwise left shift, bitwise right arithmetic shift, bitwise right logical shift - * @return {Node} node - * @private - */ - function parseShift () { - var node, operators, name, fn, params; - - node = parseConversion(); - - operators = { - '<<' : 'leftShift', - '>>' : 'rightArithShift', - '>>>' : 'rightLogShift' - }; - - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; - - getTokenSkipNewline(); - params = [node, parseConversion()]; - node = new OperatorNode$$1(name, fn, params); - } - - return node; - } - - /** - * conversion operators 'to' and 'in' - * @return {Node} node - * @private - */ - function parseConversion () { - var node, operators, name, fn, params; - - node = parseRange(); - - operators = { - 'to' : 'to', - 'in' : 'to' // alias of 'to' - }; - - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; - - getTokenSkipNewline(); - - if (name === 'in' && token === '') { - // end of expression -> this is the unit 'in' ('inch') - node = new OperatorNode$$1('*', 'multiply', [node, new SymbolNode$$1('in')], true); - } - else { - // operator 'a to b' or 'a in b' - params = [node, parseRange()]; - node = new OperatorNode$$1(name, fn, params); - } - } - - return node; - } - - /** - * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc - * @return {Node} node - * @private - */ - function parseRange () { - var node, params = []; - - if (token === ':') { - // implicit start=1 (one-based) - node = new ConstantNode$$1(1); - } - else { - // explicit start - node = parseAddSubtract(); - } - - if (token === ':' && (conditional_level !== nesting_level)) { - // we ignore the range operator when a conditional operator is being processed on the same level - params.push(node); - - // parse step and end - while (token === ':' && params.length < 3) { - getTokenSkipNewline(); - - if (token === ')' || token === ']' || token === ',' || token === '') { - // implicit end - params.push(new SymbolNode$$1('end')); - } - else { - // explicit end - params.push(parseAddSubtract()); - } - } - - if (params.length === 3) { - // params = [start, step, end] - node = new RangeNode$$1(params[0], params[2], params[1]); // start, end, step - } - else { // length === 2 - // params = [start, end] - node = new RangeNode$$1(params[0], params[1]); // start, end - } - } - - return node; - } - - /** - * add or subtract - * @return {Node} node - * @private - */ - function parseAddSubtract () { - var node, operators, name, fn, params; - - node = parseMultiplyDivide(); - - operators = { - '+': 'add', - '-': 'subtract' - }; - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; - - getTokenSkipNewline(); - params = [node, parseMultiplyDivide()]; - node = new OperatorNode$$1(name, fn, params); - } - - return node; - } - - /** - * multiply, divide, modulus - * @return {Node} node - * @private - */ - function parseMultiplyDivide () { - var node, last, operators, name, fn; - - node = parseImplicitMultiplication(); - last = node; - - operators = { - '*': 'multiply', - '.*': 'dotMultiply', - '/': 'divide', - './': 'dotDivide', - '%': 'mod', - 'mod': 'mod' - }; - - while (true) { - if (operators.hasOwnProperty(token)) { - // explicit operators - name = token; - fn = operators[name]; - - getTokenSkipNewline(); - - last = parseImplicitMultiplication(); - node = new OperatorNode$$1(name, fn, [node, last]); - } - else { - break; - } - } - - return node; - } - - /** - * implicit multiplication - * @return {Node} node - * @private - */ - function parseImplicitMultiplication () { - var node, last; - - node = parseRule2(); - last = node; - - while (true) { - if ((token_type === TOKENTYPE.SYMBOL) || - (token === 'in' && type.isConstantNode(node)) || - (token_type === TOKENTYPE.NUMBER && - !type.isConstantNode(last) && - (!type.isOperatorNode(last) || last.op === '!')) || - (token === '(')) { - // parse implicit multiplication - // - // symbol: implicit multiplication like '2a', '(2+3)a', 'a b' - // number: implicit multiplication like '(2+3)2' - // parenthesis: implicit multiplication like '2(3+4)', '(3+4)(1+2)' - last = parseRule2(); - node = new OperatorNode$$1('*', 'multiply', [node, last], true /*implicit*/); - } - else { - break; - } - } - - return node; - } - - /** - * Infamous "rule 2" as described in https://github.com/josdejong/mathjs/issues/792#issuecomment-361065370 - * Explicit division gets higher precedence than implicit multiplication - * when the division matches this pattern: [number] / [number] [symbol] - * @return {Node} node - * @private - */ - function parseRule2 () { - var node, last; - - node = parseUnary(); - last = node; - - - while(true) { - - // Match the "number /" part of the pattern "number / number symbol" - if(token === '/' && type.isConstantNode(last)) { - - // Look ahead to see if the next token is a number - pushTokenState(); - getTokenSkipNewline(); - - // Match the "number / number" part of the pattern - if(token_type === TOKENTYPE.NUMBER) { - - // Look ahead again - pushTokenState(); - getTokenSkipNewline(); - - // Match the "symbol" part of the pattern, or a left parenthesis - if(token_type === TOKENTYPE.SYMBOL || token === '(') { - // We've matched the pattern "number / number symbol". - // Rewind once and build the "number / number" node; the symbol will be consumed later - popTokenState(); - discardTokenState(); - last = parseUnary(); - node = new OperatorNode$$1('/', 'divide', [node, last]); - } - else { - // Not a match, so rewind - popTokenState(); - popTokenState(); - break; - } - } - else { - // Not a match, so rewind - popTokenState(); - break; - } - } - else { - break; - } - } - - return node; - } - - /** - * Unary plus and minus, and logical and bitwise not - * @return {Node} node - * @private - */ - function parseUnary () { - var name, params, fn; - var operators = { - '-': 'unaryMinus', - '+': 'unaryPlus', - '~': 'bitNot', - 'not': 'not' - }; - - if (operators.hasOwnProperty(token)) { - fn = operators[token]; - name = token; - - getTokenSkipNewline(); - params = [parseUnary()]; - - return new OperatorNode$$1(name, fn, params); - } - - return parsePow(); - } - - /** - * power - * Note: power operator is right associative - * @return {Node} node - * @private - */ - function parsePow () { - var node, name, fn, params; - - node = parseLeftHandOperators(); - - if (token === '^' || token === '.^') { - name = token; - fn = (name === '^') ? 'pow' : 'dotPow'; - - getTokenSkipNewline(); - params = [node, parseUnary()]; // Go back to unary, we can have '2^-3' - node = new OperatorNode$$1(name, fn, params); - } - - return node; - } - - /** - * Left hand operators: factorial x!, transpose x' - * @return {Node} node - * @private - */ - function parseLeftHandOperators () { - var node, operators, name, fn, params; - - node = parseCustomNodes(); - - operators = { - '!': 'factorial', - '\'': 'transpose' - }; - - while (operators.hasOwnProperty(token)) { - name = token; - fn = operators[name]; - - getToken(); - params = [node]; - - node = new OperatorNode$$1(name, fn, params); - node = parseAccessors(node); - } - - return node; - } - - /** - * Parse a custom node handler. A node handler can be used to process - * nodes in a custom way, for example for handling a plot. - * - * A handler must be passed as second argument of the parse function. - * - must extend math.expression.node.Node - * - must contain a function _compile(defs: Object) : string - * - must contain a function find(filter: Object) : Node[] - * - must contain a function toString() : string - * - the constructor is called with a single argument containing all parameters - * - * For example: - * - * nodes = { - * 'plot': PlotHandler - * }; - * - * The constructor of the handler is called as: - * - * node = new PlotHandler(params); - * - * The handler will be invoked when evaluating an expression like: - * - * node = math.parse('plot(sin(x), x)', nodes); - * - * @return {Node} node - * @private - */ - function parseCustomNodes () { - var params = []; - - if (token_type === TOKENTYPE.SYMBOL && extra_nodes.hasOwnProperty(token)) { - var CustomNode = extra_nodes[token]; - - getToken(); - - // parse parameters - if (token === '(') { - params = []; - - openParams(); - getToken(); - - if (token !== ')') { - params.push(parseAssignment()); - - // parse a list with parameters - while (token === ',') { - getToken(); - params.push(parseAssignment()); - } - } - - if (token !== ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - closeParams(); - getToken(); - } - - // create a new custom node - //noinspection JSValidateTypes - return new CustomNode(params); - } - - return parseSymbol(); - } - - /** - * parse symbols: functions, variables, constants, units - * @return {Node} node - * @private - */ - function parseSymbol () { - var node, name; - - if (token_type === TOKENTYPE.SYMBOL || - (token_type === TOKENTYPE.DELIMITER && token in NAMED_DELIMITERS)) { - name = token; - - getToken(); - - if (CONSTANTS.hasOwnProperty(name)) { // true, false, null, ... - node = new ConstantNode$$1(CONSTANTS[name]); - } - else if (NUMERIC_CONSTANTS.indexOf(name) !== -1) { // NaN, Infinity - node = new ConstantNode$$1(numeric$$1(name)); - } - else { - node = new SymbolNode$$1(name); - } - - // parse function parameters and matrix index - node = parseAccessors(node); - return node; - } - - return parseString(); - } - - /** - * parse accessors: - * - function invocation in round brackets (...), for example sqrt(2) - * - index enclosed in square brackets [...], for example A[2,3] - * - dot notation for properties, like foo.bar - * @param {Node} node Node on which to apply the parameters. If there - * are no parameters in the expression, the node - * itself is returned - * @param {string[]} [types] Filter the types of notations - * can be ['(', '[', '.'] - * @return {Node} node - * @private - */ - function parseAccessors (node, types) { - var params; - - while ((token === '(' || token === '[' || token === '.') && - (!types || types.indexOf(token) !== -1)) { - params = []; - - if (token === '(') { - if (type.isSymbolNode(node) || type.isAccessorNode(node)) { - // function invocation like fn(2, 3) or obj.fn(2, 3) - openParams(); - getToken(); - - if (token !== ')') { - params.push(parseAssignment()); - - // parse a list with parameters - while (token === ',') { - getToken(); - params.push(parseAssignment()); - } - } - - if (token !== ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - closeParams(); - getToken(); - - node = new FunctionNode$$1(node, params); - } - else { - // implicit multiplication like (2+3)(4+5) or sqrt(2)(1+2) - // don't parse it here but let it be handled by parseImplicitMultiplication - // with correct precedence - return node; - } - } - else if (token === '[') { - // index notation like variable[2, 3] - openParams(); - getToken(); - - if (token !== ']') { - params.push(parseAssignment()); - - // parse a list with parameters - while (token === ',') { - getToken(); - params.push(parseAssignment()); - } - } - - if (token !== ']') { - throw createSyntaxError('Parenthesis ] expected'); - } - closeParams(); - getToken(); - - node = new AccessorNode$$1(node, new IndexNode$$1(params)); - } - else { - // dot notation like variable.prop - getToken(); - - if (token_type !== TOKENTYPE.SYMBOL) { - throw createSyntaxError('Property name expected after dot'); - } - params.push(new ConstantNode$$1(token)); - getToken(); - - var dotNotation = true; - node = new AccessorNode$$1(node, new IndexNode$$1(params, dotNotation)); - } - } - - return node; - } - - /** - * parse a string. - * A string is enclosed by double quotes - * @return {Node} node - * @private - */ - function parseString () { - var node, str; - - if (token === '"') { - str = parseStringToken(); - - // create constant - node = new ConstantNode$$1(str); - - // parse index parameters - node = parseAccessors(node); - - return node; - } - - return parseMatrix(); - } - - /** - * Parse a string surrounded by double quotes "..." - * @return {string} - */ - function parseStringToken () { - var str = ''; - - while (c !== '' && c !== '\"') { - if (c === '\\') { - // escape character, immediately process the next - // character to prevent stopping at a next '\"' - str += c; - next(); - } - - str += c; - next(); - } - - getToken(); - if (token !== '"') { - throw createSyntaxError('End of string " expected'); - } - getToken(); - - return JSON.parse('"' + str + '"'); // unescape escaped characters - } - - /** - * parse the matrix - * @return {Node} node - * @private - */ - function parseMatrix () { - var array, params, rows, cols; - - if (token === '[') { - // matrix [...] - openParams(); - getToken(); - - if (token !== ']') { - // this is a non-empty matrix - var row = parseRow(); - - if (token === ';') { - // 2 dimensional array - rows = 1; - params = [row]; - - // the rows of the matrix are separated by dot-comma's - while (token === ';') { - getToken(); - - params[rows] = parseRow(); - rows++; - } - - if (token !== ']') { - throw createSyntaxError('End of matrix ] expected'); - } - closeParams(); - getToken(); - - // check if the number of columns matches in all rows - cols = params[0].items.length; - for (var r = 1; r < rows; r++) { - if (params[r].items.length !== cols) { - throw createError('Column dimensions mismatch ' + - '(' + params[r].items.length + ' !== ' + cols + ')'); - } - } - - array = new ArrayNode$$1(params); - } - else { - // 1 dimensional vector - if (token !== ']') { - throw createSyntaxError('End of matrix ] expected'); - } - closeParams(); - getToken(); - - array = row; - } - } - else { - // this is an empty matrix "[ ]" - closeParams(); - getToken(); - array = new ArrayNode$$1([]); - } - - return parseAccessors(array); - } - - return parseObject(); - } - - /** - * Parse a single comma-separated row from a matrix, like 'a, b, c' - * @return {ArrayNode} node - */ - function parseRow () { - var params = [parseAssignment()]; - var len = 1; - - while (token === ',') { - getToken(); - - // parse expression - params[len] = parseAssignment(); - len++; - } - - return new ArrayNode$$1(params); - } - - /** - * parse an object, enclosed in angle brackets{...}, for example {value: 2} - * @return {Node} node - * @private - */ - function parseObject () { - if (token === '{') { - var key; - - var properties = {}; - do { - getToken(); - - if (token !== '}') { - // parse key - if (token === '"') { - key = parseStringToken(); - } - else if (token_type === TOKENTYPE.SYMBOL) { - key = token; - getToken(); - } - else { - throw createSyntaxError('Symbol or string expected as object key'); - } - - // parse key/value separator - if (token !== ':') { - throw createSyntaxError('Colon : expected after object key'); - } - getToken(); - - // parse key - properties[key] = parseAssignment(); - } - } - while (token === ','); - - if (token !== '}') { - throw createSyntaxError('Comma , or bracket } expected after object value'); - } - getToken(); - - var node = new ObjectNode$$1(properties); - - // parse index parameters - node = parseAccessors(node); - - return node; - } - - return parseNumber(); - } - - /** - * parse a number - * @return {Node} node - * @private - */ - function parseNumber () { - var numberStr; - - if (token_type === TOKENTYPE.NUMBER) { - // this is a number - numberStr = token; - getToken(); - - return new ConstantNode$$1(numeric$$1(numberStr, config.number)); - } - - return parseParentheses(); - } - - /** - * parentheses - * @return {Node} node - * @private - */ - function parseParentheses () { - var node; - - // check if it is a parenthesized expression - if (token === '(') { - // parentheses (...) - openParams(); - getToken(); - - node = parseAssignment(); // start again - - if (token !== ')') { - throw createSyntaxError('Parenthesis ) expected'); - } - closeParams(); - getToken(); - - node = new ParenthesisNode$$1(node); - node = parseAccessors(node); - return node; - } - - return parseEnd(); - } - - /** - * Evaluated when the expression is not yet ended but expected to end - * @return {Node} res - * @private - */ - function parseEnd () { - if (token === '') { - // syntax error or unexpected end of expression - throw createSyntaxError('Unexpected end of expression'); - } else if (token === "'") { - throw createSyntaxError('Value expected. Note: strings must be enclosed by double quotes'); - } else { - throw createSyntaxError('Value expected'); - } - } - - /** - * Shortcut for getting the current row value (one based) - * Returns the line of the currently handled expression - * @private - */ - /* TODO: implement keeping track on the row number - function row () { - return null; - } - */ - - /** - * Shortcut for getting the current col value (one based) - * Returns the column (position) where the last token starts - * @private - */ - function col () { - return index - token.length + 1; - } - - /** - * Create an error - * @param {string} message - * @return {SyntaxError} instantiated error - * @private - */ - function createSyntaxError (message) { - var c = col(); - var error = new SyntaxError(message + ' (char ' + c + ')'); - error['char'] = c; - - return error; - } - - /** - * Create an error - * @param {string} message - * @return {Error} instantiated error - * @private - */ - function createError (message) { - var c = col(); - var error = new SyntaxError(message + ' (char ' + c + ')'); - error['char'] = c; - - return error; - } - - return parse; - } - - var name$54 = 'parse'; - var path$29 = 'expression'; - var factory_1$59 = factory$60; - - var parse = { - name: name$54, - path: path$29, - factory: factory_1$59 - }; - - function factory$61 (type, config, load, typed) { - var parse$$1 = load(parse); - - /** - * Parse and compile an expression. - * Returns a an object with a function `eval([scope])` to evaluate the - * compiled expression. - * - * Syntax: - * - * math.compile(expr) // returns one node - * math.compile([expr1, expr2, expr3, ...]) // returns an array with nodes - * - * Examples: - * - * var code = math.compile('sqrt(3^2 + 4^2)'); - * code.eval(); // 5 - * - * var scope = {a: 3, b: 4} - * var code = math.compile('a * b'); // 12 - * code.eval(scope); // 12 - * scope.a = 5; - * code.eval(scope); // 20 - * - * var nodes = math.compile(['a = 3', 'b = 4', 'a * b']); - * nodes[2].eval(); // 12 - * - * See also: - * - * parse, eval - * - * @param {string | string[] | Array | Matrix} expr - * The expression to be compiled - * @return {{eval: Function} | Array.<{eval: Function}>} code - * An object with the compiled expression - * @throws {Error} - */ - return typed('compile', { - 'string': function (expr) { - return parse$$1(expr).compile(); - }, - - 'Array | Matrix': function (expr) { - return deepMap(expr, function (entry) { - return parse$$1(entry).compile(); - }); - } - }); - } - - var name$55 = 'compile'; - var factory_1$60 = factory$61; - - var compile = { - name: name$55, - factory: factory_1$60 - }; - - function factory$62 (type, config, load, typed) { - var parse$$1 = load(parse); - - /** - * Evaluate an expression. - * - * Note the evaluating arbitrary expressions may involve security risks, - * see [http://mathjs.org/docs/expressions/security.html](http://mathjs.org/docs/expressions/security.html) for more information. - * - * Syntax: - * - * math.eval(expr) - * math.eval(expr, scope) - * math.eval([expr1, expr2, expr3, ...]) - * math.eval([expr1, expr2, expr3, ...], scope) - * - * Example: - * - * math.eval('(2+3)/4'); // 1.25 - * math.eval('sqrt(3^2 + 4^2)'); // 5 - * math.eval('sqrt(-4)'); // 2i - * math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12] - * - * var scope = {a:3, b:4}; - * math.eval('a * b', scope); // 12 - * - * See also: - * - * parse, compile - * - * @param {string | string[] | Matrix} expr The expression to be evaluated - * @param {Object} [scope] Scope to read/write variables - * @return {*} The result of the expression - * @throws {Error} - */ - return typed('compile', { - 'string': function (expr) { - var scope = {}; - return parse$$1(expr).compile().eval(scope); - }, - - 'string, Object': function (expr, scope) { - return parse$$1(expr).compile().eval(scope); - }, - - 'Array | Matrix': function (expr) { - var scope = {}; - return deepMap(expr, function (entry) { - return parse$$1(entry).compile().eval(scope); - }); - }, - - 'Array | Matrix, Object': function (expr, scope) { - return deepMap(expr, function (entry) { - return parse$$1(entry).compile().eval(scope); - }); - } - }); - } - - var name$56 = 'eval'; - var factory_1$61 = factory$62; - - var _eval$1 = { - name: name$56, - factory: factory_1$61 - }; - - var getSafeProperty$8 = customs.getSafeProperty; - - function factory$63 (type, config, load, typed, math) { - var docs = load(embeddedDocs); - - /** - * Retrieve help on a function or data type. - * Help files are retrieved from the documentation in math.expression.docs. - * - * Syntax: - * - * math.help(search) - * - * Examples: - * - * console.log(math.help('sin').toString()); - * console.log(math.help(math.add).toString()); - * console.log(math.help(math.add).toJSON()); - * - * @param {Function | string | Object} search A function or function name - * for which to get help - * @return {Help} A help object - */ - return typed('help', { - 'any': function (search) { - var prop; - var name = search; - - if (typeof search !== 'string') { - for (prop in math) { - // search in functions and constants - if (math.hasOwnProperty(prop) && (search === math[prop])) { - name = prop; - break; - } - } - - /* TODO: implement help for data types - if (!text) { - // search data type - for (prop in math.type) { - if (math.type.hasOwnProperty(prop)) { - if (search === math.type[prop]) { - text = prop; - break; - } - } - } - } - */ - } - - var doc = getSafeProperty$8(docs, name); - if (!doc) { - throw new Error('No documentation found on "' + name + '"'); - } - return new type.Help(doc); - } - }); - } - - var math$9 = true; // request access to the math namespace as 5th argument of the factory function - var name$57 = 'help'; - var factory_1$62 = factory$63; - - var help$1 = { - math: math$9, - name: name$57, - factory: factory_1$62 - }; - - function factory$64 (type, config, load, typed) { - var parse$$1 = load(parse); - - /** - * Parse an expression. Returns a node tree, which can be evaluated by - * invoking node.eval(); - * - * Note the evaluating arbitrary expressions may involve security risks, - * see [http://mathjs.org/docs/expressions/security.html](http://mathjs.org/docs/expressions/security.html) for more information. - * - * Syntax: - * - * math.parse(expr) - * math.parse(expr, options) - * math.parse([expr1, expr2, expr3, ...]) - * math.parse([expr1, expr2, expr3, ...], options) - * - * Example: - * - * var node = math.parse('sqrt(3^2 + 4^2)'); - * node.compile().eval(); // 5 - * - * var scope = {a:3, b:4} - * var node = math.parse('a * b'); // 12 - * var code = node.compile(); - * code.eval(scope); // 12 - * scope.a = 5; - * code.eval(scope); // 20 - * - * var nodes = math.parse(['a = 3', 'b = 4', 'a * b']); - * nodes[2].compile().eval(); // 12 - * - * See also: - * - * eval, compile - * - * @param {string | string[] | Matrix} expr Expression to be parsed - * @param {{nodes: Object}} [options] Available options: - * - `nodes` a set of custom nodes - * @return {Node | Node[]} node - * @throws {Error} - */ - return typed('parse', { - 'string | Array | Matrix': parse$$1, - 'string | Array | Matrix, Object': parse$$1 - }); - } - - var name$58 = 'parse'; - var factory_1$63 = factory$64; - - var parse$1 = { - name: name$58, - factory: factory_1$63 - }; - - var extend$1 = object.extend; - - - function factory$65 (type, config, load, typed, math) { - var _parse = load(parse); - - /** - * @constructor Parser - * Parser contains methods to evaluate or parse expressions, and has a number - * of convenience methods to get, set, and remove variables from memory. Parser - * keeps a scope containing variables in memory, which is used for all - * evaluations. - * - * Methods: - * var result = parser.eval(expr); // evaluate an expression - * var value = parser.get(name); // retrieve a variable from the parser - * var values = parser.getAll(); // retrieve all defined variables - * parser.set(name, value); // set a variable in the parser - * parser.remove(name); // clear a variable from the - * // parsers scope - * parser.clear(); // clear the parsers scope - * - * Example usage: - * var parser = new Parser(); - * // Note: there is a convenience method which can be used instead: - * // var parser = new math.parser(); - * - * // evaluate expressions - * parser.eval('sqrt(3^2 + 4^2)'); // 5 - * parser.eval('sqrt(-4)'); // 2i - * parser.eval('2 inch in cm'); // 5.08 cm - * parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { - * return 'hello, ' + name + '!'; - * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - * - */ - function Parser() { - if (!(this instanceof Parser)) { - throw new SyntaxError( - 'Constructor must be called with the new operator'); - } - this.scope = {}; - } - - /** - * Attach type information - */ - Parser.prototype.type = 'Parser'; - Parser.prototype.isParser = true; - - /** - * Parse an expression and return the parsed function node. - * The node tree can be compiled via `code = node.compile(math)`, - * and the compiled code can be executed as `code.eval([scope])` - * @param {string} expr - * @return {Node} node - * @throws {Error} - */ - Parser.prototype.parse = function (expr) { - throw new Error('Parser.parse is deprecated. Use math.parse instead.'); - }; - - /** - * Parse and compile an expression, return the compiled javascript code. - * The node can be evaluated via code.eval([scope]) - * @param {string} expr - * @return {{eval: function}} code - * @throws {Error} - */ - Parser.prototype.compile = function (expr) { - throw new Error('Parser.compile is deprecated. Use math.compile instead.'); - }; - - /** - * Parse and evaluate the given expression - * @param {string} expr A string containing an expression, for example "2+3" - * @return {*} result The result, or undefined when the expression was empty - * @throws {Error} - */ - Parser.prototype.eval = function (expr) { - // TODO: validate arguments - return _parse(expr) - .compile() - .eval(this.scope); - }; - - /** - * Get a variable (a function or variable) by name from the parsers scope. - * Returns undefined when not found - * @param {string} name - * @return {* | undefined} value - */ - Parser.prototype.get = function (name) { - // TODO: validate arguments - return name in this.scope - ? customs.getSafeProperty(this.scope, name) - : undefined; - }; - - /** - * Get a map with all defined variables - * @return {Object} values - */ - Parser.prototype.getAll = function () { - return extend$1({}, this.scope); - }; - - /** - * Set a symbol (a function or variable) by name from the parsers scope. - * @param {string} name - * @param {* | undefined} value - */ - Parser.prototype.set = function (name, value) { - // TODO: validate arguments - return customs.setSafeProperty(this.scope, name, value); - }; - - /** - * Remove a variable from the parsers scope - * @param {string} name - */ - Parser.prototype.remove = function (name) { - // TODO: validate arguments - delete this.scope[name]; - }; - - /** - * Clear the scope with variables and functions - */ - Parser.prototype.clear = function () { - for (var name in this.scope) { - if (this.scope.hasOwnProperty(name)) { - delete this.scope[name]; - } - } - }; - - return Parser; - } - - var name$59 = 'Parser'; - var path$30 = 'expression'; - var factory_1$64 = factory$65; - var math$10 = true; // requires the math namespace as 5th argument - - var Parser = { - name: name$59, - path: path$30, - factory: factory_1$64, - math: math$10 - }; - - function factory$66 (type, config, load, typed, math) { - var Parser$$1 = load(Parser); - - /** - * Create a parser. The function creates a new `math.expression.Parser` object. - * - * Syntax: - * - * math.parser() - * - * Examples: - * - * var parser = new math.parser(); - * - * // evaluate expressions - * var a = parser.eval('sqrt(3^2 + 4^2)'); // 5 - * var b = parser.eval('sqrt(-4)'); // 2i - * var c = parser.eval('2 inch in cm'); // 5.08 cm - * var d = parser.eval('cos(45 deg)'); // 0.7071067811865476 - * - * // define variables and functions - * parser.eval('x = 7 / 2'); // 3.5 - * parser.eval('x + 3'); // 6.5 - * parser.eval('function f(x, y) = x^y'); // f(x, y) - * parser.eval('f(2, 3)'); // 8 - * - * // get and set variables and functions - * var x = parser.get('x'); // 7 - * var f = parser.get('f'); // function - * var g = f(3, 2); // 9 - * parser.set('h', 500); - * var i = parser.eval('h / 2'); // 250 - * parser.set('hello', function (name) { - * return 'hello, ' + name + '!'; - * }); - * parser.eval('hello("user")'); // "hello, user!" - * - * // clear defined functions and variables - * parser.clear(); - * - * See also: - * - * eval, compile, parse - * - * @return {Parser} Parser - */ - return typed('parser', { - '': function () { - return new Parser$$1(math); - } - }); - } - - var name$60 = 'parser'; - var factory_1$65 = factory$66; - var math$11 = true; // requires the math namespace as 5th argument - - var parser = { - name: name$60, - factory: factory_1$65, - math: math$11 - }; - - var _function$2 = [ - compile, - _eval$1, - help$1, - parse$1, - parser - ]; - - function factory$67 (type, config, load, typed) { - /** - * @constructor UpdateNode - */ - function UpdateNode() { - // TODO: deprecated since v3. Cleanup some day - throw new Error('UpdateNode is deprecated. Use AssignmentNode instead.'); - } - - return UpdateNode; - } - - var name$61 = 'UpdateNode'; - var path$31 = 'expression.node'; - var factory_1$66 = factory$67; - - var UpdateNode = { - name: name$61, - path: path$31, - factory: factory_1$66 - }; - - var node = [ - AccessorNode, - ArrayNode, - AssignmentNode, - BlockNode, - ConditionalNode, - ConstantNode, - IndexNode, - FunctionAssignmentNode, - FunctionNode, - Node, - ObjectNode, - OperatorNode, - ParenthesisNode, - RangeNode, - SymbolNode, - UpdateNode - ]; - - var clone$4 = object.clone; - var isInteger$4 = number.isInteger; - - - - - function factory$68 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Concatenate two or more matrices. - * - * Syntax: - * - * math.concat(A, B, C, ...) - * math.concat(A, B, C, ..., dim) - * - * Where: - * - * - `dim: number` is a zero-based dimension over which to concatenate the matrices. - * By default the last dimension of the matrices. - * - * Examples: - * - * var A = [[1, 2], [5, 6]]; - * var B = [[3, 4], [7, 8]]; - * - * math.concat(A, B); // returns [[1, 2, 3, 4], [5, 6, 7, 8]] - * math.concat(A, B, 0); // returns [[1, 2], [5, 6], [3, 4], [7, 8]] - * math.concat('hello', ' ', 'world'); // returns 'hello world' - * - * See also: - * - * size, squeeze, subset, transpose - * - * @param {... Array | Matrix} args Two or more matrices - * @return {Array | Matrix} Concatenated matrix - */ - var concat = typed('concat', { - // TODO: change signature to '...Array | Matrix, dim?' when supported - '...Array | Matrix | number | BigNumber': function (args) { - var i; - var len = args.length; - var dim = -1; // zero-based dimension - var prevDim; - var asMatrix = false; - var matrices = []; // contains multi dimensional arrays - - for (i = 0; i < len; i++) { - var arg = args[i]; - - // test whether we need to return a Matrix (if not we return an Array) - if (type.isMatrix(arg)) { - asMatrix = true; - } - - if (type.isNumber(arg) || type.isBigNumber(arg)) { - if (i !== len - 1) { - throw new Error('Dimension must be specified as last argument'); - } - - // last argument contains the dimension on which to concatenate - prevDim = dim; - dim = arg.valueOf(); // change BigNumber to number - - if (!isInteger$4(dim)) { - throw new TypeError('Integer number expected for dimension'); - } - - if (dim < 0 || (i > 0 && dim > prevDim)) { - // TODO: would be more clear when throwing a DimensionError here - throw new IndexError_1(dim, prevDim + 1); - } - } - else { - // this is a matrix or array - var m = clone$4(arg).valueOf(); - var size = array.size(m); - matrices[i] = m; - prevDim = dim; - dim = size.length - 1; - - // verify whether each of the matrices has the same number of dimensions - if (i > 0 && dim != prevDim) { - throw new DimensionError_1(prevDim + 1, dim + 1); - } - } - } - - if (matrices.length == 0) { - throw new SyntaxError('At least one matrix expected'); - } - - var res = matrices.shift(); - while (matrices.length) { - res = _concat(res, matrices.shift(), dim, 0); - } - - return asMatrix ? matrix$$1(res) : res; - }, - - '...string': function (args) { - return args.join(''); - } - }); - - concat.toTex = undefined; // use default template - - return concat; - } - - /** - * Recursively concatenate two matrices. - * The contents of the matrices is not cloned. - * @param {Array} a Multi dimensional array - * @param {Array} b Multi dimensional array - * @param {number} concatDim The dimension on which to concatenate (zero-based) - * @param {number} dim The current dim (zero-based) - * @return {Array} c The concatenated matrix - * @private - */ - function _concat(a, b, concatDim, dim) { - if (dim < concatDim) { - // recurse into next dimension - if (a.length != b.length) { - throw new DimensionError_1(a.length, b.length); - } - - var c = []; - for (var i = 0; i < a.length; i++) { - c[i] = _concat(a[i], b[i], concatDim, dim + 1); - } - return c; - } - else { - // concatenate this dimension - return a.concat(b); - } - } - - var name$62 = 'concat'; - var factory_1$67 = factory$68; - - var concat$1 = { - name: name$62, - factory: factory_1$67 - }; - - var errorTransform$2 = error_transform.transform; - - /** - * Attach a transform function to math.range - * Adds a property transform containing the transform function. - * - * This transform changed the last `dim` parameter of function concat - * from one-based to zero based - */ - function factory$69 (type, config, load, typed) { - var concat = load(concat$1); - - // @see: comment of concat itself - return typed('concat', { - '...any': function (args) { - // change last argument from one-based to zero-based - var lastIndex = args.length - 1; - var last = args[lastIndex]; - if (type.isNumber(last)) { - args[lastIndex] = last - 1; - } - else if (type.isBigNumber(last)) { - args[lastIndex] = last.minus(1); - } - - try { - return concat.apply(null, args); - } - catch (err) { - throw errorTransform$2(err); - } - } - }); - } - - var name$63 = 'concat'; - var path$32 = 'expression.transform'; - var factory_1$68 = factory$69; - - var concat_transform = { - name: name$63, - path: path$32, - factory: factory_1$68 - }; - - function factory$70 (type, config, load, typed) { - /** - * Compile an inline expression like "x > 0" - * @param {Node} expression - * @param {Object} math - * @param {Object} scope - * @return {function} Returns a function with one argument which fills in the - * undefined variable (like "x") and evaluates the expression - */ - return function compileInlineExpression(expression, math, scope) { - // find an undefined symbol - var symbol = expression.filter(function (node) { - return type.isSymbolNode(node) && - !(node.name in math) && - !(node.name in scope); - })[0]; - - if (!symbol) { - throw new Error('No undefined variable found in inline expression "' + expression + '"'); - } - - // create a test function for this equation - var name = symbol.name; // variable name - var subScope = Object.create(scope); - var eq = expression.compile(); - return function inlineExpression(x) { - subScope[name] = x; - return eq.eval(subScope); - } - }; - } - - var factory_1$69 = factory$70; - - var compileInlineExpression = { - factory: factory_1$69 - }; - - var filter$1 = array.filter; - var filterRegExp = array.filterRegExp; - var maxArgumentCount$1 = _function.maxArgumentCount; - - /** - * Attach a transform function to math.filter - * Adds a property transform containing the transform function. - * - * This transform adds support for equations as test function for math.filter, - * so you can do something like 'filter([3, -2, 5], x > 0)'. - */ - function factory$71 (type, config, load, typed) { - var compileInlineExpression$$1 = load(compileInlineExpression); - var matrix$$1 = load(matrix); - - function filterTransform(args, math, scope) { - var x, callback; - - if (args[0]) { - x = args[0].compile().eval(scope); - } - - if (args[1]) { - if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { - // a function pointer, like filter([3, -2, 5], myTestFunction); - callback = args[1].compile().eval(scope); - } - else { - // an expression like filter([3, -2, 5], x > 0) - callback = compileInlineExpression$$1(args[1], math, scope); - } - } - - return filter(x, callback); - } - filterTransform.rawArgs = true; - - // one based version of function filter - var filter = typed('filter', { - 'Array, function': _filter, - - 'Matrix, function': function (x, test) { - return matrix$$1(_filter(x.toArray(), test)); - }, - - 'Array, RegExp': filterRegExp, - - 'Matrix, RegExp': function (x, test) { - return matrix$$1(filterRegExp(x.toArray(), test)); - } - }); - - filter.toTex = undefined; // use default template - - return filterTransform; - } - - /** - * Filter values in a callback given a callback function - * - * !!! Passes a one-based index !!! - * - * @param {Array} x - * @param {Function} callback - * @return {Array} Returns the filtered array - * @private - */ - function _filter (x, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$1(callback); - - return filter$1(x, function (value, index, array$$1) { - // invoke the callback function with the right number of arguments - if (args === 1) { - return callback(value); - } - else if (args === 2) { - return callback(value, [index + 1]); - } - else { // 3 or -1 - return callback(value, [index + 1], array$$1); - } - }); - } - - var name$64 = 'filter'; - var path$33 = 'expression.transform'; - var factory_1$70 = factory$71; - - var filter_transform = { - name: name$64, - path: path$33, - factory: factory_1$70 - }; - - var maxArgumentCount$2 = _function.maxArgumentCount; - var forEach$3 = array.forEach; - - /** - * Attach a transform function to math.forEach - * Adds a property transform containing the transform function. - * - * This transform creates a one-based index instead of a zero-based index - */ - function factory$72 (type, config, load, typed) { - var compileInlineExpression$$1 = load(compileInlineExpression); - - function forEachTransform(args, math, scope) { - var x, callback; - - if (args[0]) { - x = args[0].compile().eval(scope); - } - - if (args[1]) { - if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { - // a function pointer, like forEach([3, -2, 5], myTestFunction); - callback = args[1].compile().eval(scope); - } - else { - // an expression like forEach([3, -2, 5], x > 0 ? callback1(x) : callback2(x) ) - callback = compileInlineExpression$$1(args[1], math, scope); - } - } - - return _forEach(x, callback); - } - forEachTransform.rawArgs = true; - - // one-based version of forEach - var _forEach = typed('forEach', { - 'Array | Matrix, function': function (array$$1, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$2(callback); - - var recurse = function (value, index) { - if (Array.isArray(value)) { - forEach$3(value, function (child, i) { - // we create a copy of the index array and append the new index value - recurse(child, index.concat(i + 1)); // one based index, hence i+1 - }); - } - else { - // invoke the callback function with the right number of arguments - if (args === 1) { - callback(value); - } - else if (args === 2) { - callback(value, index); - } - else { // 3 or -1 - callback(value, index, array$$1); - } - } - }; - recurse(array$$1.valueOf(), []); // pass Array - } - }); - - return forEachTransform; - } - - var name$65 = 'forEach'; - var path$34 = 'expression.transform'; - var factory_1$71 = factory$72; - - var forEach_transform = { - name: name$65, - path: path$34, - factory: factory_1$71 - }; - - /** - * Attach a transform function to math.index - * Adds a property transform containing the transform function. - * - * This transform creates a one-based index instead of a zero-based index - */ - function factory$73 (type, config, load) { - - return function indexTransform() { - var args = []; - for (var i = 0, ii = arguments.length; i < ii; i++) { - var arg = arguments[i]; - - // change from one-based to zero based, and convert BigNumber to number - if (type.isRange(arg)) { - arg.start--; - arg.end -= (arg.step > 0 ? 0 : 2); - } - else if (arg && arg.isSet === true) { - arg = arg.map(function (v) { return v - 1; }); - } - else if (type.isArray(arg) || type.isMatrix(arg)) { - arg = arg.map(function (v) { return v - 1; }); - } - else if (type.isNumber(arg)) { - arg--; - } - else if (type.isBigNumber(arg)) { - arg = arg.toNumber() - 1; - } - else if (typeof arg === 'string') { - // leave as is - } - else { - throw new TypeError('Dimension must be an Array, Matrix, number, string, or Range'); - } - - args[i] = arg; - } - - var res = new type.Index(); - type.Index.apply(res, args); - return res; - }; - } - - var name$66 = 'index'; - var path$35 = 'expression.transform'; - var factory_1$72 = factory$73; - - var index_transform = { - name: name$66, - path: path$35, - factory: factory_1$72 - }; - - var maxArgumentCount$3 = _function.maxArgumentCount; - var map$6 = array.map; - - /** - * Attach a transform function to math.map - * Adds a property transform containing the transform function. - * - * This transform creates a one-based index instead of a zero-based index - */ - function factory$74 (type, config, load, typed) { - var compileInlineExpression$$1 = load(compileInlineExpression); - var matrix$$1 = load(matrix); - - function mapTransform(args, math, scope) { - var x, callback; - - if (args[0]) { - x = args[0].compile().eval(scope); - } - - if (args[1]) { - if (type.isSymbolNode(args[1]) || type.isFunctionAssignmentNode(args[1])) { - // a function pointer, like filter([3, -2, 5], myTestFunction); - callback = args[1].compile().eval(scope); - } - else { - // an expression like filter([3, -2, 5], x > 0) - callback = compileInlineExpression$$1(args[1], math, scope); - } - } - - return map(x, callback); - } - mapTransform.rawArgs = true; - - // one-based version of map function - var map = typed('map', { - 'Array, function': function (x, callback) { - return _map(x, callback, x); - }, - - 'Matrix, function': function (x, callback) { - return matrix$$1(_map(x.valueOf(), callback, x)); - } - }); - - return mapTransform; - } - - /** - * Map for a multi dimensional array. One-based indexes - * @param {Array} array - * @param {function} callback - * @param {Array} orig - * @return {Array} - * @private - */ - function _map (array$$1, callback, orig) { - // figure out what number of arguments the callback function expects - var argsCount = maxArgumentCount$3(callback); - - function recurse(value, index) { - if (Array.isArray(value)) { - return map$6(value, function (child, i) { - // we create a copy of the index array and append the new index value - return recurse(child, index.concat(i + 1)); // one based index, hence i + 1 - }); - } - else { - // invoke the (typed) callback function with the right number of arguments - if (argsCount === 1) { - return callback(value); - } - else if (argsCount === 2) { - return callback(value, index); - } - else { // 3 or -1 - return callback(value, index, orig); - } - } - } - - return recurse(array$$1, []); - } - - var name$67 = 'map'; - var path$36 = 'expression.transform'; - var factory_1$73 = factory$74; - - var map_transform = { - name: name$67, - path: path$36, - factory: factory_1$73 - }; - - /** - * Test whether a value is a collection: an Array or Matrix - * @param {*} x - * @returns {boolean} isCollection - */ - var isCollection = function isCollection (x) { - return Array.isArray(x) || isMatrix(x); - }; - - /** - * Recursively loop over all elements in a given multi dimensional array - * and invoke the callback on each of the elements. - * @param {Array | Matrix} array - * @param {Function} callback The callback method is invoked with one - * parameter: the current element in the array - */ - var deepForEach = function deepForEach (array, callback) { - if (isMatrix(array)) { - array = array.valueOf(); - } - - for (var i = 0, ii = array.length; i < ii; i++) { - var value = array[i]; - - if (Array.isArray(value)) { - deepForEach(value, callback); - } - else { - callback(value); - } - } - }; - - var arraySize = array.size; - - - - /** - * Reduce a given matrix or array to a new matrix or - * array with one less dimension, applying the given - * callback in the selected dimension. - * @param {Array | Matrix} mat - * @param {number} dim - * @param {Function} callback - * @return {Array | Matrix} res - */ - var reduce = function(mat, dim, callback) { - var size = Array.isArray(mat) ? arraySize(mat) : mat.size(); - if (dim < 0 || (dim >= size.length)) { - // TODO: would be more clear when throwing a DimensionError here - throw new IndexError_1(dim, size.length); - } - - if (isMatrix(mat)) { - return mat.create(_reduce(mat.valueOf(), dim, callback)); - }else { - return _reduce(mat, dim, callback); - } - }; - - /** - * Recursively reduce a matrix - * @param {Array} mat - * @param {number} dim - * @param {Function} callback - * @returns {Array} ret - * @private - */ - function _reduce(mat, dim, callback){ - var i, ret, val, tran; - - if(dim<=0){ - if( !Array.isArray(mat[0]) ){ - val = mat[0]; - for(i=1; i 2 - ? ' (type: ' + getType(value) + ', value: ' + JSON.stringify(value) + ')' - : ' (type: ' + err.data.actual + ')'; - - return new TypeError('Cannot calculate ' + fnName + ', unexpected type of argument' + details); - } - - if (String(err).indexOf('complex numbers') !== -1) { - details = arguments.length > 2 - ? ' (type: ' + getType(value) + ', value: ' + JSON.stringify(value) + ')' - : ''; - - return new TypeError('Cannot calculate ' + fnName + ', no ordering relation is defined for complex numbers' + details); - } - - return err; - } - } - - var factory_1$74 = factory$75; - - var improveErrorMessage = { - factory: factory_1$74 - }; - - function factory$76 (type, config, load, typed) { - var larger$$1 = load(larger); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the maximum value of a matrix or a list with values. - * In case of a multi dimensional array, the maximum of the flattened array - * will be calculated. When `dim` is provided, the maximum over the selected - * dimension will be calculated. Parameter `dim` is zero-based. - * - * Syntax: - * - * math.max(a, b, c, ...) - * math.max(A) - * math.max(A, dim) - * - * Examples: - * - * math.max(2, 1, 4, 3); // returns 4 - * math.max([2, 1, 4, 3]); // returns 4 - * - * // maximum over a specified dimension (zero-based) - * math.max([[2, 5], [4, 3], [1, 7]], 0); // returns [4, 7] - * math.max([[2, 5], [4, 3]], [1, 7], 1); // returns [5, 4, 7] - * - * math.max(2.7, 7.1, -4.5, 2.0, 4.1); // returns 7.1 - * math.min(2.7, 7.1, -4.5, 2.0, 4.1); // returns -4.5 - * - * See also: - * - * mean, median, min, prod, std, sum, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The maximum value - */ - var max = typed('max', { - // max([a, b, c, d, ...]) - 'Array | Matrix': _max, - - // max([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': function (array, dim) { - return reduce(array, dim.valueOf(), _largest); - }, - - // max(a, b, c, d, ...) - '...': function (args) { - if (containsCollections(args)) { - throw new TypeError('Scalar values expected in function max'); - } - - return _max(args); - } - }); - - max.toTex = '\\max\\left(${args}\\right)'; - - return max; - - /** - * Return the largest of two values - * @param {*} x - * @param {*} y - * @returns {*} Returns x when x is largest, or y when y is largest - * @private - */ - function _largest(x, y) { - try { - return larger$$1(x, y) ? x : y; - } - catch (err) { - throw improveErrorMessage$$1(err, 'max', y); - } - } - - /** - * Recursively calculate the maximum value in an n-dimensional array - * @param {Array} array - * @return {number} max - * @private - */ - function _max(array) { - var max = undefined; - - deepForEach(array, function (value) { - try { - if (max === undefined || larger$$1(value, max)) { - max = value; - } - } - catch (err) { - throw improveErrorMessage$$1(err, 'max', value); - } - }); - - if (max === undefined) { - throw new Error('Cannot calculate max of an empty array'); - } - - return max; - } - - } - - var name$68 = 'max'; - var factory_1$75 = factory$76; - - var max$1 = { - name: name$68, - factory: factory_1$75 - }; - - var errorTransform$3 = error_transform.transform; - - - /** - * Attach a transform function to math.max - * Adds a property transform containing the transform function. - * - * This transform changed the last `dim` parameter of function max - * from one-based to zero based - */ - function factory$77 (type, config, load, typed) { - var max = load(max$1); - - return typed('max', { - '...any': function (args) { - // change last argument dim from one-based to zero-based - if (args.length == 2 && isCollection(args[0])) { - var dim = args[1]; - if (type.isNumber(dim)) { - args[1] = dim - 1; - } - else if (type.isBigNumber(dim)) { - args[1] = dim.minus(1); - } - } - - try { - return max.apply(null, args); - } - catch (err) { - throw errorTransform$3(err); - } - } - }); - } - - var name$69 = 'max'; - var path$37 = 'expression.transform'; - var factory_1$76 = factory$77; - - var max_transform = { - name: name$69, - path: path$37, - factory: factory_1$76 - }; - - function factory$78(type, config, load, typed) { - - /** - * Multiply two scalar values, `x * y`. - * This function is meant for internal use: it is used by the public function - * `multiply` - * - * This function does not support collections (Array or Matrix), and does - * not validate the number of of inputs. - * - * @param {number | BigNumber | Fraction | Complex | Unit} x First value to multiply - * @param {number | BigNumber | Fraction | Complex} y Second value to multiply - * @return {number | BigNumber | Fraction | Complex | Unit} Multiplication of `x` and `y` - * @private - */ - var multiplyScalar = typed('multiplyScalar', { - - 'number, number': function (x, y) { - return x * y; - }, - - 'Complex, Complex': function (x, y) { - return x.mul(y); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.times(y); - }, - - 'Fraction, Fraction': function (x, y) { - return x.mul(y); - }, - - 'number | Fraction | BigNumber | Complex, Unit': function (x, y) { - var res = y.clone(); - res.value = (res.value === null) ? res._normalize(x) : multiplyScalar(res.value, x); - return res; - }, - - 'Unit, number | Fraction | BigNumber | Complex': function (x, y) { - var res = x.clone(); - res.value = (res.value === null) ? res._normalize(y) : multiplyScalar(res.value, y); - return res; - }, - - 'Unit, Unit': function (x, y) { - return x.multiply(y); - } - - }); - - return multiplyScalar; - } - - var factory_1$77 = factory$78; - - var multiplyScalar = { - factory: factory_1$77 - }; - - function factory$79(type, config, load, typed) { - var multiplyScalar$$1 = load(multiplyScalar); - - /** - * Divide two scalar values, `x / y`. - * This function is meant for internal use: it is used by the public functions - * `divide` and `inv`. - * - * This function does not support collections (Array or Matrix), and does - * not validate the number of of inputs. - * - * @param {number | BigNumber | Fraction | Complex | Unit} x Numerator - * @param {number | BigNumber | Fraction | Complex} y Denominator - * @return {number | BigNumber | Fraction | Complex | Unit} Quotient, `x / y` - * @private - */ - var divideScalar = typed('divide', { - 'number, number': function (x, y) { - return x / y; - }, - - 'Complex, Complex': function (x, y) { - return x.div(y); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.div(y); - }, - - 'Fraction, Fraction': function (x, y) { - return x.div(y); - }, - - 'Unit, number | Fraction | BigNumber': function (x, y) { - var res = x.clone(); - // TODO: move the divide function to Unit.js, it uses internals of Unit - res.value = divideScalar(((res.value === null) ? res._normalize(1) : res.value), y); - return res; - }, - - 'number | Fraction | BigNumber, Unit': function (x, y) { - var res = y.pow(-1); - // TODO: move the divide function to Unit.js, it uses internals of Unit - res.value = multiplyScalar$$1(((res.value === null) ? res._normalize(1) : res.value), x); - return res; - }, - - 'Unit, Unit': function (x, y) { - return x.divide(y); - } - - }); - - return divideScalar; - } - - var factory_1$78 = factory$79; - - var divideScalar = { - factory: factory_1$78 - }; - - function factory$80 (type, config, load, typed) { - - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; - - /** - * Iterates over SparseMatrix S nonzero items and invokes the callback function f(Sij, b). - * Callback function invoked NZ times (number of nonzero items in S). - * - * - * ┌ f(Sij, b) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} s The SparseMatrix instance (S) - * @param {Scalar} b The Scalar value - * @param {Function} callback The f(Aij,b) operation to invoke - * @param {boolean} inverse A true value indicates callback should be invoked f(b,Sij) - * - * @return {Matrix} SparseMatrix (C) - * - * https://github.com/josdejong/mathjs/pull/346#issuecomment-97626813 - */ - var algorithm11 = function (s, b, callback, inverse) { - // sparse matrix arrays - var avalues = s._values; - var aindex = s._index; - var aptr = s._ptr; - var asize = s._size; - var adt = s._datatype; - - // sparse matrix cannot be a Pattern matrix - if (!avalues) - throw new Error('Cannot perform operation on Pattern Sparse Matrix and Scalar value'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string') { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // convert b to the same datatype - b = typed.convert(b, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = []; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - - // loop columns - for (var j = 0; j < columns; j++) { - // initialize ptr - cptr[j] = cindex.length; - // values in j - for (var k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - var i = aindex[k]; - // invoke callback - var v = inverse ? cf(b, avalues[k]) : cf(avalues[k], b); - // check value is zero - if (!eq(v, zero)) { - // push index & value - cindex.push(i); - cvalues.push(v); - } - } - } - // update ptr - cptr[columns] = cindex.length; - - // return sparse matrix - return c; - }; - - return algorithm11; - } - - var name$70 = 'algorithm11'; - var factory_1$79 = factory$80; - - var algorithm11 = { - name: name$70, - factory: factory_1$79 - }; - - var extend$2 = object.extend; - - - function factory$81 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - var addScalar$$1 = load(addScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var equalScalar$$1 = load(equalScalar); - - var algorithm11$$1 = load(algorithm11); - var algorithm14$$1 = load(algorithm14); - - var DenseMatrix = type.DenseMatrix; - var SparseMatrix = type.SparseMatrix; - - /** - * Multiply two or more values, `x * y`. - * For matrices, the matrix product is calculated. - * - * Syntax: - * - * math.multiply(x, y) - * math.multiply(x, y, z, ...) - * - * Examples: - * - * math.multiply(4, 5.2); // returns number 20.8 - * math.multiply(2, 3, 4); // returns number 24 - * - * var a = math.complex(2, 3); - * var b = math.complex(4, 1); - * math.multiply(a, b); // returns Complex 5 + 14i - * - * var c = [[1, 2], [4, 3]]; - * var d = [[1, 2, 3], [3, -4, 7]]; - * math.multiply(c, d); // returns Array [[7, -6, 17], [13, -4, 33]] - * - * var e = math.unit('2.1 km'); - * math.multiply(3, e); // returns Unit 6.3 km - * - * See also: - * - * divide, prod, cross, dot - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First value to multiply - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second value to multiply - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` - */ - var multiply = typed('multiply', extend$2({ - // we extend the signatures of multiplyScalar with signatures dealing with matrices - - 'Array, Array': function (x, y) { - // check dimensions - _validateMatrixDimensions(array.size(x), array.size(y)); - - // use dense matrix implementation - var m = multiply(matrix$$1(x), matrix$$1(y)); - // return array or scalar - return type.isMatrix(m) ? m.valueOf() : m; - }, - - 'Matrix, Matrix': function (x, y) { - // dimensions - var xsize = x.size(); - var ysize = y.size(); - - // check dimensions - _validateMatrixDimensions(xsize, ysize); - - // process dimensions - if (xsize.length === 1) { - // process y dimensions - if (ysize.length === 1) { - // Vector * Vector - return _multiplyVectorVector(x, y, xsize[0]); - } - // Vector * Matrix - return _multiplyVectorMatrix(x, y); - } - // process y dimensions - if (ysize.length === 1) { - // Matrix * Vector - return _multiplyMatrixVector(x, y); - } - // Matrix * Matrix - return _multiplyMatrixMatrix(x, y); - }, - - 'Matrix, Array': function (x, y) { - // use Matrix * Matrix implementation - return multiply(x, matrix$$1(y)); - }, - - 'Array, Matrix': function (x, y) { - // use Matrix * Matrix implementation - return multiply(matrix$$1(x, y.storage()), y); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, multiplyScalar$$1, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, multiplyScalar$$1, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm11$$1(y, x, multiplyScalar$$1, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, multiplyScalar$$1, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, multiplyScalar$$1, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, multiplyScalar$$1, true).valueOf(); - }, - - 'any, any': multiplyScalar$$1, - - 'any, any, ...any': function (x, y, rest) { - var result = multiply(x, y); - - for (var i = 0; i < rest.length; i++) { - result = multiply(result, rest[i]); - } - - return result; - } - }, multiplyScalar$$1.signatures)); - - var _validateMatrixDimensions = function (size1, size2) { - // check left operand dimensions - switch (size1.length) { - case 1: - // check size2 - switch (size2.length) { - case 1: - // Vector x Vector - if (size1[0] !== size2[0]) { - // throw error - throw new RangeError('Dimension mismatch in multiplication. Vectors must have the same length'); - } - break; - case 2: - // Vector x Matrix - if (size1[0] !== size2[0]) { - // throw error - throw new RangeError('Dimension mismatch in multiplication. Vector length (' + size1[0] + ') must match Matrix rows (' + size2[0] + ')'); - } - break; - default: - throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)'); - } - break; - case 2: - // check size2 - switch (size2.length) { - case 1: - // Matrix x Vector - if (size1[1] !== size2[0]) { - // throw error - throw new RangeError('Dimension mismatch in multiplication. Matrix columns (' + size1[1] + ') must match Vector length (' + size2[0] + ')'); - } - break; - case 2: - // Matrix x Matrix - if (size1[1] !== size2[0]) { - // throw error - throw new RangeError('Dimension mismatch in multiplication. Matrix A columns (' + size1[1] + ') must match Matrix B rows (' + size2[0] + ')'); - } - break; - default: - throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix B has ' + size2.length + ' dimensions)'); - } - break; - default: - throw new Error('Can only multiply a 1 or 2 dimensional matrix (Matrix A has ' + size1.length + ' dimensions)'); - } - }; - - /** - * C = A * B - * - * @param {Matrix} a Dense Vector (N) - * @param {Matrix} b Dense Vector (N) - * - * @return {number} Scalar value - */ - var _multiplyVectorVector = function (a, b, n) { - // check empty vector - if (n === 0) - throw new Error('Cannot multiply two empty vectors'); - - // a dense - var adata = a._data; - var adt = a._datatype; - // b dense - var bdata = b._data; - var bdt = b._datatype; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - } - - // result (do not initialize it with zero) - var c = mf(adata[0], bdata[0]); - // loop data - for (var i = 1; i < n; i++) { - // multiply and accumulate - c = af(c, mf(adata[i], bdata[i])); - } - return c; - }; - - /** - * C = A * B - * - * @param {Matrix} a Dense Vector (M) - * @param {Matrix} b Matrix (MxN) - * - * @return {Matrix} Dense Vector (N) - */ - var _multiplyVectorMatrix = function (a, b) { - // process storage - if (b.storage() !== 'dense') { - throw new Error('Support for SparseMatrix not implemented'); - } - return _multiplyVectorDenseMatrix(a, b); - }; - - /** - * C = A * B - * - * @param {Matrix} a Dense Vector (M) - * @param {Matrix} b Dense Matrix (MxN) - * - * @return {Matrix} Dense Vector (N) - */ - var _multiplyVectorDenseMatrix = function (a, b) { - // a dense - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b dense - var bdata = b._data; - var bsize = b._size; - var bdt = b._datatype; - // rows & columns - var alength = asize[0]; - var bcolumns = bsize[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - } - - // result - var c = []; - - // loop matrix columns - for (var j = 0; j < bcolumns; j++) { - // sum (do not initialize it with zero) - var sum = mf(adata[0], bdata[0][j]); - // loop vector - for (var i = 1; i < alength; i++) { - // multiply & accumulate - sum = af(sum, mf(adata[i], bdata[i][j])); - } - c[j] = sum; - } - - // return matrix - return new DenseMatrix({ - data: c, - size: [bcolumns], - datatype: dt - }); - }; - - /** - * C = A * B - * - * @param {Matrix} a Matrix (MxN) - * @param {Matrix} b Dense Vector (N) - * - * @return {Matrix} Dense Vector (M) - */ - var _multiplyMatrixVector = typed('_multiplyMatrixVector', { - 'DenseMatrix, any': _multiplyDenseMatrixVector, - 'SparseMatrix, any': _multiplySparseMatrixVector - }); - - /** - * C = A * B - * - * @param {Matrix} a Matrix (MxN) - * @param {Matrix} b Matrix (NxC) - * - * @return {Matrix} Matrix (MxC) - */ - var _multiplyMatrixMatrix = typed('_multiplyMatrixMatrix', { - 'DenseMatrix, DenseMatrix': _multiplyDenseMatrixDenseMatrix, - 'DenseMatrix, SparseMatrix': _multiplyDenseMatrixSparseMatrix, - 'SparseMatrix, DenseMatrix': _multiplySparseMatrixDenseMatrix, - 'SparseMatrix, SparseMatrix': _multiplySparseMatrixSparseMatrix - }); - - /** - * C = A * B - * - * @param {Matrix} a DenseMatrix (MxN) - * @param {Matrix} b Dense Vector (N) - * - * @return {Matrix} Dense Vector (M) - */ - function _multiplyDenseMatrixVector(a, b) { - // a dense - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b dense - var bdata = b._data; - var bdt = b._datatype; - // rows & columns - var arows = asize[0]; - var acolumns = asize[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - } - - // result - var c = []; - - // loop matrix a rows - for (var i = 0; i < arows; i++) { - // current row - var row = adata[i]; - // sum (do not initialize it with zero) - var sum = mf(row[0], bdata[0]); - // loop matrix a columns - for (var j = 1; j < acolumns; j++) { - // multiply & accumulate - sum = af(sum, mf(row[j], bdata[j])); - } - c[i] = sum; - } - - // return matrix - return new DenseMatrix({ - data: c, - size: [arows], - datatype: dt - }); - } - - /** - * C = A * B - * - * @param {Matrix} a DenseMatrix (MxN) - * @param {Matrix} b DenseMatrix (NxC) - * - * @return {Matrix} DenseMatrix (MxC) - */ - function _multiplyDenseMatrixDenseMatrix (a, b) { - // a dense - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b dense - var bdata = b._data; - var bsize = b._size; - var bdt = b._datatype; - // rows & columns - var arows = asize[0]; - var acolumns = asize[1]; - var bcolumns = bsize[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - } - - // result - var c = []; - - // loop matrix a rows - for (var i = 0; i < arows; i++) { - // current row - var row = adata[i]; - // initialize row array - c[i] = []; - // loop matrix b columns - for (var j = 0; j < bcolumns; j++) { - // sum (avoid initializing sum to zero) - var sum = mf(row[0], bdata[0][j]); - // loop matrix a columns - for (var x = 1; x < acolumns; x++) { - // multiply & accumulate - sum = af(sum, mf(row[x], bdata[x][j])); - } - c[i][j] = sum; - } - } - - // return matrix - return new DenseMatrix({ - data: c, - size: [arows, bcolumns], - datatype: dt - }); - } - - /** - * C = A * B - * - * @param {Matrix} a DenseMatrix (MxN) - * @param {Matrix} b SparseMatrix (NxC) - * - * @return {Matrix} SparseMatrix (MxC) - */ - function _multiplyDenseMatrixSparseMatrix (a, b) { - // a dense - var adata = a._data; - var asize = a._size; - var adt = a._datatype; - // b sparse - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - // validate b matrix - if (!bvalues) - throw new Error('Cannot multiply Dense Matrix times Pattern only Matrix'); - // rows & columns - var arows = asize[0]; - var bcolumns = bsize[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - // equalScalar signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - } - - // result - var cvalues = []; - var cindex = []; - var cptr = []; - // c matrix - var c = new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, bcolumns], - datatype: dt - }); - - // loop b columns - for (var jb = 0; jb < bcolumns; jb++) { - // update ptr - cptr[jb] = cindex.length; - // indeces in column jb - var kb0 = bptr[jb]; - var kb1 = bptr[jb + 1]; - // do not process column jb if no data exists - if (kb1 > kb0) { - // last row mark processed - var last = 0; - // loop a rows - for (var i = 0; i < arows; i++) { - // column mark - var mark = i + 1; - // C[i, jb] - var cij; - // values in b column j - for (var kb = kb0; kb < kb1; kb++) { - // row - var ib = bindex[kb]; - // check value has been initialized - if (last !== mark) { - // first value in column jb - cij = mf(adata[i][ib], bvalues[kb]); - // update mark - last = mark; - } - else { - // accumulate value - cij = af(cij, mf(adata[i][ib], bvalues[kb])); - } - } - // check column has been processed and value != 0 - if (last === mark && !eq(cij, zero)) { - // push row & value - cindex.push(i); - cvalues.push(cij); - } - } - } - } - // update ptr - cptr[bcolumns] = cindex.length; - - // return sparse matrix - return c; - } - - /** - * C = A * B - * - * @param {Matrix} a SparseMatrix (MxN) - * @param {Matrix} b Dense Vector (N) - * - * @return {Matrix} SparseMatrix (M, 1) - */ - function _multiplySparseMatrixVector(a, b) { - // a sparse - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var adt = a._datatype; - // validate a matrix - if (!avalues) - throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix'); - // b dense - var bdata = b._data; - var bdt = b._datatype; - // rows & columns - var arows = a._size[0]; - var brows = b._size[0]; - // result - var cvalues = []; - var cindex = []; - var cptr = []; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - // equalScalar signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - } - - // workspace - var x = []; - // vector with marks indicating a value x[i] exists in a given column - var w = []; - - // update ptr - cptr[0] = 0; - // rows in b - for (var ib = 0; ib < brows; ib++) { - // b[ib] - var vbi = bdata[ib]; - // check b[ib] != 0, avoid loops - if (!eq(vbi, zero)) { - // A values & index in ib column - for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // a row - var ia = aindex[ka]; - // check value exists in current j - if (!w[ia]) { - // ia is new entry in j - w[ia] = true; - // add i to pattern of C - cindex.push(ia); - // x(ia) = A - x[ia] = mf(vbi, avalues[ka]); - } - else { - // i exists in C already - x[ia] = af(x[ia], mf(vbi, avalues[ka])); - } - } - } - } - // copy values from x to column jb of c - for (var p1 = cindex.length, p = 0; p < p1; p++) { - // row - var ic = cindex[p]; - // copy value - cvalues[p] = x[ic]; - } - // update ptr - cptr[1] = cindex.length; - - // return sparse matrix - return new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, 1], - datatype: dt - }); - } - - /** - * C = A * B - * - * @param {Matrix} a SparseMatrix (MxN) - * @param {Matrix} b DenseMatrix (NxC) - * - * @return {Matrix} SparseMatrix (MxC) - */ - function _multiplySparseMatrixDenseMatrix(a, b) { - // a sparse - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var adt = a._datatype; - // validate a matrix - if (!avalues) - throw new Error('Cannot multiply Pattern only Matrix times Dense Matrix'); - // b dense - var bdata = b._data; - var bdt = b._datatype; - // rows & columns - var arows = a._size[0]; - var brows = b._size[0]; - var bcolumns = b._size[1]; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - // equalScalar signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - } - - // result - var cvalues = []; - var cindex = []; - var cptr = []; - // c matrix - var c = new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, bcolumns], - datatype: dt - }); - - // workspace - var x = []; - // vector with marks indicating a value x[i] exists in a given column - var w = []; - - // loop b columns - for (var jb = 0; jb < bcolumns; jb++) { - // update ptr - cptr[jb] = cindex.length; - // mark in workspace for current column - var mark = jb + 1; - // rows in jb - for (var ib = 0; ib < brows; ib++) { - // b[ib, jb] - var vbij = bdata[ib][jb]; - // check b[ib, jb] != 0, avoid loops - if (!eq(vbij, zero)) { - // A values & index in ib column - for (var ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // a row - var ia = aindex[ka]; - // check value exists in current j - if (w[ia] !== mark) { - // ia is new entry in j - w[ia] = mark; - // add i to pattern of C - cindex.push(ia); - // x(ia) = A - x[ia] = mf(vbij, avalues[ka]); - } - else { - // i exists in C already - x[ia] = af(x[ia], mf(vbij, avalues[ka])); - } - } - } - } - // copy values from x to column jb of c - for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) { - // row - var ic = cindex[p]; - // copy value - cvalues[p] = x[ic]; - } - } - // update ptr - cptr[bcolumns] = cindex.length; - - // return sparse matrix - return c; - } - - /** - * C = A * B - * - * @param {Matrix} a SparseMatrix (MxN) - * @param {Matrix} b SparseMatrix (NxC) - * - * @return {Matrix} SparseMatrix (MxC) - */ - function _multiplySparseMatrixSparseMatrix(a, b) { - // a sparse - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var adt = a._datatype; - // b sparse - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bdt = b._datatype; - - // rows & columns - var arows = a._size[0]; - var bcolumns = b._size[1]; - // flag indicating both matrices (a & b) contain data - var values = avalues && bvalues; - - // datatype - var dt; - // addScalar signature to use - var af = addScalar$$1; - // multiplyScalar signature to use - var mf = multiplyScalar$$1; - - // process data types - if (adt && bdt && adt === bdt && typeof adt === 'string') { - // datatype - dt = adt; - // find signatures that matches (dt, dt) - af = typed.find(addScalar$$1, [dt, dt]); - mf = typed.find(multiplyScalar$$1, [dt, dt]); - } - - // result - var cvalues = values ? [] : undefined; - var cindex = []; - var cptr = []; - // c matrix - var c = new SparseMatrix({ - values : cvalues, - index: cindex, - ptr: cptr, - size: [arows, bcolumns], - datatype: dt - }); - - // workspace - var x = values ? [] : undefined; - // vector with marks indicating a value x[i] exists in a given column - var w = []; - // variables - var ka, ka0, ka1, kb, kb0, kb1, ia, ib; - // loop b columns - for (var jb = 0; jb < bcolumns; jb++) { - // update ptr - cptr[jb] = cindex.length; - // mark in workspace for current column - var mark = jb + 1; - // B values & index in j - for (kb0 = bptr[jb], kb1 = bptr[jb + 1], kb = kb0; kb < kb1; kb++) { - // b row - ib = bindex[kb]; - // check we need to process values - if (values) { - // loop values in a[:,ib] - for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // row - ia = aindex[ka]; - // check value exists in current j - if (w[ia] !== mark) { - // ia is new entry in j - w[ia] = mark; - // add i to pattern of C - cindex.push(ia); - // x(ia) = A - x[ia] = mf(bvalues[kb], avalues[ka]); - } - else { - // i exists in C already - x[ia] = af(x[ia], mf(bvalues[kb], avalues[ka])); - } - } - } - else { - // loop values in a[:,ib] - for (ka0 = aptr[ib], ka1 = aptr[ib + 1], ka = ka0; ka < ka1; ka++) { - // row - ia = aindex[ka]; - // check value exists in current j - if (w[ia] !== mark) { - // ia is new entry in j - w[ia] = mark; - // add i to pattern of C - cindex.push(ia); - } - } - } - } - // check we need to process matrix values (pattern matrix) - if (values) { - // copy values from x to column jb of c - for (var p0 = cptr[jb], p1 = cindex.length, p = p0; p < p1; p++) { - // row - var ic = cindex[p]; - // copy value - cvalues[p] = x[ic]; - } - } - } - // update ptr - cptr[bcolumns] = cindex.length; - - // return sparse matrix - return c; - } - - multiply.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['multiply'] + '${args[1]}\\right)' - }; - - return multiply; - } - - var name$71 = 'multiply'; - var factory_1$80 = factory$81; - - var multiply$1 = { - name: name$71, - factory: factory_1$80 - }; - - function factory$82 (type, config, load, typed) { - var latex$$1 = latex; - - /** - * Inverse the sign of a value, apply a unary minus operation. - * - * For matrices, the function is evaluated element wise. Boolean values and - * strings will be converted to a number. For complex numbers, both real and - * complex value are inverted. - * - * Syntax: - * - * math.unaryMinus(x) - * - * Examples: - * - * math.unaryMinus(3.5); // returns -3.5 - * math.unaryMinus(-4.2); // returns 4.2 - * - * See also: - * - * add, subtract, unaryPlus - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Number to be inverted. - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Returns the value with inverted sign. - */ - var unaryMinus = typed('unaryMinus', { - 'number': function (x) { - return -x; - }, - - 'Complex': function (x) { - return x.neg(); - }, - - 'BigNumber': function (x) { - return x.neg(); - }, - - 'Fraction': function (x) { - return x.neg(); - }, - - 'Unit': function (x) { - var res = x.clone(); - res.value = unaryMinus(x.value); - return res; - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since unaryMinus(0) = 0 - return deepMap(x, unaryMinus, true); - } - - // TODO: add support for string - }); - - unaryMinus.toTex = { - 1: latex$$1.operators['unaryMinus'] + '\\left(${args[0]}\\right)' - }; - - return unaryMinus; - } - - var name$72 = 'unaryMinus'; - var factory_1$81 = factory$82; - - var unaryMinus$1 = { - name: name$72, - factory: factory_1$81 - }; - - function factory$83 (type, config, load, typed) { - - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; - - /** - * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). - * Callback function invoked MAX(NNZA, NNZB) times - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 || B(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm05 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = avalues && bvalues ? [] : undefined; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - - // workspaces - var xa = cvalues ? [] : undefined; - var xb = cvalues ? [] : undefined; - // marks indicating we have a value in x for a given column - var wa = []; - var wb = []; - - // vars - var i, j, k, k1; - - // loop columns - for (j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // columns mark - var mark = j + 1; - // loop values A(:,j) - for (k = aptr[j], k1 = aptr[j + 1]; k < k1; k++) { - // row - i = aindex[k]; - // push index - cindex.push(i); - // update workspace - wa[i] = mark; - // check we need to process values - if (xa) - xa[i] = avalues[k]; - } - // loop values B(:,j) - for (k = bptr[j], k1 = bptr[j + 1]; k < k1; k++) { - // row - i = bindex[k]; - // check row existed in A - if (wa[i] !== mark) { - // push index - cindex.push(i); - } - // update workspace - wb[i] = mark; - // check we need to process values - if (xb) - xb[i] = bvalues[k]; - } - // check we need to process values (non pattern matrix) - if (cvalues) { - // initialize first index in j - k = cptr[j]; - // loop index in j - while (k < cindex.length) { - // row - i = cindex[k]; - // marks - var wai = wa[i]; - var wbi = wb[i]; - // check Aij or Bij are nonzero - if (wai === mark || wbi === mark) { - // matrix values @ i,j - var va = wai === mark ? xa[i] : zero; - var vb = wbi === mark ? xb[i] : zero; - // Cij - var vc = cf(va, vb); - // check for zero - if (!eq(vc, zero)) { - // push value - cvalues.push(vc); - // increment pointer - k++; - } - else { - // remove value @ i, do not increment pointer - cindex.splice(k, 1); - } - } - } - } - } - // update cptr - cptr[columns] = cindex.length; - - // return sparse matrix - return c; - }; - - return algorithm05; - } - - var name$73 = 'algorithm05'; - var factory_1$82 = factory$83; - - var algorithm05 = { - name: name$73, - factory: factory_1$82 - }; - - function factory$84 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - var addScalar$$1 = load(addScalar); - var unaryMinus = load(unaryMinus$1); - - var algorithm01$$1 = load(algorithm01); - var algorithm03$$1 = load(algorithm03); - var algorithm05$$1 = load(algorithm05); - var algorithm10$$1 = load(algorithm10); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - // TODO: split function subtract in two: subtract and subtractScalar - - /** - * Subtract two values, `x - y`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.subtract(x, y) - * - * Examples: - * - * math.subtract(5.3, 2); // returns number 3.3 - * - * var a = math.complex(2, 3); - * var b = math.complex(4, 1); - * math.subtract(a, b); // returns Complex -2 + 2i - * - * math.subtract([5, 7, 4], 4); // returns Array [1, 3, 0] - * - * var c = math.unit('2.1 km'); - * var d = math.unit('500m'); - * math.subtract(c, d); // returns Unit 1.6 km - * - * See also: - * - * add - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x - * Initial value - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y - * Value to subtract from `x` - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} - * Subtraction of `x` and `y` - */ - var subtract = typed('subtract', { - - 'number, number': function (x, y) { - return x - y; - }, - - 'Complex, Complex': function (x, y) { - return x.sub(y); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.minus(y); - }, - - 'Fraction, Fraction': function (x, y) { - return x.sub(y); - }, - - 'Unit, Unit': function (x, y) { - if (x.value == null) { - throw new Error('Parameter x contains a unit with undefined value'); - } - - if (y.value == null) { - throw new Error('Parameter y contains a unit with undefined value'); - } - - if (!x.equalBase(y)) { - throw new Error('Units do not match'); - } - - var res = x.clone(); - res.value = subtract(res.value, y.value); - res.fixPrefix = false; - - return res; - }, - - 'SparseMatrix, SparseMatrix': function (x, y) { - checkEqualDimensions(x, y); - return algorithm05$$1(x, y, subtract); - }, - - 'SparseMatrix, DenseMatrix': function (x, y) { - checkEqualDimensions(x, y); - return algorithm03$$1(y, x, subtract, true); - }, - - 'DenseMatrix, SparseMatrix': function (x, y) { - checkEqualDimensions(x, y); - return algorithm01$$1(x, y, subtract, false); - }, - - 'DenseMatrix, DenseMatrix': function (x, y) { - checkEqualDimensions(x, y); - return algorithm13$$1(x, y, subtract); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return subtract(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return subtract(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return subtract(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm10$$1(x, unaryMinus(y), addScalar$$1); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, subtract); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm10$$1(y, x, subtract, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, subtract, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, subtract, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, subtract, true).valueOf(); - } - }); - - subtract.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['subtract'] + '${args[1]}\\right)' - }; - - return subtract; - } - - /** - * Check whether matrix x and y have the same number of dimensions. - * Throws a DimensionError when dimensions are not equal - * @param {Matrix} x - * @param {Matrix} y - */ - function checkEqualDimensions(x, y) { - var xsize = x.size(); - var ysize = y.size(); - - if (xsize.length !== ysize.length) { - throw new DimensionError_1(xsize.length, ysize.length); - } - } - - var name$74 = 'subtract'; - var factory_1$83 = factory$84; - - var subtract$1 = { - name: name$74, - factory: factory_1$83 - }; - - function factory$85 (type, config, load, typed) { - /** - * Calculate the absolute value of a number. For matrices, the function is - * evaluated element wise. - * - * Syntax: - * - * math.abs(x) - * - * Examples: - * - * math.abs(3.5); // returns number 3.5 - * math.abs(-4.2); // returns number 4.2 - * - * math.abs([3, -5, -1, 0, 2]); // returns Array [3, 5, 1, 0, 2] - * - * See also: - * - * sign - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x - * A number or matrix for which to get the absolute value - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} - * Absolute value of `x` - */ - var abs = typed('abs', { - 'number': Math.abs, - - 'Complex': function (x) { - return x.abs(); - }, - - 'BigNumber': function (x) { - return x.abs(); - }, - - 'Fraction': function (x) { - return x.abs(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since abs(0) = 0 - return deepMap(x, abs, true); - }, - - 'Unit': function(x) { - return x.abs(); - } - }); - - abs.toTex = {1: '\\left|${args[0]}\\right|'}; - - return abs; - } - - var name$75 = 'abs'; - var factory_1$84 = factory$85; - - var abs$1 = { - name: name$75, - factory: factory_1$84 - }; - - var object$4 = utils.object; - - function factory$86 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var abs = load(abs$1); - var addScalar$$1 = load(addScalar); - var divideScalar$$1 = load(divideScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var subtract = load(subtract$1); - var larger$$1 = load(larger); - var equalScalar$$1 = load(equalScalar); - var unaryMinus = load(unaryMinus$1); - - var SparseMatrix = type.SparseMatrix; - var DenseMatrix = type.DenseMatrix; - var Spa = type.Spa; - - /** - * Calculate the Matrix LU decomposition with partial pivoting. Matrix `A` is decomposed in two matrices (`L`, `U`) and a - * row permutation vector `p` where `A[p,:] = L * U` - * - * Syntax: - * - * math.lup(A); - * - * Example: - * - * var m = [[2, 1], [1, 4]]; - * var r = math.lup(m); - * // r = { - * // L: [[1, 0], [0.5, 1]], - * // U: [[2, 1], [0, 3.5]], - * // P: [0, 1] - * // } - * - * See also: - * - * slu, lsolve, lusolve, usolve - * - * @param {Matrix | Array} A A two dimensional matrix or array for which to get the LUP decomposition. - * - * @return {{L: Array | Matrix, U: Array | Matrix, P: Array.}} The lower triangular matrix, the upper triangular matrix and the permutation matrix. - */ - var lup = typed('lup', { - - 'DenseMatrix': function (m) { - return _denseLUP(m); - }, - - 'SparseMatrix': function (m) { - return _sparseLUP(m); - }, - - 'Array': function (a) { - // create dense matrix from array - var m = matrix$$1(a); - // lup, use matrix implementation - var r = _denseLUP(m); - // result - return { - L: r.L.valueOf(), - U: r.U.valueOf(), - p: r.p - }; - } - }); - - var _denseLUP = function (m) { - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // minimum rows and columns - var n = Math.min(rows, columns); - // matrix array, clone original data - var data = object$4.clone(m._data); - // l matrix arrays - var ldata = []; - var lsize = [rows, n]; - // u matrix arrays - var udata = []; - var usize = [n, columns]; - // vars - var i, j, k; - // permutation vector - var p = []; - for (i = 0; i < rows; i++) - p[i] = i; - // loop columns - for (j = 0; j < columns; j++) { - // skip first column in upper triangular matrix - if (j > 0) { - // loop rows - for (i = 0; i < rows; i++) { - // min i,j - var min = Math.min(i, j); - // v[i, j] - var s = 0; - // loop up to min - for (k = 0; k < min; k++) { - // s = l[i, k] - data[k, j] - s = addScalar$$1(s, multiplyScalar$$1(data[i][k], data[k][j])); - } - data[i][j] = subtract(data[i][j], s); - } - } - // row with larger value in cvector, row >= j - var pi = j; - var pabsv = 0; - var vjj = 0; - // loop rows - for (i = j; i < rows; i++) { - // data @ i, j - var v = data[i][j]; - // absolute value - var absv = abs(v); - // value is greater than pivote value - if (larger$$1(absv, pabsv)) { - // store row - pi = i; - // update max value - pabsv = absv; - // value @ [j, j] - vjj = v; - } - } - // swap rows (j <-> pi) - if (j !== pi) { - // swap values j <-> pi in p - p[j] = [p[pi], p[pi] = p[j]][0]; - // swap j <-> pi in data - DenseMatrix._swapRows(j, pi, data); - } - // check column is in lower triangular matrix - if (j < rows) { - // loop rows (lower triangular matrix) - for (i = j + 1; i < rows; i++) { - // value @ i, j - var vij = data[i][j]; - if (!equalScalar$$1(vij, 0)) { - // update data - data[i][j] = divideScalar$$1(data[i][j], vjj); - } - } - } - } - // loop columns - for (j = 0; j < columns; j++) { - // loop rows - for (i = 0; i < rows; i++) { - // initialize row in arrays - if (j === 0) { - // check row exists in upper triangular matrix - if (i < columns) { - // U - udata[i] = []; - } - // L - ldata[i] = []; - } - // check we are in the upper triangular matrix - if (i < j) { - // check row exists in upper triangular matrix - if (i < columns) { - // U - udata[i][j] = data[i][j]; - } - // check column exists in lower triangular matrix - if (j < rows) { - // L - ldata[i][j] = 0; - } - continue; - } - // diagonal value - if (i === j) { - // check row exists in upper triangular matrix - if (i < columns) { - // U - udata[i][j] = data[i][j]; - } - // check column exists in lower triangular matrix - if (j < rows) { - // L - ldata[i][j] = 1; - } - continue; - } - // check row exists in upper triangular matrix - if (i < columns) { - // U - udata[i][j] = 0; - } - // check column exists in lower triangular matrix - if (j < rows) { - // L - ldata[i][j] = data[i][j]; - } - } - } - // l matrix - var l = new DenseMatrix({ - data: ldata, - size: lsize - }); - // u matrix - var u = new DenseMatrix({ - data: udata, - size: usize - }); - // p vector - var pv = []; - for (i = 0, n = p.length; i < n; i++) - pv[p[i]] = i; - // return matrices - return { - L: l, - U: u, - p: pv, - toString: function () { - return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\nP: ' + this.p; - } - }; - }; - - var _sparseLUP = function (m) { - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // minimum rows and columns - var n = Math.min(rows, columns); - // matrix arrays (will not be modified, thanks to permutation vector) - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // l matrix arrays - var lvalues = []; - var lindex = []; - var lptr = []; - var lsize = [rows, n]; - // u matrix arrays - var uvalues = []; - var uindex = []; - var uptr = []; - var usize = [n, columns]; - // vars - var i, j, k; - // permutation vectors, (current index -> original index) and (original index -> current index) - var pv_co = []; - var pv_oc = []; - for (i = 0; i < rows; i++) { - pv_co[i] = i; - pv_oc[i] = i; - } - // swap indices in permutation vectors (condition x < y)! - var swapIndeces = function (x, y) { - // find pv indeces getting data from x and y - var kx = pv_oc[x]; - var ky = pv_oc[y]; - // update permutation vector current -> original - pv_co[kx] = y; - pv_co[ky] = x; - // update permutation vector original -> current - pv_oc[x] = ky; - pv_oc[y] = kx; - }; - // loop columns - for (j = 0; j < columns; j++) { - // sparse accumulator - var spa = new Spa(); - // check lower triangular matrix has a value @ column j - if (j < rows) { - // update ptr - lptr.push(lvalues.length); - // first value in j column for lower triangular matrix - lvalues.push(1); - lindex.push(j); - } - // update ptr - uptr.push(uvalues.length); - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // copy column j into sparse accumulator - for (k = k0; k < k1; k++) { - // row - i = index[k]; - // copy column values into sparse accumulator (use permutation vector) - spa.set(pv_co[i], values[k]); - } - // skip first column in upper triangular matrix - if (j > 0) { - // loop rows in column j (above diagonal) - spa.forEach(0, j - 1, function (k, vkj) { - // loop rows in column k (L) - SparseMatrix._forEachRow(k, lvalues, lindex, lptr, function (i, vik) { - // check row is below k - if (i > k) { - // update spa value - spa.accumulate(i, unaryMinus(multiplyScalar$$1(vik, vkj))); - } - }); - }); - } - // row with larger value in spa, row >= j - var pi = j; - var vjj = spa.get(j); - var pabsv = abs(vjj); - // loop values in spa (order by row, below diagonal) - spa.forEach(j + 1, rows - 1, function (x, v) { - // absolute value - var absv = abs(v); - // value is greater than pivote value - if (larger$$1(absv, pabsv)) { - // store row - pi = x; - // update max value - pabsv = absv; - // value @ [j, j] - vjj = v; - } - }); - // swap rows (j <-> pi) - if (j !== pi) { - // swap values j <-> pi in L - SparseMatrix._swapRows(j, pi, lsize[1], lvalues, lindex, lptr); - // swap values j <-> pi in U - SparseMatrix._swapRows(j, pi, usize[1], uvalues, uindex, uptr); - // swap values in spa - spa.swap(j, pi); - // update permutation vector (swap values @ j, pi) - swapIndeces(j, pi); - } - // loop values in spa (order by row) - spa.forEach(0, rows - 1, function (x, v) { - // check we are above diagonal - if (x <= j) { - // update upper triangular matrix - uvalues.push(v); - uindex.push(x); - } - else { - // update value - v = divideScalar$$1(v, vjj); - // check value is non zero - if (!equalScalar$$1(v, 0)) { - // update lower triangular matrix - lvalues.push(v); - lindex.push(x); - } - } - }); - } - // update ptrs - uptr.push(uvalues.length); - lptr.push(lvalues.length); - - // return matrices - return { - L: new SparseMatrix({ - values: lvalues, - index: lindex, - ptr: lptr, - size: lsize - }), - U: new SparseMatrix({ - values: uvalues, - index: uindex, - ptr: uptr, - size: usize - }), - p: pv_co, - toString: function () { - return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\nP: ' + this.p; - } - }; - }; - - return lup; - } - - var name$76 = 'lup'; - var factory_1$85 = factory$86; - - var lup$1 = { - name: name$76, - factory: factory_1$85 - }; - - var object$5 = utils.object; - var string$8 = utils.string; - - function factory$87 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var add$$1 = load(add); - var subtract = load(subtract$1); - var multiply = load(multiply$1); - var unaryMinus = load(unaryMinus$1); - var lup = load(lup$1); - - /** - * Calculate the determinant of a matrix. - * - * Syntax: - * - * math.det(x) - * - * Examples: - * - * math.det([[1, 2], [3, 4]]); // returns -2 - * - * var A = [ - * [-2, 2, 3], - * [-1, 1, 3], - * [2, 0, -1] - * ] - * math.det(A); // returns 6 - * - * See also: - * - * inv - * - * @param {Array | Matrix} x A matrix - * @return {number} The determinant of `x` - */ - var det = typed('det', { - 'any': function (x) { - return object$5.clone(x); - }, - - 'Array | Matrix': function det (x) { - var size; - if (type.isMatrix(x)) { - size = x.size(); - } - else if (Array.isArray(x)) { - x = matrix$$1(x); - size = x.size(); - } - else { - // a scalar - size = []; - } - - switch (size.length) { - case 0: - // scalar - return object$5.clone(x); - - case 1: - // vector - if (size[0] == 1) { - return object$5.clone(x.valueOf()[0]); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string$8.format(size) + ')'); - } - - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - return _det(x.clone().valueOf(), rows, cols); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string$8.format(size) + ')'); - } - - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + string$8.format(size) + ')'); - } - } - }); - - det.toTex = {1: '\\det\\left(${args[0]}\\right)'}; - - return det; - - /** - * Calculate the determinant of a matrix - * @param {Array[]} matrix A square, two dimensional matrix - * @param {number} rows Number of rows of the matrix (zero-based) - * @param {number} cols Number of columns of the matrix (zero-based) - * @returns {number} det - * @private - */ - function _det (matrix$$1, rows, cols) { - if (rows == 1) { - // this is a 1 x 1 matrix - return object$5.clone(matrix$$1[0][0]); - } - else if (rows == 2) { - // this is a 2 x 2 matrix - // the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12 - return subtract( - multiply(matrix$$1[0][0], matrix$$1[1][1]), - multiply(matrix$$1[1][0], matrix$$1[0][1]) - ); - } - else { - - // Compute the LU decomposition - var decomp = lup(matrix$$1); - - // The determinant is the product of the diagonal entries of U (and those of L, but they are all 1) - var det = decomp.U[0][0]; - for(var i=1; i= rows) break; - var j=i; - var cycleLen = 0; - while(!visited[decomp.p[j]]) { - visited[decomp.p[j]] = true; - j = decomp.p[j]; - cycleLen++; - } - if(cycleLen % 2 === 0) { - evenCycles++; - } - } - - return evenCycles % 2 === 0 ? det : unaryMinus(det); - - } - } - } - - var name$77 = 'det'; - var factory_1$86 = factory$87; - - var det$1 = { - name: name$77, - factory: factory_1$86 - }; - - var isInteger$5 = number.isInteger; - - function factory$88 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - /** - * Create a 2-dimensional identity matrix with size m x n or n x n. - * The matrix has ones on the diagonal and zeros elsewhere. - * - * Syntax: - * - * math.eye(n) - * math.eye(n, format) - * math.eye(m, n) - * math.eye(m, n, format) - * math.eye([m, n]) - * math.eye([m, n], format) - * - * Examples: - * - * math.eye(3); // returns [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - * math.eye(3, 2); // returns [[1, 0], [0, 1], [0, 0]] - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.eye(math.size(A)); // returns [[1, 0, 0], [0, 1, 0]] - * - * See also: - * - * diag, ones, zeros, size, range - * - * @param {...number | Matrix | Array} size The size for the matrix - * @param {string} [format] The Matrix storage format - * - * @return {Matrix | Array | number} A matrix with ones on the diagonal. - */ - var eye = typed('eye', { - '': function () { - return (config.matrix === 'Matrix') ? matrix$$1([]) : []; - }, - - 'string': function (format) { - return matrix$$1(format); - }, - - 'number | BigNumber': function (rows) { - return _eye(rows, rows, config.matrix === 'Matrix' ? 'default' : undefined); - }, - - 'number | BigNumber, string': function (rows, format) { - return _eye(rows, rows, format); - }, - - 'number | BigNumber, number | BigNumber': function (rows, cols) { - return _eye(rows, cols, config.matrix === 'Matrix' ? 'default' : undefined); - }, - - 'number | BigNumber, number | BigNumber, string': function (rows, cols, format) { - return _eye(rows, cols, format); - }, - - 'Array': function (size) { - return _eyeVector(size); - }, - - 'Array, string': function (size, format) { - return _eyeVector(size, format); - }, - - 'Matrix': function (size) { - return _eyeVector(size.valueOf(), size.storage()); - }, - - 'Matrix, string': function (size, format) { - return _eyeVector(size.valueOf(), format); - } - }); - - eye.toTex = undefined; // use default template - - return eye; - - function _eyeVector (size, format) { - switch (size.length) { - case 0: return format ? matrix$$1(format) : []; - case 1: return _eye(size[0], size[0], format); - case 2: return _eye(size[0], size[1], format); - default: throw new Error('Vector containing two values expected'); - } - } - - /** - * Create an identity matrix - * @param {number | BigNumber} rows - * @param {number | BigNumber} cols - * @param {string} [format] - * @returns {Matrix} - * @private - */ - function _eye (rows, cols, format) { - // BigNumber constructor with the right precision - var Big = (type.isBigNumber(rows) || type.isBigNumber(cols)) - ? type.BigNumber - : null; - - if (type.isBigNumber(rows)) rows = rows.toNumber(); - if (type.isBigNumber(cols)) cols = cols.toNumber(); - - if (!isInteger$5(rows) || rows < 1) { - throw new Error('Parameters in function eye must be positive integers'); - } - if (!isInteger$5(cols) || cols < 1) { - throw new Error('Parameters in function eye must be positive integers'); - } - - var one = Big ? new type.BigNumber(1) : 1; - var defaultValue = Big ? new Big(0) : 0; - var size = [rows, cols]; - - // check we need to return a matrix - if (format) { - // get matrix storage constructor - var F = type.Matrix.storage(format); - // create diagonal matrix (use optimized implementation for storage format) - return F.diagonal(size, one, 0, defaultValue); - } - - // create and resize array - var res = array.resize([], size, defaultValue); - // fill in ones on the diagonal - var minimum = rows < cols ? rows : cols; - // fill diagonal - for (var d = 0; d < minimum; d++) { - res[d][d] = one; - } - return res; - } - } - - var name$78 = 'eye'; - var factory_1$87 = factory$88; - - var eye$1 = { - name: name$78, - factory: factory_1$87 - }; - - function factory$89 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var divideScalar$$1 = load(divideScalar); - var addScalar$$1 = load(addScalar); - var multiply = load(multiply$1); - var unaryMinus = load(unaryMinus$1); - var det = load(det$1); - var eye = load(eye$1); - var abs = load(abs$1); - - /** - * Calculate the inverse of a square matrix. - * - * Syntax: - * - * math.inv(x) - * - * Examples: - * - * math.inv([[1, 2], [3, 4]]); // returns [[-2, 1], [1.5, -0.5]] - * math.inv(4); // returns 0.25 - * 1 / 4; // returns 0.25 - * - * See also: - * - * det, transpose - * - * @param {number | Complex | Array | Matrix} x Matrix to be inversed - * @return {number | Complex | Array | Matrix} The inverse of `x`. - */ - var inv = typed('inv', { - 'Array | Matrix': function (x) { - var size = type.isMatrix(x) ? x.size() : utils.array.size(x); - switch (size.length) { - case 1: - // vector - if (size[0] == 1) { - if (type.isMatrix(x)) { - return matrix$$1([ - divideScalar$$1(1, x.valueOf()[0]) - ]); - } - else { - return [ - divideScalar$$1(1, x[0]) - ]; - } - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + utils.string.format(size) + ')'); - } - - case 2: - // two dimensional array - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - if (type.isMatrix(x)) { - return matrix$$1( - _inv(x.valueOf(), rows, cols), - x.storage() - ); - } - else { - // return an Array - return _inv(x, rows, cols); - } - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + utils.string.format(size) + ')'); - } - - default: - // multi dimensional array - throw new RangeError('Matrix must be two dimensional ' + - '(size: ' + utils.string.format(size) + ')'); - } - }, - - 'any': function (x) { - // scalar - return divideScalar$$1(1, x); // FIXME: create a BigNumber one when configured for bignumbers - } - }); - - /** - * Calculate the inverse of a square matrix - * @param {Array[]} mat A square matrix - * @param {number} rows Number of rows - * @param {number} cols Number of columns, must equal rows - * @return {Array[]} inv Inverse matrix - * @private - */ - function _inv (mat, rows, cols){ - var r, s, f, value, temp; - - if (rows == 1) { - // this is a 1 x 1 matrix - value = mat[0][0]; - if (value == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [[ - divideScalar$$1(1, value) - ]]; - } - else if (rows == 2) { - // this is a 2 x 2 matrix - var d = det(mat); - if (d == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - return [ - [ - divideScalar$$1(mat[1][1], d), - divideScalar$$1(unaryMinus(mat[0][1]), d) - ], - [ - divideScalar$$1(unaryMinus(mat[1][0]), d), - divideScalar$$1(mat[0][0], d) - ] - ]; - } - else { - // this is a matrix of 3 x 3 or larger - // calculate inverse using gauss-jordan elimination - // http://en.wikipedia.org/wiki/Gaussian_elimination - // http://mathworld.wolfram.com/MatrixInverse.html - // http://math.uww.edu/~mcfarlat/inverse.htm - - // make a copy of the matrix (only the arrays, not of the elements) - var A = mat.concat(); - for (r = 0; r < rows; r++) { - A[r] = A[r].concat(); - } - - // create an identity matrix which in the end will contain the - // matrix inverse - var B = eye(rows).valueOf(); - - // loop over all columns, and perform row reductions - for (var c = 0; c < cols; c++) { - // Pivoting: Swap row c with row r, where row r contains the largest element A[r][c] - var A_big = abs(A[c][c]); - var r_big = c; - r = c+1; - while (r < rows) { - if(abs(A[r][c]) > A_big) { - A_big = abs(A[r][c]); - r_big = r; - } - r++; - } - if(A_big == 0) { - throw Error('Cannot calculate inverse, determinant is zero'); - } - r = r_big; - if (r != c) { - temp = A[c]; A[c] = A[r]; A[r] = temp; - temp = B[c]; B[c] = B[r]; B[r] = temp; - } - - // eliminate non-zero values on the other rows at column c - var Ac = A[c], - Bc = B[c]; - for (r = 0; r < rows; r++) { - var Ar = A[r], - Br = B[r]; - if(r != c) { - // eliminate value at column c and row r - if (Ar[c] != 0) { - f = divideScalar$$1(unaryMinus(Ar[c]), Ac[c]); - - // add (f * row c) to row r to eliminate the value - // at column c - for (s = c; s < cols; s++) { - Ar[s] = addScalar$$1(Ar[s], multiply(f, Ac[s])); - } - for (s = 0; s < cols; s++) { - Br[s] = addScalar$$1(Br[s], multiply(f, Bc[s])); - } - } - } - else { - // normalize value at Acc to 1, - // divide each value on row r with the value at Acc - f = Ac[c]; - for (s = c; s < cols; s++) { - Ar[s] = divideScalar$$1(Ar[s], f); - } - for (s = 0; s < cols; s++) { - Br[s] = divideScalar$$1(Br[s], f); - } - } - } - } - return B; - } - } - - inv.toTex = {1: '\\left(${args[0]}\\right)^{-1}'}; - - return inv; - } - - var name$79 = 'inv'; - var factory_1$88 = factory$89; - - var inv$1 = { - name: name$79, - factory: factory_1$88 - }; - - var extend$3 = object.extend; - - function factory$90 (type, config, load, typed) { - - var divideScalar$$1 = load(divideScalar); - var multiply = load(multiply$1); - var inv = load(inv$1); - var matrix$$1 = load(matrix); - - var algorithm11$$1 = load(algorithm11); - var algorithm14$$1 = load(algorithm14); - - /** - * Divide two values, `x / y`. - * To divide matrices, `x` is multiplied with the inverse of `y`: `x * inv(y)`. - * - * Syntax: - * - * math.divide(x, y) - * - * Examples: - * - * math.divide(2, 3); // returns number 0.6666666666666666 - * - * var a = math.complex(5, 14); - * var b = math.complex(4, 1); - * math.divide(a, b); // returns Complex 2 + 3i - * - * var c = [[7, -6], [13, -4]]; - * var d = [[1, 2], [4, 3]]; - * math.divide(c, d); // returns Array [[-9, 4], [-11, 6]] - * - * var e = math.unit('18 km'); - * math.divide(e, 4.5); // returns Unit 4 km - * - * See also: - * - * multiply - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Numerator - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} y Denominator - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Quotient, `x / y` - */ - var divide = typed('divide', extend$3({ - // we extend the signatures of divideScalar with signatures dealing with matrices - - 'Array | Matrix, Array | Matrix': function (x, y) { - // TODO: implement matrix right division using pseudo inverse - // http://www.mathworks.nl/help/matlab/ref/mrdivide.html - // http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html - // http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour - return multiply(x, inv(y)); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, divideScalar$$1, false); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, divideScalar$$1, false); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, divideScalar$$1, false).valueOf(); - }, - - 'any, Array | Matrix': function (x, y) { - return multiply(x, inv(y)); - } - }, divideScalar$$1.signatures)); - - divide.toTex = {2: '\\frac{${args[0]}}{${args[1]}}'}; - - return divide; - } - - var name$80 = 'divide'; - var factory_1$89 = factory$90; - - var divide$1 = { - name: name$80, - factory: factory_1$89 - }; - - var size$1 = array.size; - - - - - function factory$91 (type, config, load, typed) { - var add$$1 = load(add); - var divide = load(divide$1); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the mean value of matrix or a list with values. - * In case of a multi dimensional array, the mean of the flattened array - * will be calculated. When `dim` is provided, the maximum over the selected - * dimension will be calculated. Parameter `dim` is zero-based. - * - * Syntax: - * - * math.mean(a, b, c, ...) - * math.mean(A) - * math.mean(A, dim) - * - * Examples: - * - * math.mean(2, 1, 4, 3); // returns 2.5 - * math.mean([1, 2.7, 3.2, 4]); // returns 2.725 - * - * math.mean([[2, 5], [6, 3], [1, 7]], 0); // returns [3, 5] - * math.mean([[2, 5], [6, 3], [1, 7]], 1); // returns [3.5, 4.5, 4] - * - * See also: - * - * median, min, max, sum, prod, std, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The mean of all values - */ - var mean = typed('mean', { - // mean([a, b, c, d, ...]) - 'Array | Matrix': _mean, - - // mean([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': _nmeanDim, - - // mean(a, b, c, d, ...) - '...': function (args) { - if (containsCollections(args)) { - throw new TypeError('Scalar values expected in function mean'); - } - - return _mean(args); - } - }); - - mean.toTex = undefined; // use default template - - return mean; - - /** - * Calculate the mean value in an n-dimensional array, returning a - * n-1 dimensional array - * @param {Array} array - * @param {number} dim - * @return {number} mean - * @private - */ - function _nmeanDim(array$$1, dim) { - try { - var sum = reduce(array$$1, dim, add$$1); - var s = Array.isArray(array$$1) ? size$1(array$$1) : array$$1.size(); - return divide(sum, s[dim]); - } - catch (err) { - throw improveErrorMessage$$1(err, 'mean'); - } - } - - /** - * Recursively calculate the mean value in an n-dimensional array - * @param {Array} array - * @return {number} mean - * @private - */ - function _mean(array$$1) { - var sum = 0; - var num = 0; - - deepForEach(array$$1, function (value) { - try { - sum = add$$1(sum, value); - num++; - } - catch (err) { - throw improveErrorMessage$$1(err, 'mean', value); - } - }); - - if (num === 0) { - throw new Error('Cannot calculate mean of an empty array'); - } - - return divide(sum, num); - } - } - - var name$81 = 'mean'; - var factory_1$90 = factory$91; - - var mean$1 = { - name: name$81, - factory: factory_1$90 - }; - - var errorTransform$4 = error_transform.transform; - - - /** - * Attach a transform function to math.mean - * Adds a property transform containing the transform function. - * - * This transform changed the last `dim` parameter of function mean - * from one-based to zero based - */ - function factory$92 (type, config, load, typed) { - var mean = load(mean$1); - - return typed('mean', { - '...any': function (args) { - // change last argument dim from one-based to zero-based - if (args.length == 2 && isCollection(args[0])) { - var dim = args[1]; - if (type.isNumber(dim)) { - args[1] = dim - 1; - } - else if (type.isBigNumber(dim)) { - args[1] = dim.minus(1); - } - } - - try { - return mean.apply(null, args); - } - catch (err) { - throw errorTransform$4(err); - } - } - }); - } - - var name$82 = 'mean'; - var path$38 = 'expression.transform'; - var factory_1$91 = factory$92; - - var mean_transform = { - name: name$82, - path: path$38, - factory: factory_1$91 - }; - - function factory$93 (type, config, load, typed) { - var smaller$$1 = load(smaller); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the maximum value of a matrix or a list of values. - * In case of a multi dimensional array, the maximum of the flattened array - * will be calculated. When `dim` is provided, the maximum over the selected - * dimension will be calculated. Parameter `dim` is zero-based. - * - * Syntax: - * - * math.min(a, b, c, ...) - * math.min(A) - * math.min(A, dim) - * - * Examples: - * - * math.min(2, 1, 4, 3); // returns 1 - * math.min([2, 1, 4, 3]); // returns 1 - * - * // maximum over a specified dimension (zero-based) - * math.min([[2, 5], [4, 3], [1, 7]], 0); // returns [1, 3] - * math.min([[2, 5], [4, 3], [1, 7]], 1); // returns [2, 3, 1] - * - * math.max(2.7, 7.1, -4.5, 2.0, 4.1); // returns 7.1 - * math.min(2.7, 7.1, -4.5, 2.0, 4.1); // returns -4.5 - * - * See also: - * - * mean, median, max, prod, std, sum, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The minimum value - */ - var min = typed('min', { - // min([a, b, c, d, ...]) - 'Array | Matrix': _min, - - // min([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': function (array, dim) { - return reduce(array, dim.valueOf(), _smallest); - }, - - // min(a, b, c, d, ...) - '...': function (args) { - if (containsCollections(args)) { - throw new TypeError('Scalar values expected in function min'); - } - - return _min(args); - } - }); - - min.toTex = '\\min\\left(${args}\\right)'; - - return min; - - /** - * Return the smallest of two values - * @param {*} x - * @param {*} y - * @returns {*} Returns x when x is smallest, or y when y is smallest - * @private - */ - function _smallest(x, y) { - try { - return smaller$$1(x, y) ? x : y; - } - catch (err) { - throw improveErrorMessage$$1(err, 'min', y); - } - } - - /** - * Recursively calculate the minimum value in an n-dimensional array - * @param {Array} array - * @return {number} min - * @private - */ - function _min(array) { - var min = undefined; - - deepForEach(array, function (value) { - try { - if (min === undefined || smaller$$1(value, min)) { - min = value; - } - } - catch (err) { - throw improveErrorMessage$$1(err, 'min', value); - } - }); - - if (min === undefined) { - throw new Error('Cannot calculate min of an empty array'); - } - - return min; - } - } - - var name$83 = 'min'; - var factory_1$92 = factory$93; - - var min$1 = { - name: name$83, - factory: factory_1$92 - }; - - var errorTransform$5 = error_transform.transform; - - - /** - * Attach a transform function to math.min - * Adds a property transform containing the transform function. - * - * This transform changed the last `dim` parameter of function min - * from one-based to zero based - */ - function factory$94 (type, config, load, typed) { - var min = load(min$1); - - return typed('min', { - '...any': function (args) { - // change last argument dim from one-based to zero-based - if (args.length == 2 && isCollection(args[0])) { - var dim = args[1]; - if (type.isNumber(dim)) { - args[1] = dim - 1; - } - else if (type.isBigNumber(dim)) { - args[1] = dim.minus(1); - } - } - - try { - return min.apply(null, args); - } - catch (err) { - throw errorTransform$5(err); - } - } - }); - } - - var name$84 = 'min'; - var path$39 = 'expression.transform'; - var factory_1$93 = factory$94; - - var min_transform = { - name: name$84, - path: path$39, - factory: factory_1$93 - }; - - function factory$95 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - var ZERO = new type.BigNumber(0); - var ONE = new type.BigNumber(1); - - /** - * Create an array from a range. - * By default, the range end is excluded. This can be customized by providing - * an extra parameter `includeEnd`. - * - * Syntax: - * - * math.range(str [, includeEnd]) // Create a range from a string, - * // where the string contains the - * // start, optional step, and end, - * // separated by a colon. - * math.range(start, end [, includeEnd]) // Create a range with start and - * // end and a step size of 1. - * math.range(start, end, step [, includeEnd]) // Create a range with start, step, - * // and end. - * - * Where: - * - * - `str: string` - * A string 'start:end' or 'start:step:end' - * - `start: {number | BigNumber}` - * Start of the range - * - `end: number | BigNumber` - * End of the range, excluded by default, included when parameter includeEnd=true - * - `step: number | BigNumber` - * Step size. Default value is 1. - * - `includeEnd: boolean` - * Option to specify whether to include the end or not. False by default. - * - * Examples: - * - * math.range(2, 6); // [2, 3, 4, 5] - * math.range(2, -3, -1); // [2, 1, 0, -1, -2] - * math.range('2:1:6'); // [2, 3, 4, 5] - * math.range(2, 6, true); // [2, 3, 4, 5, 6] - * - * See also: - * - * ones, zeros, size, subset - * - * @param {*} args Parameters describing the ranges `start`, `end`, and optional `step`. - * @return {Array | Matrix} range - */ - var range = typed('range', { - // TODO: simplify signatures when typed-function supports default values and optional arguments - - // TODO: a number or boolean should not be converted to string here - 'string': _strRange, - 'string, boolean': _strRange, - - 'number, number': function (start, end) { - return _out(_rangeEx(start, end, 1)); - }, - 'number, number, number': function (start, end, step) { - return _out(_rangeEx(start, end, step)); - }, - 'number, number, boolean': function (start, end, includeEnd) { - return includeEnd - ? _out(_rangeInc(start, end, 1)) - : _out(_rangeEx(start, end, 1)); - }, - 'number, number, number, boolean': function (start, end, step, includeEnd) { - return includeEnd - ? _out(_rangeInc(start, end, step)) - : _out(_rangeEx(start, end, step)); - }, - - 'BigNumber, BigNumber': function (start, end) { - return _out(_bigRangeEx(start, end, ONE)); - }, - 'BigNumber, BigNumber, BigNumber': function (start, end, step) { - return _out(_bigRangeEx(start, end, step)); - }, - 'BigNumber, BigNumber, boolean': function (start, end, includeEnd) { - return includeEnd - ? _out(_bigRangeInc(start, end, ONE)) - : _out(_bigRangeEx(start, end, ONE)); - }, - 'BigNumber, BigNumber, BigNumber, boolean': function (start, end, step, includeEnd) { - return includeEnd - ? _out(_bigRangeInc(start, end, step)) - : _out(_bigRangeEx(start, end, step)); - } - - }); - - range.toTex = undefined; // use default template - - return range; - - function _out(arr) { - return config.matrix === 'Array' ? arr : matrix$$1(arr); - } - - function _strRange (str, includeEnd) { - var r = _parse(str); - if (!r){ - throw new SyntaxError('String "' + str + '" is no valid range'); - } - - var fn; - if (config.number === 'BigNumber') { - fn = includeEnd ? _bigRangeInc : _bigRangeEx; - return _out(fn( - new type.BigNumber(r.start), - new type.BigNumber(r.end), - new type.BigNumber(r.step))); - } - else { - fn = includeEnd ? _rangeInc : _rangeEx; - return _out(fn(r.start, r.end, r.step)); - } - } - - /** - * Create a range with numbers. End is excluded - * @param {number} start - * @param {number} end - * @param {number} step - * @returns {Array} range - * @private - */ - function _rangeEx (start, end, step) { - var array = [], - x = start; - if (step > 0) { - while (x < end) { - array.push(x); - x += step; - } - } - else if (step < 0) { - while (x > end) { - array.push(x); - x += step; - } - } - - return array; - } - - /** - * Create a range with numbers. End is included - * @param {number} start - * @param {number} end - * @param {number} step - * @returns {Array} range - * @private - */ - function _rangeInc (start, end, step) { - var array = [], - x = start; - if (step > 0) { - while (x <= end) { - array.push(x); - x += step; - } - } - else if (step < 0) { - while (x >= end) { - array.push(x); - x += step; - } - } - - return array; - } - - /** - * Create a range with big numbers. End is excluded - * @param {BigNumber} start - * @param {BigNumber} end - * @param {BigNumber} step - * @returns {Array} range - * @private - */ - function _bigRangeEx (start, end, step) { - var array = [], - x = start; - if (step.gt(ZERO)) { - while (x.lt(end)) { - array.push(x); - x = x.plus(step); - } - } - else if (step.lt(ZERO)) { - while (x.gt(end)) { - array.push(x); - x = x.plus(step); - } - } - - return array; - } - - /** - * Create a range with big numbers. End is included - * @param {BigNumber} start - * @param {BigNumber} end - * @param {BigNumber} step - * @returns {Array} range - * @private - */ - function _bigRangeInc (start, end, step) { - var array = [], - x = start; - if (step.gt(ZERO)) { - while (x.lte(end)) { - array.push(x); - x = x.plus(step); - } - } - else if (step.lt(ZERO)) { - while (x.gte(end)) { - array.push(x); - x = x.plus(step); - } - } - - return array; - } - - /** - * 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 {{start: number, end: number, step: number} | null} range Object containing properties start, end, step - * @private - */ - function _parse (str) { - var args = str.split(':'); - - // number - var nums = args.map(function (arg) { - // use Number and not parseFloat as Number returns NaN on invalid garbage in the string - return Number(arg); - }); - - var invalid = nums.some(function (num) { - return isNaN(num); - }); - if(invalid) { - return null; - } - - switch (nums.length) { - case 2: - return { - start: nums[0], - end: nums[1], - step: 1 - }; - - case 3: - return { - start: nums[0], - end: nums[2], - step: nums[1] - }; - - default: - return null; - } - } - - } - - var name$85 = 'range'; - var factory_1$94 = factory$95; - - var range$1 = { - name: name$85, - factory: factory_1$94 - }; - - /** - * Attach a transform function to math.range - * Adds a property transform containing the transform function. - * - * This transform creates a range which includes the end value - */ - function factory$96 (type, config, load, typed) { - var range = load(range$1); - - return typed('range', { - '...any': function (args) { - var lastIndex = args.length - 1; - var last = args[lastIndex]; - if (typeof last !== 'boolean') { - // append a parameter includeEnd=true - args.push(true); - } - - return range.apply(null, args); - } - }); - } - - var name$86 = 'range'; - var path$40 = 'expression.transform'; - var factory_1$95 = factory$96; - - var range_transform = { - name: name$86, - path: path$40, - factory: factory_1$95 - }; - - var errorTransform$6 = error_transform.transform; - - /** - * Attach a transform function to math.subset - * Adds a property transform containing the transform function. - * - * This transform creates a range which includes the end value - */ - function factory$97 (type, config, load, typed) { - var subset = load(subset$1); - - return typed('subset', { - '...any': function (args) { - try { - return subset.apply(null, args); - } - catch (err) { - throw errorTransform$6(err); - } - } - }); - } - - var name$87 = 'subset'; - var path$41 = 'expression.transform'; - var factory_1$96 = factory$97; - - var subset_transform = { - name: name$87, - path: path$41, - factory: factory_1$96 - }; - - var transform$1 = [ - concat_transform, - filter_transform, - forEach_transform, - index_transform, - map_transform, - max_transform, - mean_transform, - min_transform, - range_transform, - subset_transform - ]; - - function factory$98 (type, config, load, typed) { - var parser$$1 = load(parser)(); - - /** - * Documentation object - * @param {Object} doc Object containing properties: - * {string} name - * {string} category - * {string} description - * {string[]} syntax - * {string[]} examples - * {string[]} seealso - * @constructor - */ - function Help(doc) { - if (!(this instanceof Help)) { - throw new SyntaxError('Constructor must be called with the new operator'); - } - - if (!doc) throw new Error('Argument "doc" missing'); - - this.doc = doc; - } - - /** - * Attach type information - */ - Help.prototype.type = 'Help'; - Help.prototype.isHelp = true; - - /** - * Generate a string representation of the Help object - * @return {string} Returns a string - * @private - */ - Help.prototype.toString = function () { - var doc = this.doc || {}; - var desc = '\n'; - - if (doc.name) { - desc += 'Name: ' + doc.name + '\n\n'; - } - if (doc.category) { - desc += 'Category: ' + doc.category + '\n\n'; - } - if (doc.description) { - desc += 'Description:\n ' + doc.description + '\n\n'; - } - if (doc.syntax) { - desc += 'Syntax:\n ' + doc.syntax.join('\n ') + '\n\n'; - } - if (doc.examples) { - desc += 'Examples:\n'; - for (var i = 0; i < doc.examples.length; i++) { - var expr = doc.examples[i]; - desc += ' ' + expr + '\n'; - - var res; - try { - // note: res can be undefined when `expr` is an empty string - res = parser$$1.eval(expr); - } - catch (e) { - res = e; - } - if (res !== undefined && !type.isHelp(res)) { - desc += ' ' + string.format(res, {precision: 14}) + '\n'; - } - } - desc += '\n'; - } - if (doc.seealso && doc.seealso.length) { - desc += 'See also: ' + doc.seealso.join(', ') + '\n'; - } - - return desc; - }; - - /** - * Export the help object to JSON - */ - Help.prototype.toJSON = function () { - var obj = object.clone(this.doc); - obj.mathjs = 'Help'; - return obj; - }; - - /** - * Instantiate a Help object from a JSON object - * @param {Object} json - * @returns {Help} Returns a new Help object - */ - Help.fromJSON = function (json) { - var doc = {}; - for (var prop in json) { - if (prop !== 'mathjs') { // ignore mathjs field - doc[prop] = json[prop]; - } - } - return new Help(doc); - }; - - /** - * Returns a string representation of the Help object - */ - Help.prototype.valueOf = Help.prototype.toString; - - return Help; - } - - var name$88 = 'Help'; - var path$42 = 'type'; - var factory_1$97 = factory$98; - - var Help = { - name: name$88, - path: path$42, - factory: factory_1$97 - }; - - var expression = [ - // Note that the docs folder is called "embeddedDocs" and not "docs" to prevent issues - // with yarn autoclean. See https://github.com/josdejong/mathjs/issues/969 - embeddedDocs, - _function$2, - node, - transform$1, - - Help, - parse, - Parser - ]; - - function factory$99 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - var latex$$1 = latex; - - /** - * Test whether two values are equal. - * - * The function tests whether the relative difference between x and y is - * smaller than the configured epsilon. The function cannot be used to - * compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, x.re must equal y.re, and x.im must equal y.im. - * - * Values `null` and `undefined` are compared strictly, thus `null` is only - * equal to `null` and nothing else, and `undefined` is only equal to - * `undefined` and nothing else. Strings are compared by their numerical value. - * - * Syntax: - * - * math.equal(x, y) - * - * Examples: - * - * math.equal(2 + 2, 3); // returns false - * math.equal(2 + 2, 4); // returns true - * - * var a = math.unit('50 cm'); - * var b = math.unit('5 m'); - * math.equal(a, b); // returns true - * - * var c = [2, 5, 1]; - * var d = [2, 7, 1]; - * - * math.equal(c, d); // returns [true, false, true] - * math.deepEqual(c, d); // returns false - * - * math.equal("1000", "1e3"); // returns true - * math.equal(0, null); // returns false - * - * See also: - * - * unequal, smaller, smallerEq, larger, largerEq, compare, deepEqual, equalText - * - * @param {number | BigNumber | boolean | Complex | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | boolean | Complex | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the compared values are equal, else returns false - */ - var equal = typed('equal', { - - 'any, any': function (x, y) { - // strict equality for null and undefined? - if (x === null) { return y === null; } - if (y === null) { return x === null; } - if (x === undefined) { return y === undefined; } - if (y === undefined) { return x === undefined; } - - return equalScalar$$1(x, y); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, equalScalar$$1); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, equalScalar$$1, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, equalScalar$$1, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, equalScalar$$1); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return equal(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return equal(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return equal(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, equalScalar$$1, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, equalScalar$$1, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, equalScalar$$1, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, equalScalar$$1, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, equalScalar$$1, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, equalScalar$$1, true).valueOf(); - } - }); - - equal.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['equal'] + '${args[1]}\\right)' - }; - - return equal; - } - - var name$89 = 'equal'; - var factory_1$98 = factory$99; - - var equal$1 = { - name: name$89, - factory: factory_1$98 - }; - - function factory$100(type, config, load, typed, math) { - var FunctionNode = math.expression.node.FunctionNode; - var OperatorNode = math.expression.node.OperatorNode; - var SymbolNode = math.expression.node.SymbolNode; - - // TODO commutative/associative properties rely on the arguments - // e.g. multiply is not commutative for matrices - // The properties should be calculated from an argument to simplify, or possibly something in math.config - // the other option is for typed() to specify a return type so that we can evaluate the type of arguments - var commutative = { - 'add': true, - 'multiply': true - }; - var associative = { - 'add': true, - 'multiply': true - }; - - - function isCommutative(node, context) { - if (!type.isOperatorNode(node)) { - return true; - } - var name = node.fn.toString(); - if (context && context.hasOwnProperty(name) && context[name].hasOwnProperty('commutative')) { - return context[name].commutative; - } - return commutative[name] || false; - } - - function isAssociative(node, context) { - if (!type.isOperatorNode(node)) { - return false; - } - var name = node.fn.toString(); - if (context && context.hasOwnProperty(name) && context[name].hasOwnProperty('associative')) { - return context[name].associative; - } - return associative[name] || false; - } - - /** - * Flatten all associative operators in an expression tree. - * Assumes parentheses have already been removed. - */ - function flatten(node) { - if (!node.args || node.args.length === 0) { - return node; - } - node.args = allChildren(node); - for (var i=0; i 2 && isAssociative(node)) { - var curnode = node.args.pop(); - while (node.args.length > 0) { - curnode = makeNode([node.args.pop(), curnode]); - } - node.args = curnode.args; - } - } - - /** - * Unflatten all flattened operators to a left-heavy binary tree. - */ - function unflattenl(node) { - if (!node.args || node.args.length === 0) { - return; - } - var makeNode = createMakeNodeFunction(node); - var l = node.args.length; - for (var i = 0; i < l; i++) { - unflattenl(node.args[i]); - } - if (l > 2 && isAssociative(node)) { - var curnode = node.args.shift(); - while (node.args.length > 0) { - curnode = makeNode([curnode, node.args.shift()]); - } - node.args = curnode.args; - } - } - - function createMakeNodeFunction(node) { - if (type.isOperatorNode(node)) { - return function(args){ - try{ - return new OperatorNode(node.op, node.fn, args); - } catch(err){ - console.error(err); - return []; - } - }; - } - else { - return function(args){ - return new FunctionNode(new SymbolNode(node.name), args); - }; - } - } - return { - createMakeNodeFunction: createMakeNodeFunction, - isCommutative: isCommutative, - isAssociative: isAssociative, - flatten: flatten, - allChildren: allChildren, - unflattenr: unflattenr, - unflattenl: unflattenl - }; - } - - var factory_1$99 = factory$100; - var math$12 = true; - - var util = { - factory: factory_1$99, - math: math$12 - }; - - function factory$101 (type, config, load, typed) { - /** - * Test whether a value is an numeric value. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isNumeric(x) - * - * Examples: - * - * math.isNumeric(2); // returns true - * math.isNumeric(0); // returns true - * math.isNumeric(math.bignumber(500)); // returns true - * math.isNumeric(math.fraction(4)); // returns true - * math.isNumeric(math.complex('2-4i'); // returns false - * math.isNumeric('3'); // returns false - * math.isNumeric([2.3, 'foo', false]); // returns [true, false, true] - * - * See also: - * - * isZero, isPositive, isNegative, isInteger - * - * @param {*} x Value to be tested - * @return {boolean} Returns true when `x` is a `number`, `BigNumber`, - * `Fraction`, or `boolean`. Returns false for other types. - * Throws an error in case of unknown types. - */ - var isNumeric = typed('isNumeric', { - 'number | BigNumber | Fraction | boolean': function () { - return true; - }, - - 'Complex | Unit | string': function () { - return false; - }, - - 'Array | Matrix': function (x) { - return deepMap(x, isNumeric); - } - }); - - return isNumeric; - } - - var name$90 = 'isNumeric'; - var factory_1$100 = factory$101; - - var isNumeric$1 = { - name: name$90, - factory: factory_1$100 - }; - - var digits$1 = number.digits; - // TODO this could be improved by simplifying seperated constants under associative and commutative operators - function factory$102(type, config, load, typed, math) { - var util$$1 = load(util); - var isNumeric = load(isNumeric$1); - var isCommutative = util$$1.isCommutative; - var isAssociative = util$$1.isAssociative; - var allChildren = util$$1.allChildren; - var createMakeNodeFunction = util$$1.createMakeNodeFunction; - var ConstantNode = math.expression.node.ConstantNode; - var OperatorNode = math.expression.node.OperatorNode; - var FunctionNode = math.expression.node.FunctionNode; - - function simplifyConstant(expr) { - var res = foldFraction(expr); - return type.isNode(res) ? res : _toNode(res); - } - - function _eval(fnname, args) { - try { - return _toNumber(math[fnname].apply(null, args)); - } - catch (ignore) { - // sometimes the implicit type conversion causes the evaluation to fail, so we'll try again after removing Fractions - args = args.map(function(x){ - if (type.isFraction(x)) { - return x.valueOf(); - } - return x; - }); - return _toNumber(math[fnname].apply(null, args)); - } - } - - var _toNode = typed({ - 'Fraction': _fractionToNode, - 'number': function(n) { - if (n < 0) { - return unaryMinusNode(new ConstantNode(-n)); - } - return new ConstantNode(n); - }, - 'BigNumber': function(n) { - if (n < 0) { - return unaryMinusNode(new ConstantNode(n.negated().toString(), 'number')); - } - return new ConstantNode(n.toString(), 'number'); - }, - 'Complex': function(s) { - throw 'Cannot convert Complex number to Node'; - } - }); - - // convert a number to a fraction only if it can be expressed exactly - function _exactFraction(n) { - if (isFinite(n)) { - var f = math.fraction(n); - if (f.valueOf() === n) { - return f; - } - } - return n; - } - - // Convert numbers to a preferred number type in preference order: Fraction, number, Complex - // BigNumbers are left alone - var _toNumber = typed({ - 'string': function(s) { - if (config.number === 'BigNumber') { - return math.bignumber(s); - } - else if (config.number === 'Fraction') { - return math.fraction(s); - } - else { - return _exactFraction(parseFloat(s)); - } - }, - - 'Fraction': function(s) { return s; }, - - 'BigNumber': function(s) { return s; }, - - 'number': function(s) { - return _exactFraction(s); - }, - - 'Complex': function(s) { - if (s.im !== 0) { - return s; - } - return _exactFraction(s.re); - }, - }); - - function unaryMinusNode(n) { - return new OperatorNode('-', 'unaryMinus', [n]); - } - - function _fractionToNode(f) { - var n; - var vn = f.s*f.n; - if (vn < 0) { - n = new OperatorNode('-', 'unaryMinus', [new ConstantNode(-vn)]); - } - else { - n = new ConstantNode(vn); - } - - if (f.d === 1) { - return n; - } - return new OperatorNode('/', 'divide', [n, new ConstantNode(f.d)]); - } - - /* - * Create a binary tree from a list of Fractions and Nodes. - * Tries to fold Fractions by evaluating them until the first Node in the list is hit, so - * `args` should be sorted to have the Fractions at the start (if the operator is commutative). - * @param args - list of Fractions and Nodes - * @param fn - evaluator for the binary operation evaluator that accepts two Fractions - * @param makeNode - creates a binary OperatorNode/FunctionNode from a list of child Nodes - * if args.length is 1, returns args[0] - * @return - Either a Node representing a binary expression or Fraction - */ - function foldOp(fn, args, makeNode) { - return args.reduce(function(a, b) { - if (!type.isNode(a) && !type.isNode(b)) { - try { - return _eval(fn, [a,b]); - } - catch (ignoreandcontinue) {} - a = _toNode(a); - b = _toNode(b); - } - else if (!type.isNode(a)) { - a = _toNode(a); - } - else if (!type.isNode(b)) { - b = _toNode(b); - } - - return makeNode([a, b]); - }); - } - - // destroys the original node and returns a folded one - function foldFraction(node) { - switch(node.type) { - case 'SymbolNode': - return node; - case 'ConstantNode': - if (typeof node.value === 'number') { - return _toNumber(node.value); - } - return node; - case 'FunctionNode': - if (math[node.name] && math[node.name].rawArgs) { - return node; - } - - // Process operators as OperatorNode - var operatorFunctions = [ 'add', 'multiply' ]; - if (operatorFunctions.indexOf(node.name) === -1) { - var args = node.args.map(foldFraction); - - // If all args are numbers - if (!args.some(type.isNode)) { - try { - return _eval(node.name, args); - } - catch (ignoreandcontine) {} - } - - // Convert all args to nodes and construct a symbolic function call - args = args.map(function(arg) { - return type.isNode(arg) ? arg : _toNode(arg); - }); - return new FunctionNode(node.name, args); - } - else { - // treat as operator - } - /* falls through */ - case 'OperatorNode': - var fn = node.fn.toString(); - var args; - var res; - var makeNode = createMakeNodeFunction(node); - if (node.isUnary()) { - args = [foldFraction(node.args[0])]; - if (!type.isNode(args[0])) { - res = _eval(fn, args); - } - else { - res = makeNode(args); - } - } - else if (isAssociative(node)) { - args = allChildren(node); - args = args.map(foldFraction); - - if (isCommutative(fn)) { - // commutative binary operator - var consts = [], vars = []; - - for (var i=0; i < args.length; i++) { - if (!type.isNode(args[i])) { - consts.push(args[i]); - } - else { - vars.push(args[i]); - } - } - - if (consts.length > 1) { - res = foldOp(fn, consts, makeNode); - vars.unshift(res); - res = foldOp(fn, vars, makeNode); - } - else { - // we won't change the children order since it's not neccessary - res = foldOp(fn, args, makeNode); - } - } - else { - // non-commutative binary operator - res = foldOp(fn, args, makeNode); - } - } - else { - // non-associative binary operator - args = node.args.map(foldFraction); - res = foldOp(fn, args, makeNode); - } - return res; - case 'ParenthesisNode': - // remove the uneccessary parenthesis - return foldFraction(node.content); - case 'AccessorNode': - /* falls through */ - case 'ArrayNode': - /* falls through */ - case 'AssignmentNode': - /* falls through */ - case 'BlockNode': - /* falls through */ - case 'FunctionAssignmentNode': - /* falls through */ - case 'IndexNode': - /* falls through */ - case 'ObjectNode': - /* falls through */ - case 'RangeNode': - /* falls through */ - case 'UpdateNode': - /* falls through */ - case 'ConditionalNode': - /* falls through */ - default: - throw 'Unimplemented node type in simplifyConstant: '+node.type; - } - } - - return simplifyConstant; - } - - var math$13 = true; - var name$91 = 'simplifyConstant'; - var path$43 = 'algebra.simplify'; - var factory_1$101 = factory$102; - - var simplifyConstant = { - math: math$13, - name: name$91, - path: path$43, - factory: factory_1$101 - }; - - function factory$103 (type, config, load, typed) { - /** - * Test whether a value is zero. - * The function can check for zero for types `number`, `BigNumber`, `Fraction`, - * `Complex`, and `Unit`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isZero(x) - * - * Examples: - * - * math.isZero(0); // returns true - * math.isZero(2); // returns false - * math.isZero(0.5); // returns false - * math.isZero(math.bignumber(0)); // returns true - * math.isZero(math.fraction(0)); // returns true - * math.isZero(math.fraction(1,3)); // returns false - * math.isZero(math.complex('2 - 4i'); // returns false - * math.isZero(math.complex('0i'); // returns true - * math.isZero('0'); // returns true - * math.isZero('2'); // returns false - * math.isZero([2, 0, -3]'); // returns [false, true, false] - * - * See also: - * - * isNumeric, isPositive, isNegative, isInteger - * - * @param {number | BigNumber | Complex | Fraction | Unit | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is zero. - * Throws an error in case of an unknown data type. - */ - var isZero = typed('isZero', { - 'number': function (x) { - return x === 0; - }, - - 'BigNumber': function (x) { - return x.isZero(); - }, - - 'Complex': function (x) { - return x.re === 0 && x.im === 0; - }, - - 'Fraction': function (x) { - return x.d === 1 && x.n === 0; - }, - - 'Unit': function (x) { - return isZero(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, isZero); - } - }); - - return isZero; - } - - var name$92 = 'isZero'; - var factory_1$102 = factory$103; - - var isZero$1 = { - name: name$92, - factory: factory_1$102 - }; - - var isInteger$6 = number.isInteger; - var size$2 = array.size; - - function factory$104 (type, config, load, typed) { - var latex$$1 = latex; - var eye = load(eye$1); - var multiply = load(multiply$1); - var matrix$$1 = load(matrix); - var fraction = load(fraction$2); - var number$$1 = load(number$3); - - /** - * Calculates the power of x to y, `x ^ y`. - * Matrix exponentiation is supported for square matrices `x`, and positive - * integer exponents `y`. - * - * For cubic roots of negative numbers, the function returns the principal - * root by default. In order to let the function return the real root, - * math.js can be configured with `math.config({predictable: true})`. - * To retrieve all cubic roots of a value, use `math.cbrt(x, true)`. - * - * Syntax: - * - * math.pow(x, y) - * - * Examples: - * - * math.pow(2, 3); // returns number 8 - * - * var a = math.complex(2, 3); - * math.pow(a, 2) // returns Complex -5 + 12i - * - * var b = [[1, 2], [4, 3]]; - * math.pow(b, 2); // returns Array [[9, 8], [16, 17]] - * - * See also: - * - * multiply, sqrt, cbrt, nthRoot - * - * @param {number | BigNumber | Complex | Array | Matrix} x The base - * @param {number | BigNumber | Complex} y The exponent - * @return {number | BigNumber | Complex | Array | Matrix} The value of `x` to the power `y` - */ - var pow = typed('pow', { - 'number, number': _pow, - - 'Complex, Complex': function (x, y) { - return x.pow(y); - }, - - 'BigNumber, BigNumber': function (x, y) { - if (y.isInteger() || x >= 0 || config.predictable) { - return x.pow(y); - } - else { - return new type.Complex(x.toNumber(), 0).pow(y.toNumber(), 0); - } - }, - - 'Fraction, Fraction': function (x, y) { - if (y.d !== 1) { - if (config.predictable) { - throw new Error('Function pow does not support non-integer exponents for fractions.'); - } - else { - return _pow(x.valueOf(), y.valueOf()); - } - } - else { - return x.pow(y); - } - }, - - 'Array, number': _powArray, - - 'Array, BigNumber': function (x, y) { - return _powArray(x, y.toNumber()); - }, - - 'Matrix, number': _powMatrix, - - 'Matrix, BigNumber': function (x, y) { - return _powMatrix(x, y.toNumber()); - }, - - 'Unit, number': function (x, y) { - return x.pow(y); - } - - }); - - /** - * Calculates the power of x to y, x^y, for two numbers. - * @param {number} x - * @param {number} y - * @return {number | Complex} res - * @private - */ - function _pow(x, y) { - - // Alternatively could define a 'realmode' config option or something, but - // 'predictable' will work for now - if (config.predictable && !isInteger$6(y) && x < 0) { - // Check to see if y can be represented as a fraction - try { - var yFrac = fraction(y); - var yNum = number$$1(yFrac); - if(y === yNum || Math.abs((y - yNum) / y) < 1e-14) { - if(yFrac.d % 2 === 1) { - return (yFrac.n % 2 === 0 ? 1 : -1) * Math.pow(-x, y); - } - } - } - catch (ex) { - // fraction() throws an error if y is Infinity, etc. - } - - // Unable to express y as a fraction, so continue on - } - - - // x^Infinity === 0 if -1 < x < 1 - // A real number 0 is returned instead of complex(0) - if ((x*x < 1 && y === Infinity) || - (x*x > 1 && y === -Infinity)) { - return 0; - } - - // **for predictable mode** x^Infinity === NaN if x < -1 - // N.B. this behavour is different from `Math.pow` which gives - // (-2)^Infinity === Infinity - if (config.predictable && - ((x < -1 && y === Infinity) || - (x > -1 && x < 0 && y === -Infinity))) { - return NaN; - } - - if (isInteger$6(y) || x >= 0 || config.predictable) { - return Math.pow(x, y); - } - else { - return new type.Complex(x, 0).pow(y, 0); - } - } - - /** - * Calculate the power of a 2d array - * @param {Array} x must be a 2 dimensional, square matrix - * @param {number} y a positive, integer value - * @returns {Array} - * @private - */ - function _powArray(x, y) { - if (!isInteger$6(y) || y < 0) { - throw new TypeError('For A^b, b must be a positive integer (value is ' + y + ')'); - } - // verify that A is a 2 dimensional square matrix - var s = size$2(x); - if (s.length != 2) { - throw new Error('For A^b, A must be 2 dimensional (A has ' + s.length + ' dimensions)'); - } - if (s[0] != s[1]) { - throw new Error('For A^b, A must be square (size is ' + s[0] + 'x' + s[1] + ')'); - } - - var res = eye(s[0]).valueOf(); - var px = x; - while (y >= 1) { - if ((y & 1) == 1) { - res = multiply(px, res); - } - y >>= 1; - px = multiply(px, px); - } - return res; - } - - /** - * Calculate the power of a 2d matrix - * @param {Matrix} x must be a 2 dimensional, square matrix - * @param {number} y a positive, integer value - * @returns {Matrix} - * @private - */ - function _powMatrix (x, y) { - return matrix$$1(_powArray(x.valueOf(), y)); - } - - - - pow.toTex = { - 2: '\\left(${args[0]}\\right)' + latex$$1.operators['pow'] + '{${args[1]}}' - }; - - return pow; - } - - var name$93 = 'pow'; - var factory_1$103 = factory$104; - - var pow$1 = { - name: name$93, - factory: factory_1$103 - }; - - function factory$105(type, config, load, typed, math) { - var equal = load(equal$1); - var isZero = load(isZero$1); - var isNumeric = load(isNumeric$1); - var add$$1 = load(add); - var subtract = load(subtract$1); - var multiply = load(multiply$1); - var divide = load(divide$1); - var pow = load(pow$1); - - var ConstantNode = math.expression.node.ConstantNode; - var OperatorNode = math.expression.node.OperatorNode; - var FunctionNode = math.expression.node.FunctionNode; - var ParenthesisNode = math.expression.node.ParenthesisNode; - - var node0 = new ConstantNode(0); - var node1 = new ConstantNode(1); - - /** - * simplifyCore() performs single pass simplification suitable for - * applications requiring ultimate performance. In contrast, simplify() - * extends simplifyCore() with additional passes to provide deeper - * simplification. - * - * Syntax: - * - * simplify.simplifyCore(expr) - * - * Examples: - * - * var f = math.parse('2 * 1 * x ^ (2 - 1)'); - * math.simplify.simpifyCore(f); // Node {2 * x} - * math.simplify('2 * 1 * x ^ (2 - 1)', [math.simplify.simpifyCore]); // Node {2 * x}; - * - * See also: - * - * derivative - * - * @param {Node} node - * The expression to be simplified - */ - function simplifyCore(node) { - if (type.isOperatorNode(node) && node.isUnary()) { - var a0 = simplifyCore(node.args[0]); - - if (node.op === '+') { // unary plus - return a0; - } - - if (node.op === '-') { // unary minus - if (type.isOperatorNode(a0)) { - if (a0.isUnary() && a0.op === '-') { - return a0.args[0]; - } else if (a0.isBinary() && a0.fn === 'subtract') { - return new OperatorNode('-', 'subtract', [a0.args[1], a0.args[0]]); - } - } - return new OperatorNode(node.op, node.fn, [a0]); - } - } - else if (type.isOperatorNode(node) && node.isBinary()) { - var a0 = simplifyCore(node.args[0]); - var a1 = simplifyCore(node.args[1]); - - if (node.op === "+") { - if (type.isConstantNode(a0)) { - if (isZero(a0.value)) { - return a1; - } else if (type.isConstantNode(a1)) { - return new ConstantNode(add$$1(a0.value, a1.value)); - } - } - if (type.isConstantNode(a1) && isZero(a1.value)) { - return a0; - } - if (type.isOperatorNode(a1) && a1.isUnary() && a1.op === '-') { - return new OperatorNode('-', 'subtract', [a0,a1.args[0]]); - } - return new OperatorNode(node.op, node.fn, a1 ? [a0,a1] : [a0]); - } else if (node.op === "-") { - if (type.isConstantNode(a0) && a1) { - if (type.isConstantNode(a1)) { - return new ConstantNode(subtract(a0.value, a1.value)); - } else if (isZero(a0.value)) { - return new OperatorNode("-", "unaryMinus", [a1]); - } - } - // if (node.fn === "subtract" && node.args.length === 2) { - if (node.fn === "subtract") { - if (type.isConstantNode(a1) && isZero(a1.value)) { - return a0; - } - if (type.isOperatorNode(a1) && a1.isUnary() && a1.op === '-') { - return simplifyCore(new OperatorNode("+", "add", [a0, a1.args[0]])); - } - return new OperatorNode(node.op, node.fn, [a0,a1]); - } - } else if (node.op === "*") { - if (type.isConstantNode(a0)) { - if (isZero(a0.value)) { - return node0; - } else if (equal(a0.value, 1)) { - return a1; - } else if (type.isConstantNode(a1)) { - return new ConstantNode(multiply(a0.value, a1.value)); - } - } - if (type.isConstantNode(a1)) { - if (isZero(a1.value)) { - return node0; - } else if (equal(a1.value, 1)) { - return a0; - } else if (type.isOperatorNode(a0) && a0.isBinary() && a0.op === node.op) { - var a00 = a0.args[0]; - if (type.isConstantNode(a00)) { - var a00_a1 = new ConstantNode(multiply(a00.value, a1.value)); - return new OperatorNode(node.op, node.fn, [a00_a1, a0.args[1]]); // constants on left - } - } - return new OperatorNode(node.op, node.fn, [a1, a0]); // constants on left - } - return new OperatorNode(node.op, node.fn, [a0, a1]); - } else if (node.op === "/") { - if (type.isConstantNode(a0)) { - if (isZero(a0.value)) { - return node0; - } else if (type.isConstantNode(a1) && - (equal(a1.value, 1) || equal(a1.value, 2) || equal(a1.value, 4))) { - return new ConstantNode(divide(a0.value, a1.value)); - } - } - return new OperatorNode(node.op, node.fn, [a0, a1]); - } else if (node.op === "^") { - if (type.isConstantNode(a1)) { - if (isZero(a1.value)) { - return node1; - } else if (equal(a1.value, 1)) { - return a0; - } else { - if (type.isConstantNode(a0)) { - // fold constant - return new ConstantNode(pow(a0.value, a1.value)); - } else if (type.isOperatorNode(a0) && a0.isBinary() && a0.op === "^") { - var a01 = a0.args[1]; - if (type.isConstantNode(a01)) { - return new OperatorNode(node.op, node.fn, [ - a0.args[0], - new ConstantNode(multiply(a01.value, a1.value)) - ]); - } - } - } - } - return new OperatorNode(node.op, node.fn, [a0, a1]); - } - } else if (type.isParenthesisNode(node)) { - var c = simplifyCore(node.content); - if (type.isParenthesisNode(c) || type.isSymbolNode(c) || type.isConstantNode(c)) { - return c; - } - return new ParenthesisNode(c); - } else if (type.isFunctionNode(node)) { - var args = node.args - .map(simplifyCore) - .map(function (arg) { - return type.isParenthesisNode(arg) ? arg.content : arg; - }); - return new FunctionNode(simplifyCore(node.fn), args); - } else { - // cannot simplify - } - return node; - } - - return simplifyCore; - } - - var math$14 = true; - var name$94 = 'simplifyCore'; - var path$44 = 'algebra.simplify'; - var factory_1$104 = factory$105; - - var simplifyCore = { - math: math$14, - name: name$94, - path: path$44, - factory: factory_1$104 - }; - - function factory$106(type, config, load, typed, math) { - var Node = math.expression.node.Node; - var OperatorNode = math.expression.node.OperatorNode; - var FunctionNode = math.expression.node.FunctionNode; - var ParenthesisNode = math.expression.node.ParenthesisNode; - - /** - * resolve(expr, scope) replaces variable nodes with their scoped values - * - * Syntax: - * - * simplify.resolve(expr, scope) - * - * Examples: - * - * math.simplify.resolve('x + y', {x:1, y:2}) // Node {1 + 2} - * math.simplify.resolve(math.parse('x+y'), {x:1, y:2}) // Node {1 + 2} - * math.simplify('x+y', {x:2, y:'x+x'}).toString(); // "6" - * - * @param {Node} node - * The expression tree to be simplified - * @param {Object} scope with variables to be resolved - */ - function resolve(node, scope) { - if (!scope) { - return node; - } - if (type.isSymbolNode(node)) { - var value = scope[node.name]; - if (value instanceof Node) { - return resolve(value, scope); - } else if (typeof value === 'number') { - return math.parse(String(value)); - } - } else if (type.isOperatorNode(node)) { - var args = node.args.map(function (arg) { - return resolve(arg, scope) - }); - return new OperatorNode(node.op, node.fn, args); - } else if (type.isParenthesisNode(node)) { - return new ParenthesisNode(resolve(node.content, scope)); - } else if (type.isFunctionNode(node)) { - var args = node.args.map(function (arg) { - return resolve(arg, scope) - }); - return new FunctionNode(node.name, args); - } - return node; - } - - return resolve; - } - - var math$15 = true; - var name$95 = 'resolve'; - var path$45 = 'algebra.simplify'; - var factory_1$105 = factory$106; - - var resolve = { - math: math$15, - name: name$95, - path: path$45, - factory: factory_1$105 - }; - - function factory$107 (type, config, load, typed, math) { - var parse$$1 = load(parse); - var equal = load(equal$1); - var ConstantNode$$1 = load(ConstantNode); - var FunctionNode$$1 = load(FunctionNode); - var OperatorNode$$1 = load(OperatorNode); - var ParenthesisNode$$1 = load(ParenthesisNode); - var SymbolNode$$1 = load(SymbolNode); - var Node$$1 = load(Node); - var simplifyConstant$$1 = load(simplifyConstant); - var simplifyCore$$1 = load(simplifyCore); - var resolve$$1 = load(resolve); - - var util$$1 = load(util); - var isCommutative = util$$1.isCommutative; - var isAssociative = util$$1.isAssociative; - var flatten = util$$1.flatten; - var unflattenr = util$$1.unflattenr; - var unflattenl = util$$1.unflattenl; - var createMakeNodeFunction = util$$1.createMakeNodeFunction; - - /** - * Simplify an expression tree. - * - * A list of rules are applied to an expression, repeating over the list until - * no further changes are made. - * It's possible to pass a custom set of rules to the function as second - * argument. A rule can be specified as an object, string, or function: - * - * var rules = [ - * { l: 'n1*n3 + n2*n3', r: '(n1+n2)*n3' }, - * 'n1*n3 + n2*n3 -> (n1+n2)*n3', - * function (node) { - * // ... return a new node or return the node unchanged - * return node - * } - * ] - * - * String and object rules consist of a left and right pattern. The left is - * used to match against the expression and the right determines what matches - * are replaced with. The main difference between a pattern and a normal - * expression is that variables starting with the following characters are - * interpreted as wildcards: - * - * - 'n' - matches any Node - * - 'c' - matches any ConstantNode - * - 'v' - matches any Node that is not a ConstantNode - * - * The default list of rules is exposed on the function as `simplify.rules` - * and can be used as a basis to built a set of custom rules. - * - * For more details on the theory, see: - * - * - [Strategies for simplifying math expressions (Stackoverflow)](http://stackoverflow.com/questions/7540227/strategies-for-simplifying-math-expressions) - * - [Symbolic computation - Simplification (Wikipedia)](https://en.wikipedia.org/wiki/Symbolic_computation#Simplification) - * - * Syntax: - * - * simplify(expr) - * simplify(expr, rules) - * simplify(expr, rules, scope) - * simplify(expr, scope) - * - * Examples: - * - * math.simplify('2 * 1 * x ^ (2 - 1)'); // Node {2 * x} - * math.simplify('2 * 3 * x', {x: 4}); // Node {24} - * var f = math.parse('2 * 1 * x ^ (2 - 1)'); - * math.simplify(f); // Node {2 * x} - * - * See also: - * - * derivative, parse, eval - * - * @param {Node | string} expr - * The expression to be simplified - * @param {Array<{l:string, r: string} | string | function>} [rules] - * Optional list with custom rules - * @return {Node} Returns the simplified form of `expr` - */ - var simplify = typed('simplify', { - 'string': function (expr) { - return simplify(parse$$1(expr), simplify.rules, {}); - }, - - 'string, Object': function (expr, scope) { - return simplify(parse$$1(expr), simplify.rules, scope); - }, - - 'string, Array': function (expr, rules) { - return simplify(parse$$1(expr), rules, {}); - }, - - 'string, Array, Object': function (expr, rules, scope) { - return simplify(parse$$1(expr), rules, scope); - }, - - 'Node, Object': function (expr, scope) { - return simplify(expr, simplify.rules, scope); - }, - - 'Node': function (expr) { - return simplify(expr, simplify.rules, {}); - }, - - 'Node, Array': function (expr, rules) { - return simplify(expr, rules, {}); - }, - - 'Node, Array, Object': function (expr, rules, scope) { - rules = _buildRules(rules); - - var res = resolve$$1(expr, scope); - var res = removeParens(res); - var visited = {}; - - var str = res.toString({parenthesis: 'all'}); - while(!visited[str]) { - visited[str] = true; - _lastsym = 0; // counter for placeholder symbols - for (var i=0; i c1 * n1' - */ - function _buildRules(rules) { - // Array of rules to be used to simplify expressions - var ruleSet = []; - for(var i=0; i'); - if (lr.length !== 2) { - throw SyntaxError('Could not parse rule: ' + rule); - } - rule = {l: lr[0], r: lr[1]}; - /* falls through */ - case 'object': - newRule = { - l: removeParens(parse$$1(rule.l)), - r: removeParens(parse$$1(rule.r)), - }; - if(rule.context) { - newRule.evaluate = rule.context; - } - if(rule.evaluate) { - newRule.evaluate = parse$$1(rule.evaluate); - } - - if (isAssociative(newRule.l)) { - var makeNode = createMakeNodeFunction(newRule.l); - var expandsym = _getExpandPlaceholderSymbol(); - newRule.expanded = {}; - newRule.expanded.l = makeNode([newRule.l.clone(), expandsym]); - // Push the expandsym into the deepest possible branch. - // This helps to match the newRule against nodes returned from getSplits() later on. - flatten(newRule.expanded.l); - unflattenr(newRule.expanded.l); - newRule.expanded.r = makeNode([newRule.r, expandsym]); - } - break; - case 'function': - newRule = rule; - break; - default: - throw TypeError('Unsupported type of rule: ' + ruleType); - } - // console.log('Adding rule: ' + rules[i]); - // console.log(newRule); - ruleSet.push(newRule); - } - return ruleSet; - } - - var _lastsym = 0; - function _getExpandPlaceholderSymbol() { - return new SymbolNode$$1('_p' + _lastsym++); - } - - /** - * Returns a simplfied form of node, or the original node if no simplification was possible. - * - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node - * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The simplified form of `expr`, or the original node if no simplification was possible. - */ - var applyRule = typed('applyRule', { - 'Node, Object': function (node, rule) { - - //console.log('Entering applyRule(' + node.toString() + ')'); - - // Do not clone node unless we find a match - var res = node; - - // First replace our child nodes with their simplified versions - // If a child could not be simplified, the assignments will have - // no effect since the node is returned unchanged - if (res instanceof OperatorNode$$1 || res instanceof FunctionNode$$1) { - if (res.args) { - for(var i=0; i [ - * +(node1, +(node2, node3)), - * +(node2, +(node1, node3)), - * +(node3, +(node1, node2))] - * - */ - function getSplits(node, context) { - var res = []; - var right, rightArgs; - var makeNode = createMakeNodeFunction(node); - if (isCommutative(node, context)) { - for (var i=0; i= 2 && rule.args.length === 2) { // node is flattened, rule is not - // Associative operators/functions can be split in different ways so we check if the rule matches each - // them and return their union. - var splits = getSplits(node, rule.context); - var splitMatches = []; - for(var i = 0; i < splits.length; i++) { - var matchSet = _ruleMatch(rule, splits[i], true); // recursing at the same tree depth here - splitMatches = splitMatches.concat(matchSet); - } - return splitMatches; - } - else if (rule.args.length > 2) { - throw Error('Unexpected non-binary associative function: ' + rule.toString()); - } - else { - // Incorrect number of arguments in rule and node, so no match - return []; - } - } - else if (rule instanceof SymbolNode$$1) { - // If the rule is a SymbolNode, then it carries a special meaning - // according to the first character of the symbol node name. - // c.* matches a ConstantNode - // n.* matches any node - if (rule.name.length === 0) { - throw new Error('Symbol in rule has 0 length...!?'); - } - if (math.hasOwnProperty(rule.name)) { - if (!SUPPORTED_CONSTANTS[rule.name]) { - throw new Error('Built in constant: ' + rule.name + ' is not supported by simplify.'); - } - - // built-in constant must match exactly - if(rule.name !== node.name) { - return []; - } - } - else if (rule.name[0] === 'n' || rule.name.substring(0,2) === '_p') { - // rule matches _anything_, so assign this node to the rule.name placeholder - // Assign node to the rule.name placeholder. - // Our parent will check for matches among placeholders. - res[0].placeholders[rule.name] = node; - } - else if (rule.name[0] === 'v') { - // rule matches any variable thing (not a ConstantNode) - if(!type.isConstantNode(node)) { - res[0].placeholders[rule.name] = node; - } - else { - // Mis-match: rule was expecting something other than a ConstantNode - return []; - } - } - else if (rule.name[0] === 'c') { - // rule matches any ConstantNode - if(node instanceof ConstantNode$$1) { - res[0].placeholders[rule.name] = node; - } - else { - // Mis-match: rule was expecting a ConstantNode - return []; - } - } - else { - throw new Error('Invalid symbol in rule: ' + rule.name); - } - } - else if (rule instanceof ConstantNode$$1) { - // Literal constant must match exactly - if(!equal(rule.value, node.value)) { - return []; - } - } - else { - // Some other node was encountered which we aren't prepared for, so no match - return []; - } - - // It's a match! - - // console.log('_ruleMatch(' + rule.toString() + ', ' + node.toString() + ') found a match'); - return res; - } - - - /** - * Determines whether p and q (and all their children nodes) are identical. - * - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} p - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} q - * @return {Object} Information about the match, if it exists. - */ - function _exactMatch(p, q) { - if(p instanceof ConstantNode$$1 && q instanceof ConstantNode$$1) { - if(!equal(p.value, q.value)) { - return false; - } - } - else if(p instanceof SymbolNode$$1 && q instanceof SymbolNode$$1) { - if(p.name !== q.name) { - return false; - } - } - else if(p instanceof OperatorNode$$1 && q instanceof OperatorNode$$1 - || p instanceof FunctionNode$$1 && q instanceof FunctionNode$$1) { - if (p instanceof OperatorNode$$1) { - if (p.op !== q.op || p.fn !== q.fn) { - return false; - } - } - else if (p instanceof FunctionNode$$1) { - if (p.name !== q.name) { - return false; - } - } - - if(p.args.length !== q.args.length) { - return false; - } - - for(var i=0; i implement as an option {order: number} - 'Node, SymbolNode, ConstantNode': function (expr, variable, {order}) { - var res = expr; - for (var i = 0; i < order; i++) { - var constNodes = {}; - constTag(constNodes, expr, variable.name); - res = _derivative(res, constNodes); - } - return res; - } - */ - }); - - derivative._simplify = true; - - derivative.toTex = function(deriv) { - return _derivTex.apply(null, deriv.args); - }; - - var _derivTex = typed('_derivTex', { - 'Node, SymbolNode': function (expr, x) { - return _derivTex(expr.toString(), x.toString(), 1); - }, - 'Node, SymbolNode, ConstantNode': function (expr, x, order) { - return _derivTex(expr.toString(), x.name, order.value); - }, - 'string, string, number': function (expr, x, order) { - var d; - if (order === 1) { - d = "{d\\over d" + x + "}"; - } - else { - d = "{d^{" + order + "}\\over d" + x + "^{" + order + "}}"; - } - return d + "\\left[" + expr + "\\right]" - } - }); - - /** - * Does a depth-first search on the expression tree to identify what Nodes - * are constants (e.g. 2 + 2), and stores the ones that are constants in - * constNodes. Classification is done as follows: - * - * 1. ConstantNodes are constants. - * 2. If there exists a SymbolNode, of which we are differentiating over, - * in the subtree it is not constant. - * - * @param {Object} constNodes Holds the nodes that are constant - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node - * @param {string} varName Variable that we are differentiating - * @return {boolean} if node is constant - */ - // TODO: can we rewrite constTag into a pure function? - var constTag = typed('constTag', { - 'Object, ConstantNode, string': function (constNodes, node) { - return constNodes[node] = true; - }, - - 'Object, SymbolNode, string': function (constNodes, node, varName) { - // Treat other variables like constants. For reasoning, see: - // https://en.wikipedia.org/wiki/Partial_derivative - if (node.name !== varName) { - return constNodes[node] = true; - } - return false; - }, - - 'Object, ParenthesisNode, string': function (constNodes, node, varName) { - return constTag(constNodes, node.content, varName); - }, - - 'Object, FunctionAssignmentNode, string': function (constNodes, node, varName) { - if (node.params.indexOf(varName) === -1) { - return constNodes[node] = true; - } - return constTag(constNodes, node.expr, varName); - }, - - 'Object, FunctionNode | OperatorNode, string': function (constNodes, node, varName) { - if (node.args.length > 0) { - var isConst = constTag(constNodes, node.args[0], varName); - for (var i = 1; i < node.args.length; ++i) { - isConst = constTag(constNodes, node.args[i], varName) && isConst; - } - - if (isConst) { - return constNodes[node] = true; - } - } - return false; - } - }); - - /** - * Applies differentiation rules. - * - * @param {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} node - * @param {Object} constNodes Holds the nodes that are constant - * @return {ConstantNode | SymbolNode | ParenthesisNode | FunctionNode | OperatorNode} The derivative of `expr` - */ - var _derivative = typed('_derivative', { - 'ConstantNode, Object': function (node) { - return createConstantNode(0); - }, - - 'SymbolNode, Object': function (node, constNodes) { - if (constNodes[node] !== undefined) { - return createConstantNode(0); - } - return createConstantNode(1); - }, - - 'ParenthesisNode, Object': function (node, constNodes) { - return new ParenthesisNode$$1(_derivative(node.content, constNodes)); - }, - - 'FunctionAssignmentNode, Object': function (node, constNodes) { - if (constNodes[node] !== undefined) { - return createConstantNode(0); - } - return _derivative(node.expr, constNodes); - }, - - 'FunctionNode, Object': function (node, constNodes) { - if (node.args.length !== 1) { - funcArgsCheck(node); - } - - if (constNodes[node] !== undefined) { - return createConstantNode(0); - } - - var arg0 = node.args[0]; - var arg1; - - var div = false; // is output a fraction? - var negative = false; // is output negative? - - var funcDerivative; - switch (node.name) { - case 'cbrt': - // d/dx(cbrt(x)) = 1 / (3x^(2/3)) - div = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - createConstantNode(3), - new OperatorNode$$1('^', 'pow', [ - arg0, - new OperatorNode$$1('/', 'divide', [ - createConstantNode(2), - createConstantNode(3) - ]) - ]) - ]); - break; - case 'sqrt': - case 'nthRoot': - // d/dx(sqrt(x)) = 1 / (2*sqrt(x)) - if (node.args.length === 1) { - div = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - createConstantNode(2), - new FunctionNode$$1('sqrt', [arg0]) - ]); - } - else if (node.args.length === 2) { - // Rearrange from nthRoot(x, a) -> x^(1/a) - arg1 = new OperatorNode$$1('/', 'divide', [ - createConstantNode(1), - node.args[1] - ]); - - // Is a variable? - constNodes[arg1] = constNodes[node.args[1]]; - - return _derivative(new OperatorNode$$1('^', 'pow', [arg0, arg1]), constNodes); - } - break; - case 'log10': - arg1 = createConstantNode(10); - /* fall through! */ - case 'log': - if (!arg1 && node.args.length === 1) { - // d/dx(log(x)) = 1 / x - funcDerivative = arg0.clone(); - div = true; - } else if ((node.args.length === 1 && arg1) || - (node.args.length === 2 && constNodes[node.args[1]] !== undefined)) { - // d/dx(log(x, c)) = 1 / (x*ln(c)) - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - arg0.clone(), - new FunctionNode$$1('log', [arg1 || node.args[1]]) - ]); - div = true; - } else if (node.args.length === 2) { - // d/dx(log(f(x), g(x))) = d/dx(log(f(x)) / log(g(x))) - return _derivative(new OperatorNode$$1('/', 'divide', [ - new FunctionNode$$1('log', [arg0]), - new FunctionNode$$1('log', [node.args[1]]) - ]), constNodes); - } - break; - case 'exp': - // d/dx(e^x) = e^x - funcDerivative = new FunctionNode$$1('exp', [arg0.clone()]); - break; - case 'sin': - // d/dx(sin(x)) = cos(x) - funcDerivative = new FunctionNode$$1('cos', [arg0.clone()]); - break; - case 'cos': - // d/dx(cos(x)) = -sin(x) - funcDerivative = new OperatorNode$$1('-', 'unaryMinus', [ - new FunctionNode$$1('sin', [arg0.clone()]) - ]); - break; - case 'tan': - // d/dx(tan(x)) = sec(x)^2 - funcDerivative = new OperatorNode$$1('^', 'pow', [ - new FunctionNode$$1('sec', [arg0.clone()]), - createConstantNode(2) - ]); - break; - case 'sec': - // d/dx(sec(x)) = sec(x)tan(x) - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - node, - new FunctionNode$$1('tan', [arg0.clone()]) - ]); - break; - case 'csc': - // d/dx(csc(x)) = -csc(x)cot(x) - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - node, - new FunctionNode$$1('cot', [arg0.clone()]) - ]); - break; - case 'cot': - // d/dx(cot(x)) = -csc(x)^2 - negative = true; - funcDerivative = new OperatorNode$$1('^', 'pow', [ - new FunctionNode$$1('csc', [arg0.clone()]), - createConstantNode(2) - ]); - break; - case 'asin': - // d/dx(asin(x)) = 1 / sqrt(1 - x^2) - div = true; - funcDerivative = new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]) - ]); - break; - case 'acos': - // d/dx(acos(x)) = -1 / sqrt(1 - x^2) - div = true; - negative = true; - funcDerivative = new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]) - ]); - break; - case 'atan': - // d/dx(atan(x)) = 1 / (x^2 + 1) - div = true; - funcDerivative = new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]); - break; - case 'asec': - // d/dx(asec(x)) = 1 / (|x|*sqrt(x^2 - 1)) - div = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - new FunctionNode$$1('abs', [arg0.clone()]), - new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]) - ]); - break; - case 'acsc': - // d/dx(acsc(x)) = -1 / (|x|*sqrt(x^2 - 1)) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - new FunctionNode$$1('abs', [arg0.clone()]), - new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]) - ]); - break; - case 'acot': - // d/dx(acot(x)) = -1 / (x^2 + 1) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]); - break; - case 'sinh': - // d/dx(sinh(x)) = cosh(x) - funcDerivative = new FunctionNode$$1('cosh', [arg0.clone()]); - break; - case 'cosh': - // d/dx(cosh(x)) = sinh(x) - funcDerivative = new FunctionNode$$1('sinh', [arg0.clone()]); - break; - case 'tanh': - // d/dx(tanh(x)) = sech(x)^2 - funcDerivative = new OperatorNode$$1('^', 'pow', [ - new FunctionNode$$1('sech', [arg0.clone()]), - createConstantNode(2) - ]); - break; - case 'sech': - // d/dx(sech(x)) = -sech(x)tanh(x) - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - node, - new FunctionNode$$1('tanh', [arg0.clone()]) - ]); - break; - case 'csch': - // d/dx(csch(x)) = -csch(x)coth(x) - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - node, - new FunctionNode$$1('coth', [arg0.clone()]) - ]); - break; - case 'coth': - // d/dx(coth(x)) = -csch(x)^2 - negative = true; - funcDerivative = new OperatorNode$$1('^', 'pow', [ - new FunctionNode$$1('csch', [arg0.clone()]), - createConstantNode(2) - ]); - break; - case 'asinh': - // d/dx(asinh(x)) = 1 / sqrt(x^2 + 1) - div = true; - funcDerivative = new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]); - break; - case 'acosh': - // d/dx(acosh(x)) = 1 / sqrt(x^2 - 1); XXX potentially only for x >= 1 (the real spectrum) - div = true; - funcDerivative = new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]); - break; - case 'atanh': - // d/dx(atanh(x)) = 1 / (1 - x^2) - div = true; - funcDerivative = new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]); - break; - case 'asech': - // d/dx(asech(x)) = -1 / (x*sqrt(1 - x^2)) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - arg0.clone(), - new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]) - ]) - ]); - break; - case 'acsch': - // d/dx(acsch(x)) = -1 / (|x|*sqrt(x^2 + 1)) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('*', 'multiply', [ - new FunctionNode$$1('abs', [arg0.clone()]), - new FunctionNode$$1('sqrt', [ - new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]), - createConstantNode(1) - ]) - ]) - ]); - break; - case 'acoth': - // d/dx(acoth(x)) = -1 / (1 - x^2) - div = true; - negative = true; - funcDerivative = new OperatorNode$$1('-', 'subtract', [ - createConstantNode(1), - new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - createConstantNode(2) - ]) - ]); - break; - case 'abs': - // d/dx(abs(x)) = abs(x)/x - funcDerivative = new OperatorNode$$1('/', 'divide', [ - new FunctionNode$$1(new SymbolNode$$1('abs'), [arg0.clone()]), - arg0.clone() - ]); - break; - case 'gamma': // Needs digamma function, d/dx(gamma(x)) = gamma(x)digamma(x) - default: throw new Error('Function "' + node.name + '" is not supported by derivative, or a wrong number of arguments is passed'); - } - - var op, func; - if (div) { - op = '/'; - func = 'divide'; - } else { - op = '*'; - func = 'multiply'; - } - - /* Apply chain rule to all functions: - F(x) = f(g(x)) - F'(x) = g'(x)*f'(g(x)) */ - var chainDerivative = _derivative(arg0, constNodes); - if (negative) { - chainDerivative = new OperatorNode$$1('-', 'unaryMinus', [chainDerivative]); - } - return new OperatorNode$$1(op, func, [chainDerivative, funcDerivative]); - }, - - 'OperatorNode, Object': function (node, constNodes) { - if (constNodes[node] !== undefined) { - return createConstantNode(0); - } - - if (node.op === '+') { - // d/dx(sum(f(x)) = sum(f'(x)) - return new OperatorNode$$1(node.op, node.fn, node.args.map(function(arg) { - return _derivative(arg, constNodes); - })); - } - - if (node.op === '-') { - // d/dx(+/-f(x)) = +/-f'(x) - if (node.isUnary()) { - return new OperatorNode$$1(node.op, node.fn, [ - _derivative(node.args[0], constNodes) - ]); - } - - // Linearity of differentiation, d/dx(f(x) +/- g(x)) = f'(x) +/- g'(x) - if (node.isBinary()) { - return new OperatorNode$$1(node.op, node.fn, [ - _derivative(node.args[0], constNodes), - _derivative(node.args[1], constNodes) - ]); - } - } - - if (node.op === '*') { - // d/dx(c*f(x)) = c*f'(x) - var constantTerms = node.args.filter(function(arg) { - return constNodes[arg] !== undefined; - }); - - if (constantTerms.length > 0) { - var nonConstantTerms = node.args.filter(function(arg) { - return constNodes[arg] === undefined; - }); - - var nonConstantNode = nonConstantTerms.length === 1 - ? nonConstantTerms[0] - : new OperatorNode$$1('*', 'multiply', nonConstantTerms); - - var newArgs = constantTerms.concat(_derivative(nonConstantNode, constNodes)); - - return new OperatorNode$$1('*', 'multiply', newArgs); - } - - // Product Rule, d/dx(f(x)*g(x)) = f'(x)*g(x) + f(x)*g'(x) - return new OperatorNode$$1('+', 'add', node.args.map(function(argOuter) { - return new OperatorNode$$1('*', 'multiply', node.args.map(function(argInner) { - return (argInner === argOuter) - ? _derivative(argInner, constNodes) - : argInner.clone(); - })); - })); - } - - if (node.op === '/' && node.isBinary()) { - var arg0 = node.args[0]; - var arg1 = node.args[1]; - - // d/dx(f(x) / c) = f'(x) / c - if (constNodes[arg1] !== undefined) { - return new OperatorNode$$1('/', 'divide', [_derivative(arg0, constNodes), arg1]); - } - - // Reciprocal Rule, d/dx(c / f(x)) = -c(f'(x)/f(x)^2) - if (constNodes[arg0] !== undefined) { - return new OperatorNode$$1('*', 'multiply', [ - new OperatorNode$$1('-', 'unaryMinus', [arg0]), - new OperatorNode$$1('/', 'divide', [ - _derivative(arg1, constNodes), - new OperatorNode$$1('^', 'pow', [arg1.clone(), createConstantNode(2)]) - ]) - ]); - } - - // Quotient rule, d/dx(f(x) / g(x)) = (f'(x)g(x) - f(x)g'(x)) / g(x)^2 - return new OperatorNode$$1('/', 'divide', [ - new OperatorNode$$1('-', 'subtract', [ - new OperatorNode$$1('*', 'multiply', [_derivative(arg0, constNodes), arg1.clone()]), - new OperatorNode$$1('*', 'multiply', [arg0.clone(), _derivative(arg1, constNodes)]) - ]), - new OperatorNode$$1('^', 'pow', [arg1.clone(), createConstantNode(2)]) - ]); - } - - if (node.op === '^' && node.isBinary()) { - var arg0 = node.args[0]; - var arg1 = node.args[1]; - - if (constNodes[arg0] !== undefined) { - // If is secretly constant; 0^f(x) = 1 (in JS), 1^f(x) = 1 - if (type.isConstantNode(arg0) && (isZero(arg0.value) || equal(arg0.value, 1))) { - return createConstantNode(0); - } - - // d/dx(c^f(x)) = c^f(x)*ln(c)*f'(x) - return new OperatorNode$$1('*', 'multiply', [ - node, - new OperatorNode$$1('*', 'multiply', [ - new FunctionNode$$1('log', [arg0.clone()]), - _derivative(arg1.clone(), constNodes) - ]) - ]); - } - - if (constNodes[arg1] !== undefined) { - if (type.isConstantNode(arg1)) { - // If is secretly constant; f(x)^0 = 1 -> d/dx(1) = 0 - if (isZero(arg1.value)) { - return createConstantNode(0); - } - // Ignore exponent; f(x)^1 = f(x) - if (equal(arg1.value,1)) { - return _derivative(arg0, constNodes); - } - } - - // Elementary Power Rule, d/dx(f(x)^c) = c*f'(x)*f(x)^(c-1) - var powMinusOne = new OperatorNode$$1('^', 'pow', [ - arg0.clone(), - new OperatorNode$$1('-', 'subtract', [ - arg1, - createConstantNode(1) - ]) - ]); - - return new OperatorNode$$1('*', 'multiply', [ - arg1.clone(), - new OperatorNode$$1('*', 'multiply', [ - _derivative(arg0, constNodes), - powMinusOne - ]) - ]); - } - - // Functional Power Rule, d/dx(f^g) = f^g*[f'*(g/f) + g'ln(f)] - return new OperatorNode$$1('*', 'multiply', [ - new OperatorNode$$1('^', 'pow', [arg0.clone(), arg1.clone()]), - new OperatorNode$$1('+', 'add', [ - new OperatorNode$$1('*', 'multiply', [ - _derivative(arg0, constNodes), - new OperatorNode$$1('/', 'divide', [arg1.clone(), arg0.clone()]) - ]), - new OperatorNode$$1('*', 'multiply', [ - _derivative(arg1, constNodes), - new FunctionNode$$1('log', [arg0.clone()]) - ]) - ]) - ]); - } - - throw new Error('Operator "' + node.op + '" is not supported by derivative, or a wrong number of arguments is passed'); - } - }); - - /** - * Ensures the number of arguments for a function are correct, - * and will throw an error otherwise. - * - * @param {FunctionNode} node - */ - function funcArgsCheck(node) { - //TODO add min, max etc - if ((node.name === 'log' || node.name === 'nthRoot') && node.args.length === 2) { - return; - } - - // There should be an incorrect number of arguments if we reach here - - // Change all args to constants to avoid unidentified - // symbol error when compiling function - for (var i = 0; i < node.args.length; ++i) { - node.args[i] = createConstantNode(0); - } - - node.compile().eval(); - throw new Error('Expected TypeError, but none found'); - } - - /** - * Helper function to create a constant node with a specific type - * (number, BigNumber, Fraction) - * @param {number} value - * @param {string} [valueType] - * @return {ConstantNode} - */ - function createConstantNode(value, valueType) { - return new ConstantNode$$1(numeric$$1(value, valueType || config.number)); - } - - return derivative; - } - - var name$97 = 'derivative'; - var factory_1$107 = factory$108; - - var derivative$1 = { - name: name$97, - factory: factory_1$107 - }; - - function factory$109 (type, config, load, typed) { - var simplify = load(simplify$1); - var simplifyCore$$1 = load(simplifyCore); - var simplifyConstant$$1 = load(simplifyConstant); - var ArgumentsError = ArgumentsError_1; - var parse = load(parse$1); - var number$$1 = number; - var ConstantNode$$1 = load(ConstantNode); - var OperatorNode$$1 = load(OperatorNode); - var SymbolNode$$1 = load(SymbolNode); - - /** - * Transform a rationalizable expression in a rational fraction. - * If rational fraction is one variable polynomial then converts - * the numerator and denominator in canonical form, with decreasing - * exponents, returning the coefficients of numerator. - * - * Syntax: - * - * rationalize(expr) - * rationalize(expr, detailed) - * rationalize(expr, scope) - * rationalize(expr, scope, detailed) - * - * Examples: - * - * math.rationalize('sin(x)+y') // Error: There is an unsolved function call - * math.rationalize('2x/y - y/(x+1)') // (2*x^2-y^2+2*x)/(x*y+y) - * math.rationalize('(2x+1)^6') - * // 64*x^6+192*x^5+240*x^4+160*x^3+60*x^2+12*x+1 - * math.rationalize('2x/( (2x-1) / (3x+2) ) - 5x/ ( (3x+4) / (2x^2-5) ) + 3') - * // -20*x^4+28*x^3+104*x^2+6*x-12)/(6*x^2+5*x-4) - * math.rationalize('x/(1-x)/(x-2)/(x-3)/(x-4) + 2x/ ( (1-2x)/(2-3x) )/ ((3-4x)/(4-5x) )') = - * // (-30*x^7+344*x^6-1506*x^5+3200*x^4-3472*x^3+1846*x^2-381*x)/ - * // (-8*x^6+90*x^5-383*x^4+780*x^3-797*x^2+390*x-72) - * - * math.rationalize('x+x+x+y',{y:1}) // 3*x+1 - * math.rationalize('x+x+x+y',{}) // 3*x+y - * ret = math.rationalize('x+x+x+y',{},true) - * // ret.expression=3*x+y, ret.variables = ["x","y"] - * ret = math.rationalize('-2+5x^2',{},true) - * // ret.expression=5*x^2-2, ret.variables = ["x"], ret.coefficients=[-2,0,5] - * - * See also: - * - * simplify - * - * @param {Node|string} expr The expression to check if is a polynomial expression - * @param {Object|boolean} optional scope of expression or true for already evaluated rational expression at input - * @param {Boolean} detailed optional True if return an object, false if return expression node (default) - * - * @return {Object | Expression Node} The rational polynomial of `expr` or na object - * {Object} - * {Expression Node} expression: node simplified expression - * {Expression Node} numerator: simplified numerator of expression - * {Expression Node | boolean} denominator: simplified denominator or false (if there is no denominator) - * {Array} variables: variable names - * {Array} coefficients: coefficients of numerator sorted by increased exponent - * {Expression Node} node simplified expression - * - */ - var rationalize = typed('rationalize', { - 'string': function (expr) { - return rationalize(parse(expr), {}, false); - }, - - 'string, boolean': function (expr, detailed) { - return rationalize(parse(expr), {} , detailed); - }, - - 'string, Object': function (expr, scope) { - return rationalize(parse(expr), scope, false); - }, - - 'string, Object, boolean': function (expr, scope, detailed) { - return rationalize(parse(expr), scope, detailed); - }, - - 'Node': function (expr) { - return rationalize(expr, {}, false); - }, - - 'Node, boolean': function (expr, detailed) { - return rationalize(expr, {}, detailed); - }, - - 'Node, Object': function (expr, scope) { - return rationalize(expr, scope, false); - }, - - 'Node, Object, boolean': function (expr, scope, detailed) { - - var polyRet = polynomial(expr, scope, true); // Check if expression is a rationalizable polynomial - var nVars = polyRet.variables.length; - var expr = polyRet.expression; - - if (nVars>=1) { // If expression in not a constant - var setRules = rulesRationalize(); // Rules for change polynomial in near canonical form - expr = expandPower(expr); // First expand power of polynomials (cannot be made from rules!) - var redoInic = true; // If has change after start, redo the beginning - var s = ""; // New expression - var sBefore; // Previous expression - var rules; - var eDistrDiv = true; - - expr = simplify(expr, setRules.firstRules); // Apply the initial rules, including succ div rules - s = expr.toString(); - - - while (true) { // Apply alternately successive division rules and distr.div.rules - rules = eDistrDiv ? setRules.distrDivRules : setRules.sucDivRules; - expr = simplify(expr,rules); // until no more changes - eDistrDiv = ! eDistrDiv; // Swap between Distr.Div and Succ. Div. Rules - - s = expr.toString(); - if (s===sBefore) break // No changes : end of the loop - - redoInic = true; - sBefore = s; - } - - if (redoInic) { // Apply first rules again without succ div rules (if there are changes) - expr = simplify(expr,setRules.firstRulesAgain); - } - expr = simplify(expr,setRules.finalRules); // Aplly final rules - - } // NVars >= 1 - - var coefficients=[]; - var retRationalize = {}; - - if (expr.type === 'OperatorNode' && expr.isBinary() && expr.op === '/') { // Separate numerator from denominator - if (nVars==1) { - expr.args[0] = polyToCanonical(expr.args[0],coefficients); - expr.args[1] = polyToCanonical(expr.args[1]); - } - if (detailed) { - retRationalize.numerator = expr.args[0]; - retRationalize.denominator = expr.args[1]; - } - } else { - if (nVars==1) expr = polyToCanonical(expr,coefficients); - if (detailed) { - retRationalize.numerator = expr; - retRationalize.denominator = null; - } - } - // nVars - - if (! detailed) return expr; - retRationalize.coefficients = coefficients; - retRationalize.variables = polyRet.variables; - retRationalize.expression = expr; - return retRationalize; - } // ^^^^^^^ end of rationalize ^^^^^^^^ - }); // end of typed rationalize - - /** - * Function to simplify an expression using an optional scope and - * return it if the expression is a polynomial expression, i.e. - * an expression with one or more variables and the operators - * +, -, *, and ^, where the exponent can only be a positive integer. - * - * Syntax: - * - * polynomial(expr,scope,extended) - * - * @param {Node | string} expr The expression to simplify and check if is polynomial expression - * @param {object} scope Optional scope for expression simplification - * @param {boolean} extended Optional. Default is false. When true allows divide operator. - * - * - * @return {Object} - * {Object} node: node simplified expression - * {Array} variables: variable names - */ - function polynomial (expr, scope, extended) { - var variables = []; - var node = simplify(expr,scope); // Resolves any variables and functions with all defined parameters - extended = !! extended; - - var oper = '+-*' + (extended ? '/' : ''); - recPoly(node); - var retFunc ={}; - retFunc.expression = node; - retFunc.variables = variables; - return retFunc; - - //------------------------------------------------------------------------------------------------------- - - /** - * Function to simplify an expression using an optional scope and - * return it if the expression is a polynomial expression, i.e. - * an expression with one or more variables and the operators - * +, -, *, and ^, where the exponent can only be a positive integer. - * - * Syntax: - * - * recPoly(node) - * - * - * @param {Node} node The current sub tree expression in recursion - * - * @return nothing, throw an exception if error - */ - function recPoly(node) { - var tp = node.type; // node type - if (tp==='FunctionNode') - throw new ArgumentsError('There is an unsolved function call') // No function call in polynomial expression - else if (tp==='OperatorNode') { - if (node.op === '^' && node.isBinary()) { - if (node.args[1].type!=='ConstantNode' || ! number$$1.isInteger(parseFloat(node.args[1].value))) - throw new ArgumentsError('There is a non-integer exponent'); - else - recPoly(node.args[0]); - } else { - if (oper.indexOf(node.op) === -1) throw new ArgumentsError('Operator ' + node.op + ' invalid in polynomial expression'); - for (var i=0;i infinite loop - // setRules.allRules =oldRules.concat(rulesFirst,rulesDistrDiv,rulesSucDiv); - - setRules.firstRules =oldRules.concat(rulesFirst,rulesSucDiv); // First rule set - setRules.distrDivRules = rulesDistrDiv; // Just distr. div. rules - setRules.sucDivRules = rulesSucDiv; // Jus succ. div. rules - setRules.firstRulesAgain = oldRules.concat(rulesFirst); // Last rules set without succ. div. - - // Division simplification - - // Second rule set. - // There is no aggregate expression with parentesis, but the only variable can be scattered. - setRules.finalRules=[ simplifyCore$$1, // simplify.rules[0] - { l: 'n*-n', r: '-n^2' }, // Joining multiply with power 1 - { l: 'n*n', r: 'n^2' }, // Joining multiply with power 2 - simplifyConstant$$1, // simplify.rules[14] old 3rd index in oldRules - { l: 'n*-n^n1', r: '-n^(n1+1)' }, // Joining multiply with power 3 - { l: 'n*n^n1', r: 'n^(n1+1)' }, // Joining multiply with power 4 - { l: 'n^n1*-n^n2', r: '-n^(n1+n2)' }, // Joining multiply with power 5 - { l: 'n^n1*n^n2', r: 'n^(n1+n2)' }, // Joining multiply with power 6 - { l: 'n^n1*-n', r: '-n^(n1+1)' }, // Joining multiply with power 7 - { l: 'n^n1*n', r: 'n^(n1+1)' }, // Joining multiply with power 8 - { l: 'n^n1/-n', r: '-n^(n1-1)' }, // Joining multiply with power 8 - { l: 'n^n1/n', r: 'n^(n1-1)' }, // Joining division with power 1 - { l: 'n/-n^n1', r: '-n^(1-n1)' }, // Joining division with power 2 - { l: 'n/n^n1', r: 'n^(1-n1)' }, // Joining division with power 3 - { l: 'n^n1/-n^n2', r: 'n^(n1-n2)' }, // Joining division with power 4 - { l: 'n^n1/n^n2', r: 'n^(n1-n2)' }, // Joining division with power 5 - { l: 'n1+(-n2*n3)', r: 'n1-n2*n3' }, // Solving useless parenthesis 1 - { l: 'v*(-c)', r: '-c*v' }, // Solving useless unary 2 - { l: 'n1+-n2', r: 'n1-n2' }, // Solving +- together (new!) - { l: 'v*c', r: 'c*v' }, // inversion constant with variable - { l: '(n1^n2)^n3', r:'(n1^(n2*n3))'}, // Power to Power - - ]; - return setRules; - } // End rulesRationalize - - //--------------------------------------------------------------------------------------- - /** - * Expand recursively a tree node for handling with expressions with exponents - * (it's not for constants, symbols or functions with exponents) - * PS: The other parameters are internal for recursion - * - * Syntax: - * - * expandPower(node) - * - * @param {Node} node Current expression node - * @param {node} parent Parent current node inside the recursion - * @param (int} Parent number of chid inside the rercursion - * - * @return {node} node expression with all powers expanded. - */ - function expandPower(node,parent,indParent) { - var tp = node.type; - var internal = (arguments.length>1); // TRUE in internal calls - - if (tp === 'OperatorNode' && node.isBinary()) { - var does = false; - if (node.op==='^') { // First operator: Parenthesis or UnaryMinus - if ( ( node.args[0].type==='ParenthesisNode' || - node.args[0].type==='OperatorNode' ) - && (node.args[1].type==='ConstantNode') ) { // Second operator: Constant - var val = parseFloat(node.args[1].value); - does = (val>=2 && number$$1.isInteger(val)); - } - } - - if (does) { // Exponent >= 2 - //Before: - // operator A --> Subtree - // parent pow - // constant - // - if (val>2) { // Exponent > 2, - //AFTER: (exponent > 2) - // operator A --> Subtree - // parent * - // deep clone (operator A --> Subtree - // pow - // constant - 1 - // - var nEsqTopo = node.args[0]; - var nDirTopo = new OperatorNode$$1('^', 'pow', [node.args[0].cloneDeep(),new ConstantNode$$1(val-1)]); - node = new OperatorNode$$1('*', 'multiply', [nEsqTopo, nDirTopo]); - } else // Expo = 2 - no power - - //AFTER: (exponent = 2) - // operator A --> Subtree - // parent oper - // deep clone (operator A --> Subtree) - // - node = new OperatorNode$$1('*', 'multiply', [node.args[0], node.args[0].cloneDeep()]); - - if (internal) // Change parent references in internal recursive calls - if (indParent==='content') - parent.content = node; - else - parent.args[indParent] = node; - } // does - } // binary OperatorNode - - if (tp==='ParenthesisNode' ) // Recursion - expandPower(node.content,node,'content'); - else if (tp!=='ConstantNode' && tp!=='SymbolNode') - for (var i=0;i=0 ;i--) { - if (coefficients[i]===0) continue; - var n1 = new ConstantNode$$1( - first ? coefficients[i] : Math.abs(coefficients[i])); - var op = coefficients[i]<0 ? '-' : '+'; - - if (i>0) { // Is not a constant without variable - var n2 = new SymbolNode$$1(varname); - if (i>1) { - var n3 = new ConstantNode$$1(i); - n2 = new OperatorNode$$1('^', 'pow', [n2, n3]); - } - if (coefficients[i]===-1 && first) - n1 = new OperatorNode$$1('-', 'unaryMinus', [n2]); - else if (Math.abs(coefficients[i])===1) - n1 = n2; - else - n1 = new OperatorNode$$1('*', 'multiply', [n1, n2]); - } - - var no; - if (first) - no = n1; - else if (op==='+') - no = new OperatorNode$$1('+', 'add', [no, n1]); - else - no = new OperatorNode$$1('-', 'subtract', [no, n1]); - - first = false; - } // for - - if (first) - return new ConstantNode$$1(0); - else - return no; - - /** - * Recursive auxilary function inside polyToCanonical for - * converting expression in canonical form - * - * Syntax: - * - * recurPol(node, noPai, obj) - * - * @param {Node} node The current subpolynomial expression - * @param {Node | Null} noPai The current parent node - * @param {object} obj Object with many internal flags - * - * @return {} No return. If error, throws an exception - */ - function recurPol(node,noPai,o) { - - var tp = node.type; - if (tp==='FunctionNode') // ***** FunctionName ***** - // No function call in polynomial expression - throw new ArgumentsError('There is an unsolved function call') - - else if (tp==='OperatorNode') { // ***** OperatorName ***** - if ('+-*^'.indexOf(node.op) === -1) throw new ArgumentsError('Operator ' + node.op + ' invalid'); - - if (noPai!==null) { - // -(unary),^ : children of *,+,- - if ( (node.fn==='unaryMinus' || node.fn==='pow') && noPai.fn !=='add' && - noPai.fn!=='subtract' && noPai.fn!=='multiply' ) - throw new ArgumentsError('Invalid ' + node.op + ' placing') - - // -,+,* : children of +,- - if ((node.fn==='subtract' || node.fn==='add' || node.fn==='multiply') && - noPai.fn!=='add' && noPai.fn!=='subtract' ) - throw new ArgumentsError('Invalid ' + node.op + ' placing'); - - // -,+ : first child - if ((node.fn==='subtract' || node.fn==='add' || - node.fn==='unaryMinus' ) && o.noFil!==0 ) - throw new ArgumentsError('Invalid ' + node.op + ' placing') - } // Has parent - - // Firers: ^,* Old: ^,&,-(unary): firers - if (node.op==='^' || node.op==='*') o.fire = node.op; - - for (var i=0;i it means there is no exponent above, so it's 1 (cte * var) - if (o.fire==='' || o.fire==='*' ) { - if (maxExpo<1) coefficients[1]=0; - coefficients[1] += o.cte* (o.oper==='+' ? 1 : -1); - maxExpo = Math.max(1,maxExpo); - } - - } else if (tp==='ConstantNode') { - var valor = parseFloat(node.value); - if (noPai === null) { - coefficients[0] = valor; - return; - } - if (noPai.op==='^') { - // cte: second child of power - if (o.noFil!==1) throw new ArgumentsError('Constant cannot be powered') - - if (! number$$1.isInteger(valor) || valor<=0 ) - throw new ArgumentsError('Non-integer exponent is not allowed'); - - for (var i=maxExpo+1;imaxExpo) coefficients[valor]=0; - coefficients[valor] += o.cte * (o.oper==='+' ? 1 : -1); - maxExpo = Math.max(valor,maxExpo); - return; - } - o.cte = valor; - - // Cte: firer '' => There is no exponent and no multiplication, so the exponent is 0. - if (o.fire==='') - coefficients[0] += o.cte * (o.oper==='+'? 1 : -1); - - - } else - throw new ArgumentsError('Type ' + tp + ' is not allowed'); - return; - } // End of recurPol - - } // End of polyToCanonical - - return rationalize; - } // end of factory - - var name$98 = 'rationalize'; - var factory_1$108 = factory$109; - - var rationalize$1 = { - name: name$98, - factory: factory_1$108 - }; - - var isInteger$7 = number.isInteger; - var resize$1 = array.resize; - - function factory$110 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Create a matrix filled with zeros. The created matrix can have one or - * multiple dimensions. - * - * Syntax: - * - * math.zeros(m) - * math.zeros(m, format) - * math.zeros(m, n) - * math.zeros(m, n, format) - * math.zeros([m, n]) - * math.zeros([m, n], format) - * - * Examples: - * - * math.zeros(3); // returns [0, 0, 0] - * math.zeros(3, 2); // returns [[0, 0], [0, 0], [0, 0]] - * math.zeros(3, 'dense'); // returns [0, 0, 0] - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.zeros(math.size(A)); // returns [[0, 0, 0], [0, 0, 0]] - * - * See also: - * - * ones, eye, size, range - * - * @param {...number | Array} size The size of each dimension of the matrix - * @param {string} [format] The Matrix storage format - * - * @return {Array | Matrix} A matrix filled with zeros - */ - var zeros = typed('zeros', { - '': function () { - return (config.matrix === 'Array') - ? _zeros([]) - : _zeros([], 'default'); - }, - - // math.zeros(m, n, p, ..., format) - // TODO: more accurate signature '...number | BigNumber, string' as soon as typed-function supports this - '...number | BigNumber | string': function (size) { - var last = size[size.length - 1]; - if (typeof last === 'string') { - var format = size.pop(); - return _zeros(size, format); - } - else if (config.matrix === 'Array') { - return _zeros(size); - } - else { - return _zeros(size, 'default'); - } - }, - - 'Array': _zeros, - - 'Matrix': function (size) { - var format = size.storage(); - return _zeros(size.valueOf(), format); - }, - - 'Array | Matrix, string': function (size, format) { - return _zeros (size.valueOf(), format); - } - }); - - zeros.toTex = undefined; // use default template - - return zeros; - - /** - * Create an Array or Matrix with zeros - * @param {Array} size - * @param {string} [format='default'] - * @return {Array | Matrix} - * @private - */ - function _zeros(size, format) { - var hasBigNumbers = _normalize(size); - var defaultValue = hasBigNumbers ? new type.BigNumber(0) : 0; - _validate(size); - - if (format) { - // return a matrix - var m = matrix$$1(format); - if (size.length > 0) { - return m.resize(size, defaultValue); - } - return m; - } - else { - // return an Array - var arr = []; - if (size.length > 0) { - return resize$1(arr, size, defaultValue); - } - return arr; - } - } - - // replace BigNumbers with numbers, returns true if size contained BigNumbers - function _normalize(size) { - var hasBigNumbers = false; - size.forEach(function (value, index, arr) { - if (type.isBigNumber(value)) { - hasBigNumbers = true; - arr[index] = value.toNumber(); - } - }); - return hasBigNumbers; - } - - // validate arguments - function _validate (size) { - size.forEach(function (value) { - if (typeof value !== 'number' || !isInteger$7(value) || value < 0) { - throw new Error('Parameters in function zeros must be positive integers'); - } - }); - } - } - - // TODO: zeros contains almost the same code as ones. Reuse this? - - var name$99 = 'zeros'; - var factory_1$109 = factory$110; - - var zeros$1 = { - name: name$99, - factory: factory_1$109 - }; - - function factory$111 (type, config, load, typed) { - /** - * Clone an object. - * - * Syntax: - * - * math.clone(x) - * - * Examples: - * - * math.clone(3.5); // returns number 3.5 - * math.clone(math.complex('2-4i'); // returns Complex 2 - 4i - * math.clone(math.unit(45, 'deg')); // returns Unit 45 deg - * math.clone([[1, 2], [3, 4]]); // returns Array [[1, 2], [3, 4]] - * math.clone("hello world"); // returns string "hello world" - * - * @param {*} x Object to be cloned - * @return {*} A clone of object x - */ - var clone = typed('clone', { - 'any': object.clone - }); - - clone.toTex = undefined; // use default template - - return clone; - } - - var name$100 = 'clone'; - var factory_1$110 = factory$111; - - var clone$5 = { - name: name$100, - factory: factory_1$110 - }; - - function factory$112 (type, config, load, typed) { - /** - * Test whether a value is positive: larger than zero. - * The function supports types `number`, `BigNumber`, `Fraction`, and `Unit`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isPositive(x) - * - * Examples: - * - * math.isPositive(3); // returns true - * math.isPositive(-2); // returns false - * math.isPositive(0); // returns false - * math.isPositive(-0); // returns false - * math.isPositive(0.5); // returns true - * math.isPositive(math.bignumber(2)); // returns true - * math.isPositive(math.fraction(-2, 5)); // returns false - * math.isPositive(math.fraction(1,3)); // returns false - * math.isPositive('2'); // returns true - * math.isPositive([2, 0, -3]'); // returns [true, false, false] - * - * See also: - * - * isNumeric, isZero, isNegative, isInteger - * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is larger than zero. - * Throws an error in case of an unknown data type. - */ - var isPositive = typed('isPositive', { - 'number': function (x) { - return x > 0; - }, - - 'BigNumber': function (x) { - return !x.isNeg() && !x.isZero() && !x.isNaN(); - }, - - 'Fraction': function (x) { - return x.s > 0 && x.n > 0; - }, - - 'Unit': function (x) { - return isPositive(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, isPositive); - } - }); - - return isPositive; - } - - var name$101 = 'isPositive'; - var factory_1$111 = factory$112; - - var isPositive$1 = { - name: name$101, - factory: factory_1$111 - }; - - var nearlyEqual$4 = number.nearlyEqual; - - - function factory$113 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - var latex$$1 = latex; - - /** - * Test whether two values are unequal. - * - * The function tests whether the relative difference between x and y is - * larger than the configured epsilon. The function cannot be used to compare - * values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im. - * Strings are compared by their numerical value. - * - * Values `null` and `undefined` are compared strictly, thus `null` is unequal - * with everything except `null`, and `undefined` is unequal with everything - * except `undefined`. - * - * Syntax: - * - * math.unequal(x, y) - * - * Examples: - * - * math.unequal(2 + 2, 3); // returns true - * math.unequal(2 + 2, 4); // returns false - * - * var a = math.unit('50 cm'); - * var b = math.unit('5 m'); - * math.unequal(a, b); // returns false - * - * var c = [2, 5, 1]; - * var d = [2, 7, 1]; - * - * math.unequal(c, d); // returns [false, true, false] - * math.deepEqual(c, d); // returns false - * - * math.unequal(0, null); // returns true - * See also: - * - * equal, deepEqual, smaller, smallerEq, larger, largerEq, compare - * - * @param {number | BigNumber | Fraction | boolean | Complex | Unit | string | Array | Matrix | undefined} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Complex | Unit | string | Array | Matrix | undefined} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the compared values are unequal, else returns false - */ - var unequal = typed('unequal', { - - 'any, any': function (x, y) { - // strict equality for null and undefined? - if (x === null) { return y !== null; } - if (y === null) { return x !== null; } - if (x === undefined) { return y !== undefined; } - if (y === undefined) { return x !== undefined; } - - return _unequal(x, y); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, _unequal); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, _unequal, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, _unequal, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, _unequal); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return unequal(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return unequal(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return unequal(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, _unequal, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, _unequal, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, _unequal, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, _unequal, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, _unequal, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, _unequal, true).valueOf(); - } - }); - - var _unequal = typed('_unequal', { - - 'boolean, boolean': function (x, y) { - return x !== y; - }, - - 'number, number': function (x, y) { - return !nearlyEqual$4(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return !nearlyEqual(x, y, config.epsilon); - }, - - 'Fraction, Fraction': function (x, y) { - return !x.equals(y); - }, - - 'Complex, Complex': function (x, y) { - return !x.equals(y); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return unequal(x.value, y.value); - } - }); - - unequal.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['unequal'] + '${args[1]}\\right)' - }; - - return unequal; - } - - var name$102 = 'unequal'; - var factory_1$112 = factory$113; - - var unequal$1 = { - name: name$102, - factory: factory_1$112 - }; - - function factory$114 (type, config, load, typed) { - /** - * Compute the sign of a value. The sign of a value x is: - * - * - 1 when x > 1 - * - -1 when x < 0 - * - 0 when x == 0 - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sign(x) - * - * Examples: - * - * math.sign(3.5); // returns 1 - * math.sign(-4.2); // returns -1 - * math.sign(0); // returns 0 - * - * math.sign([3, 5, -2, 0, 2]); // returns [1, 1, -1, 0, 1] - * - * See also: - * - * abs - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x - * The number for which to determine the sign - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit}e - * The sign of `x` - */ - var sign = typed('sign', { - 'number': number.sign, - - 'Complex': function (x) { - return x.sign(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(x.cmp(0)); - }, - - 'Fraction': function (x) { - return new type.Fraction(x.s, 1); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since sign(0) = 0 - return deepMap(x, sign, true); - }, - - 'Unit': function(x) { - return sign(x.value); - } - }); - - sign.toTex = {1: '\\mathrm{${name}}\\left(${args[0]}\\right)'}; - - return sign; - } - - var name$103 = 'sign'; - var factory_1$113 = factory$114; - - var sign$1 = { - name: name$103, - factory: factory_1$113 - }; - - function factory$115 (type, config, load, typed) { - /** - * Calculate the square root of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sqrt(x) - * - * Examples: - * - * math.sqrt(25); // returns 5 - * math.square(5); // returns 25 - * math.sqrt(-4); // returns Complex 2i - * - * See also: - * - * square, multiply, cube, cbrt, sqrtm - * - * @param {number | BigNumber | Complex | Array | Matrix | Unit} x - * Value for which to calculate the square root. - * @return {number | BigNumber | Complex | Array | Matrix | Unit} - * Returns the square root of `x` - */ - var sqrt = typed('sqrt', { - 'number': _sqrtNumber, - - 'Complex': function (x) { - return x.sqrt(); - }, - - 'BigNumber': function (x) { - if (!x.isNegative() || config.predictable) { - return x.sqrt(); - } - else { - // negative value -> downgrade to number to do complex value computation - return _sqrtNumber(x.toNumber()); - } - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since sqrt(0) = 0 - return deepMap(x, sqrt, true); - }, - - 'Unit': function (x) { - // Someday will work for complex units when they are implemented - return x.pow(0.5); - } - - }); - - /** - * Calculate sqrt for a number - * @param {number} x - * @returns {number | Complex} Returns the square root of x - * @private - */ - function _sqrtNumber(x) { - if (x >= 0 || config.predictable) { - return Math.sqrt(x); - } - else { - return new type.Complex(x, 0).sqrt(); - } - } - - sqrt.toTex = {1: '\\sqrt{${args[0]}}'}; - - return sqrt; - } - - var name$104 = 'sqrt'; - var factory_1$114 = factory$115; - - var sqrt$1 = { - name: name$104, - factory: factory_1$114 - }; - - function factory$116 (type, config, load, typed) { - /** - * Compute the complex conjugate of a complex value. - * If `x = a+bi`, the complex conjugate of `x` is `a - bi`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.conj(x) - * - * Examples: - * - * math.conj(math.complex('2 + 3i')); // returns Complex 2 - 3i - * math.conj(math.complex('2 - 3i')); // returns Complex 2 + 3i - * math.conj(math.complex('-5.2i')); // returns Complex 5.2i - * - * See also: - * - * re, im, arg, abs - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * A complex number or array with complex numbers - * @return {number | BigNumber | Complex | Array | Matrix} - * The complex conjugate of x - */ - var conj = typed('conj', { - 'number': function (x) { - return x; - }, - - 'BigNumber': function (x) { - return x; - }, - - 'Complex': function (x) { - return x.conjugate(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, conj); - } - }); - - conj.toTex = {1: '\\left(${args[0]}\\right)^*'}; - - return conj; - } - - var name$105 = 'conj'; - var factory_1$115 = factory$116; - - var conj$1 = { - name: name$105, - factory: factory_1$115 - }; - - function factory$117 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var zeros = load(zeros$1); - var eye = load(eye$1); - var clone = load(clone$5); - - var isZero = load(isZero$1); - var isPositive = load(isPositive$1); - var unequal = load(unequal$1); - - var abs = load(abs$1); - var sign = load(sign$1); - var sqrt = load(sqrt$1); - var conj = load(conj$1); - - var unaryMinus = load(unaryMinus$1); - var addScalar$$1 = load(addScalar); - var divideScalar$$1 = load(divideScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var subtract = load(subtract$1); - - - /** - * Calculate the Matrix QR decomposition. Matrix `A` is decomposed in - * two matrices (`Q`, `R`) where `Q` is an - * orthogonal matrix and `R` is an upper triangular matrix. - * - * Syntax: - * - * math.qr(A); - * - * Example: - * - * var m = [ - * [1, -1, 4], - * [1, 4, -2], - * [1, 4, 2], - * [1, -1, 0] - * ]; - * var result = math.qr(m); - * // r = { - * // Q: [ - * // [0.5, -0.5, 0.5], - * // [0.5, 0.5, -0.5], - * // [0.5, 0.5, 0.5], - * // [0.5, -0.5, -0.5], - * // ], - * // R: [ - * // [2, 3, 2], - * // [0, 5, -2], - * // [0, 0, 4], - * // [0, 0, 0] - * // ] - * // } - * - * See also: - * - * lu - * - * @param {Matrix | Array} A A two dimensional matrix or array - * for which to get the QR decomposition. - * - * @return {{Q: Array | Matrix, R: Array | Matrix}} Q: the orthogonal - * matrix and R: the upper triangular matrix - */ - var qr = typed('qr', { - - 'DenseMatrix': function (m) { - return _denseQR(m); - }, - - 'SparseMatrix': function (m) { - return _sparseQR(m); - }, - - 'Array': function (a) { - // create dense matrix from array - var m = matrix$$1(a); - // lup, use matrix implementation - var r = _denseQR(m); - // result - return { - Q: r.Q.valueOf(), - R: r.R.valueOf() - }; - } - }); - - var _denseQR = function (m) { - - // rows & columns (m x n) - var rows = m._size[0]; // m - var cols = m._size[1]; // n - - var Q = eye([rows], 'dense'); - var Qdata = Q._data; - - var R = m.clone(); - var Rdata = R._data; - - // vars - var i, j, k; - - var w = zeros([rows], ''); - - for (k = 0; k < Math.min(cols, rows); ++k) { - - /* - * **k-th Household matrix** - * - * The matrix I - 2*v*transpose(v) - * x = first column of A - * x1 = first element of x - * alpha = x1 / |x1| * |x| - * e1 = tranpose([1, 0, 0, ...]) - * u = x - alpha * e1 - * v = u / |u| - * - * Household matrix = I - 2 * v * tranpose(v) - * - * * Initially Q = I and R = A. - * * Household matrix is a reflection in a plane normal to v which - * will zero out all but the top right element in R. - * * Appplying reflection to both Q and R will not change product. - * * Repeat this process on the (1,1) minor to get R as an upper - * triangular matrix. - * * Reflections leave the magnitude of the columns of Q unchanged - * so Q remains othoganal. - * - */ - - var pivot = Rdata[k][k]; - var sgn = unaryMinus(sign(pivot)); - var conjSgn = conj(sgn); - - var alphaSquared = 0; - - for(i = k; i < rows; i++) { - alphaSquared = addScalar$$1(alphaSquared, multiplyScalar$$1(Rdata[i][k], conj(Rdata[i][k]))); - } - - var alpha = multiplyScalar$$1(sgn, sqrt(alphaSquared)); - - - if (!isZero(alpha)) { - - // first element in vector u - var u1 = subtract(pivot, alpha); - - // w = v * u1 / |u| (only elements k to (rows-1) are used) - w[k] = 1; - - for (i = k+1; i < rows; i++) { - w[i] = divideScalar$$1(Rdata[i][k], u1); - } - - // tau = - conj(u1 / alpha) - var tau = unaryMinus(conj(divideScalar$$1(u1, alpha))); - - var s; - - /* - * tau and w have been choosen so that - * - * 2 * v * tranpose(v) = tau * w * tranpose(w) - */ - - /* - * -- calculate R = R - tau * w * tranpose(w) * R -- - * Only do calculation with rows k to (rows-1) - * Additionally columns 0 to (k-1) will not be changed by this - * multiplication so do not bother recalculating them - */ - for (j = k; j < cols; j++) { - s = 0.0; - - // calculate jth element of [tranpose(w) * R] - for (i = k; i < rows; i++) { - s = addScalar$$1(s, multiplyScalar$$1(conj(w[i]), Rdata[i][j])); - } - - // calculate the jth element of [tau * transpose(w) * R] - s = multiplyScalar$$1(s, tau); - - for (i = k; i < rows; i++) { - Rdata[i][j] = multiplyScalar$$1( - subtract(Rdata[i][j], multiplyScalar$$1(w[i], s)), - conjSgn - ); - } - } - /* - * -- calculate Q = Q - tau * Q * w * transpose(w) -- - * Q is a square matrix (rows x rows) - * Only do calculation with columns k to (rows-1) - * Additionally rows 0 to (k-1) will not be changed by this - * multiplication so do not bother recalculating them - */ - for (i = 0; i < rows; i++) { - s = 0.0; - - // calculate ith element of [Q * w] - for (j = k; j < rows; j++) { - s = addScalar$$1(s, multiplyScalar$$1(Qdata[i][j], w[j])); - } - - // calculate the ith element of [tau * Q * w] - s = multiplyScalar$$1(s, tau); - - for (j = k; j < rows; ++j) { - Qdata[i][j] = divideScalar$$1( - subtract(Qdata[i][j], multiplyScalar$$1(s, conj(w[j]))), - conjSgn - ); - } - - } - } - - } - - // coerse almost zero elements to zero - // TODO I feel uneasy just zeroing these values - for (i = 0; i < rows; ++i) { - for (j = 0; j < i && j < cols; ++j) { - if (unequal(0, divideScalar$$1(Rdata[i][j], 1e5))) { - throw new Error('math.qr(): unknown error - ' + - 'R is not lower triangular (element (' + - i + ', ' + j + ') = ' + Rdata[i][j] + ')' - ); - } - Rdata[i][j] = multiplyScalar$$1(Rdata[i][j], 0); - } - } - - // return matrices - return { - Q: Q, - R: R, - toString: function () { - return 'Q: ' + this.Q.toString() + '\nR: ' + this.R.toString(); - } - }; - }; - - var _sparseQR = function (m) { - - throw new Error('qr not implemented for sparse matrices yet'); - - }; - - return qr; - } - - var name$106 = 'qr'; - var factory_1$116 = factory$117; - - var qr$1 = { - name: name$106, - factory: factory_1$116 - }; - - function factory$118 () { - - /** - * This function "flips" its input about the integer -1. - * - * @param {Number} i The value to flip - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_flip = function (i) { - // flip the value - return -i - 2; - }; - - return cs_flip; - } - - var name$107 = 'cs_flip'; - var path$46 = 'sparse'; - var factory_1$117 = factory$118; - - var cs_flip = { - name: name$107, - path: path$46, - factory: factory_1$117 - }; - - function factory$119 () { - - /** - * Keeps entries in the matrix when the callback function returns true, removes the entry otherwise - * - * @param {Matrix} a The sparse matrix - * @param {function} callback The callback function, function will be invoked with the following args: - * - The entry row - * - The entry column - * - The entry value - * - The state parameter - * @param {any} other The state - * - * @return The number of nonzero elements in the matrix - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_fkeep = function (a, callback, other) { - // a arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - // columns - var n = asize[1]; - // nonzero items - var nz = 0; - // loop columns - for (var j = 0; j < n; j++) { - // get current location of col j - var p = aptr[j]; - // record new location of col j - aptr[j] = nz; - for (; p < aptr[j+1]; p++) { - // check we need to keep this item - if (callback(aindex[p], j, avalues ? avalues[p] : 1, other)) { - // keep A(i,j) - aindex[nz] = aindex[p]; - // check we need to process values (pattern only) - if (avalues) - avalues[nz] = avalues[p]; - // increment nonzero items - nz++; - } - } - } - // finalize A - aptr[n] = nz; - // trim arrays - aindex.splice(nz, aindex.length - nz); - // check we need to process values (pattern only) - if (avalues) - avalues.splice(nz, avalues.length - nz); - // return number of nonzero items - return (nz); - }; - - return cs_fkeep; - } - - var name$108 = 'cs_fkeep'; - var path$47 = 'sparse'; - var factory_1$118 = factory$119; - - var cs_fkeep = { - name: name$108, - path: path$47, - factory: factory_1$118 - }; - - function factory$120 () { - - /** - * Depth-first search and postorder of a tree rooted at node j - * - * @param {Number} j The tree node - * @param {Number} k - * @param {Array} w The workspace array - * @param {Number} head The index offset within the workspace for the head array - * @param {Number} next The index offset within the workspace for the next array - * @param {Array} post The post ordering array - * @param {Number} stack The index offset within the workspace for the stack array - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_tdfs = function (j, k, w, head, next, post, stack) { - // variables - var top = 0; - // place j on the stack - w[stack] = j; - // while (stack is not empty) - while (top >= 0) { - // p = top of stack - var p = w[stack + top]; - // i = youngest child of p - var i = w[head + p]; - if (i == -1) { - // p has no unordered children left - top--; - // node p is the kth postordered node - post[k++] = p; - } - else { - // remove i from children of p - w[head + p] = w[next + i]; - // increment top - ++top; - // start dfs on child node i - w[stack + top] = i; - } - } - return k; - }; - - return cs_tdfs; - } - - var name$109 = 'cs_tdfs'; - var path$48 = 'sparse'; - var factory_1$119 = factory$120; - - var cs_tdfs = { - name: name$109, - path: path$48, - factory: factory_1$119 - }; - - var clone$6 = object.clone; - var format$4 = string.format; - - function factory$121 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - - var DenseMatrix = type.DenseMatrix, - SparseMatrix = type.SparseMatrix; - - /** - * Transpose a matrix. All values of the matrix are reflected over its - * main diagonal. Only applicable to two dimensional matrices containing - * a vector (i.e. having size `[1,n]` or `[n,1]`). One dimensional - * vectors and scalars return the input unchanged. - * - * Syntax: - * - * math.transpose(x) - * - * Examples: - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.transpose(A); // returns [[1, 4], [2, 5], [3, 6]] - * - * See also: - * - * diag, inv, subset, squeeze - * - * @param {Array | Matrix} x Matrix to be transposed - * @return {Array | Matrix} The transposed matrix - */ - var transpose = typed('transpose', { - - 'Array': function (x) { - // use dense matrix implementation - return transpose(matrix$$1(x)).valueOf(); - }, - - 'Matrix': function (x) { - // matrix size - var size = x.size(); - - // result - var c; - - // process dimensions - switch (size.length) { - case 1: - // vector - c = x.clone(); - break; - - case 2: - // rows and columns - var rows = size[0]; - var columns = size[1]; - - // check columns - if (columns === 0) { - // throw exception - throw new RangeError('Cannot transpose a 2D matrix with no columns (size: ' + format$4(size) + ')'); - } - - // process storage format - switch (x.storage()) { - case 'dense': - c = _denseTranspose(x, rows, columns); - break; - case 'sparse': - c = _sparseTranspose(x, rows, columns); - break; - } - break; - - default: - // multi dimensional - throw new RangeError('Matrix must be a vector or two dimensional (size: ' + format$4(this._size) + ')'); - } - return c; - }, - - // scalars - 'any': function (x) { - return clone$6(x); - } - }); - - var _denseTranspose = function (m, rows, columns) { - // matrix array - var data = m._data; - // transposed matrix data - var transposed = []; - var transposedRow; - // loop columns - for (var j = 0; j < columns; j++) { - // initialize row - transposedRow = transposed[j] = []; - // loop rows - for (var i = 0; i < rows; i++) { - // set data - transposedRow[i] = clone$6(data[i][j]); - } - } - // return matrix - return new DenseMatrix({ - data: transposed, - size: [columns, rows], - datatype: m._datatype - }); - }; - - var _sparseTranspose = function (m, rows, columns) { - // matrix arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // result matrices - var cvalues = values ? [] : undefined; - var cindex = []; - var cptr = []; - // row counts - var w = []; - for (var x = 0; x < rows; x++) - w[x] = 0; - // vars - var p, l, j; - // loop values in matrix - for (p = 0, l = index.length; p < l; p++) { - // number of values in row - w[index[p]]++; - } - // cumulative sum - var sum = 0; - // initialize cptr with the cummulative sum of row counts - for (var i = 0; i < rows; i++) { - // update cptr - cptr.push(sum); - // update sum - sum += w[i]; - // update w - w[i] = cptr[i]; - } - // update cptr - cptr.push(sum); - // loop columns - for (j = 0; j < columns; j++) { - // values & index in column - for (var k0 = ptr[j], k1 = ptr[j + 1], k = k0; k < k1; k++) { - // C values & index - var q = w[index[k]]++; - // C[j, i] = A[i, j] - cindex[q] = j; - // check we need to process values (pattern matrix) - if (values) - cvalues[q] = clone$6(values[k]); - } - } - // return matrix - return new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [columns, rows], - datatype: m._datatype - }); - }; - - transpose.toTex = {1: '\\left(${args[0]}\\right)' + latex$$1.operators['transpose']}; - - return transpose; - } - - var name$110 = 'transpose'; - var factory_1$120 = factory$121; - - var transpose$1 = { - name: name$110, - factory: factory_1$120 - }; - - function factory$122 (type, config, load) { - - var cs_flip$$1 = load(cs_flip); - var cs_fkeep$$1 = load(cs_fkeep); - var cs_tdfs$$1 = load(cs_tdfs); - - var add$$1 = load(add); - var multiply = load(multiply$1); - var transpose = load(transpose$1); - - /** - * Approximate minimum degree ordering. The minimum degree algorithm is a widely used - * heuristic for finding a permutation P so that P*A*P' has fewer nonzeros in its factorization - * than A. It is a gready method that selects the sparsest pivot row and column during the course - * of a right looking sparse Cholesky factorization. - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - * - * @param {Number} order 0: Natural, 1: Cholesky, 2: LU, 3: QR - * @param {Matrix} m Sparse Matrix - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_amd = function (order, a) { - // check input parameters - if (!a || order <= 0 || order > 3) - return null; - // a matrix arrays - var asize = a._size; - // rows and columns - var m = asize[0]; - var n = asize[1]; - // initialize vars - var lemax = 0; - // dense threshold - var dense = Math.max(16, 10 * Math.sqrt(n)); - dense = Math.min(n - 2, dense); - // create target matrix C - var cm = _createTargetMatrix(order, a, m, n, dense); - // drop diagonal entries - cs_fkeep$$1(cm, _diag, null); - // C matrix arrays - var cindex = cm._index; - var cptr = cm._ptr; - - // number of nonzero elements in C - var cnz = cptr[n]; - - // allocate result (n+1) - var P = []; - - // create workspace (8 * (n + 1)) - var W = []; - var len = 0; // first n + 1 entries - var nv = n + 1; // next n + 1 entries - var next = 2 * (n + 1); // next n + 1 entries - var head = 3 * (n + 1); // next n + 1 entries - var elen = 4 * (n + 1); // next n + 1 entries - var degree = 5 * (n + 1); // next n + 1 entries - var w = 6 * (n + 1); // next n + 1 entries - var hhead = 7 * (n + 1); // last n + 1 entries - - // use P as workspace for last - var last = P; - - // initialize quotient graph - var mark = _initializeQuotientGraph(n, cptr, W, len, head, last, next, hhead, nv, w, elen, degree); - - // initialize degree lists - var nel = _initializeDegreeLists(n, cptr, W, degree, elen, w, dense, nv, head, last, next); - - // minimum degree node - var mindeg = 0; - - // vars - var i, j, k, k1, k2, e, pj, ln, nvi, pk, eln, p1, p2, pn, h, d; - - // while (selecting pivots) do - while (nel < n) { - // select node of minimum approximate degree. amd() is now ready to start eliminating the graph. It first - // finds a node k of minimum degree and removes it from its degree list. The variable nel keeps track of thow - // many nodes have been eliminated. - for (k = -1; mindeg < n && (k = W[head + mindeg]) == -1; mindeg++); - if (W[next + k] != -1) - last[W[next + k]] = -1; - // remove k from degree list - W[head + mindeg] = W[next + k]; - // elenk = |Ek| - var elenk = W[elen + k]; - // # of nodes k represents - var nvk = W[nv + k]; - // W[nv + k] nodes of A eliminated - nel += nvk; - - // Construct a new element. The new element Lk is constructed in place if |Ek| = 0. nv[i] is - // negated for all nodes i in Lk to flag them as members of this set. Each node i is removed from the - // degree lists. All elements e in Ek are absorved into element k. - var dk = 0; - // flag k as in Lk - W[nv + k] = -nvk; - var p = cptr[k]; - // do in place if W[elen + k] == 0 - var pk1 = (elenk === 0) ? p : cnz; - var pk2 = pk1; - for (k1 = 1; k1 <= elenk + 1; k1++) { - if (k1 > elenk) { - // search the nodes in k - e = k; - // list of nodes starts at cindex[pj] - pj = p; - // length of list of nodes in k - ln = W[len + k] - elenk; - } - else { - // search the nodes in e - e = cindex[p++]; - pj = cptr[e]; - // length of list of nodes in e - ln = W[len + e]; - } - for (k2 = 1; k2 <= ln; k2++) { - i = cindex[pj++]; - // check node i dead, or seen - if ((nvi = W[nv + i]) <= 0) - continue; - // W[degree + Lk] += size of node i - dk += nvi; - // negate W[nv + i] to denote i in Lk - W[nv + i] = -nvi; - // place i in Lk - cindex[pk2++] = i; - if (W[next + i] != -1) - last[W[next + i]] = last[i]; - // check we need to remove i from degree list - if (last[i] != -1) - W[next + last[i]] = W[next + i]; - else - W[head + W[degree + i]] = W[next + i]; - } - if (e != k) { - // absorb e into k - cptr[e] = cs_flip$$1(k); - // e is now a dead element - W[w + e] = 0; - } - } - // cindex[cnz...nzmax] is free - if (elenk !== 0) - cnz = pk2; - // external degree of k - |Lk\i| - W[degree + k] = dk; - // element k is in cindex[pk1..pk2-1] - cptr[k] = pk1; - W[len + k] = pk2 - pk1; - // k is now an element - W[elen + k] = -2; - - // Find set differences. The scan1 function now computes the set differences |Le \ Lk| for all elements e. At the start of the - // scan, no entry in the w array is greater than or equal to mark. - - // clear w if necessary - mark = _wclear(mark, lemax, W, w, n); - // scan 1: find |Le\Lk| - for (pk = pk1; pk < pk2; pk++) { - i = cindex[pk]; - // check if W[elen + i] empty, skip it - if ((eln = W[elen + i]) <= 0) - continue; - // W[nv + i] was negated - nvi = -W[nv + i]; - var wnvi = mark - nvi; - // scan Ei - for (p = cptr[i], p1 = cptr[i] + eln - 1; p <= p1; p++) { - e = cindex[p]; - if (W[w + e] >= mark) { - // decrement |Le\Lk| - W[w + e] -= nvi; - } - else if (W[w + e] !== 0) { - // ensure e is a live element, 1st time e seen in scan 1 - W[w + e] = W[degree + e] + wnvi; - } - } - } - - // degree update - // The second pass computes the approximate degree di, prunes the sets Ei and Ai, and computes a hash - // function h(i) for all nodes in Lk. - - // scan2: degree update - for (pk = pk1; pk < pk2; pk++) { - // consider node i in Lk - i = cindex[pk]; - p1 = cptr[i]; - p2 = p1 + W[elen + i] - 1; - pn = p1; - // scan Ei - for (h = 0, d = 0, p = p1; p <= p2; p++) { - e = cindex[p]; - // check e is an unabsorbed element - if (W[w + e] !== 0) { - // dext = |Le\Lk| - var dext = W[w + e] - mark; - if (dext > 0) { - // sum up the set differences - d += dext; - // keep e in Ei - cindex[pn++] = e; - // compute the hash of node i - h += e; - } - else { - // aggressive absorb. e->k - cptr[e] = cs_flip$$1(k); - // e is a dead element - W[w + e] = 0; - } - } - } - // W[elen + i] = |Ei| - W[elen + i] = pn - p1 + 1; - var p3 = pn; - var p4 = p1 + W[len + i]; - // prune edges in Ai - for (p = p2 + 1; p < p4; p++) { - j = cindex[p]; - // check node j dead or in Lk - var nvj = W[nv + j]; - if (nvj <= 0) - continue; - // degree(i) += |j| - d += nvj; - // place j in node list of i - cindex[pn++] = j; - // compute hash for node i - h += j; - } - // check for mass elimination - if (d === 0) { - // absorb i into k - cptr[i] = cs_flip$$1(k); - nvi = -W[nv + i]; - // |Lk| -= |i| - dk -= nvi; - // |k| += W[nv + i] - nvk += nvi; - nel += nvi; - W[nv + i] = 0; - // node i is dead - W[elen + i] = -1; - } - else { - // update degree(i) - W[degree + i] = Math.min(W[degree + i], d); - // move first node to end - cindex[pn] = cindex[p3]; - // move 1st el. to end of Ei - cindex[p3] = cindex[p1]; - // add k as 1st element in of Ei - cindex[p1] = k; - // new len of adj. list of node i - W[len + i] = pn - p1 + 1; - // finalize hash of i - h = (h < 0 ? -h : h) % n; - // place i in hash bucket - W[next + i] = W[hhead + h]; - W[hhead + h] = i; - // save hash of i in last[i] - last[i] = h; - } - } - // finalize |Lk| - W[degree + k] = dk; - lemax = Math.max(lemax, dk); - // clear w - mark = _wclear(mark + lemax, lemax, W, w, n); - - // Supernode detection. Supernode detection relies on the hash function h(i) computed for each node i. - // If two nodes have identical adjacency lists, their hash functions wil be identical. - for (pk = pk1; pk < pk2; pk++) { - i = cindex[pk]; - // check i is dead, skip it - if (W[nv + i] >= 0) - continue; - // scan hash bucket of node i - h = last[i]; - i = W[hhead + h]; - // hash bucket will be empty - W[hhead + h] = -1; - for (; i != -1 && W[next + i] != -1; i = W[next + i], mark++) { - ln = W[len + i]; - eln = W[elen + i]; - for (p = cptr[i] + 1; p <= cptr[i] + ln - 1; p++) - W[w + cindex[p]] = mark; - var jlast = i; - // compare i with all j - for (j = W[next + i]; j != -1; ) { - var ok = W[len + j] === ln && W[elen + j] === eln; - for (p = cptr[j] + 1; ok && p <= cptr[j] + ln - 1; p++) { - // compare i and j - if (W[w + cindex[p]] != mark) - ok = 0; - } - // check i and j are identical - if (ok) { - // absorb j into i - cptr[j] = cs_flip$$1(i); - W[nv + i] += W[nv + j]; - W[nv + j] = 0; - // node j is dead - W[elen + j] = -1; - // delete j from hash bucket - j = W[next + j]; - W[next + jlast] = j; - } - else { - // j and i are different - jlast = j; - j = W[next + j]; - } - } - } - } - - // Finalize new element. The elimination of node k is nearly complete. All nodes i in Lk are scanned one last time. - // Node i is removed from Lk if it is dead. The flagged status of nv[i] is cleared. - for (p = pk1, pk = pk1; pk < pk2; pk++) { - i = cindex[pk]; - // check i is dead, skip it - if ((nvi = -W[nv + i]) <= 0) - continue; - // restore W[nv + i] - W[nv + i] = nvi; - // compute external degree(i) - d = W[degree + i] + dk - nvi; - d = Math.min(d, n - nel - nvi); - if (W[head + d] != -1) - last[W[head + d]] = i; - // put i back in degree list - W[next + i] = W[head + d]; - last[i] = -1; - W[head + d] = i; - // find new minimum degree - mindeg = Math.min(mindeg, d); - W[degree + i] = d; - // place i in Lk - cindex[p++] = i; - } - // # nodes absorbed into k - W[nv + k] = nvk; - // length of adj list of element k - if ((W[len + k] = p - pk1) === 0) { - // k is a root of the tree - cptr[k] = -1; - // k is now a dead element - W[w + k] = 0; - } - if (elenk !== 0) { - // free unused space in Lk - cnz = p; - } - } - - // Postordering. The elimination is complete, but no permutation has been computed. All that is left - // of the graph is the assembly tree (ptr) and a set of dead nodes and elements (i is a dead node if - // nv[i] is zero and a dead element if nv[i] > 0). It is from this information only that the final permutation - // is computed. The tree is restored by unflipping all of ptr. - - // fix assembly tree - for (i = 0; i < n; i++) - cptr[i] = cs_flip$$1(cptr[i]); - for (j = 0; j <= n; j++) - W[head + j] = -1; - // place unordered nodes in lists - for (j = n; j >= 0; j--) { - // skip if j is an element - if (W[nv + j] > 0) - continue; - // place j in list of its parent - W[next + j] = W[head + cptr[j]]; - W[head + cptr[j]] = j; - } - // place elements in lists - for (e = n; e >= 0; e--) { - // skip unless e is an element - if (W[nv + e] <= 0) - continue; - if (cptr[e] != -1) { - // place e in list of its parent - W[next + e] = W[head + cptr[e]]; - W[head + cptr[e]] = e; - } - } - // postorder the assembly tree - for (k = 0, i = 0; i <= n; i++) { - if (cptr[i] == -1) - k = cs_tdfs$$1(i, k, W, head, next, P, w); - } - // remove last item in array - P.splice(P.length - 1, 1); - // return P - return P; - }; - - /** - * Creates the matrix that will be used by the approximate minimum degree ordering algorithm. The function accepts the matrix M as input and returns a permutation - * vector P. The amd algorithm operates on a symmetrix matrix, so one of three symmetric matrices is formed. - * - * Order: 0 - * A natural ordering P=null matrix is returned. - * - * Order: 1 - * Matrix must be square. This is appropriate for a Cholesky or LU factorization. - * P = M + M' - * - * Order: 2 - * Dense columns from M' are dropped, M recreated from M'. This is appropriatefor LU factorization of unsymmetric matrices. - * P = M' * M - * - * Order: 3 - * This is best used for QR factorization or LU factorization is matrix M has no dense rows. A dense row is a row with more than 10*sqr(columns) entries. - * P = M' * M - */ - var _createTargetMatrix = function (order, a, m, n, dense) { - // compute A' - var at = transpose(a); - - // check order = 1, matrix must be square - if (order === 1 && n === m) { - // C = A + A' - return add$$1(a, at); - } - - // check order = 2, drop dense columns from M' - if (order == 2) { - // transpose arrays - var tindex = at._index; - var tptr = at._ptr; - // new column index - var p2 = 0; - // loop A' columns (rows) - for (var j = 0; j < m; j++) { - // column j of AT starts here - var p = tptr[j]; - // new column j starts here - tptr[j] = p2; - // skip dense col j - if (tptr[j + 1] - p > dense) - continue; - // map rows in column j of A - for (var p1 = tptr[j + 1]; p < p1; p++) - tindex[p2++] = tindex[p]; - } - // finalize AT - tptr[m] = p2; - // recreate A from new transpose matrix - a = transpose(at); - // use A' * A - return multiply(at, a); - } - - // use A' * A, square or rectangular matrix - return multiply(at, a); - }; - - /** - * Initialize quotient graph. There are four kind of nodes and elements that must be represented: - * - * - A live node is a node i (or a supernode) that has not been selected as a pivot nad has not been merged into another supernode. - * - A dead node i is one that has been removed from the graph, having been absorved into r = flip(ptr[i]). - * - A live element e is one that is in the graph, having been formed when node e was selected as the pivot. - * - A dead element e is one that has benn absorved into a subsequent element s = flip(ptr[e]). - */ - var _initializeQuotientGraph = function (n, cptr, W, len, head, last, next, hhead, nv, w, elen, degree) { - // Initialize quotient graph - for (var k = 0; k < n; k++) - W[len + k] = cptr[k + 1] - cptr[k]; - W[len + n] = 0; - // initialize workspace - for (var i = 0; i <= n; i++) { - // degree list i is empty - W[head + i] = -1; - last[i] = -1; - W[next + i] = -1; - // hash list i is empty - W[hhead + i] = -1; - // node i is just one node - W[nv + i] = 1; - // node i is alive - W[w + i] = 1; - // Ek of node i is empty - W[elen + i] = 0; - // degree of node i - W[degree + i] = W[len + i]; - } - // clear w - var mark = _wclear(0, 0, W, w, n); - // n is a dead element - W[elen + n] = -2; - // n is a root of assembly tree - cptr[n] = -1; - // n is a dead element - W[w + n] = 0; - // return mark - return mark; - }; - - /** - * Initialize degree lists. Each node is placed in its degree lists. Nodes of zero degree are eliminated immediately. Nodes with - * degree >= dense are alsol eliminated and merged into a placeholder node n, a dead element. Thes nodes will appera last in the - * output permutation p. - */ - var _initializeDegreeLists = function (n, cptr, W, degree, elen, w, dense, nv, head, last, next) { - // result - var nel = 0; - // loop columns - for (var i = 0; i < n; i++) { - // degree @ i - var d = W[degree + i]; - // check node i is empty - if (d === 0) { - // element i is dead - W[elen + i] = -2; - nel++; - // i is a root of assembly tree - cptr[i] = -1; - W[w + i] = 0; - } - else if (d > dense) { - // absorb i into element n - W[nv + i] = 0; - // node i is dead - W[elen + i] = -1; - nel++; - cptr[i] = cs_flip$$1(n); - W[nv + n]++; - } - else { - var h = W[head + d]; - if (h != -1) - last[h] = i; - // put node i in degree list d - W[next + i] = W[head + d]; - W[head + d] = i; - } - } - return nel; - }; - - var _wclear = function(mark, lemax, W, w, n) { - if (mark < 2 || (mark + lemax < 0)) { - for (var k = 0; k < n; k++) { - if (W[w + k] !== 0) - W[w + k] = 1; - } - mark = 2 ; - } - // at this point, W [0..n-1] < mark holds - return mark; - }; - - var _diag = function (i, j) { - return i != j; - }; - - return cs_amd; - } - - var name$111 = 'cs_amd'; - var path$49 = 'sparse'; - var factory_1$121 = factory$122; - - var cs_amd = { - name: name$111, - path: path$49, - factory: factory_1$121 - }; - - function factory$123 (type) { - - var SparseMatrix = type.SparseMatrix; - - /** - * Permutes a sparse matrix C = P * A * Q - * - * @param {Matrix} a The Matrix A - * @param {Array} pinv The row permutation vector - * @param {Array} q The column permutation vector - * @param {boolean} values Create a pattern matrix (false), values and pattern otherwise - * - * @return {Matrix} C = P * A * Q, null on error - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_permute = function (a, pinv, q, values) { - // a arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // rows & columns - var m = asize[0]; - var n = asize[1]; - // c arrays - var cvalues = values && a._values ? [] : null; - var cindex = []; // (aptr[n]); - var cptr = []; // (n + 1); - // initialize vars - var nz = 0; - // loop columns - for (var k = 0; k < n; k++) { - // column k of C is column q[k] of A - cptr[k] = nz; - // apply column permutation - var j = q ? (q[k]) : k; - // loop values in column j of A - for (var t0 = aptr[j], t1 = aptr[j + 1], t = t0; t < t1; t++) { - // row i of A is row pinv[i] of C - var r = pinv ? pinv[aindex[t]] : aindex[t]; - // index - cindex[nz] = r; - // check we need to populate values - if (cvalues) - cvalues[nz] = avalues[t]; - // increment number of nonzero elements - nz++; - } - } - // finalize the last column of C - cptr[n] = nz; - // return C matrix - return new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [m, n], - datatype: adt - }); - }; - - return cs_permute; - } - - var name$112 = 'cs_permute'; - var path$50 = 'sparse'; - var factory_1$122 = factory$123; - - var cs_permute = { - name: name$112, - path: path$50, - factory: factory_1$122 - }; - - function factory$124 () { - - /** - * Computes the elimination tree of Matrix A (using triu(A)) or the - * elimination tree of A'A without forming A'A. - * - * @param {Matrix} a The A Matrix - * @param {boolean} ata A value of true the function computes the etree of A'A - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_etree = function (a, ata) { - // check inputs - if (!a) - return null; - // a arrays - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - // rows & columns - var m = asize[0]; - var n = asize[1]; - - // allocate result - var parent = []; // (n) - - // allocate workspace - var w = []; // (n + (ata ? m : 0)) - var ancestor = 0; // first n entries in w - var prev = n; // last m entries (ata = true) - - var i, inext; - - // check we are calculating A'A - if (ata) { - // initialize workspace - for (i = 0; i < m; i++) - w[prev + i] = -1; - } - // loop columns - for (var k = 0; k < n; k++) { - // node k has no parent yet - parent[k] = -1; - // nor does k have an ancestor - w[ancestor + k] = -1; - // values in column k - for (var p0 = aptr[k], p1 = aptr[k + 1], p = p0; p < p1; p++) { - // row - var r = aindex[p]; - // node - i = ata ? (w[prev + r]) : r; - // traverse from i to k - for (; i != -1 && i < k; i = inext) { - // inext = ancestor of i - inext = w[ancestor + i]; - // path compression - w[ancestor + i] = k; - // check no anc., parent is k - if (inext == -1) - parent[i] = k; - } - if (ata) - w[prev + r] = k; - } - } - return parent; - }; - - return cs_etree; - } - - var name$113 = 'cs_etree'; - var path$51 = 'sparse'; - var factory_1$123 = factory$124; - - var cs_etree = { - name: name$113, - path: path$51, - factory: factory_1$123 - }; - - function factory$125 (type, config, load) { - - var cs_tdfs$$1 = load(cs_tdfs); - - /** - * Post order a tree of forest - * - * @param {Array} parent The tree or forest - * @param {Number} n Number of columns - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_post = function (parent, n) { - // check inputs - if (!parent) - return null; - // vars - var k = 0; - var j; - // allocate result - var post = []; // (n); - // workspace, head: first n entries, next: next n entries, stack: last n entries - var w = []; // (3 * n); - var head = 0; - var next = n; - var stack = 2 * n; - // initialize workspace - for (j = 0; j < n; j++) { - // empty linked lists - w[head + j] = -1; - } - // traverse nodes in reverse order - for (j = n-1; j >= 0; j--) { - // check j is a root - if (parent[j] == -1) - continue; - // add j to list of its parent - w[next + j] = w[head + parent[j]]; - w[head + parent[j]] = j; - } - // loop nodes - for (j = 0; j < n; j++) { - // skip j if it is not a root - if (parent[j] != -1) - continue; - // depth-first search - k = cs_tdfs$$1(j, k, w, head, next, post, stack); - } - return post; - }; - - return cs_post; - } - - var name$114 = 'cs_post'; - var path$52 = 'sparse'; - var factory_1$124 = factory$125; - - var cs_post = { - name: name$114, - path: path$52, - factory: factory_1$124 - }; - - function factory$126 () { - - /** - * This function determines if j is a leaf of the ith row subtree. - * Consider A(i,j), node j in ith row subtree and return lca(jprev,j) - * - * @param {Number} i The ith row subtree - * @param {Number} j The node to test - * @param {Array} w The workspace array - * @param {Number} first The index offset within the workspace for the first array - * @param {Number} maxfirst The index offset within the workspace for the maxfirst array - * @param {Number} prevleaf The index offset within the workspace for the prevleaf array - * @param {Number} ancestor The index offset within the workspace for the ancestor array - * - * @return {Object} - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_leaf = function (i, j, w, first, maxfirst, prevleaf, ancestor) { - - var s, sparent, jprev; - - // our result - var jleaf = 0; - var q; - - // check j is a leaf - if (i <= j || w[first + j] <= w[maxfirst + i]) - return (-1); - // update max first[j] seen so far - w[maxfirst + i] = w[first + j]; - // jprev = previous leaf of ith subtree - jprev = w[prevleaf + i]; - w[prevleaf + i] = j; - - // check j is first or subsequent leaf - if (jprev === -1) { - // 1st leaf, q = root of ith subtree - jleaf = 1; - q = i; - } - else { - // update jleaf - jleaf = 2; - // q = least common ancester (jprev,j) - for (q = jprev; q != w[ancestor + q]; q = w[ancestor + q]); - for (s = jprev; s != q; s = sparent) { - // path compression - sparent = w[ancestor + s]; - w[ancestor + s] = q; - } - } - return { - jleaf: jleaf, - q: q - }; - }; - - return cs_leaf; - } - - var name$115 = 'cs_leaf'; - var path$53 = 'sparse'; - var factory_1$125 = factory$126; - - var cs_leaf = { - name: name$115, - path: path$53, - factory: factory_1$125 - }; - - function factory$127 (type, config, load) { - - var transpose = load(transpose$1); - - var cs_leaf$$1 = load(cs_leaf); - - /** - * Computes the column counts using the upper triangular part of A. - * It transposes A internally, none of the input parameters are modified. - * - * @param {Matrix} a The sparse matrix A - * - * @param {Matrix} ata Count the columns of A'A instead - * - * @return An array of size n of the column counts or null on error - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_counts = function (a, parent, post, ata) { - // check inputs - if (!a || !parent || !post) - return null; - // a matrix arrays - var asize = a._size; - // rows and columns - var m = asize[0]; - var n = asize[1]; - // variables - var i, j, k, J, p, p0, p1; - - // workspace size - var s = 4 * n + (ata ? (n + m + 1) : 0); - // allocate workspace - var w = []; // (s) - var ancestor = 0; // first n entries - var maxfirst = n; // next n entries - var prevleaf = 2 * n; // next n entries - var first = 3 * n; // next n entries - var head = 4 * n; // next n + 1 entries (used when ata is true) - var next = 5 * n + 1; // last entries in workspace - // clear workspace w[0..s-1] - for (k = 0; k < s; k++) - w[k] = -1; - - // allocate result - var colcount = []; // (n); - - // AT = A' - var at = transpose(a); - // at arrays - var tindex = at._index; - var tptr = at._ptr; - - // find w[first + j] - for (k = 0; k < n; k++) { - j = post[k]; - // colcount[j]=1 if j is a leaf - colcount[j] = (w[first + j] == -1) ? 1 : 0; - for (; j != -1 && w[first + j] == -1; j = parent[j]) - w[first + j] = k; - } - - // initialize ata if needed - if (ata) { - // invert post - for (k = 0; k < n; k++) - w[post[k]] = k; - // loop rows (columns in AT) - for (i = 0; i < m; i++) { - // values in column i of AT - for (k = n, p0 = tptr[i], p1 = tptr[i + 1], p = p0; p < p1; p++) - k = Math.min(k, w[tindex[p]]); - // place row i in linked list k - w[next + i] = w[head + k]; - w[head + k] = i; - } - } - - // each node in its own set - for (i = 0; i < n; i++) - w[ancestor + i] = i; - - for (k = 0; k < n; k++) { - // j is the kth node in postordered etree - j = post[k]; - // check j is not a root - if (parent[j] != -1) - colcount[parent[j]]--; - - // J=j for LL'=A case - for (J = (ata ? w[head + k] : j); J != -1; J = (ata ? w[next + J] : -1)) { - for (p = tptr[J]; p < tptr[J+1]; p++) { - i = tindex[p]; - var r = cs_leaf$$1(i, j, w, first, maxfirst, prevleaf, ancestor); - // check A(i,j) is in skeleton - if (r.jleaf >= 1) - colcount[j]++; - // check account for overlap in q - if (r.jleaf == 2) - colcount[r.q]--; - } - } - if (parent[j] != -1) - w[ancestor + j] = parent[j]; - } - // sum up colcount's of each child - for (j = 0; j < n; j++) { - if (parent[j] != -1) - colcount[parent[j]] += colcount[j]; - } - return colcount; - }; - - return cs_counts; - } - - var name$116 = 'cs_counts'; - var path$54 = 'sparse'; - var factory_1$126 = factory$127; - - var cs_counts = { - name: name$116, - path: path$54, - factory: factory_1$126 - }; - - function factory$128 (type, config, load) { - - var cs_amd$$1 = load(cs_amd); - var cs_permute$$1 = load(cs_permute); - var cs_etree$$1 = load(cs_etree); - var cs_post$$1 = load(cs_post); - var cs_counts$$1 = load(cs_counts); - - /** - * Symbolic ordering and analysis for QR and LU decompositions. - * - * @param {Number} order The ordering strategy (see cs_amd for more details) - * @param {Matrix} a The A matrix - * @param {boolean} qr Symbolic ordering and analysis for QR decomposition (true) or - * symbolic ordering and analysis for LU decomposition (false) - * - * @return {Object} The Symbolic ordering and analysis for matrix A - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_sqr = function (order, a, qr) { - // a arrays - var aptr = a._ptr; - var asize = a._size; - // columns - var n = asize[1]; - // vars - var k; - // symbolic analysis result - var s = {}; - // fill-reducing ordering - s.q = cs_amd$$1(order, a); - // validate results - if (order && !s.q) - return null; - // QR symbolic analysis - if (qr) { - // apply permutations if needed - var c = order ? cs_permute$$1(a, null, s.q, 0) : a; - // etree of C'*C, where C=A(:,q) - s.parent = cs_etree$$1(c, 1); - // post order elimination tree - var post = cs_post$$1 (s.parent, n); - // col counts chol(C'*C) - s.cp = cs_counts$$1(c, s.parent, post, 1); - // check we have everything needed to calculate number of nonzero elements - if (c && s.parent && s.cp && _vcount(c, s)) { - // calculate number of nonzero elements - for (s.unz = 0, k = 0; k < n; k++) - s.unz += s.cp[k]; - } - } - else { - // for LU factorization only, guess nnz(L) and nnz(U) - s.unz = 4 * (aptr[n]) + n; - s.lnz = s.unz; - } - // return result S - return s; - }; - - /** - * Compute nnz(V) = s.lnz, s.pinv, s.leftmost, s.m2 from A and s.parent - */ - var _vcount = function (a, s) { - // a arrays - var aptr = a._ptr; - var aindex = a._index; - var asize = a._size; - // rows & columns - var m = asize[0]; - var n = asize[1]; - // initialize s arrays - s.pinv = []; // (m + n); - s.leftmost = []; // (m); - // vars - var parent = s.parent; - var pinv = s.pinv; - var leftmost = s.leftmost; - // workspace, next: first m entries, head: next n entries, tail: next n entries, nque: next n entries - var w = []; // (m + 3 * n); - var next = 0; - var head = m; - var tail = m + n; - var nque = m + 2 * n; - // vars - var i, k, p, p0, p1; - // initialize w - for (k = 0; k < n; k++) { - // queue k is empty - w[head + k] = -1; - w[tail + k] = -1; - w[nque + k] = 0; - } - // initialize row arrays - for (i = 0; i < m; i++) - leftmost[i] = -1; - // loop columns backwards - for (k = n - 1; k >= 0; k--) { - // values & index for column k - for (p0 = aptr[k], p1 = aptr[k + 1], p = p0; p < p1; p++) { - // leftmost[i] = min(find(A(i,:))) - leftmost[aindex[p]] = k; - } - } - // scan rows in reverse order - for (i = m - 1; i >= 0; i--) { - // row i is not yet ordered - pinv[i] = -1; - k = leftmost[i]; - // check row i is empty - if (k == -1) - continue; - // first row in queue k - if (w[nque + k]++ === 0) - w[tail + k] = i; - // put i at head of queue k - w[next + i] = w[head + k]; - w[head + k] = i; - } - s.lnz = 0; - s.m2 = m; - // find row permutation and nnz(V) - for (k = 0; k < n; k++) { - // remove row i from queue k - i = w[head + k]; - // count V(k,k) as nonzero - s.lnz++; - // add a fictitious row - if (i < 0) - i = s.m2++; - // associate row i with V(:,k) - pinv[i] = k; - // skip if V(k+1:m,k) is empty - if (--nque[k] <= 0) - continue; - // nque[k] is nnz (V(k+1:m,k)) - s.lnz += w[nque + k]; - // move all rows to parent of k - var pa = parent[k]; - if (pa != -1) { - if (w[nque + pa] === 0) - w[tail + pa] = w[tail + k]; - w[next + w[tail + k]] = w[head + pa]; - w[head + pa] = w[next + i]; - w[nque + pa] += w[nque + k]; - } - } - for (i = 0; i < m; i++) { - if (pinv[i] < 0) - pinv[i] = k++; - } - return true; - }; - - return cs_sqr; - } - - var name$117 = 'cs_sqr'; - var path$55 = 'sparse'; - var factory_1$127 = factory$128; - - var cs_sqr = { - name: name$117, - path: path$55, - factory: factory_1$127 - }; - - var nearlyEqual$5 = number.nearlyEqual; - - - function factory$129 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - var latex$$1 = latex; - - /** - * Test whether value x is larger or equal to y. - * - * The function returns true when x is larger than y or the relative - * difference between x and y is smaller than the configured epsilon. The - * function cannot be used to compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.largerEq(x, y) - * - * Examples: - * - * math.larger(2, 1 + 1); // returns false - * math.largerEq(2, 1 + 1); // returns true - * - * See also: - * - * equal, unequal, smaller, smallerEq, larger, compare - * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the x is larger or equal to y, else returns false - */ - var largerEq = typed('largerEq', { - - 'boolean, boolean': function (x, y) { - return x >= y; - }, - - 'number, number': function (x, y) { - return x >= y || nearlyEqual$5(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.gte(y) || nearlyEqual(x, y, config.epsilon); - }, - - 'Fraction, Fraction': function (x, y) { - return x.compare(y) !== -1; - }, - - 'Complex, Complex': function () { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return largerEq(x.value, y.value); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, largerEq); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, largerEq, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, largerEq, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, largerEq); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return largerEq(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return largerEq(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return largerEq(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, largerEq, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, largerEq, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, largerEq, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, largerEq, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, largerEq, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, largerEq, true).valueOf(); - } - }); - - largerEq.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['largerEq'] + '${args[1]}\\right)' - }; - - return largerEq; - } - - var name$118 = 'largerEq'; - var factory_1$128 = factory$129; - - var largerEq$1 = { - name: name$118, - factory: factory_1$128 - }; - - function factory$130 () { - - /** - * Checks if the node at w[j] is marked - * - * @param {Array} w The array - * @param {Number} j The array index - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_marked = function (w, j) { - // check node is marked - return w[j] < 0; - }; - - return cs_marked; - } - - var name$119 = 'cs_marked'; - var path$56 = 'sparse'; - var factory_1$129 = factory$130; - - var cs_marked = { - name: name$119, - path: path$56, - factory: factory_1$129 - }; - - function factory$131 (type, config, load) { - - var cs_flip$$1 = load(cs_flip); - - /** - * Marks the node at w[j] - * - * @param {Array} w The array - * @param {Number} j The array index - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_mark = function (w, j) { - // mark w[j] - w[j] = cs_flip$$1(w [j]); - }; - - return cs_mark; - } - - var name$120 = 'cs_mark'; - var path$57 = 'sparse'; - var factory_1$130 = factory$131; - - var cs_mark = { - name: name$120, - path: path$57, - factory: factory_1$130 - }; - - function factory$132 (type, config, load) { - - var cs_flip$$1 = load(cs_flip); - - /** - * Flips the value if it is negative of returns the same value otherwise. - * - * @param {Number} i The value to flip - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_unflip = function (i) { - // flip the value if it is negative - return i < 0 ? cs_flip$$1(i) : i; - }; - - return cs_unflip; - } - - var name$121 = 'cs_unflip'; - var path$58 = 'sparse'; - var factory_1$131 = factory$132; - - var cs_unflip = { - name: name$121, - path: path$58, - factory: factory_1$131 - }; - - function factory$133 (type, config, load) { - - var cs_marked$$1 = load(cs_marked); - var cs_mark$$1 = load(cs_mark); - var cs_unflip$$1 = load(cs_unflip); - - /** - * Depth-first search computes the nonzero pattern xi of the directed graph G (Matrix) starting - * at nodes in B (see cs_reach()). - * - * @param {Number} j The starting node for the DFS algorithm - * @param {Matrix} g The G matrix to search, ptr array modified, then restored - * @param {Number} top Start index in stack xi[top..n-1] - * @param {Number} k The kth column in B - * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n - * The first n entries is the nonzero pattern, the last n entries is the stack - * @param {Array} pinv The inverse row permutation vector, must be null for L * x = b - * - * @return {Number} New value of top - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_dfs = function (j, g, top, xi, pinv) { - // g arrays - var index = g._index; - var ptr = g._ptr; - var size = g._size; - // columns - var n = size[1]; - // vars - var i, p, p2; - // initialize head - var head = 0; - // initialize the recursion stack - xi[0] = j; - // loop - while (head >= 0) { - // get j from the top of the recursion stack - j = xi[head]; - // apply permutation vector - var jnew = pinv ? pinv[j] : j; - // check node j is marked - if (!cs_marked$$1(ptr, j)) { - // mark node j as visited - cs_mark$$1(ptr, j); - // update stack (last n entries in xi) - xi[n + head] = jnew < 0 ? 0 : cs_unflip$$1(ptr[jnew]); - } - // node j done if no unvisited neighbors - var done = 1; - // examine all neighbors of j, stack (last n entries in xi) - for (p = xi[n + head], p2 = jnew < 0 ? 0 : cs_unflip$$1(ptr[jnew+1]); p < p2; p++) { - // consider neighbor node i - i = index[p]; - // check we have visited node i, skip it - if (cs_marked$$1(ptr, i)) - continue; - // pause depth-first search of node j, update stack (last n entries in xi) - xi[n + head] = p; - // start dfs at node i - xi[++head] = i; - // node j is not done - done = 0; - // break, to start dfs(i) - break; - } - // check depth-first search at node j is done - if (done) { - // remove j from the recursion stack - head--; - // and place in the output stack - xi[--top] = j; - } - } - return top; - }; - - return cs_dfs; - } - - var name$122 = 'cs_dfs'; - var path$59 = 'sparse'; - var factory_1$132 = factory$133; - - var cs_dfs = { - name: name$122, - path: path$59, - factory: factory_1$132 - }; - - function factory$134 (type, config, load) { - - var cs_dfs$$1 = load(cs_dfs); - var cs_marked$$1 = load(cs_marked); - var cs_mark$$1 = load(cs_mark); - - /** - * The cs_reach function computes X = Reach(B), where B is the nonzero pattern of the n-by-1 - * sparse column of vector b. The function returns the set of nodes reachable from any node in B. The - * nonzero pattern xi of the solution x to the sparse linear system Lx=b is given by X=Reach(B). - * - * @param {Matrix} g The G matrix - * @param {Matrix} b The B matrix - * @param {Number} k The kth column in B - * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n - * The first n entries is the nonzero pattern, the last n entries is the stack - * @param {Array} pinv The inverse row permutation vector - * - * @return {Number} The index for the nonzero pattern - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_reach = function (g, b, k, xi, pinv) { - // g arrays - var gptr = g._ptr; - var gsize = g._size; - // b arrays - var bindex = b._index; - var bptr = b._ptr; - // columns - var n = gsize[1]; - // vars - var p, p0, p1; - // initialize top - var top = n; - // loop column indeces in B - for (p0 = bptr[k], p1 = bptr[k + 1], p = p0; p < p1; p++) { - // node i - var i = bindex[p]; - // check node i is marked - if (!cs_marked$$1(gptr, i)) { - // start a dfs at unmarked node i - top = cs_dfs$$1(i, g, top, xi, pinv); - } - } - // loop columns from top -> n - 1 - for (p = top; p < n; p++) { - // restore G - cs_mark$$1(gptr, xi[p]); - } - return top; - }; - - return cs_reach; - } - - var name$123 = 'cs_reach'; - var path$60 = 'sparse'; - var factory_1$133 = factory$134; - - var cs_reach = { - name: name$123, - path: path$60, - factory: factory_1$133 - }; - - function factory$135 (type, config, load) { - - var divideScalar$$1 = load(divideScalar); - var multiply = load(multiply$1); - var subtract = load(subtract$1); - - var cs_reach$$1 = load(cs_reach); - - /** - * The function cs_spsolve() computes the solution to G * x = bk, where bk is the - * kth column of B. When lo is true, the function assumes G = L is lower triangular with the - * diagonal entry as the first entry in each column. When lo is true, the function assumes G = U - * is upper triangular with the diagonal entry as the last entry in each column. - * - * @param {Matrix} g The G matrix - * @param {Matrix} b The B matrix - * @param {Number} k The kth column in B - * @param {Array} xi The nonzero pattern xi[top] .. xi[n - 1], an array of size = 2 * n - * The first n entries is the nonzero pattern, the last n entries is the stack - * @param {Array} x The soluton to the linear system G * x = b - * @param {Array} pinv The inverse row permutation vector, must be null for L * x = b - * @param {boolean} lo The lower (true) upper triangular (false) flag - * - * @return {Number} The index for the nonzero pattern - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_spsolve = function (g, b, k, xi, x, pinv, lo) { - // g arrays - var gvalues = g._values; - var gindex = g._index; - var gptr = g._ptr; - var gsize = g._size; - // columns - var n = gsize[1]; - // b arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - // vars - var p, p0, p1, q; - // xi[top..n-1] = cs_reach(B(:,k)) - var top = cs_reach$$1(g, b, k, xi, pinv); - // clear x - for (p = top; p < n; p++) - x[xi[p]] = 0; - // scatter b - for (p0 = bptr[k], p1 = bptr[k + 1], p = p0; p < p1; p++) - x[bindex[p]] = bvalues[p]; - // loop columns - for (var px = top; px < n; px++) { - // x array index for px - var j = xi[px]; - // apply permutation vector (U x = b), j maps to column J of G - var J = pinv ? pinv[j] : j; - // check column J is empty - if (J < 0) - continue; - // column value indeces in G, p0 <= p < p1 - p0 = gptr[J]; - p1 = gptr[J + 1]; - // x(j) /= G(j,j) - x[j] = divideScalar$$1(x[j], gvalues[lo ? p0 : (p1 - 1)]); - // first entry L(j,j) - p = lo ? (p0 + 1) : p0; - q = lo ? (p1) : (p1 - 1); - // loop - for ( ; p < q ; p++) { - // row - var i = gindex[p]; - // x(i) -= G(i,j) * x(j) - x[i] = subtract(x[i], multiply(gvalues[p], x[j])); - } - } - // return top of stack - return top; - }; - - return cs_spsolve; - } - - var name$124 = 'cs_spsolve'; - var path$61 = 'sparse'; - var factory_1$134 = factory$135; - - var cs_spsolve = { - name: name$124, - path: path$61, - factory: factory_1$134 - }; - - function factory$136 (type, config, load) { - - var abs = load(abs$1); - var divideScalar$$1 = load(divideScalar); - var multiply = load(multiply$1); - - var larger$$1 = load(larger); - var largerEq = load(largerEq$1); - - var cs_spsolve$$1 = load(cs_spsolve); - - var SparseMatrix = type.SparseMatrix; - - /** - * Computes the numeric LU factorization of the sparse matrix A. Implements a Left-looking LU factorization - * algorithm that computes L and U one column at a tume. At the kth step, it access columns 1 to k-1 of L - * and column k of A. Given the fill-reducing column ordering q (see parameter s) computes L, U and pinv so - * L * U = A(p, q), where p is the inverse of pinv. - * - * @param {Matrix} m The A Matrix to factorize - * @param {Object} s The symbolic analysis from cs_sqr(). Provides the fill-reducing - * column ordering q - * @param {Number} tol Partial pivoting threshold (1 for partial pivoting) - * - * @return {Number} The numeric LU factorization of A or null - * - * Reference: http://faculty.cse.tamu.edu/davis/publications.html - */ - var cs_lu = function (m, s, tol) { - // validate input - if (!m) - return null; - // m arrays - var size = m._size; - // columns - var n = size[1]; - // symbolic analysis result - var q; - var lnz = 100; - var unz = 100; - // update symbolic analysis parameters - if (s) { - q = s.q; - lnz = s.lnz || lnz; - unz = s.unz || unz; - } - // L arrays - var lvalues = []; // (lnz) - var lindex = []; // (lnz); - var lptr = []; // (n + 1); - // L - var L = new SparseMatrix({ - values: lvalues, - index: lindex, - ptr: lptr, - size: [n, n] - }); - // U arrays - var uvalues = []; // (unz); - var uindex = []; // (unz); - var uptr = []; // (n + 1); - // U - var U = new SparseMatrix({ - values: uvalues, - index: uindex, - ptr: uptr, - size: [n, n] - }); - // inverse of permutation vector - var pinv = []; // (n); - // vars - var i, p; - // allocate arrays - var x = []; // (n); - var xi = []; // (2 * n); - // initialize variables - for (i = 0; i < n; i++) { - // clear workspace - x[i] = 0; - // no rows pivotal yet - pinv[i] = -1; - // no cols of L yet - lptr[i + 1] = 0; - } - // reset number of nonzero elements in L and U - lnz = 0; - unz = 0; - // compute L(:,k) and U(:,k) - for (var k = 0; k < n; k++) { - // update ptr - lptr[k] = lnz; - uptr[k] = unz; - // apply column permutations if needed - var col = q ? q[k] : k; - // solve triangular system, x = L\A(:,col) - var top = cs_spsolve$$1(L, m, col, xi, x, pinv, 1); - // find pivot - var ipiv = -1; - var a = -1; - // loop xi[] from top -> n - for (p = top; p < n; p++) { - // x[i] is nonzero - i = xi[p]; - // check row i is not yet pivotal - if (pinv[i] < 0) { - // absolute value of x[i] - var xabs = abs(x[i]); - // check absoulte value is greater than pivot value - if (larger$$1(xabs, a)) { - // largest pivot candidate so far - a = xabs; - ipiv = i; - } - } - else { - // x(i) is the entry U(pinv[i],k) - uindex[unz] = pinv[i]; - uvalues[unz++] = x[i]; - } - } - // validate we found a valid pivot - if (ipiv == -1 || a <= 0) - return null; - // update actual pivot column, give preference to diagonal value - if (pinv[col] < 0 && largerEq(abs(x[col]), multiply(a, tol))) - ipiv = col; - // the chosen pivot - var pivot = x[ipiv]; - // last entry in U(:,k) is U(k,k) - uindex[unz] = k; - uvalues[unz++] = pivot; - // ipiv is the kth pivot row - pinv[ipiv] = k; - // first entry in L(:,k) is L(k,k) = 1 - lindex[lnz] = ipiv; - lvalues[lnz++] = 1; - // L(k+1:n,k) = x / pivot - for (p = top; p < n; p++) { - // row - i = xi[p]; - // check x(i) is an entry in L(:,k) - if (pinv[i] < 0) { - // save unpermuted row in L - lindex[lnz] = i; - // scale pivot column - lvalues[lnz++] = divideScalar$$1(x[i], pivot); - } - // x[0..n-1] = 0 for next k - x[i] = 0; - } - } - // update ptr - lptr[n] = lnz; - uptr[n] = unz; - // fix row indices of L for final pinv - for (p = 0; p < lnz; p++) - lindex[p] = pinv[lindex[p]]; - // trim arrays - lvalues.splice(lnz, lvalues.length - lnz); - lindex.splice(lnz, lindex.length - lnz); - uvalues.splice(unz, uvalues.length - unz); - uindex.splice(unz, uindex.length - unz); - // return LU factor - return { - L: L, - U: U, - pinv: pinv - }; - }; - - return cs_lu; - } - - var name$125 = 'cs_lu'; - var path$62 = 'sparse'; - var factory_1$135 = factory$136; - - var cs_lu = { - name: name$125, - path: path$62, - factory: factory_1$135 - }; - - var number$5 = utils.number, - - isInteger$8 = number$5.isInteger; - - function factory$137 (type, config, load, typed) { - - var cs_sqr$$1 = load(cs_sqr); - var cs_lu$$1 = load(cs_lu); - - /** - * Calculate the Sparse Matrix LU decomposition with full pivoting. Sparse Matrix `A` is decomposed in two matrices (`L`, `U`) and two permutation vectors (`pinv`, `q`) where - * - * `P * A * Q = L * U` - * - * Syntax: - * - * math.slu(A, order, threshold); - * - * Examples: - * - * var A = math.sparse([[4,3], [6, 3]]) - * math.slu(A, 1, 0.001) - * // returns: - * // { - * // L: [[1, 0], [1.5, 1]] - * // U: [[4, 3], [0, -1.5]] - * // p: [0, 1] - * // q: [0, 1] - * // } - * - * See also: - * - * lup, lsolve, usolve, lusolve - * - * @param {SparseMatrix} A A two dimensional sparse matrix for which to get the LU decomposition. - * @param {Number} order The Symbolic Ordering and Analysis order: - * 0 - Natural ordering, no permutation vector q is returned - * 1 - Matrix must be square, symbolic ordering and analisis is performed on M = A + A' - * 2 - Symbolic ordering and analisis is performed on M = A' * A. Dense columns from A' are dropped, A recreated from A'. - * This is appropriatefor LU factorization of unsymmetric matrices. - * 3 - Symbolic ordering and analisis is performed on M = A' * A. This is best used for LU factorization is matrix M has no dense rows. - * A dense row is a row with more than 10*sqr(columns) entries. - * @param {Number} threshold Partial pivoting threshold (1 for partial pivoting) - * - * @return {Object} The lower triangular matrix, the upper triangular matrix and the permutation vectors. - */ - var slu = typed('slu', { - - 'SparseMatrix, number, number': function (a, order, threshold) { - // verify order - if (!isInteger$8(order) || order < 0 || order > 3) - throw new Error('Symbolic Ordering and Analysis order must be an integer number in the interval [0, 3]'); - // verify threshold - if (threshold < 0 || threshold > 1) - throw new Error('Partial pivoting threshold must be a number from 0 to 1'); - - // perform symbolic ordering and analysis - var s = cs_sqr$$1(order, a, false); - - // perform lu decomposition - var f = cs_lu$$1(a, s, threshold); - - // return decomposition - return { - L: f.L, - U: f.U, - p: f.pinv, - q: s.q, - toString: function () { - return 'L: ' + this.L.toString() + '\nU: ' + this.U.toString() + '\np: ' + this.p.toString() + (this.q ? '\nq: ' + this.q.toString() : '') + '\n'; - } - }; - } - }); - - return slu; - } - - var name$126 = 'slu'; - var factory_1$136 = factory$137; - - var slu$1 = { - name: name$126, - factory: factory_1$136 - }; - - var string$9 = utils.string; - var array$3 = utils.array; - - var isArray$3 = Array.isArray; - - function factory$138 (type) { - - var DenseMatrix = type.DenseMatrix; - - /** - * Validates matrix and column vector b for backward/forward substitution algorithms. - * - * @param {Matrix} m An N x N matrix - * @param {Array | Matrix} b A column vector - * @param {Boolean} copy Return a copy of vector b - * - * @return {DenseMatrix} Dense column vector b - */ - var solveValidation = function (m, b, copy) { - // matrix size - var size = m.size(); - // validate matrix dimensions - if (size.length !== 2) - throw new RangeError('Matrix must be two dimensional (size: ' + string$9.format(size) + ')'); - // rows & columns - var rows = size[0]; - var columns = size[1]; - // validate rows & columns - if (rows !== columns) - throw new RangeError('Matrix must be square (size: ' + string$9.format(size) + ')'); - // vars - var data, i, bdata; - // check b is matrix - if (type.isMatrix(b)) { - // matrix size - var msize = b.size(); - // vector - if (msize.length === 1) { - // check vector length - if (msize[0] !== rows) - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - // create data array - data = []; - // matrix data (DenseMatrix) - bdata = b._data; - // loop b data - for (i = 0; i < rows; i++) { - // row array - data[i] = [bdata[i]]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1], - datatype: b._datatype - }); - } - // two dimensions - if (msize.length === 2) { - // array must be a column vector - if (msize[0] !== rows || msize[1] !== 1) - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - // check matrix type - if (type.isDenseMatrix(b)) { - // check a copy is needed - if (copy) { - // create data array - data = []; - // matrix data (DenseMatrix) - bdata = b._data; - // loop b data - for (i = 0; i < rows; i++) { - // row array - data[i] = [bdata[i][0]]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1], - datatype: b._datatype - }); - } - // b is already a column vector - return b; - } - // create data array - data = []; - for (i = 0; i < rows; i++) - data[i] = [0]; - // sparse matrix arrays - var values = b._values; - var index = b._index; - var ptr = b._ptr; - // loop values in column 0 - for (var k1 = ptr[1], k = ptr[0]; k < k1; k++) { - // row - i = index[k]; - // add to data - data[i][0] = values[k]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1], - datatype: b._datatype - }); - } - // throw error - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - } - // check b is array - if (isArray$3(b)) { - // size - var asize = array$3.size(b); - // check matrix dimensions, vector - if (asize.length === 1) { - // check vector length - if (asize[0] !== rows) - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - // create data array - data = []; - // loop b - for (i = 0; i < rows; i++) { - // row array - data[i] = [b[i]]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1] - }); - } - if (asize.length === 2) { - // array must be a column vector - if (asize[0] !== rows || asize[1] !== 1) - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - // create data array - data = []; - // loop b data - for (i = 0; i < rows; i++) { - // row array - data[i] = [b[i][0]]; - } - // return Dense Matrix - return new DenseMatrix({ - data: data, - size: [rows, 1] - }); - } - // throw error - throw new RangeError('Dimension mismatch. Matrix columns must match vector length.'); - } - }; - - return solveValidation; - } - - var factory_1$137 = factory$138; - - var solveValidation = { - factory: factory_1$137 - }; - - function factory$139 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var divideScalar$$1 = load(divideScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var subtract = load(subtract$1); - var equalScalar$$1 = load(equalScalar); - - var solveValidation$$1 = load(solveValidation); - - var DenseMatrix = type.DenseMatrix; - - /** - * Solves the linear equation system by forwards substitution. Matrix must be a lower triangular matrix. - * - * `L * x = b` - * - * Syntax: - * - * math.lsolve(L, b); - * - * Examples: - * - * var a = [[-2, 3], [2, 1]]; - * var b = [11, 9]; - * var x = lsolve(a, b); // [[-5.5], [20]] - * - * See also: - * - * lup, slu, usolve, lusolve - * - * @param {Matrix, Array} L A N x N matrix or array (L) - * @param {Matrix, Array} b A column vector with the b values - * - * @return {DenseMatrix | Array} A column vector with the linear system solution (x) - */ - var lsolve = typed('lsolve', { - - 'SparseMatrix, Array | Matrix': function (m, b) { - // process matrix - return _sparseForwardSubstitution(m, b); - }, - - 'DenseMatrix, Array | Matrix': function (m, b) { - // process matrix - return _denseForwardSubstitution(m, b); - }, - - 'Array, Array | Matrix': function (a, b) { - // create dense matrix from array - var m = matrix$$1(a); - // use matrix implementation - var r = _denseForwardSubstitution(m, b); - // result - return r.valueOf(); - } - }); - - var _denseForwardSubstitution = function (m, b) { - // validate matrix and vector, return copy of column vector b - b = solveValidation$$1(m, b, true); - // column vector data - var bdata = b._data; - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // result - var x = []; - // data - var data = m._data; - // forward solve m * x = b, loop columns - for (var j = 0; j < columns; j++) { - // b[j] - var bj = bdata[j][0] || 0; - // x[j] - var xj; - // forward substitution (outer product) avoids inner looping when bj == 0 - if (!equalScalar$$1(bj, 0)) { - // value @ [j, j] - var vjj = data[j][j]; - // check vjj - if (equalScalar$$1(vjj, 0)) { - // system cannot be solved - throw new Error('Linear system cannot be solved since matrix is singular'); - } - // calculate xj - xj = divideScalar$$1(bj, vjj); - // loop rows - for (var i = j + 1; i < rows; i++) { - // update copy of b - bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, data[i][j]))]; - } - } - else { - // zero @ j - xj = 0; - } - // update x - x[j] = [xj]; - } - // return vector - return new DenseMatrix({ - data: x, - size: [rows, 1] - }); - }; - - var _sparseForwardSubstitution = function (m, b) { - // validate matrix and vector, return copy of column vector b - b = solveValidation$$1(m, b, true); - // column vector data - var bdata = b._data; - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // matrix arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // vars - var i, k; - // result - var x = []; - // forward solve m * x = b, loop columns - for (var j = 0; j < columns; j++) { - // b[j] - var bj = bdata[j][0] || 0; - // forward substitution (outer product) avoids inner looping when bj == 0 - if (!equalScalar$$1(bj, 0)) { - // value @ [j, j] - var vjj = 0; - // lower triangular matrix values & index (column j) - var jvalues = []; - var jindex = []; - // last index in column - var l = ptr[j + 1]; - // values in column, find value @ [j, j] - for (k = ptr[j]; k < l; k++) { - // row - i = index[k]; - // check row (rows are not sorted!) - if (i === j) { - // update vjj - vjj = values[k]; - } - else if (i > j) { - // store lower triangular - jvalues.push(values[k]); - jindex.push(i); - } - } - // at this point we must have a value @ [j, j] - if (equalScalar$$1(vjj, 0)) { - // system cannot be solved, there is no value @ [j, j] - throw new Error('Linear system cannot be solved since matrix is singular'); - } - // calculate xj - var xj = divideScalar$$1(bj, vjj); - // loop lower triangular - for (k = 0, l = jindex.length; k < l; k++) { - // row - i = jindex[k]; - // update copy of b - bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, jvalues[k]))]; - } - // update x - x[j] = [xj]; - } - else { - // update x - x[j] = [0]; - } - } - // return vector - return new DenseMatrix({ - data: x, - size: [rows, 1] - }); - }; - - return lsolve; - } - - var name$127 = 'lsolve'; - var factory_1$138 = factory$139; - - var lsolve$1 = { - name: name$127, - factory: factory_1$138 - }; - - function factory$140 () { - - /** - * Permutes a vector; x = P'b. In MATLAB notation, x(p)=b. - * - * @param {Array} p The permutation vector of length n. null value denotes identity - * @param {Array} b The input vector - * - * @return {Array} The output vector x = P'b - */ - var cs_ipvec = function (p, b, n) { - // vars - var k; - var n = b.length; - var x = []; - // check permutation vector was provided, p = null denotes identity - if (p) { - // loop vector - for (k = 0; k < n; k++) { - // apply permutation - x[p[k]] = b[k]; - } - } - else { - // loop vector - for (k = 0; k < n; k++) { - // x[i] = b[i] - x[k] = b[k]; - } - } - return x; - }; - - return cs_ipvec; - } - - var name$128 = 'cs_ipvec'; - var path$63 = 'sparse'; - var factory_1$139 = factory$140; - - var cs_ipvec = { - name: name$128, - path: path$63, - factory: factory_1$139 - }; - - function factory$141 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var divideScalar$$1 = load(divideScalar); - var multiplyScalar$$1 = load(multiplyScalar); - var subtract = load(subtract$1); - var equalScalar$$1 = load(equalScalar); - - var solveValidation$$1 = load(solveValidation); - - var DenseMatrix = type.DenseMatrix; - - /** - * Solves the linear equation system by backward substitution. Matrix must be an upper triangular matrix. - * - * `U * x = b` - * - * Syntax: - * - * math.usolve(U, b); - * - * Examples: - * - * var a = [[-2, 3], [2, 1]]; - * var b = [11, 9]; - * var x = usolve(a, b); // [[8], [9]] - * - * See also: - * - * lup, slu, usolve, lusolve - * - * @param {Matrix, Array} U A N x N matrix or array (U) - * @param {Matrix, Array} b A column vector with the b values - * - * @return {DenseMatrix | Array} A column vector with the linear system solution (x) - */ - var usolve = typed('usolve', { - - 'SparseMatrix, Array | Matrix': function (m, b) { - // process matrix - return _sparseBackwardSubstitution(m, b); - }, - - 'DenseMatrix, Array | Matrix': function (m, b) { - // process matrix - return _denseBackwardSubstitution(m, b); - }, - - 'Array, Array | Matrix': function (a, b) { - // create dense matrix from array - var m = matrix$$1(a); - // use matrix implementation - var r = _denseBackwardSubstitution(m, b); - // result - return r.valueOf(); - } - }); - - var _denseBackwardSubstitution = function (m, b) { - // validate matrix and vector, return copy of column vector b - b = solveValidation$$1(m, b, true); - // column vector data - var bdata = b._data; - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // result - var x = []; - // arrays - var data = m._data; - // backward solve m * x = b, loop columns (backwards) - for (var j = columns - 1; j >= 0 ; j--) { - // b[j] - var bj = bdata[j][0] || 0; - // x[j] - var xj; - // backward substitution (outer product) avoids inner looping when bj == 0 - if (!equalScalar$$1(bj, 0)) { - // value @ [j, j] - var vjj = data[j][j]; - // check vjj - if (equalScalar$$1(vjj, 0)) { - // system cannot be solved - throw new Error('Linear system cannot be solved since matrix is singular'); - } - // calculate xj - xj = divideScalar$$1(bj, vjj); - // loop rows - for (var i = j - 1; i >= 0; i--) { - // update copy of b - bdata[i] = [subtract(bdata[i][0] || 0, multiplyScalar$$1(xj, data[i][j]))]; - } - } - else { - // zero value @ j - xj = 0; - } - // update x - x[j] = [xj]; - } - // return column vector - return new DenseMatrix({ - data: x, - size: [rows, 1] - }); - }; - - var _sparseBackwardSubstitution = function (m, b) { - // validate matrix and vector, return copy of column vector b - b = solveValidation$$1(m, b, true); - // column vector data - var bdata = b._data; - // rows & columns - var rows = m._size[0]; - var columns = m._size[1]; - // matrix arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - // vars - var i, k; - // result - var x = []; - // backward solve m * x = b, loop columns (backwards) - for (var j = columns - 1; j >= 0 ; j--) { - // b[j] - var bj = bdata[j][0] || 0; - // backward substitution (outer product) avoids inner looping when bj == 0 - if (!equalScalar$$1(bj, 0)) { - // value @ [j, j] - var vjj = 0; - // upper triangular matrix values & index (column j) - var jvalues = []; - var jindex = []; - // first & last indeces in column - var f = ptr[j]; - var l = ptr[j + 1]; - // values in column, find value @ [j, j], loop backwards - for (k = l - 1; k >= f; k--) { - // row - i = index[k]; - // check row - if (i === j) { - // update vjj - vjj = values[k]; - } - else if (i < j) { - // store upper triangular - jvalues.push(values[k]); - jindex.push(i); - } - } - // at this point we must have a value @ [j, j] - if (equalScalar$$1(vjj, 0)) { - // system cannot be solved, there is no value @ [j, j] - throw new Error('Linear system cannot be solved since matrix is singular'); - } - // calculate xj - var xj = divideScalar$$1(bj, vjj); - // loop upper triangular - for (k = 0, l = jindex.length; k < l; k++) { - // row - i = jindex[k]; - // update copy of b - bdata[i] = [subtract(bdata[i][0], multiplyScalar$$1(xj, jvalues[k]))]; - } - // update x - x[j] = [xj]; - } - else { - // update x - x[j] = [0]; - } - } - // return vector - return new DenseMatrix({ - data: x, - size: [rows, 1] - }); - }; - - return usolve; - } - - var name$129 = 'usolve'; - var factory_1$140 = factory$141; - - var usolve$1 = { - name: name$129, - factory: factory_1$140 - }; - - var isArray$4 = Array.isArray; - - function factory$142 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var lup = load(lup$1); - var slu = load(slu$1); - var cs_ipvec$$1 = load(cs_ipvec); - - var solveValidation$$1 = load(solveValidation); - - var usolve = load(usolve$1); - var lsolve = load(lsolve$1); - - /** - * Solves the linear system `A * x = b` where `A` is an [n x n] matrix and `b` is a [n] column vector. - * - * Syntax: - * - * math.lusolve(A, b) // returns column vector with the solution to the linear system A * x = b - * math.lusolve(lup, b) // returns column vector with the solution to the linear system A * x = b, lup = math.lup(A) - * - * Examples: - * - * var m = [[1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 3, 0], [0, 0, 0, 4]]; - * - * var x = math.lusolve(m, [-1, -1, -1, -1]); // x = [[-1], [-0.5], [-1/3], [-0.25]] - * - * var f = math.lup(m); - * var x1 = math.lusolve(f, [-1, -1, -1, -1]); // x1 = [[-1], [-0.5], [-1/3], [-0.25]] - * var x2 = math.lusolve(f, [1, 2, 1, -1]); // x2 = [[1], [1], [1/3], [-0.25]] - * - * var a = [[-2, 3], [2, 1]]; - * var b = [11, 9]; - * var x = math.lusolve(a, b); // [[2], [5]] - * - * See also: - * - * lup, slu, lsolve, usolve - * - * @param {Matrix | Array | Object} A Invertible Matrix or the Matrix LU decomposition - * @param {Matrix | Array} b Column Vector - * @param {number} [order] The Symbolic Ordering and Analysis order, see slu for details. Matrix must be a SparseMatrix - * @param {Number} [threshold] Partial pivoting threshold (1 for partial pivoting), see slu for details. Matrix must be a SparseMatrix. - * - * @return {DenseMatrix | Array} Column vector with the solution to the linear system A * x = b - */ - var lusolve = typed('lusolve', { - - 'Array, Array | Matrix': function (a, b) { - // convert a to matrix - a = matrix$$1(a); - // matrix lup decomposition - var d = lup(a); - // solve - var x = _lusolve(d.L, d.U, d.p, null, b); - // convert result to array - return x.valueOf(); - }, - - 'DenseMatrix, Array | Matrix': function (a, b) { - // matrix lup decomposition - var d = lup(a); - // solve - return _lusolve(d.L, d.U, d.p, null, b); - }, - - 'SparseMatrix, Array | Matrix': function (a, b) { - // matrix lup decomposition - var d = lup(a); - // solve - return _lusolve(d.L, d.U, d.p, null, b); - }, - - 'SparseMatrix, Array | Matrix, number, number': function (a, b, order, threshold) { - // matrix lu decomposition - var d = slu(a, order, threshold); - // solve - return _lusolve(d.L, d.U, d.p, d.q, b); - }, - - 'Object, Array | Matrix': function (d, b) { - // solve - return _lusolve(d.L, d.U, d.p, d.q, b); - } - }); - - var _toMatrix = function (a) { - // check it is a matrix - if (type.isMatrix(a)) - return a; - // check array - if (isArray$4(a)) - return matrix$$1(a); - // throw - throw new TypeError('Invalid Matrix LU decomposition'); - }; - - var _lusolve = function (l, u, p, q, b) { - // verify L, U, P - l = _toMatrix(l); - u = _toMatrix(u); - // validate matrix and vector - b = solveValidation$$1(l, b, false); - // apply row permutations if needed (b is a DenseMatrix) - if (p) - b._data = cs_ipvec$$1(p, b._data); - // use forward substitution to resolve L * y = b - var y = lsolve(l, b); - // use backward substitution to resolve U * x = y - var x = usolve(u, y); - // apply column permutations if needed (x is a DenseMatrix) - if (q) - x._data = cs_ipvec$$1(q, x._data); - // return solution - return x; - }; - - return lusolve; - } - - var name$130 = 'lusolve'; - var factory_1$141 = factory$142; - - var lusolve$1 = { - name: name$130, - factory: factory_1$141 - }; - - var algebra = [ - derivative$1, - - // simplify - simplify$1, - - // polynomial - rationalize$1, - - - // decomposition - qr$1, - lup$1, - slu$1, - - // solver - lsolve$1, - lusolve$1, - usolve$1 - ]; - - function factory$143 (type, config, load, typed) { - /** - * Test whether a value is negative: smaller than zero. - * The function supports types `number`, `BigNumber`, `Fraction`, and `Unit`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isNegative(x) - * - * Examples: - * - * math.isNegative(3); // returns false - * math.isNegative(-2); // returns true - * math.isNegative(0); // returns false - * math.isNegative(-0); // returns false - * math.isNegative(math.bignumber(2)); // returns false - * math.isNegative(math.fraction(-2, 5)); // returns true - * math.isNegative('-2'); // returns true - * math.isNegative([2, 0, -3]'); // returns [false, false, true] - * - * See also: - * - * isNumeric, isPositive, isZero, isInteger - * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is larger than zero. - * Throws an error in case of an unknown data type. - */ - var isNegative = typed('isNegative', { - 'number': function (x) { - return x < 0; - }, - - 'BigNumber': function (x) { - return x.isNeg() && !x.isZero() && !x.isNaN(); - }, - - 'Fraction': function (x) { - return x.s < 0; // It's enough to decide on the sign - }, - - 'Unit': function (x) { - return isNegative(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, isNegative); - } - }); - - return isNegative; - } - - var name$131 = 'isNegative'; - var factory_1$142 = factory$143; - - var isNegative$1 = { - name: name$131, - factory: factory_1$142 - }; - - function factory$144 (type, config, load, typed) { - var unaryMinus = load(unaryMinus$1); - var isNegative = load(isNegative$1); - var matrix$$1 = load(matrix); - - /** - * Calculate the cubic root of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cbrt(x) - * math.cbrt(x, allRoots) - * - * Examples: - * - * math.cbrt(27); // returns 3 - * math.cube(3); // returns 27 - * math.cbrt(-64); // returns -4 - * math.cbrt(math.unit('27 m^3')); // returns Unit 3 m - * math.cbrt([27, 64, 125]); // returns [3, 4, 5] - * - * var x = math.complex('8i'); - * math.cbrt(x); // returns Complex 1.7320508075689 + i - * math.cbrt(x, true); // returns Matrix [ - * // 1.7320508075689 + i - * // -1.7320508075689 + i - * // -2i - * // ] - * - * See also: - * - * square, sqrt, cube - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x - * Value for which to calculate the cubic root. - * @param {boolean} [allRoots] Optional, false by default. Only applicable - * when `x` is a number or complex number. If true, all complex - * roots are returned, if false (default) the principal root is - * returned. - * @return {number | BigNumber | Complex | Unit | Array | Matrix} - * Returns the cubic root of `x` - */ - var cbrt = typed('cbrt', { - 'number': _cbrtNumber, - // note: signature 'number, boolean' is also supported, - // created by typed as it knows how to convert number to Complex - - 'Complex': _cbrtComplex, - - 'Complex, boolean': _cbrtComplex, - - 'BigNumber': function (x) { - return x.cbrt(); - }, - - 'Unit': _cbrtUnit, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since cbrt(0) = 0 - return deepMap(x, cbrt, true); - } - }); - - /** - * Calculate the cubic root for a complex number - * @param {Complex} x - * @param {boolean} [allRoots] If true, the function will return an array - * with all three roots. If false or undefined, - * the principal root is returned. - * @returns {Complex | Array. | Matrix.} Returns the cubic root(s) of x - * @private - */ - function _cbrtComplex(x, allRoots) { - // https://www.wikiwand.com/en/Cube_root#/Complex_numbers - - var arg_3 = x.arg() / 3; - var abs = x.abs(); - - // principal root: - var principal = new type.Complex(_cbrtNumber(abs), 0).mul( - new type.Complex(0, arg_3).exp()); - - if (allRoots) { - var all = [ - principal, - new type.Complex(_cbrtNumber(abs), 0).mul( - new type.Complex(0, arg_3 + Math.PI * 2 / 3).exp()), - new type.Complex(_cbrtNumber(abs), 0).mul( - new type.Complex(0, arg_3 - Math.PI * 2 / 3).exp()) - ]; - - return (config.matrix === 'Array') ? all : matrix$$1(all); - } - else { - return principal; - } - } - - /** - * Calculate the cubic root for a Unit - * @param {Unit} x - * @return {Unit} Returns the cubic root of x - * @private - */ - function _cbrtUnit(x) { - if(x.value && type.isComplex(x.value)) { - var result = x.clone(); - result.value = 1.0; - result = result.pow(1.0/3); // Compute the units - result.value = _cbrtComplex(x.value); // Compute the value - return result; - } - else { - var negate = isNegative(x.value); - if (negate) { - x.value = unaryMinus(x.value); - } - - // TODO: create a helper function for this - var third; - if (type.isBigNumber(x.value)) { - third = new type.BigNumber(1).div(3); - } - else if (type.isFraction(x.value)) { - third = new type.Fraction(1, 3); - } - else { - third = 1/3; - } - - var result = x.pow(third); - - if (negate) { - result.value = unaryMinus(result.value); - } - - return result; - } - } - - cbrt.toTex = {1: '\\sqrt[3]{${args[0]}}'}; - - return cbrt; - } - - /** - * Calculate cbrt for a number - * - * Code from es6-shim.js: - * https://github.com/paulmillr/es6-shim/blob/master/es6-shim.js#L1564-L1577 - * - * @param {number} x - * @returns {number | Complex} Returns the cubic root of x - * @private - */ - var _cbrtNumber = Math.cbrt || function (x) { - if (x === 0) { - return x; - } - - var negate = x < 0; - var result; - if (negate) { - x = -x; - } - - if (isFinite(x)) { - result = Math.exp(Math.log(x) / 3); - // from http://en.wikipedia.org/wiki/Cube_root#Numerical_methods - result = (x / (result * result) + (2 * result)) / 3; - } else { - result = x; - } - - return negate ? -result : result; - }; - - var name$132 = 'cbrt'; - var factory_1$143 = factory$144; - - var cbrt$1 = { - name: name$132, - factory: factory_1$143 - }; - - function factory$145 (type, config, load, typed) { - /** - * Round a value towards plus infinity - * If `x` is complex, both real and imaginary part are rounded towards plus infinity. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.ceil(x) - * - * Examples: - * - * math.ceil(3.2); // returns number 4 - * math.ceil(3.8); // returns number 4 - * math.ceil(-4.2); // returns number -4 - * math.ceil(-4.7); // returns number -4 - * - * var c = math.complex(3.2, -2.7); - * math.ceil(c); // returns Complex 4 - 2i - * - * math.ceil([3.2, 3.8, -4.7]); // returns Array [4, 4, -4] - * - * See also: - * - * floor, fix, round - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded - * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value - */ - var ceil = typed('ceil', { - 'number': Math.ceil, - - 'Complex': function (x) { - return x.ceil(); - }, - - 'BigNumber': function (x) { - return x.ceil(); - }, - - 'Fraction': function (x) { - return x.ceil(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since ceil(0) = 0 - return deepMap(x, ceil, true); - } - }); - - ceil.toTex = {1: '\\left\\lceil${args[0]}\\right\\rceil'}; - - return ceil; - } - - var name$133 = 'ceil'; - var factory_1$144 = factory$145; - - var ceil$1 = { - name: name$133, - factory: factory_1$144 - }; - - function factory$146 (type, config, load, typed) { - - /** - * Compute the cube of a value, `x * x * x`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cube(x) - * - * Examples: - * - * math.cube(2); // returns number 8 - * math.pow(2, 3); // returns number 8 - * math.cube(4); // returns number 64 - * 4 * 4 * 4; // returns number 64 - * - * math.cube([1, 2, 3, 4]); // returns Array [1, 8, 27, 64] - * - * See also: - * - * multiply, square, pow, cbrt - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x Number for which to calculate the cube - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} Cube of x - */ - var cube = typed('cube', { - 'number': function (x) { - return x * x * x; - }, - - 'Complex': function (x) { - return x.mul(x).mul(x); // Is faster than pow(x, 3) - }, - - 'BigNumber': function (x) { - return x.times(x).times(x); - }, - - 'Fraction': function (x) { - return x.pow(3); // Is faster than mul()mul()mul() - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since cube(0) = 0 - return deepMap(x, cube, true); - }, - - 'Unit': function(x) { - return x.pow(3); - } - }); - - cube.toTex = {1: '\\left(${args[0]}\\right)^3'}; - - return cube; - } - - var name$134 = 'cube'; - var factory_1$145 = factory$146; - - var cube$1 = { - name: name$134, - factory: factory_1$145 - }; - - function factory$147 (type, config, load, typed) { - - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; - - /** - * Iterates over SparseMatrix nonzero items and invokes the callback function f(Dij, Sij). - * Callback function invoked NNZ times (number of nonzero items in SparseMatrix). - * - * - * ┌ f(Dij, Sij) ; S(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} denseMatrix The DenseMatrix instance (D) - * @param {Matrix} sparseMatrix The SparseMatrix instance (S) - * @param {Function} callback The f(Dij,Sij) operation to invoke, where Dij = DenseMatrix(i,j) and Sij = SparseMatrix(i,j) - * @param {boolean} inverse A true value indicates callback should be invoked f(Sij,Dij) - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97477571 - */ - var algorithm02 = function (denseMatrix, sparseMatrix, callback, inverse) { - // dense matrix arrays - var adata = denseMatrix._data; - var asize = denseMatrix._size; - var adt = denseMatrix._datatype; - // sparse matrix arrays - var bvalues = sparseMatrix._values; - var bindex = sparseMatrix._index; - var bptr = sparseMatrix._ptr; - var bsize = sparseMatrix._size; - var bdt = sparseMatrix._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // sparse matrix cannot be a Pattern matrix - if (!bvalues) - throw new Error('Cannot perform operation on Dense Matrix and Pattern Sparse Matrix'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result (SparseMatrix) - var cvalues = []; - var cindex = []; - var cptr = []; - - // loop columns in b - for (var j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // values in column j - for (var k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - var i = bindex[k]; - // update C(i,j) - var cij = inverse ? cf(bvalues[k], adata[i][j]) : cf(adata[i][j], bvalues[k]); - // check for nonzero - if (!eq(cij, zero)) { - // push i & v - cindex.push(i); - cvalues.push(cij); - } - } - } - // update cptr - cptr[columns] = cindex.length; - - // return sparse matrix - return new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - }; - - return algorithm02; - } - - var name$135 = 'algorithm02'; - var factory_1$146 = factory$147; - - var algorithm02 = { - name: name$135, - factory: factory_1$146 - }; - - function factory$148 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var divideScalar$$1 = load(divideScalar); - var latex$$1 = latex; - - var algorithm02$$1 = load(algorithm02); - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Divide two matrices element wise. The function accepts both matrices and - * scalar values. - * - * Syntax: - * - * math.dotDivide(x, y) - * - * Examples: - * - * math.dotDivide(2, 4); // returns 0.5 - * - * a = [[9, 5], [6, 1]]; - * b = [[3, 2], [5, 2]]; - * - * math.dotDivide(a, b); // returns [[3, 2.5], [1.2, 0.5]] - * math.divide(a, b); // returns [[1.75, 0.75], [-1.75, 2.25]] - * - * See also: - * - * divide, multiply, dotMultiply - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Numerator - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Denominator - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Quotient, `x ./ y` - */ - var dotDivide = typed('dotDivide', { - - 'any, any': divideScalar$$1, - - 'SparseMatrix, SparseMatrix': function (x, y) { - return algorithm07$$1(x, y, divideScalar$$1, false); - }, - - 'SparseMatrix, DenseMatrix': function (x, y) { - return algorithm02$$1(y, x, divideScalar$$1, true); - }, - - 'DenseMatrix, SparseMatrix': function (x, y) { - return algorithm03$$1(x, y, divideScalar$$1, false); - }, - - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, divideScalar$$1); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return dotDivide(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return dotDivide(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return dotDivide(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, divideScalar$$1, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, divideScalar$$1, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, divideScalar$$1, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, divideScalar$$1, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, divideScalar$$1, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, divideScalar$$1, true).valueOf(); - } - }); - - dotDivide.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['dotDivide'] + '${args[1]}\\right)' - }; - - return dotDivide; - } - - var name$136 = 'dotDivide'; - var factory_1$147 = factory$148; - - var dotDivide$1 = { - name: name$136, - factory: factory_1$147 - }; - - function factory$149 (type, config, load, typed) { - - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; - - /** - * Iterates over SparseMatrix A and invokes the callback function f(Aij, Bij). - * Callback function invoked NZA times, number of nonzero elements in A. - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm09 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = avalues && bvalues ? [] : undefined; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - - // workspaces - var x = cvalues ? [] : undefined; - // marks indicating we have a value in x for a given column - var w = []; - - // vars - var i, j, k, k0, k1; - - // loop columns - for (j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // column mark - var mark = j + 1; - // check we need to process values - if (x) { - // loop B(:,j) - for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - i = bindex[k]; - // update workspace - w[i] = mark; - x[i] = bvalues[k]; - } - } - // loop A(:,j) - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // check we need to process values - if (x) { - // b value @ i,j - var vb = w[i] === mark ? x[i] : zero; - // invoke f - var vc = cf(avalues[k], vb); - // check zero value - if (!eq(vc, zero)) { - // push index - cindex.push(i); - // push value - cvalues.push(vc); - } - } - else { - // push index - cindex.push(i); - } - } - } - // update cptr - cptr[columns] = cindex.length; - - // return sparse matrix - return c; - }; - - return algorithm09; - } - - var name$137 = 'algorithm09'; - var factory_1$148 = factory$149; - - var algorithm09 = { - name: name$137, - factory: factory_1$148 - }; - - function factory$150 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var multiplyScalar$$1 = load(multiplyScalar); - var latex$$1 = latex; - - var algorithm02$$1 = load(algorithm02); - var algorithm09$$1 = load(algorithm09); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Multiply two matrices element wise. The function accepts both matrices and - * scalar values. - * - * Syntax: - * - * math.dotMultiply(x, y) - * - * Examples: - * - * math.dotMultiply(2, 4); // returns 8 - * - * a = [[9, 5], [6, 1]]; - * b = [[3, 2], [5, 2]]; - * - * math.dotMultiply(a, b); // returns [[27, 10], [30, 2]] - * math.multiply(a, b); // returns [[52, 28], [23, 14]] - * - * See also: - * - * multiply, divide, dotDivide - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x Left hand value - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Right hand value - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} Multiplication of `x` and `y` - */ - var dotMultiply = typed('dotMultiply', { - - 'any, any': multiplyScalar$$1, - - 'SparseMatrix, SparseMatrix': function (x, y) { - return algorithm09$$1(x, y, multiplyScalar$$1, false); - }, - - 'SparseMatrix, DenseMatrix': function (x, y) { - return algorithm02$$1(y, x, multiplyScalar$$1, true); - }, - - 'DenseMatrix, SparseMatrix': function (x, y) { - return algorithm02$$1(x, y, multiplyScalar$$1, false); - }, - - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, multiplyScalar$$1); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return dotMultiply(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return dotMultiply(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return dotMultiply(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, multiplyScalar$$1, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, multiplyScalar$$1, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm11$$1(y, x, multiplyScalar$$1, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, multiplyScalar$$1, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, multiplyScalar$$1, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, multiplyScalar$$1, true).valueOf(); - } - }); - - dotMultiply.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['dotMultiply'] + '${args[1]}\\right)' - }; - - return dotMultiply; - } - - var name$138 = 'dotMultiply'; - var factory_1$149 = factory$150; - - var dotMultiply$1 = { - name: name$138, - factory: factory_1$149 - }; - - function factory$151 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var pow = load(pow$1); - var latex$$1 = latex; - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Calculates the power of x to y element wise. - * - * Syntax: - * - * math.dotPow(x, y) - * - * Examples: - * - * math.dotPow(2, 3); // returns number 8 - * - * var a = [[1, 2], [4, 3]]; - * math.dotPow(a, 2); // returns Array [[1, 4], [16, 9]] - * math.pow(a, 2); // returns Array [[9, 8], [16, 17]] - * - * See also: - * - * pow, sqrt, multiply - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x The base - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y The exponent - * @return {number | BigNumber | Complex | Unit | Array | Matrix} The value of `x` to the power `y` - */ - var dotPow = typed('dotPow', { - - 'any, any': pow, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, pow, false); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, pow, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, pow, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, pow); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return dotPow(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return dotPow(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return dotPow(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, dotPow, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, dotPow, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, dotPow, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, dotPow, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, dotPow, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, dotPow, true).valueOf(); - } - }); - - dotPow.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['dotPow'] + '${args[1]}\\right)' - }; - - return dotPow; - } - - var name$139 = 'dotPow'; - var factory_1$150 = factory$151; - - var dotPow$1 = { - name: name$139, - factory: factory_1$150 - }; - - function factory$152 (type, config, load, typed) { - /** - * Calculate the exponent of a value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.exp(x) - * - * Examples: - * - * math.exp(2); // returns number 7.3890560989306495 - * math.pow(math.e, 2); // returns number 7.3890560989306495 - * math.log(math.exp(2)); // returns number 2 - * - * math.exp([1, 2, 3]); - * // returns Array [ - * // 2.718281828459045, - * // 7.3890560989306495, - * // 20.085536923187668 - * // ] - * - * See also: - * - * expm1, log, pow - * - * @param {number | BigNumber | Complex | Array | Matrix} x A number or matrix to exponentiate - * @return {number | BigNumber | Complex | Array | Matrix} Exponent of `x` - */ - var exp = typed('exp', { - 'number': Math.exp, - - 'Complex': function (x) { - return x.exp(); - }, - - 'BigNumber': function (x) { - return x.exp(); - }, - - 'Array | Matrix': function (x) { - // TODO: exp(sparse) should return a dense matrix since exp(0)==1 - return deepMap(x, exp); - } - }); - - exp.toTex = {1: '\\exp\\left(${args[0]}\\right)'}; - - return exp; - } - - var name$140 = 'exp'; - var factory_1$151 = factory$152; - - var exp$1 = { - name: name$140, - factory: factory_1$151 - }; - - function factory$153 (type, config, load, typed) { - var latex$$1 = latex; - - /** - * Calculate the value of subtracting 1 from the exponential value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.expm1(x) - * - * Examples: - * - * math.expm1(2); // returns number 6.38905609893065 - * math.pow(math.e, 2) - 1; // returns number 6.3890560989306495 - * math.log(math.expm1(2) + 1); // returns number 2 - * - * math.expm1([1, 2, 3]); - * // returns Array [ - * // 1.718281828459045, - * // 6.3890560989306495, - * // 19.085536923187668 - * // ] - * - * See also: - * - * exp, log, pow - * - * @param {number | BigNumber | Complex | Array | Matrix} x A number or matrix to apply expm1 - * @return {number | BigNumber | Complex | Array | Matrix} Exponent of `x` - */ - var expm1 = typed('expm1', { - 'number': Math.expm1 || _expm1, - - 'Complex': function (x) { - var r = Math.exp(x.re); - return new type.Complex( - r * Math.cos(x.im) - 1, - r * Math.sin(x.im) - ); - }, - - 'BigNumber': function (x) { - return x.exp().minus(1); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, expm1); - } - }); - - /** - * Calculates exponentiation minus 1. - * @param {number} x - * @return {number} res - * @private - */ - function _expm1(x) { - return (x >= 2e-4 || x <= -2e-4) - ? Math.exp(x) - 1 - : x + x*x/2 + x*x*x/6; - } - - expm1.toTex = '\\left(e' + latex$$1.operators['pow'] + '{${args[0]}}-1\\right)'; - - return expm1; - } - - var name$141 = 'expm1'; - var factory_1$152 = factory$153; - - var expm1$1 = { - name: name$141, - factory: factory_1$152 - }; - - function factory$154 (type, config, load, typed) { - /** - * Round a value towards zero. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.fix(x) - * - * Examples: - * - * math.fix(3.2); // returns number 3 - * math.fix(3.8); // returns number 3 - * math.fix(-4.2); // returns number -4 - * math.fix(-4.7); // returns number -4 - * - * var c = math.complex(3.2, -2.7); - * math.fix(c); // returns Complex 3 - 2i - * - * math.fix([3.2, 3.8, -4.7]); // returns Array [3, 3, -4] - * - * See also: - * - * ceil, floor, round - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded - * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value - */ - var fix = typed('fix', { - 'number': function (x) { - return (x > 0) ? Math.floor(x) : Math.ceil(x); - }, - - 'Complex': function (x) { - return new type.Complex( - (x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re), - (x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im) - ); - }, - - 'BigNumber': function (x) { - return x.isNegative() ? x.ceil() : x.floor(); - }, - - 'Fraction': function (x) { - return x.s < 0 ? x.ceil() : x.floor(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since fix(0) = 0 - return deepMap(x, fix, true); - } - }); - - fix.toTex = {1: '\\mathrm{${name}}\\left(${args[0]}\\right)'}; - - return fix; - } - - var name$142 = 'fix'; - var factory_1$153 = factory$154; - - var fix$1 = { - name: name$142, - factory: factory_1$153 - }; - - function factory$155 (type, config, load, typed) { - /** - * Round a value towards minus infinity. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.floor(x) - * - * Examples: - * - * math.floor(3.2); // returns number 3 - * math.floor(3.8); // returns number 3 - * math.floor(-4.2); // returns number -5 - * math.floor(-4.7); // returns number -5 - * - * var c = math.complex(3.2, -2.7); - * math.floor(c); // returns Complex 3 - 3i - * - * math.floor([3.2, 3.8, -4.7]); // returns Array [3, 3, -5] - * - * See also: - * - * ceil, fix, round - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded - * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value - */ - var floor = typed('floor', { - 'number': Math.floor, - - 'Complex': function (x) { - return x.floor(); - }, - - 'BigNumber': function (x) { - return x.floor(); - }, - - 'Fraction': function (x) { - return x.floor(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since floor(0) = 0 - return deepMap(x, floor, true); - } - }); - - floor.toTex = {1: '\\left\\lfloor${args[0]}\\right\\rfloor'}; - - return floor; - } - - var name$143 = 'floor'; - var factory_1$154 = factory$155; - - var floor$1 = { - name: name$143, - factory: factory_1$154 - }; - - var isInteger$9 = number.isInteger; - - function factory$156 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm01$$1 = load(algorithm01); - var algorithm04$$1 = load(algorithm04); - var algorithm10$$1 = load(algorithm10); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Calculate the greatest common divisor for two or more values or arrays. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.gcd(a, b) - * math.gcd(a, b, c, ...) - * - * Examples: - * - * math.gcd(8, 12); // returns 4 - * math.gcd(-4, 6); // returns 2 - * math.gcd(25, 15, -10); // returns 5 - * - * math.gcd([8, -4], [12, 6]); // returns [4, 2] - * - * See also: - * - * lcm, xgcd - * - * @param {... number | BigNumber | Fraction | Array | Matrix} args Two or more integer numbers - * @return {number | BigNumber | Fraction | Array | Matrix} The greatest common divisor - */ - var gcd = typed('gcd', { - - 'number, number': _gcd, - - 'BigNumber, BigNumber': _gcdBigNumber, - - 'Fraction, Fraction': function (x, y) { - return x.gcd(y); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm04$$1(x, y, gcd); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm01$$1(y, x, gcd, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, gcd, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, gcd); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return gcd(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return gcd(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return gcd(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm10$$1(x, y, gcd, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, gcd, false); - }, - - 'number | BigNumber, SparseMatrix': function (x, y) { - return algorithm10$$1(y, x, gcd, true); - }, - - 'number | BigNumber, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, gcd, true); - }, - - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, gcd, false).valueOf(); - }, - - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, gcd, true).valueOf(); - }, - - // TODO: need a smarter notation here - 'Array | Matrix | number | BigNumber, Array | Matrix | number | BigNumber, ...Array | Matrix | number | BigNumber': function (a, b, args) { - var res = gcd(a, b); - for (var i = 0; i < args.length; i++) { - res = gcd(res, args[i]); - } - return res; - } - }); - - gcd.toTex = '\\gcd\\left(${args}\\right)'; - - return gcd; - - /** - * Calculate gcd for BigNumbers - * @param {BigNumber} a - * @param {BigNumber} b - * @returns {BigNumber} Returns greatest common denominator of a and b - * @private - */ - function _gcdBigNumber(a, b) { - if (!a.isInt() || !b.isInt()) { - throw new Error('Parameters in function gcd must be integer numbers'); - } - - // http://en.wikipedia.org/wiki/Euclidean_algorithm - var zero = new type.BigNumber(0); - while (!b.isZero()) { - var r = a.mod(b); - a = b; - b = r; - } - return a.lt(zero) ? a.neg() : a; - } - } - - /** - * Calculate gcd for numbers - * @param {number} a - * @param {number} b - * @returns {number} Returns the greatest common denominator of a and b - * @private - */ - function _gcd(a, b) { - if (!isInteger$9(a) || !isInteger$9(b)) { - throw new Error('Parameters in function gcd must be integer numbers'); - } - - // http://en.wikipedia.org/wiki/Euclidean_algorithm - var r; - while (b != 0) { - r = a % b; - a = b; - b = r; - } - return (a < 0) ? -a : a; - } - - var name$144 = 'gcd'; - var factory_1$155 = factory$156; - - var gcd$1 = { - name: name$144, - factory: factory_1$155 - }; - - var flatten$2 = array.flatten; - - function factory$157 (type, config, load, typed) { - var abs = load(abs$1); - var add = load(addScalar); - var divide = load(divideScalar); - var multiply = load(multiplyScalar); - var sqrt = load(sqrt$1); - var smaller$$1 = load(smaller); - var isPositive = load(isPositive$1); - - /** - * Calculate the hypotenusa of a list with values. The hypotenusa is defined as: - * - * hypot(a, b, c, ...) = sqrt(a^2 + b^2 + c^2 + ...) - * - * For matrix input, the hypotenusa is calculated for all values in the matrix. - * - * Syntax: - * - * math.hypot(a, b, ...) - * math.hypot([a, b, c, ...]) - * - * Examples: - * - * math.hypot(3, 4); // 5 - * math.hypot(3, 4, 5); // 7.0710678118654755 - * math.hypot([3, 4, 5]); // 7.0710678118654755 - * math.hypot(-2); // 2 - * - * See also: - * - * abs, norm - * - * @param {... number | BigNumber | Array | Matrix} args A list with numeric values or an Array or Matrix. - * Matrix and Array input is flattened and returns a - * single number for the whole matrix. - * @return {number | BigNumber} Returns the hypothenusa of the input values. - */ - var hypot = typed('hypot', { - '... number | BigNumber': _hypot, - - 'Array': function (x) { - return hypot.apply(hypot, flatten$2(x)); - }, - - 'Matrix': function (x) { - return hypot.apply(hypot, flatten$2(x.toArray())); - } - }); - - /** - * Calculate the hypotenusa for an Array with values - * @param {Array.} args - * @return {number | BigNumber} Returns the result - * @private - */ - function _hypot (args) { - // code based on `hypot` from es6-shim: - // https://github.com/paulmillr/es6-shim/blob/master/es6-shim.js#L1619-L1633 - var result = 0; - var largest = 0; - - for (var i = 0; i < args.length; i++) { - var value = abs(args[i]); - if (smaller$$1(largest, value)) { - result = multiply(result, multiply(divide(largest, value), divide(largest, value))); - result = add(result, 1); - largest = value; - } else { - result = add(result, isPositive(value) ? multiply(divide(value, largest), divide(value, largest)) : value); - } - } - - return multiply(largest, sqrt(result)); - } - - hypot.toTex = '\\hypot\\left(${args}\\right)'; - - return hypot; - } - - var name$145 = 'hypot'; - var factory_1$156 = factory$157; - - var hypot$1 = { - name: name$145, - factory: factory_1$156 - }; - - var scatter = function scatter(a, j, w, x, u, mark, c, f, inverse, update, value) { - // a arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - // c arrays - var cindex = c._index; - - // vars - var k, k0, k1, i; - - // check we need to process values (pattern matrix) - if (x) { - // values in j - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // check value exists in current j - if (w[i] !== mark) { - // i is new entry in j - w[i] = mark; - // add i to pattern of C - cindex.push(i); - // x(i) = A, check we need to call function this time - if (update) { - // copy value to workspace calling callback function - x[i] = inverse ? f(avalues[k], value) : f(value, avalues[k]); - // function was called on current row - u[i] = mark; - } - else { - // copy value to workspace - x[i] = avalues[k]; - } - } - else { - // i exists in C already - x[i] = inverse ? f(avalues[k], x[i]) : f(x[i], avalues[k]); - // function was called on current row - u[i] = mark; - } - } - } - else { - // values in j - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // check value exists in current j - if (w[i] !== mark) { - // i is new entry in j - w[i] = mark; - // add i to pattern of C - cindex.push(i); - } - else { - // indicate function was called on current row - u[i] = mark; - } - } - } - }; - - function factory$158 (type, config, load, typed) { - - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; - - /** - * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). - * Callback function invoked (Anz U Bnz) times, where Anz and Bnz are the nonzero elements in both matrices. - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 - * C(i,j) = ┤ - * └ 0 ; otherwise - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm06 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = avalues && bvalues ? [] : undefined; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - - // workspaces - var x = cvalues ? [] : undefined; - // marks indicating we have a value in x for a given column - var w = []; - // marks indicating value in a given row has been updated - var u = []; - - // loop columns - for (var j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // columns mark - var mark = j + 1; - // scatter the values of A(:,j) into workspace - scatter(a, j, w, x, u, mark, c, cf); - // scatter the values of B(:,j) into workspace - scatter(b, j, w, x, u, mark, c, cf); - // check we need to process values (non pattern matrix) - if (x) { - // initialize first index in j - var k = cptr[j]; - // loop index in j - while (k < cindex.length) { - // row - var i = cindex[k]; - // check function was invoked on current row (Aij !=0 && Bij != 0) - if (u[i] === mark) { - // value @ i - var v = x[i]; - // check for zero value - if (!eq(v, zero)) { - // push value - cvalues.push(v); - // increment pointer - k++; - } - else { - // remove value @ i, do not increment pointer - cindex.splice(k, 1); - } - } - else { - // remove value @ i, do not increment pointer - cindex.splice(k, 1); - } - } - } - else { - // initialize first index in j - var p = cptr[j]; - // loop index in j - while (p < cindex.length) { - // row - var r = cindex[p]; - // check function was invoked on current row (Aij !=0 && Bij != 0) - if (u[r] !== mark) { - // remove value @ i, do not increment pointer - cindex.splice(p, 1); - } - else { - // increment pointer - p++; - } - } - } - } - // update cptr - cptr[columns] = cindex.length; - - // return sparse matrix - return c; - }; - - return algorithm06; - } - - var name$146 = 'algorithm06'; - var factory_1$157 = factory$158; - - var algorithm06 = { - name: name$146, - factory: factory_1$157 - }; - - var isInteger$10 = number.isInteger; - - function factory$159 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm02$$1 = load(algorithm02); - var algorithm06$$1 = load(algorithm06); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Calculate the least common multiple for two or more values or arrays. - * - * lcm is defined as: - * - * lcm(a, b) = abs(a * b) / gcd(a, b) - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.lcm(a, b) - * math.lcm(a, b, c, ...) - * - * Examples: - * - * math.lcm(4, 6); // returns 12 - * math.lcm(6, 21); // returns 42 - * math.lcm(6, 21, 5); // returns 210 - * - * math.lcm([4, 6], [6, 21]); // returns [12, 42] - * - * See also: - * - * gcd, xgcd - * - * @param {... number | BigNumber | Array | Matrix} args Two or more integer numbers - * @return {number | BigNumber | Array | Matrix} The least common multiple - */ - var lcm = typed('lcm', { - 'number, number': _lcm, - - 'BigNumber, BigNumber': _lcmBigNumber, - - 'Fraction, Fraction': function (x, y) { - - return x.lcm(y); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm06$$1(x, y, lcm); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, lcm, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm02$$1(x, y, lcm, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, lcm); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return lcm(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return lcm(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return lcm(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm11$$1(x, y, lcm, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, lcm, false); - }, - - 'number | BigNumber, SparseMatrix': function (x, y) { - return algorithm11$$1(y, x, lcm, true); - }, - - 'number | BigNumber, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, lcm, true); - }, - - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, lcm, false).valueOf(); - }, - - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, lcm, true).valueOf(); - }, - - // TODO: need a smarter notation here - 'Array | Matrix | number | BigNumber, Array | Matrix | number | BigNumber, ...Array | Matrix | number | BigNumber': function (a, b, args) { - var res = lcm(a, b); - for (var i = 0; i < args.length; i++) { - res = lcm(res, args[i]); - } - return res; - } - }); - - lcm.toTex = undefined; // use default template - - return lcm; - - /** - * Calculate lcm for two BigNumbers - * @param {BigNumber} a - * @param {BigNumber} b - * @returns {BigNumber} Returns the least common multiple of a and b - * @private - */ - function _lcmBigNumber(a, b) { - if (!a.isInt() || !b.isInt()) { - throw new Error('Parameters in function lcm must be integer numbers'); - } - - if (a.isZero() || b.isZero()) { - return new type.BigNumber(0); - } - - // http://en.wikipedia.org/wiki/Euclidean_algorithm - // evaluate lcm here inline to reduce overhead - var prod = a.times(b); - while (!b.isZero()) { - var t = b; - b = a.mod(t); - a = t; - } - return prod.div(a).abs(); - } - } - - /** - * Calculate lcm for two numbers - * @param {number} a - * @param {number} b - * @returns {number} Returns the least common multiple of a and b - * @private - */ - function _lcm (a, b) { - if (!isInteger$10(a) || !isInteger$10(b)) { - throw new Error('Parameters in function lcm must be integer numbers'); - } - - if (a == 0 || b == 0) { - return 0; - } - - // http://en.wikipedia.org/wiki/Euclidean_algorithm - // evaluate lcm here inline to reduce overhead - var t; - var prod = a * b; - while (b != 0) { - t = b; - b = a % t; - a = t; - } - return Math.abs(prod / a); - } - - var name$147 = 'lcm'; - var factory_1$158 = factory$159; - - var lcm$1 = { - name: name$147, - factory: factory_1$158 - }; - - function factory$160 (type, config, load, typed) { - var divideScalar$$1 = load(divideScalar); - - /** - * Calculate the logarithm of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.log(x) - * math.log(x, base) - * - * Examples: - * - * math.log(3.5); // returns 1.252762968495368 - * math.exp(math.log(2.4)); // returns 2.4 - * - * math.pow(10, 4); // returns 10000 - * math.log(10000, 10); // returns 4 - * math.log(10000) / math.log(10); // returns 4 - * - * math.log(1024, 2); // returns 10 - * math.pow(2, 10); // returns 1024 - * - * See also: - * - * exp, log2, log10, log1p - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the logarithm. - * @param {number | BigNumber | Complex} [base=e] - * Optional base for the logarithm. If not provided, the natural - * logarithm of `x` is calculated. - * @return {number | BigNumber | Complex | Array | Matrix} - * Returns the logarithm of `x` - */ - var log = typed('log', { - 'number': function (x) { - if (x >= 0 || config.predictable) { - return Math.log(x); - } - else { - // negative value -> complex value computation - return new type.Complex(x, 0).log(); - } - }, - - 'Complex': function (x) { - return x.log(); - }, - - 'BigNumber': function (x) { - if (!x.isNegative() || config.predictable) { - return x.ln(); - } - else { - // downgrade to number, return Complex valued result - return new type.Complex(x.toNumber(), 0).log(); - } - }, - - 'Array | Matrix': function (x) { - return deepMap(x, log); - }, - - 'any, any': function (x, base) { - // calculate logarithm for a specified base, log(x, base) - return divideScalar$$1(log(x), log(base)); - } - }); - - log.toTex = { - 1: '\\ln\\left(${args[0]}\\right)', - 2: '\\log_{${args[1]}}\\left(${args[0]}\\right)' - }; - - return log; - } - - var name$148 = 'log'; - var factory_1$159 = factory$160; - - var log$1 = { - name: name$148, - factory: factory_1$159 - }; - - function factory$161 (type, config, load, typed) { - /** - * Calculate the 10-base logarithm of a value. This is the same as calculating `log(x, 10)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.log10(x) - * - * Examples: - * - * math.log10(0.00001); // returns -5 - * math.log10(10000); // returns 4 - * math.log(10000) / math.log(10); // returns 4 - * math.pow(10, 4); // returns 10000 - * - * See also: - * - * exp, log, log1p, log2 - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the logarithm. - * @return {number | BigNumber | Complex | Array | Matrix} - * Returns the 10-base logarithm of `x` - */ - var log10 = typed('log10', { - 'number': function (x) { - if (x >= 0 || config.predictable) { - return _log10(x); - } - else { - // negative value -> complex value computation - return new type.Complex(x, 0).log().div(Math.LN10); - } - }, - - 'Complex': function (x) { - return new type.Complex(x).log().div(Math.LN10); - }, - - 'BigNumber': function (x) { - if (!x.isNegative() || config.predictable) { - return x.log(); - } - else { - // downgrade to number, return Complex valued result - return new type.Complex(x.toNumber(), 0).log().div(Math.LN10); - } - }, - - 'Array | Matrix': function (x) { - return deepMap(x, log10); - } - }); - - log10.toTex = {1: '\\log_{10}\\left(${args[0]}\\right)'}; - - return log10; - } - - /** - * Calculate the 10-base logarithm of a number - * @param {number} x - * @return {number} - * @private - */ - var _log10 = Math.log10 || function (x) { - return Math.log(x) / Math.LN10; - }; - - var name$149 = 'log10'; - var factory_1$160 = factory$161; - - var log10$1 = { - name: name$149, - factory: factory_1$160 - }; - - function factory$162 (type, config, load, typed) { - var divideScalar$$1 = load(divideScalar); - var log = load(log$1); - - /** - * Calculate the logarithm of a `value+1`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.log1p(x) - * math.log1p(x, base) - * - * Examples: - * - * math.log1p(2.5); // returns 1.252762968495368 - * math.exp(math.log1p(1.4)); // returns 2.4 - * - * math.pow(10, 4); // returns 10000 - * math.log1p(9999, 10); // returns 4 - * math.log1p(9999) / math.log(10); // returns 4 - * - * See also: - * - * exp, log, log2, log10 - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the logarithm of `x+1`. - * @param {number | BigNumber | Complex} [base=e] - * Optional base for the logarithm. If not provided, the natural - * logarithm of `x+1` is calculated. - * @return {number | BigNumber | Complex | Array | Matrix} - * Returns the logarithm of `x+1` - */ - var log1p = typed('log1p', { - 'number': _log1pNumber, - - 'Complex': _log1pComplex, - - 'BigNumber': function (x) { - var y = x.plus(1); - if (!y.isNegative() || config.predictable) { - return y.ln(); - } - else { - // downgrade to number, return Complex valued result - return _log1pComplex(new type.Complex(x.toNumber(), 0)); - } - }, - - 'Array | Matrix': function (x) { - return deepMap(x, log1p); - }, - - 'any, any': function (x, base) { - // calculate logarithm for a specified base, log1p(x, base) - return divideScalar$$1(log1p(x), log(base)); - } - }); - - /** - * Calculate the natural logarithm of a `number+1` - * @param {number} x - * @returns {number | Complex} - * @private - */ - function _log1pNumber(x) { - if (x >= -1 || config.predictable) { - return (Math.log1p) ? Math.log1p(x) : Math.log(x+1); - } - else { - // negative value -> complex value computation - return _log1pComplex(new type.Complex(x, 0)); - } - } - - /** - * Calculate the natural logarithm of a complex number + 1 - * @param {Complex} x - * @returns {Complex} - * @private - */ - function _log1pComplex(x) { - var x_re1p = x.re + 1; - return new type.Complex ( - Math.log(Math.sqrt(x_re1p * x_re1p + x.im * x.im)), - Math.atan2(x.im, x_re1p) - ); - } - - log1p.toTex = { - 1: '\\ln\\left(${args[0]}+1\\right)', - 2: '\\log_{${args[1]}}\\left(${args[0]}+1\\right)' - }; - - return log1p; - } - - var name$150 = 'log1p'; - var factory_1$161 = factory$162; - - var log1p$1 = { - name: name$150, - factory: factory_1$161 - }; - - function factory$163 (type, config, load, typed) { - /** - * Calculate the 2-base of a value. This is the same as calculating `log(x, 2)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.log2(x) - * - * Examples: - * - * math.log2(0.03125); // returns -5 - * math.log2(16); // returns 4 - * math.log2(16) / math.log2(2); // returns 4 - * math.pow(2, 4); // returns 16 - * - * See also: - * - * exp, log, log1p, log10 - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the logarithm. - * @return {number | BigNumber | Complex | Array | Matrix} - * Returns the 2-base logarithm of `x` - */ - var log2 = typed('log2', { - 'number': function (x) { - if (x >= 0 || config.predictable) { - return (Math.log2) - ? Math.log2(x) - : Math.log(x) / Math.LN2; - } - else { - // negative value -> complex value computation - return _log2Complex(new type.Complex(x, 0)); - } - }, - - 'Complex': _log2Complex, - - 'BigNumber': function (x) { - if (!x.isNegative() || config.predictable) { - return x.log(2); - } - else { - // downgrade to number, return Complex valued result - return _log2Complex(new type.Complex(x.toNumber(), 0)); - } - }, - - 'Array | Matrix': function (x) { - return deepMap(x, log2); - } - }); - - /** - * Calculate log2 for a complex value - * @param {Complex} x - * @returns {Complex} - * @private - */ - function _log2Complex(x) { - var newX = Math.sqrt(x.re * x.re + x.im * x.im); - return new type.Complex ( - (Math.log2) ? Math.log2(newX) : Math.log(newX) / Math.LN2, - Math.atan2(x.im, x.re) / Math.LN2 - ); - } - - log2.toTex = '\\log_{2}\\left(${args[0]}\\right)'; - - return log2; - - } - - var name$151 = 'log2'; - var factory_1$162 = factory$163; - - var log2$1 = { - name: name$151, - factory: factory_1$162 - }; - - function factory$164 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var latex$$1 = latex; - - var algorithm02$$1 = load(algorithm02); - var algorithm03$$1 = load(algorithm03); - var algorithm05$$1 = load(algorithm05); - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Calculates the modulus, the remainder of an integer division. - * - * For matrices, the function is evaluated element wise. - * - * The modulus is defined as: - * - * x - y * floor(x / y) - * - * See http://en.wikipedia.org/wiki/Modulo_operation. - * - * Syntax: - * - * math.mod(x, y) - * - * Examples: - * - * math.mod(8, 3); // returns 2 - * math.mod(11, 2); // returns 1 - * - * function isOdd(x) { - * return math.mod(x, 2) != 0; - * } - * - * isOdd(2); // returns false - * isOdd(3); // returns true - * - * See also: - * - * divide - * - * @param {number | BigNumber | Fraction | Array | Matrix} x Dividend - * @param {number | BigNumber | Fraction | Array | Matrix} y Divisor - * @return {number | BigNumber | Fraction | Array | Matrix} Returns the remainder of `x` divided by `y`. - */ - var mod = typed('mod', { - - 'number, number': _mod, - - 'BigNumber, BigNumber': function (x, y) { - return y.isZero() ? x : x.mod(y); - }, - - 'Fraction, Fraction': function (x, y) { - return x.mod(y); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm05$$1(x, y, mod, false); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, mod, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, mod, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, mod); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return mod(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return mod(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return mod(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, mod, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, mod, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, mod, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, mod, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, mod, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, mod, true).valueOf(); - } - }); - - mod.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['mod'] + '${args[1]}\\right)' - }; - - return mod; - - /** - * Calculate the modulus of two numbers - * @param {number} x - * @param {number} y - * @returns {number} res - * @private - */ - function _mod(x, y) { - if (y > 0) { - // We don't use JavaScript's % operator here as this doesn't work - // correctly for x < 0 and x == 0 - // see http://en.wikipedia.org/wiki/Modulo_operation - return x - y * Math.floor(x / y); - } - else if (y === 0) { - return x; - } - else { // y < 0 - // TODO: implement mod for a negative divisor - throw new Error('Cannot calculate mod for a negative divisor'); - } - } - } - - var name$152 = 'mod'; - var factory_1$163 = factory$164; - - var mod$1 = { - name: name$152, - factory: factory_1$163 - }; - - var clone$7 = object.clone; - var format$5 = string.format; - - function factory$165 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var add$$1 = load(add); - - /** - * Calculate the trace of a matrix: the sum of the elements on the main - * diagonal of a square matrix. - * - * Syntax: - * - * math.trace(x) - * - * Examples: - * - * math.trace([[1, 2], [3, 4]]); // returns 5 - * - * var A = [ - * [1, 2, 3], - * [-1, 2, 3], - * [2, 0, 3] - * ] - * math.trace(A); // returns 6 - * - * See also: - * - * diag - * - * @param {Array | Matrix} x A matrix - * - * @return {number} The trace of `x` - */ - var trace = typed('trace', { - - 'Array': function _arrayTrace(x) { - // use dense matrix implementation - return _denseTrace(matrix$$1(x)); - }, - - 'SparseMatrix': _sparseTrace, - - 'DenseMatrix': _denseTrace, - - 'any': clone$7 - }); - - function _denseTrace(m) { - // matrix size & data - var size = m._size; - var data = m._data; - - // process dimensions - switch (size.length) { - case 1: - // vector - if (size[0] === 1) { - // return data[0] - return clone$7(data[0]); - } - throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); - case 2: - // two dimensional - var rows = size[0]; - var cols = size[1]; - if (rows === cols) { - // calulate sum - var sum = 0; - // loop diagonal - for (var i = 0; i < rows; i++) - sum = add$$1(sum, data[i][i]); - // return trace - return sum; - } - throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); - default: - // multi dimensional - throw new RangeError('Matrix must be two dimensional (size: ' + format$5(size) + ')'); - } - } - - function _sparseTrace(m) { - // matrix arrays - var values = m._values; - var index = m._index; - var ptr = m._ptr; - var size = m._size; - // check dimensions - var rows = size[0]; - var columns = size[1]; - // matrix must be square - if (rows === columns) { - // calulate sum - var sum = 0; - // check we have data (avoid looping columns) - if (values.length > 0) { - // loop columns - for (var j = 0; j < columns; j++) { - // k0 <= k < k1 where k0 = _ptr[j] && k1 = _ptr[j+1] - var k0 = ptr[j]; - var k1 = ptr[j + 1]; - // loop k within [k0, k1[ - for (var k = k0; k < k1; k++) { - // row index - var i = index[k]; - // check row - if (i === j) { - // accumulate value - sum = add$$1(sum, values[k]); - // exit loop - break; - } - if (i > j) { - // exit loop, no value on the diagonal for column j - break; - } - } - } - } - // return trace - return sum; - } - throw new RangeError('Matrix must be square (size: ' + format$5(size) + ')'); - } - - trace.toTex = {1: '\\mathrm{tr}\\left(${args[0]}\\right)'}; - - return trace; - } - - var name$153 = 'trace'; - var factory_1$164 = factory$165; - - var trace$1 = { - name: name$153, - factory: factory_1$164 - }; - - function factory$166 (type, config, load, typed) { - - var abs = load(abs$1); - var add$$1 = load(add); - var pow = load(pow$1); - var conj = load(conj$1); - var sqrt = load(sqrt$1); - var multiply = load(multiply$1); - var equalScalar$$1 = load(equalScalar); - var larger$$1 = load(larger); - var smaller$$1 = load(smaller); - var matrix$$1 = load(matrix); - var trace = load(trace$1); - var transpose = load(transpose$1); - - - /** - * Calculate the norm of a number, vector or matrix. - * - * The second parameter p is optional. If not provided, it defaults to 2. - * - * Syntax: - * - * math.norm(x) - * math.norm(x, p) - * - * Examples: - * - * math.abs(-3.5); // returns 3.5 - * math.norm(-3.5); // returns 3.5 - * - * math.norm(math.complex(3, -4)); // returns 5 - * - * math.norm([1, 2, -3], Infinity); // returns 3 - * math.norm([1, 2, -3], -Infinity); // returns 1 - * - * math.norm([3, 4], 2); // returns 5 - * - * math.norm([[1, 2], [3, 4]], 1) // returns 6 - * math.norm([[1, 2], [3, 4]], 'inf'); // returns 7 - * math.norm([[1, 2], [3, 4]], 'fro'); // returns 5.477225575051661 - * - * See also: - * - * abs, hypot - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * Value for which to calculate the norm - * @param {number | BigNumber | string} [p=2] - * Vector space. - * Supported numbers include Infinity and -Infinity. - * Supported strings are: 'inf', '-inf', and 'fro' (The Frobenius norm) - * @return {number | BigNumber} the p-norm - */ - var norm = typed('norm', { - 'number': Math.abs, - - 'Complex': function (x) { - return x.abs(); - }, - - 'BigNumber': function (x) { - // norm(x) = abs(x) - return x.abs(); - }, - - 'boolean' : function (x) { - // norm(x) = abs(x) - return Math.abs(x); - }, - - 'Array': function (x) { - return _norm(matrix$$1(x), 2); - }, - - 'Matrix': function (x) { - return _norm(x, 2); - }, - - 'number | Complex | BigNumber | boolean, number | BigNumber | string': function (x) { - // ignore second parameter, TODO: remove the option of second parameter for these types - return norm(x); - }, - - 'Array, number | BigNumber | string': function (x, p) { - return _norm(matrix$$1(x), p); - }, - - 'Matrix, number | BigNumber | string': function (x, p) { - return _norm(x, p); - } - }); - - /** - * Calculate the norm for an array - * @param {Array} x - * @param {number | string} p - * @returns {number} Returns the norm - * @private - */ - function _norm (x, p) { - // size - var sizeX = x.size(); - - // check if it is a vector - if (sizeX.length == 1) { - // check p - if (p === Number.POSITIVE_INFINITY || p === 'inf') { - // norm(x, Infinity) = max(abs(x)) - var pinf = 0; - // skip zeros since abs(0) == 0 - x.forEach( - function (value) { - var v = abs(value); - if (larger$$1(v, pinf)) - pinf = v; - }, - true); - return pinf; - } - if (p === Number.NEGATIVE_INFINITY || p === '-inf') { - // norm(x, -Infinity) = min(abs(x)) - var ninf; - // skip zeros since abs(0) == 0 - x.forEach( - function (value) { - var v = abs(value); - if (!ninf || smaller$$1(v, ninf)) - ninf = v; - }, - true); - return ninf || 0; - } - if (p === 'fro') { - return _norm(x, 2); - } - if (typeof p === 'number' && !isNaN(p)) { - // check p != 0 - if (!equalScalar$$1(p, 0)) { - // norm(x, p) = sum(abs(xi) ^ p) ^ 1/p - var n = 0; - // skip zeros since abs(0) == 0 - x.forEach( - function (value) { - n = add$$1(pow(abs(value), p), n); - }, - true); - return pow(n, 1 / p); - } - return Number.POSITIVE_INFINITY; - } - // invalid parameter value - throw new Error('Unsupported parameter value'); - } - // MxN matrix - if (sizeX.length == 2) { - // check p - if (p === 1) { - // norm(x) = the largest column sum - var c = []; - // result - var maxc = 0; - // skip zeros since abs(0) == 0 - x.forEach( - function (value, index) { - var j = index[1]; - var cj = add$$1(c[j] || 0, abs(value)); - if (larger$$1(cj, maxc)) - maxc = cj; - c[j] = cj; - }, - true); - return maxc; - } - if (p === Number.POSITIVE_INFINITY || p === 'inf') { - // norm(x) = the largest row sum - var r = []; - // result - var maxr = 0; - // skip zeros since abs(0) == 0 - x.forEach( - function (value, index) { - var i = index[0]; - var ri = add$$1(r[i] || 0, abs(value)); - if (larger$$1(ri, maxr)) - maxr = ri; - r[i] = ri; - }, - true); - return maxr; - } - if (p === 'fro') { - // norm(x) = sqrt(sum(diag(x'x))) - var fro = 0; - x.forEach( - function (value, index) { - fro = add$$1( fro, multiply( value, conj(value) ) ); - }); - return sqrt(fro); - } - if (p === 2) { - // not implemented - throw new Error('Unsupported parameter value, missing implementation of matrix singular value decomposition'); - } - // invalid parameter value - throw new Error('Unsupported parameter value'); - } - } - - norm.toTex = { - 1: '\\left\\|${args[0]}\\right\\|', - 2: undefined // use default template - }; - - return norm; - } - - var name$154 = 'norm'; - var factory_1$165 = factory$166; - - var norm$1 = { - name: name$154, - factory: factory_1$165 - }; - - function factory$167 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm01$$1 = load(algorithm01); - var algorithm02$$1 = load(algorithm02); - var algorithm06$$1 = load(algorithm06); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Calculate the nth root of a value. - * The principal nth root of a positive real number A, is the positive real - * solution of the equation - * - * x^root = A - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.nthRoot(a) - * math.nthRoot(a, root) - * - * Examples: - * - * math.nthRoot(9, 2); // returns 3, as 3^2 == 9 - * math.sqrt(9); // returns 3, as 3^2 == 9 - * math.nthRoot(64, 3); // returns 4, as 4^3 == 64 - * - * See also: - * - * sqrt, pow - * - * @param {number | BigNumber | Array | Matrix | Complex} a - * Value for which to calculate the nth root - * @param {number | BigNumber} [root=2] The root. - * @return {number | Complex | Array | Matrix} Returns the nth root of `a` - */ - var nthRoot = typed('nthRoot', { - - 'number': function (x) { - return _nthRoot(x, 2); - }, - 'number, number': _nthRoot, - - 'BigNumber': function (x) { - return _bigNthRoot(x, new type.BigNumber(2)); - }, - 'Complex' : function(x) { - return _nthComplexRoot(x, 2); - }, - 'Complex, number' : _nthComplexRoot, - 'BigNumber, BigNumber': _bigNthRoot, - - 'Array | Matrix': function (x) { - return nthRoot(x, 2); - }, - - 'SparseMatrix, SparseMatrix': function (x, y) { - // density must be one (no zeros in matrix) - if (y.density() === 1) { - // sparse + sparse - return algorithm06$$1(x, y, nthRoot); - } - else { - // throw exception - throw new Error('Root must be non-zero'); - } - }, - - 'SparseMatrix, DenseMatrix': function (x, y) { - return algorithm02$$1(y, x, nthRoot, true); - }, - - 'DenseMatrix, SparseMatrix': function (x, y) { - // density must be one (no zeros in matrix) - if (y.density() === 1) { - // dense + sparse - return algorithm01$$1(x, y, nthRoot, false); - } - else { - // throw exception - throw new Error('Root must be non-zero'); - } - }, - - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, nthRoot); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return nthRoot(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return nthRoot(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return nthRoot(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm11$$1(x, y, nthRoot, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, nthRoot, false); - }, - - 'number | BigNumber, SparseMatrix': function (x, y) { - // density must be one (no zeros in matrix) - if (y.density() === 1) { - // sparse - scalar - return algorithm11$$1(y, x, nthRoot, true); - } - else { - // throw exception - throw new Error('Root must be non-zero'); - } - }, - - 'number | BigNumber, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, nthRoot, true); - }, - - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return nthRoot(matrix$$1(x), y).valueOf(); - }, - - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return nthRoot(x, matrix$$1(y)).valueOf(); - } - }); - - nthRoot.toTex = {2: '\\sqrt[${args[1]}]{${args[0]}}'}; - - return nthRoot; - - /** - * Calculate the nth root of a for BigNumbers, solve x^root == a - * http://rosettacode.org/wiki/Nth_root#JavaScript - * @param {BigNumber} a - * @param {BigNumber} root - * @private - */ - function _bigNthRoot(a, root) { - var precision = type.BigNumber.precision; - var Big = type.BigNumber.clone({precision: precision + 2}); - var zero = new type.BigNumber(0); - - var one = new Big(1); - var inv = root.isNegative(); - if (inv) { - root = root.neg(); - } - - if (root.isZero()) { - throw new Error('Root must be non-zero'); - } - if (a.isNegative() && !root.abs().mod(2).equals(1)) { - throw new Error('Root must be odd when a is negative.'); - } - - // edge cases zero and infinity - if (a.isZero()) { - return inv ? new Big(Infinity) : 0; - } - if (!a.isFinite()) { - return inv ? zero : a; - } - - var x = a.abs().pow(one.div(root)); - // If a < 0, we require that root is an odd integer, - // so (-1) ^ (1/root) = -1 - x = a.isNeg() ? x.neg() : x; - return new type.BigNumber((inv ? one.div(x) : x).toPrecision(precision)); - } - } - - /** - * Calculate the nth root of a, solve x^root == a - * http://rosettacode.org/wiki/Nth_root#JavaScript - * @param {number} a - * @param {number} root - * @private - */ - function _nthRoot(a, root) { - var inv = root < 0; - if (inv) { - root = -root; - } - - if (root === 0) { - throw new Error('Root must be non-zero'); - } - if (a < 0 && (Math.abs(root) % 2 != 1)) { - throw new Error('Root must be odd when a is negative.'); - } - - // edge cases zero and infinity - if (a == 0) { - return inv ? Infinity : 0; - } - if (!isFinite(a)) { - return inv ? 0 : a; - } - - var x = Math.pow(Math.abs(a), 1/root); - // If a < 0, we require that root is an odd integer, - // so (-1) ^ (1/root) = -1 - x = a < 0 ? -x : x; - return inv ? 1 / x : x; - - // Very nice algorithm, but fails with nthRoot(-2, 3). - // Newton's method has some well-known problems at times: - // https://en.wikipedia.org/wiki/Newton%27s_method#Failure_analysis - /* - var x = 1; // Initial guess - var xPrev = 1; - var i = 0; - var iMax = 10000; - do { - var delta = (a / Math.pow(x, root - 1) - x) / root; - xPrev = x; - x = x + delta; - i++; - } - while (xPrev !== x && i < iMax); - - if (xPrev !== x) { - throw new Error('Function nthRoot failed to converge'); - } - - return inv ? 1 / x : x; - */ - } - - /** - * Calculate the nth root of a Complex Number a using De Moviers Theorem. - * @param {Complex} a - * @param {number} root - * @return {Array} array or n Complex Roots in Polar Form. - */ - function _nthComplexRoot(a, root) { - if (root < 0) throw new Error('Root must be greater than zero'); - if (root === 0) throw new Error('Root must be non-zero'); - if (root % 1 !== 0) throw new Error('Root must be an integer'); - var arg = a.arg(); - var abs = a.abs(); - var roots = []; - var r = Math.pow(abs, 1/root); - for(var k = 0; k < root; k++) { - roots.push({r: r, phi: (arg + 2 * Math.PI * k)/root}); - } - return roots; - } - - var name$155 = 'nthRoot'; - var factory_1$166 = factory$167; - - var nthRoot$1 = { - name: name$155, - factory: factory_1$166 - }; - - var isInteger$11 = number.isInteger; - var toFixed = number.toFixed; - - - var NO_INT = 'Number of decimals in function round must be an integer'; - - function factory$168 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - var zeros = load(zeros$1); - - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm14$$1 = load(algorithm14); - - /** - * Round a value towards the nearest integer. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.round(x) - * math.round(x, n) - * - * Examples: - * - * math.round(3.2); // returns number 3 - * math.round(3.8); // returns number 4 - * math.round(-4.2); // returns number -4 - * math.round(-4.7); // returns number -5 - * math.round(math.pi, 3); // returns number 3.142 - * math.round(123.45678, 2); // returns number 123.46 - * - * var c = math.complex(3.2, -2.7); - * math.round(c); // returns Complex 3 - 3i - * - * math.round([3.2, 3.8, -4.7]); // returns Array [3, 4, -5] - * - * See also: - * - * ceil, fix, floor - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded - * @param {number | BigNumber | Array} [n=0] Number of decimals - * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value - */ - var round = typed('round', { - - 'number': Math.round, - - 'number, number': function (x, n) { - if (!isInteger$11(n)) {throw new TypeError(NO_INT);} - if (n < 0 || n > 15) {throw new Error('Number of decimals in function round must be in te range of 0-15');} - - return _round(x, n); - }, - - 'Complex': function (x) { - return x.round(); - }, - - 'Complex, number': function (x, n) { - if (n % 1) {throw new TypeError(NO_INT);} - - return x.round(n); - }, - - 'Complex, BigNumber': function (x, n) { - if (!n.isInteger()) {throw new TypeError(NO_INT);} - - var _n = n.toNumber(); - return x.round(_n); - }, - - 'number, BigNumber': function (x, n) { - if (!n.isInteger()) {throw new TypeError(NO_INT);} - - return new type.BigNumber(x).toDecimalPlaces(n.toNumber()); - }, - - 'BigNumber': function (x) { - return x.toDecimalPlaces(0); - }, - - 'BigNumber, BigNumber': function (x, n) { - if (!n.isInteger()) {throw new TypeError(NO_INT);} - - return x.toDecimalPlaces(n.toNumber()); - }, - - 'Fraction': function (x) { - return x.round(); - }, - - 'Fraction, number': function (x, n) { - if (n % 1) {throw new TypeError(NO_INT);} - return x.round(n); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since round(0) = 0 - return deepMap(x, round, true); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm11$$1(x, y, round, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, round, false); - }, - - 'number | Complex | BigNumber, SparseMatrix': function (x, y) { - // check scalar is zero - if (equalScalar$$1(x, 0)) { - // do not execute algorithm, result will be a zero matrix - return zeros(y.size(), y.storage()); - } - return algorithm12$$1(y, x, round, true); - }, - - 'number | Complex | BigNumber, DenseMatrix': function (x, y) { - // check scalar is zero - if (equalScalar$$1(x, 0)) { - // do not execute algorithm, result will be a zero matrix - return zeros(y.size(), y.storage()); - } - return algorithm14$$1(y, x, round, true); - }, - - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, round, false).valueOf(); - }, - - 'number | Complex | BigNumber, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, round, true).valueOf(); - } - }); - - round.toTex = { - 1: '\\left\\lfloor${args[0]}\\right\\rceil', - 2: undefined // use default template - }; - - return round; - } - - /** - * round a number to the given number of decimals, or to zero if decimals is - * not provided - * @param {number} value - * @param {number} decimals number of decimals, between 0 and 15 (0 by default) - * @return {number} roundedValue - * @private - */ - function _round (value, decimals) { - return parseFloat(toFixed(value, decimals)); - } - - var name$156 = 'round'; - var factory_1$167 = factory$168; - - var round$1 = { - name: name$156, - factory: factory_1$167 - }; - - function factory$169 (type, config, load, typed) { - /** - * Compute the square of a value, `x * x`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.square(x) - * - * Examples: - * - * math.square(2); // returns number 4 - * math.square(3); // returns number 9 - * math.pow(3, 2); // returns number 9 - * math.multiply(3, 3); // returns number 9 - * - * math.square([1, 2, 3, 4]); // returns Array [1, 4, 9, 16] - * - * See also: - * - * multiply, cube, sqrt, pow - * - * @param {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} x - * Number for which to calculate the square - * @return {number | BigNumber | Fraction | Complex | Array | Matrix | Unit} - * Squared value - */ - var square = typed('square', { - 'number': function (x) { - return x * x; - }, - - 'Complex': function (x) { - return x.mul(x); - }, - - 'BigNumber': function (x) { - return x.times(x); - }, - - 'Fraction': function (x) { - return x.mul(x); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since square(0) = 0 - return deepMap(x, square, true); - }, - - 'Unit': function(x) { - return x.pow(2); - } - }); - - square.toTex = {1: '\\left(${args[0]}\\right)^2'}; - - return square; - } - - var name$157 = 'square'; - var factory_1$168 = factory$169; - - var square$1 = { - name: name$157, - factory: factory_1$168 - }; - - function factory$170 (type, config, load, typed) { - var latex$$1 = latex; - - /** - * Unary plus operation. - * Boolean values and strings will be converted to a number, numeric values will be returned as is. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.unaryPlus(x) - * - * Examples: - * - * math.unaryPlus(3.5); // returns 3.5 - * math.unaryPlus(1); // returns 1 - * - * See also: - * - * unaryMinus, add, subtract - * - * @param {number | BigNumber | Fraction | string | Complex | Unit | Array | Matrix} x - * Input value - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} - * Returns the input value when numeric, converts to a number when input is non-numeric. - */ - var unaryPlus = typed('unaryPlus', { - 'number': function (x) { - return x; - }, - - 'Complex': function (x) { - return x; // complex numbers are immutable - }, - - 'BigNumber': function (x) { - return x; // bignumbers are immutable - }, - - 'Fraction': function (x) { - return x; // fractions are immutable - }, - - 'Unit': function (x) { - return x.clone(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since unaryPlus(0) = 0 - return deepMap(x, unaryPlus, true); - }, - - 'boolean | string': function (x) { - // convert to a number or bignumber - return (config.number == 'BigNumber') ? new type.BigNumber(+x): +x; - } - }); - - unaryPlus.toTex = { - 1: latex$$1.operators['unaryPlus'] + '\\left(${args[0]}\\right)' - }; - - return unaryPlus; - } - - var name$158 = 'unaryPlus'; - var factory_1$169 = factory$170; - - var unaryPlus$1 = { - name: name$158, - factory: factory_1$169 - }; - - var isInteger$12 = number.isInteger; - - function factory$171 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Calculate the extended greatest common divisor for two values. - * See http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm. - * - * Syntax: - * - * math.xgcd(a, b) - * - * Examples: - * - * math.xgcd(8, 12); // returns [4, -1, 1] - * math.gcd(8, 12); // returns 4 - * math.xgcd(36163, 21199); // returns [1247, -7, 12] - * - * See also: - * - * gcd, lcm - * - * @param {number | BigNumber} a An integer number - * @param {number | BigNumber} b An integer number - * @return {Array} Returns an array containing 3 integers `[div, m, n]` - * where `div = gcd(a, b)` and `a*m + b*n = div` - */ - var xgcd = typed('xgcd', { - 'number, number': _xgcd, - 'BigNumber, BigNumber': _xgcdBigNumber - // TODO: implement support for Fraction - }); - - xgcd.toTex = undefined; // use default template - - return xgcd; - - /** - * Calculate xgcd for two numbers - * @param {number} a - * @param {number} b - * @return {number} result - * @private - */ - function _xgcd (a, b) { - // source: http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - var t, // used to swap two variables - q, // quotient - r, // remainder - x = 0, lastx = 1, - y = 1, lasty = 0; - - if (!isInteger$12(a) || !isInteger$12(b)) { - throw new Error('Parameters in function xgcd must be integer numbers'); - } - - while (b) { - q = Math.floor(a / b); - r = a - q*b; - - t = x; - x = lastx - q * x; - lastx = t; - - t = y; - y = lasty - q * y; - lasty = t; - - a = b; - b = r; - } - - var res; - if (a < 0) { - res = [-a, -lastx, -lasty]; - } - else { - res = [a, a ? lastx : 0, lasty]; - } - return (config.matrix === 'Array') ? res : matrix$$1(res); - } - - /** - * Calculate xgcd for two BigNumbers - * @param {BigNumber} a - * @param {BigNumber} b - * @return {BigNumber[]} result - * @private - */ - function _xgcdBigNumber(a, b) { - // source: http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm - var t, // used to swap two variables - q, // quotient - r, // remainder - zero = new type.BigNumber(0), - one = new type.BigNumber(1), - x = zero, - lastx = one, - y = one, - lasty = zero; - - if (!a.isInt() || !b.isInt()) { - throw new Error('Parameters in function xgcd must be integer numbers'); - } - - while (!b.isZero()) { - q = a.div(b).floor(); - r = a.mod(b); - - t = x; - x = lastx.minus(q.times(x)); - lastx = t; - - t = y; - y = lasty.minus(q.times(y)); - lasty = t; - - a = b; - b = r; - } - - var res; - if (a.lt(zero)) { - res = [a.neg(), lastx.neg(), lasty.neg()]; - } - else { - res = [a, !a.isZero() ? lastx : 0, lasty]; - } - return (config.matrix === 'Array') ? res : matrix$$1(res); - } - } - - var name$159 = 'xgcd'; - var factory_1$170 = factory$171; - - var xgcd$1 = { - name: name$159, - factory: factory_1$170 - }; - - var arithmetic = [ - abs$1, - add, - addScalar, - cbrt$1, - ceil$1, - cube$1, - divide$1, - dotDivide$1, - dotMultiply$1, - dotPow$1, - exp$1, - expm1$1, - fix$1, - floor$1, - gcd$1, - hypot$1, - lcm$1, - log$1, - log10$1, - log1p$1, - log2$1, - mod$1, - multiply$1, - norm$1, - nthRoot$1, - pow$1, - round$1, - sign$1, - sqrt$1, - square$1, - subtract$1, - unaryMinus$1, - unaryPlus$1, - xgcd$1 - ]; - - /** - * Bitwise not - * @param {BigNumber} value - * @return {BigNumber} Result of ~`x`, fully precise - * - */ - var bitNot$1 = function bitNot (x) { - if (x.isFinite() && !x.isInteger()) { - throw new Error('Integer expected in function bitNot'); - } - - var BigNumber = x.constructor; - var prevPrec = BigNumber.precision; - BigNumber.config({precision: 1E9}); - - var x = x.plus(new BigNumber(1)); - x.s = -x.s || null; - - BigNumber.config({precision: prevPrec}); - return x; - }; - - /** - * Applies bitwise function to numbers - * @param {BigNumber} x - * @param {BigNumber} y - * @param {function (a, b)} func - * @return {BigNumber} - */ - var bitwise = function bitwise(x, y, func) { - var BigNumber = x.constructor; - - var xBits, yBits; - var xSign = +(x.s < 0); - var ySign = +(y.s < 0); - if (xSign) { - xBits = decCoefficientToBinaryString(bitNot$1(x)); - for (var i = 0; i < xBits.length; ++i) { - xBits[i] ^= 1; - } - } else { - xBits = decCoefficientToBinaryString(x); - } - if (ySign) { - yBits = decCoefficientToBinaryString(bitNot$1(y)); - for (var i = 0; i < yBits.length; ++i) { - yBits[i] ^= 1; - } - } else { - yBits = decCoefficientToBinaryString(y); - } - - var minBits, maxBits, minSign; - if (xBits.length <= yBits.length) { - minBits = xBits; - maxBits = yBits; - minSign = xSign; - } else { - minBits = yBits; - maxBits = xBits; - minSign = ySign; - } - - var shortLen = minBits.length; - var longLen = maxBits.length; - var expFuncVal = func(xSign, ySign) ^ 1; - var outVal = new BigNumber(expFuncVal ^ 1); - var twoPower = new BigNumber(1); - var two = new BigNumber(2); - - var prevPrec = BigNumber.precision; - BigNumber.config({precision: 1E9}); - - while (shortLen > 0) { - if (func(minBits[--shortLen], maxBits[--longLen]) == expFuncVal) { - outVal = outVal.plus(twoPower); - } - twoPower = twoPower.times(two); - } - while (longLen > 0) { - if (func(minSign, maxBits[--longLen]) == expFuncVal) { - outVal = outVal.plus(twoPower); - } - twoPower = twoPower.times(two); - } - - BigNumber.config({precision: prevPrec}); - - if (expFuncVal == 0) { - outVal.s = -outVal.s; - } - return outVal; - }; - - /* Extracted from decimal.js, and edited to specialize. */ - function decCoefficientToBinaryString (x) { - // Convert to string - var a = x.d; // array with digits - var r = a[0] + ''; - - for (var i = 1; i < a.length; ++i) { - var s = a[i] + ''; - for (var z = 7 - s.length; z--; ) { - s = '0' + s; - } - - r += s; - } - - var j; - for (j = r.length - 1; r.charAt(j) == '0'; --j); - - var xe = x.e; - var str = r.slice(0, j + 1 || 1); - var strL = str.length; - if (xe > 0) { - if (++xe > strL) { - // Append zeros. - for (xe -= strL; xe--; str += '0'); - } else if (xe < strL) { - str = str.slice(0, xe) + '.' + str.slice(xe); - } - } - - // Convert from base 10 (decimal) to base 2 - var arr = [0]; - for (var i = 0; i < str.length; ) { - for (var arrL = arr.length; arrL--; arr[arrL] *= 10); - - arr[0] += str.charAt(i++) << 0; // convert to int - for (var j = 0; j < arr.length; ++j) { - if (arr[j] > 1) { - if (arr[j + 1] == null) { - arr[j + 1] = 0; - } - - arr[j + 1] += arr[j] >> 1; - arr[j] &= 1; - } - } - } - - return arr.reverse(); - } - - /** - * Bitwise and for Bignumbers - * - * Special Cases: - * N & n = N - * n & 0 = 0 - * n & -1 = n - * n & n = n - * I & I = I - * -I & -I = -I - * I & -I = 0 - * I & n = n - * I & -n = I - * -I & n = 0 - * -I & -n = -I - * - * @param {BigNumber} x - * @param {BigNumber} y - * @return {BigNumber} Result of `x` & `y`, is fully precise - * @private - */ - var bitAnd$1 = function bitAnd(x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function bitAnd'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN()) { - return new BigNumber(NaN); - } - - if (x.isZero() || y.eq(-1) || x.eq(y)) { - return x; - } - if (y.isZero() || x.eq(-1)) { - return y; - } - - if (!x.isFinite() || !y.isFinite()) { - if (!x.isFinite() && !y.isFinite()) { - if (x.isNegative() == y.isNegative()) { - return x; - } - return new BigNumber(0); - } - if (!x.isFinite()) { - if (y.isNegative()) { - return x; - } - if (x.isNegative()) { - return new BigNumber(0); - } - return y; - } - if (!y.isFinite()) { - if (x.isNegative()) { - return y; - } - if (y.isNegative()) { - return new BigNumber(0); - } - return x; - } - } - return bitwise(x, y, function (a, b) { return a & b }); - }; - - var isInteger$13 = number.isInteger; - - - function factory$172 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - - var algorithm02$$1 = load(algorithm02); - var algorithm06$$1 = load(algorithm06); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise AND two values, `x & y`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.bitAnd(x, y) - * - * Examples: - * - * math.bitAnd(53, 131); // returns number 1 - * - * math.bitAnd([1, 12, 31], 42); // returns Array [0, 8, 10] - * - * See also: - * - * bitNot, bitOr, bitXor, leftShift, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x First value to and - * @param {number | BigNumber | Array | Matrix} y Second value to and - * @return {number | BigNumber | Array | Matrix} AND of `x` and `y` - */ - var bitAnd = typed('bitAnd', { - - 'number, number': function (x, y) { - if (!isInteger$13(x) || !isInteger$13(y)) { - throw new Error('Integers expected in function bitAnd'); - } - - return x & y; - }, - - 'BigNumber, BigNumber': bitAnd$1, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm06$$1(x, y, bitAnd, false); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, bitAnd, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm02$$1(x, y, bitAnd, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, bitAnd); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return bitAnd(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return bitAnd(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return bitAnd(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm11$$1(x, y, bitAnd, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, bitAnd, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm11$$1(y, x, bitAnd, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, bitAnd, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, bitAnd, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, bitAnd, true).valueOf(); - } - }); - - bitAnd.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['bitAnd'] + '${args[1]}\\right)' - }; - - return bitAnd; - } - - var name$160 = 'bitAnd'; - var factory_1$171 = factory$172; - - var bitAnd$2 = { - name: name$160, - factory: factory_1$171 - }; - - var isInteger$14 = number.isInteger; - - function factory$173 (type, config, load, typed) { - var latex$$1 = latex; - - /** - * Bitwise NOT value, `~x`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the best prefix base. - * - * Syntax: - * - * math.bitNot(x) - * - * Examples: - * - * math.bitNot(1); // returns number -2 - * - * math.bitNot([2, -3, 4]); // returns Array [-3, 2, 5] - * - * See also: - * - * bitAnd, bitOr, bitXor, leftShift, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x Value to not - * @return {number | BigNumber | Array | Matrix} NOT of `x` - */ - var bitNot = typed('bitNot', { - 'number': function (x) { - if (!isInteger$14(x)) { - throw new Error('Integer expected in function bitNot'); - } - - return ~x; - }, - - 'BigNumber': bitNot$1, - - 'Array | Matrix': function (x) { - return deepMap(x, bitNot); - } - }); - - bitNot.toTex = { - 1: latex$$1.operators['bitNot'] + '\\left(${args[0]}\\right)' - }; - - return bitNot; - } - - var name$161 = 'bitNot'; - var factory_1$172 = factory$173; - - var bitNot$2 = { - name: name$161, - factory: factory_1$172 - }; - - /** - * Bitwise OR for BigNumbers - * - * Special Cases: - * N | n = N - * n | 0 = n - * n | -1 = -1 - * n | n = n - * I | I = I - * -I | -I = -I - * I | -n = -1 - * I | -I = -1 - * I | n = I - * -I | n = -I - * -I | -n = -n - * - * @param {BigNumber} x - * @param {BigNumber} y - * @return {BigNumber} Result of `x` | `y`, fully precise - */ - var bitOr$1 = function bitOr (x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function bitOr'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN()) { - return new BigNumber(NaN); - } - - var negOne = new BigNumber(-1); - if (x.isZero() || y.eq(negOne) || x.eq(y)) { - return y; - } - if (y.isZero() || x.eq(negOne)) { - return x; - } - - if (!x.isFinite() || !y.isFinite()) { - if ((!x.isFinite() && !x.isNegative() && y.isNegative()) || - (x.isNegative() && !y.isNegative() && !y.isFinite())) { - return negOne; - } - if (x.isNegative() && y.isNegative()) { - return x.isFinite() ? x : y; - } - return x.isFinite() ? y : x; - } - - return bitwise(x, y, function (a, b) { return a | b }); - }; - - var isInteger$15 = number.isInteger; - - - function factory$174 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - - var algorithm01$$1 = load(algorithm01); - var algorithm04$$1 = load(algorithm04); - var algorithm10$$1 = load(algorithm10); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise OR two values, `x | y`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the lowest print base. - * - * Syntax: - * - * math.bitOr(x, y) - * - * Examples: - * - * math.bitOr(1, 2); // returns number 3 - * - * math.bitOr([1, 2, 3], 4); // returns Array [5, 6, 7] - * - * See also: - * - * bitAnd, bitNot, bitXor, leftShift, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x First value to or - * @param {number | BigNumber | Array | Matrix} y Second value to or - * @return {number | BigNumber | Array | Matrix} OR of `x` and `y` - */ - var bitOr = typed('bitOr', { - - 'number, number': function (x, y) { - if (!isInteger$15(x) || !isInteger$15(y)) { - throw new Error('Integers expected in function bitOr'); - } - - return x | y; - }, - - 'BigNumber, BigNumber': bitOr$1, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm04$$1(x, y, bitOr); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm01$$1(y, x, bitOr, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, bitOr, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, bitOr); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return bitOr(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return bitOr(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return bitOr(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm10$$1(x, y, bitOr, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, bitOr, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm10$$1(y, x, bitOr, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, bitOr, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, bitOr, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, bitOr, true).valueOf(); - } - }); - - bitOr.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['bitOr'] + '${args[1]}\\right)' - }; - - return bitOr; - } - - var name$162 = 'bitOr'; - var factory_1$173 = factory$174; - - var bitOr$2 = { - name: name$162, - factory: factory_1$173 - }; - - /** - * Bitwise XOR for BigNumbers - * - * Special Cases: - * N ^ n = N - * n ^ 0 = n - * n ^ n = 0 - * n ^ -1 = ~n - * I ^ n = I - * I ^ -n = -I - * I ^ -I = -1 - * -I ^ n = -I - * -I ^ -n = I - * - * @param {BigNumber} x - * @param {BigNumber} y - * @return {BigNumber} Result of `x` ^ `y`, fully precise - * - */ - var bitXor$1 = function bitXor(x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function bitXor'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN()) { - return new BigNumber(NaN); - } - if (x.isZero()) { - return y; - } - if (y.isZero()) { - return x; - } - - if (x.eq(y)) { - return new BigNumber(0); - } - - var negOne = new BigNumber(-1); - if (x.eq(negOne)) { - return bitNot$1(y); - } - if (y.eq(negOne)) { - return bitNot$1(x); - } - - if (!x.isFinite() || !y.isFinite()) { - if (!x.isFinite() && !y.isFinite()) { - return negOne; - } - return new BigNumber(x.isNegative() == y.isNegative() - ? Infinity - : -Infinity); - } - return bitwise(x, y, function (a, b) { return a ^ b }); - }; - - var isInteger$16 = number.isInteger; - - - function factory$175 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise XOR two values, `x ^ y`. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.bitXor(x, y) - * - * Examples: - * - * math.bitXor(1, 2); // returns number 3 - * - * math.bitXor([2, 3, 4], 4); // returns Array [6, 7, 0] - * - * See also: - * - * bitAnd, bitNot, bitOr, leftShift, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x First value to xor - * @param {number | BigNumber | Array | Matrix} y Second value to xor - * @return {number | BigNumber | Array | Matrix} XOR of `x` and `y` - */ - var bitXor = typed('bitXor', { - - 'number, number': function (x, y) { - if (!isInteger$16(x) || !isInteger$16(y)) { - throw new Error('Integers expected in function bitXor'); - } - - return x ^ y; - }, - - 'BigNumber, BigNumber': bitXor$1, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, bitXor); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, bitXor, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, bitXor, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, bitXor); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return bitXor(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return bitXor(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return bitXor(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, bitXor, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, bitXor, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, bitXor, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, bitXor, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, bitXor, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, bitXor, true).valueOf(); - } - }); - - bitXor.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['bitXor'] + '${args[1]}\\right)' - }; - - return bitXor; - } - - var name$163 = 'bitXor'; - var factory_1$174 = factory$175; - - var bitXor$2 = { - name: name$163, - factory: factory_1$174 - }; - - /** - * Bitwise left shift - * - * Special Cases: - * n << -n = N - * n << N = N - * N << n = N - * n << 0 = n - * 0 << n = 0 - * I << I = N - * I << n = I - * n << I = I - * - * @param {BigNumber} x - * @param {BigNumber} y - * @return {BigNumber} Result of `x` << `y` - * - */ - var leftShift$1 = function leftShift (x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function leftShift'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { - return new BigNumber(NaN); - } - if (x.isZero() || y.isZero()) { - return x; - } - if (!x.isFinite() && !y.isFinite()) { - return new BigNumber(NaN); - } - - // Math.pow(2, y) is fully precise for y < 55, and fast - if (y.lt(55)) { - return x.times(Math.pow(2, y.toNumber()) + ''); - } - return x.times(new BigNumber(2).pow(y)); - }; - - function factory$176 (type, config, load, typed) { - - var equalScalar$$1 = load(equalScalar); - - var SparseMatrix = type.SparseMatrix; - - /** - * Iterates over SparseMatrix A and SparseMatrix B nonzero items and invokes the callback function f(Aij, Bij). - * Callback function invoked MAX(NNZA, NNZB) times - * - * - * ┌ f(Aij, Bij) ; A(i,j) !== 0 && B(i,j) !== 0 - * C(i,j) = ┤ A(i,j) ; A(i,j) !== 0 - * └ 0 ; otherwise - * - * - * @param {Matrix} a The SparseMatrix instance (A) - * @param {Matrix} b The SparseMatrix instance (B) - * @param {Function} callback The f(Aij,Bij) operation to invoke - * - * @return {Matrix} SparseMatrix (C) - * - * see https://github.com/josdejong/mathjs/pull/346#issuecomment-97620294 - */ - var algorithm08 = function (a, b, callback) { - // sparse matrix arrays - var avalues = a._values; - var aindex = a._index; - var aptr = a._ptr; - var asize = a._size; - var adt = a._datatype; - // sparse matrix arrays - var bvalues = b._values; - var bindex = b._index; - var bptr = b._ptr; - var bsize = b._size; - var bdt = b._datatype; - - // validate dimensions - if (asize.length !== bsize.length) - throw new DimensionError_1(asize.length, bsize.length); - - // check rows & columns - if (asize[0] !== bsize[0] || asize[1] !== bsize[1]) - throw new RangeError('Dimension mismatch. Matrix A (' + asize + ') must match Matrix B (' + bsize + ')'); - - // sparse matrix cannot be a Pattern matrix - if (!avalues || !bvalues) - throw new Error('Cannot perform operation on Pattern Sparse Matrices'); - - // rows & columns - var rows = asize[0]; - var columns = asize[1]; - - // datatype - var dt; - // equal signature to use - var eq = equalScalar$$1; - // zero value - var zero = 0; - // callback signature to use - var cf = callback; - - // process data types - if (typeof adt === 'string' && adt === bdt) { - // datatype - dt = adt; - // find signature that matches (dt, dt) - eq = typed.find(equalScalar$$1, [dt, dt]); - // convert 0 to the same datatype - zero = typed.convert(0, dt); - // callback - cf = typed.find(callback, [dt, dt]); - } - - // result arrays - var cvalues = []; - var cindex = []; - var cptr = []; - // matrix - var c = new SparseMatrix({ - values: cvalues, - index: cindex, - ptr: cptr, - size: [rows, columns], - datatype: dt - }); - - // workspace - var x = []; - // marks indicating we have a value in x for a given column - var w = []; - - // vars - var k, k0, k1, i; - - // loop columns - for (var j = 0; j < columns; j++) { - // update cptr - cptr[j] = cindex.length; - // columns mark - var mark = j + 1; - // loop values in a - for (k0 = aptr[j], k1 = aptr[j + 1], k = k0; k < k1; k++) { - // row - i = aindex[k]; - // mark workspace - w[i] = mark; - // set value - x[i] = avalues[k]; - // add index - cindex.push(i); - } - // loop values in b - for (k0 = bptr[j], k1 = bptr[j + 1], k = k0; k < k1; k++) { - // row - i = bindex[k]; - // check value exists in workspace - if (w[i] === mark) { - // evaluate callback - x[i] = cf(x[i], bvalues[k]); - } - } - // initialize first index in j - k = cptr[j]; - // loop index in j - while (k < cindex.length) { - // row - i = cindex[k]; - // value @ i - var v = x[i]; - // check for zero value - if (!eq(v, zero)) { - // push value - cvalues.push(v); - // increment pointer - k++; - } - else { - // remove value @ i, do not increment pointer - cindex.splice(k, 1); - } - } - } - // update cptr - cptr[columns] = cindex.length; - - // return sparse matrix - return c; - }; - - return algorithm08; - } - - var name$164 = 'algorithm08'; - var factory_1$175 = factory$176; - - var algorithm08 = { - name: name$164, - factory: factory_1$175 - }; - - var isInteger$17 = number.isInteger; - - - function factory$177 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - var zeros = load(zeros$1); - - var algorithm01$$1 = load(algorithm01); - var algorithm02$$1 = load(algorithm02); - var algorithm08$$1 = load(algorithm08); - var algorithm10$$1 = load(algorithm10); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise left logical shift of a value x by y number of bits, `x << y`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the best prefix base. - * - * Syntax: - * - * math.leftShift(x, y) - * - * Examples: - * - * math.leftShift(1, 2); // returns number 4 - * - * math.leftShift([1, 2, 3], 4); // returns Array [16, 32, 64] - * - * See also: - * - * leftShift, bitNot, bitOr, bitXor, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x Value to be shifted - * @param {number | BigNumber} y Amount of shifts - * @return {number | BigNumber | Array | Matrix} `x` shifted left `y` times - */ - var leftShift = typed('leftShift', { - - 'number, number': function (x, y) { - if (!isInteger$17(x) || !isInteger$17(y)) { - throw new Error('Integers expected in function leftShift'); - } - - return x << y; - }, - - 'BigNumber, BigNumber': leftShift$1, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm08$$1(x, y, leftShift, false); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, leftShift, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, leftShift, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, leftShift); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return leftShift(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return leftShift(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return leftShift(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm11$$1(x, y, leftShift, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm14$$1(x, y, leftShift, false); - }, - - 'number | BigNumber, SparseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm10$$1(y, x, leftShift, true); - }, - - 'number | BigNumber, DenseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm14$$1(y, x, leftShift, true); - }, - - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return leftShift(matrix$$1(x), y).valueOf(); - }, - - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return leftShift(x, matrix$$1(y)).valueOf(); - } - }); - - leftShift.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['leftShift'] + '${args[1]}\\right)' - }; - - return leftShift; - } - - var name$165 = 'leftShift'; - var factory_1$176 = factory$177; - - var leftShift$2 = { - name: name$165, - factory: factory_1$176 - }; - - /* - * Special Cases: - * n >> -n = N - * n >> N = N - * N >> n = N - * I >> I = N - * n >> 0 = n - * I >> n = I - * -I >> n = -I - * -I >> I = -I - * n >> I = I - * -n >> I = -1 - * 0 >> n = 0 - * - * @param {BigNumber} value - * @param {BigNumber} value - * @return {BigNumber} Result of `x` >> `y` - * - */ - var rightArithShift$1 = function rightArithShift (x, y) { - if ((x.isFinite() && !x.isInteger()) || (y.isFinite() && !y.isInteger())) { - throw new Error('Integers expected in function rightArithShift'); - } - - var BigNumber = x.constructor; - if (x.isNaN() || y.isNaN() || (y.isNegative() && !y.isZero())) { - return new BigNumber(NaN); - } - if (x.isZero() || y.isZero()) { - return x; - } - if (!y.isFinite()) { - if (x.isNegative()) { - return new BigNumber(-1); - } - if (!x.isFinite()) { - return new BigNumber(NaN); - } - return new BigNumber(0); - } - - // Math.pow(2, y) is fully precise for y < 55, and fast - if (y.lt(55)) { - return x.div(Math.pow(2, y.toNumber()) + '').floor(); - } - return x.div(new BigNumber(2).pow(y)).floor(); - }; - - var isInteger$18 = number.isInteger; - - - function factory$178 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - var zeros = load(zeros$1); - - var algorithm01$$1 = load(algorithm01); - var algorithm02$$1 = load(algorithm02); - var algorithm08$$1 = load(algorithm08); - var algorithm10$$1 = load(algorithm10); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise right arithmetic shift of a value x by y number of bits, `x >> y`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the best prefix base. - * - * Syntax: - * - * math.rightArithShift(x, y) - * - * Examples: - * - * math.rightArithShift(4, 2); // returns number 1 - * - * math.rightArithShift([16, -32, 64], 4); // returns Array [1, -2, 3] - * - * See also: - * - * bitAnd, bitNot, bitOr, bitXor, rightArithShift, rightLogShift - * - * @param {number | BigNumber | Array | Matrix} x Value to be shifted - * @param {number | BigNumber} y Amount of shifts - * @return {number | BigNumber | Array | Matrix} `x` sign-filled shifted right `y` times - */ - var rightArithShift = typed('rightArithShift', { - - 'number, number': function (x, y) { - if (!isInteger$18(x) || !isInteger$18(y)) { - throw new Error('Integers expected in function rightArithShift'); - } - - return x >> y; - }, - - 'BigNumber, BigNumber': rightArithShift$1, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm08$$1(x, y, rightArithShift, false); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, rightArithShift, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, rightArithShift, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, rightArithShift); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return rightArithShift(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return rightArithShift(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return rightArithShift(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm11$$1(x, y, rightArithShift, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm14$$1(x, y, rightArithShift, false); - }, - - 'number | BigNumber, SparseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm10$$1(y, x, rightArithShift, true); - }, - - 'number | BigNumber, DenseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm14$$1(y, x, rightArithShift, true); - }, - - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return rightArithShift(matrix$$1(x), y).valueOf(); - }, - - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return rightArithShift(x, matrix$$1(y)).valueOf(); - } - }); - - rightArithShift.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['rightArithShift'] + '${args[1]}\\right)' - }; - - return rightArithShift; - } - - var name$166 = 'rightArithShift'; - var factory_1$177 = factory$178; - - var rightArithShift$2 = { - name: name$166, - factory: factory_1$177 - }; - - var isInteger$19 = number.isInteger; - - function factory$179 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - var equalScalar$$1 = load(equalScalar); - var zeros = load(zeros$1); - - var algorithm01$$1 = load(algorithm01); - var algorithm02$$1 = load(algorithm02); - var algorithm08$$1 = load(algorithm08); - var algorithm10$$1 = load(algorithm10); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Bitwise right logical shift of value x by y number of bits, `x >>> y`. - * For matrices, the function is evaluated element wise. - * For units, the function is evaluated on the best prefix base. - * - * Syntax: - * - * math.rightLogShift(x, y) - * - * Examples: - * - * math.rightLogShift(4, 2); // returns number 1 - * - * math.rightLogShift([16, -32, 64], 4); // returns Array [1, 2, 3] - * - * See also: - * - * bitAnd, bitNot, bitOr, bitXor, leftShift, rightLogShift - * - * @param {number | Array | Matrix} x Value to be shifted - * @param {number} y Amount of shifts - * @return {number | Array | Matrix} `x` zero-filled shifted right `y` times - */ - - var rightLogShift = typed('rightLogShift', { - - 'number, number': function (x, y) { - if (!isInteger$19(x) || !isInteger$19(y)) { - throw new Error('Integers expected in function rightLogShift'); - } - - return x >>> y; - }, - - // 'BigNumber, BigNumber': ..., // TODO: implement BigNumber support for rightLogShift - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm08$$1(x, y, rightLogShift, false); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, rightLogShift, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm01$$1(x, y, rightLogShift, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, rightLogShift); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return rightLogShift(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return rightLogShift(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return rightLogShift(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm11$$1(x, y, rightLogShift, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - // check scalar - if (equalScalar$$1(y, 0)) { - return x.clone(); - } - return algorithm14$$1(x, y, rightLogShift, false); - }, - - 'number | BigNumber, SparseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm10$$1(y, x, rightLogShift, true); - }, - - 'number | BigNumber, DenseMatrix': function (x, y) { - // check scalar - if (equalScalar$$1(x, 0)) { - return zeros(y.size(), y.storage()); - } - return algorithm14$$1(y, x, rightLogShift, true); - }, - - 'Array, number | BigNumber': function (x, y) { - // use matrix implementation - return rightLogShift(matrix$$1(x), y).valueOf(); - }, - - 'number | BigNumber, Array': function (x, y) { - // use matrix implementation - return rightLogShift(x, matrix$$1(y)).valueOf(); - } - }); - - rightLogShift.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['rightLogShift'] + '${args[1]}\\right)' - }; - - return rightLogShift; - } - - var name$167 = 'rightLogShift'; - var factory_1$178 = factory$179; - - var rightLogShift$1 = { - name: name$167, - factory: factory_1$178 - }; - - var bitwise$1 = [ - bitAnd$2, - bitNot$2, - bitOr$2, - bitXor$2, - leftShift$2, - rightArithShift$2, - rightLogShift$1 - ]; - - var isInteger$20 = number.isInteger; - - function factory$180 (type, config, load, typed) { - var multiply = load(multiply$1); - var pow = load(pow$1); - - /** - * Compute the gamma function of a value using Lanczos approximation for - * small values, and an extended Stirling approximation for large values. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.gamma(n) - * - * Examples: - * - * math.gamma(5); // returns 24 - * math.gamma(-0.5); // returns -3.5449077018110335 - * math.gamma(math.i); // returns -0.15494982830180973 - 0.49801566811835596i - * - * See also: - * - * combinations, factorial, permutations - * - * @param {number | Array | Matrix} n A real or complex number - * @return {number | Array | Matrix} The gamma of `n` - */ - var gamma = typed('gamma', { - 'number': function (n) { - var t, x; - - if (isInteger$20(n)) { - if (n <= 0) { - return isFinite(n) ? Infinity : NaN; - } - - if (n > 171) { - return Infinity; // Will overflow - } - - var value = n - 2; - var res = n - 1; - while (value > 1) { - res *= value; - value--; - } - - if (res == 0) { - res = 1; // 0! is per definition 1 - } - - return res; - } - - if (n < 0.5) { - return Math.PI / (Math.sin(Math.PI * n) * gamma(1-n)); - } - - if (n >= 171.35) { - return Infinity; // will overflow - } - - if (n > 85.0) { // Extended Stirling Approx - var twoN = n*n; - var threeN = twoN*n; - var fourN = threeN*n; - var fiveN = fourN*n; - return Math.sqrt(2*Math.PI/n) * Math.pow((n/Math.E), n) * - (1 + 1/(12*n) + 1/(288*twoN) - 139/(51840*threeN) - - 571/(2488320*fourN) + 163879/(209018880*fiveN) + - 5246819/(75246796800*fiveN*n)); - } - - --n; - x = p[0]; - for (var i = 1; i < p.length; ++i) { - x += p[i] / (n+i); - } - - t = n + g + 0.5; - return Math.sqrt(2*Math.PI) * Math.pow(t, n+0.5) * Math.exp(-t) * x; - }, - - 'Complex': function (n) { - var t, x; - - if (n.im == 0) { - return gamma(n.re); - } - - n = new type.Complex(n.re - 1, n.im); - x = new type.Complex(p[0], 0); - for (var i = 1; i < p.length; ++i) { - var real = n.re + i; // x += p[i]/(n+i) - var den = real*real + n.im*n.im; - if (den != 0) { - x.re += p[i] * real / den; - x.im += -(p[i] * n.im) / den; - } else { - x.re = p[i] < 0 - ? -Infinity - : Infinity; - } - } - - t = new type.Complex(n.re + g + 0.5, n.im); - var twoPiSqrt = Math.sqrt(2*Math.PI); - - n.re += 0.5; - var result = pow(t, n); - if (result.im == 0) { // sqrt(2*PI)*result - result.re *= twoPiSqrt; - } else if (result.re == 0) { - result.im *= twoPiSqrt; - } else { - result.re *= twoPiSqrt; - result.im *= twoPiSqrt; - } - - var r = Math.exp(-t.re); // exp(-t) - t.re = r * Math.cos(-t.im); - t.im = r * Math.sin(-t.im); - - return multiply(multiply(result, t), x); - }, - - 'BigNumber': function (n) { - if (n.isInteger()) { - return (n.isNegative() || n.isZero()) - ? new type.BigNumber(Infinity) - : bigFactorial(n.minus(1)); - } - - if (!n.isFinite()) { - return new type.BigNumber(n.isNegative() ? NaN : Infinity); - } - - throw new Error('Integer BigNumber expected'); - }, - - 'Array | Matrix': function (n) { - return deepMap(n, gamma); - } - }); - - /** - * Calculate factorial for a BigNumber - * @param {BigNumber} n - * @returns {BigNumber} Returns the factorial of n - */ - function bigFactorial(n) { - if (n.isZero()) { - return new type.BigNumber(1); // 0! is per definition 1 - } - - var precision = config.precision + (Math.log(n.toNumber()) | 0); - var Big = type.BigNumber.clone({precision: precision}); - - var res = new Big(n); - var value = n.toNumber() - 1; // number - while (value > 1) { - res = res.times(value); - value--; - } - - return new type.BigNumber(res.toPrecision(type.BigNumber.precision)); - } - - gamma.toTex = {1: '\\Gamma\\left(${args[0]}\\right)'}; - - return gamma; - } - - // TODO: comment on the variables g and p - - var g = 4.7421875; - - var p = [ - 0.99999999999999709182, - 57.156235665862923517, - -59.597960355475491248, - 14.136097974741747174, - -0.49191381609762019978, - 0.33994649984811888699e-4, - 0.46523628927048575665e-4, - -0.98374475304879564677e-4, - 0.15808870322491248884e-3, - -0.21026444172410488319e-3, - 0.21743961811521264320e-3, - -0.16431810653676389022e-3, - 0.84418223983852743293e-4, - -0.26190838401581408670e-4, - 0.36899182659531622704e-5 - ]; - - var name$168 = 'gamma'; - var factory_1$179 = factory$180; - - var gamma$1 = { - name: name$168, - factory: factory_1$179 - }; - - function factory$181 (type, config, load, typed) { - var gamma = load(gamma$1); - var latex$$1 = latex; - - /** - * Compute the factorial of a value - * - * Factorial only supports an integer value as argument. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.factorial(n) - * - * Examples: - * - * math.factorial(5); // returns 120 - * math.factorial(3); // returns 6 - * - * See also: - * - * combinations, gamma, permutations - * - * @param {number | BigNumber | Array | Matrix} n An integer number - * @return {number | BigNumber | Array | Matrix} The factorial of `n` - */ - var factorial = typed('factorial', { - 'number': function (n) { - if (n < 0) { - throw new Error('Value must be non-negative'); - } - - return gamma(n + 1); - }, - - 'BigNumber': function (n) { - if (n.isNegative()) { - throw new Error('Value must be non-negative'); - } - - return gamma(n.plus(1)); - }, - - 'Array | Matrix': function (n) { - return deepMap(n, factorial); - } - }); - - factorial.toTex = { - 1: '\\left(${args[0]}\\right)' + latex$$1.operators['factorial'] - }; - - return factorial; - } - - var name$169 = 'factorial'; - var factory_1$180 = factory$181; - - var factorial$1 = { - name: name$169, - factory: factory_1$180 - }; - - var isInteger$21 = number.isInteger; - - function factory$182 (type, config, load, typed) { - /** - * Compute the number of ways of picking `k` unordered outcomes from `n` - * possibilities. - * - * Combinations only takes integer arguments. - * The following condition must be enforced: k <= n. - * - * Syntax: - * - * math.combinations(n, k) - * - * Examples: - * - * math.combinations(7, 5); // returns 21 - * - * See also: - * - * permutations, factorial - * - * @param {number | BigNumber} n Total number of objects in the set - * @param {number | BigNumber} k Number of objects in the subset - * @return {number | BigNumber} Number of possible combinations. - */ - var combinations = typed('combinations', { - 'number, number': function (n, k) { - var max, result, i; - - if (!isInteger$21(n) || n < 0) { - throw new TypeError('Positive integer value expected in function combinations'); - } - if (!isInteger$21(k) || k < 0) { - throw new TypeError('Positive integer value expected in function combinations'); - } - if (k > n) { - throw new TypeError('k must be less than or equal to n'); - } - - max = Math.max(k, n - k); - result = 1; - for (i = 1; i <= n - max; i++) { - result = result * (max + i) / i; - } - - return result; - }, - - 'BigNumber, BigNumber': function (n, k) { - var max, result, i, ii; - var one = new type.BigNumber(1); - - if (!isPositiveInteger(n) || !isPositiveInteger(k)) { - throw new TypeError('Positive integer value expected in function combinations'); - } - if (k.gt(n)) { - throw new TypeError('k must be less than n in function combinations'); - } - - max = n.minus(k); - if (k.lt(max)) max = k; - result = one; - for (i = one, ii = n.minus(max); i.lte(ii); i = i.plus(1)) { - result = result.times(max.plus(i)).dividedBy(i); - } - - return result; - } - - // TODO: implement support for collection in combinations - }); - - combinations.toTex = {2: '\\binom{${args[0]}}{${args[1]}}'}; - - return combinations; - } - - /** - * Test whether BigNumber n is a positive integer - * @param {BigNumber} n - * @returns {boolean} isPositiveInteger - */ - function isPositiveInteger(n) { - return n.isInteger() && n.gte(0); - } - - var name$170 = 'combinations'; - var factory_1$181 = factory$182; - - var combinations$1 = { - name: name$170, - factory: factory_1$181 - }; - - function factory$183 (type, config, load, typed) { - /** - * Test whether a value is an integer number. - * The function supports `number`, `BigNumber`, and `Fraction`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isInteger(x) - * - * Examples: - * - * math.isInteger(2); // returns true - * math.isInteger(0); // returns true - * math.isInteger(0.5); // returns false - * math.isInteger(math.bignumber(500)); // returns true - * math.isInteger(math.fraction(4)); // returns true - * math.isInteger('3'); // returns true - * math.isInteger([3, 0.5, -2]); // returns [true, false, true] - * math.isInteger(math.complex('2-4i'); // throws an error - * - * See also: - * - * isNumeric, isPositive, isNegative, isZero - * - * @param {number | BigNumber | Fraction | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` contains a numeric, integer value. - * Throws an error in case of an unknown data type. - */ - var isInteger = typed('isInteger', { - 'number': number.isInteger, // TODO: what to do with isInteger(add(0.1, 0.2)) ? - - 'BigNumber': function (x) { - return x.isInt(); - }, - - 'Fraction': function (x) { - return x.d === 1 && isFinite(x.n); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, isInteger); - } - }); - - return isInteger; - } - - var name$171 = 'isInteger'; - var factory_1$182 = factory$183; - - var isInteger$22 = { - name: name$171, - factory: factory_1$182 - }; - - function factory$184 (type, config, load, typed) { - var add$$1 = load(add); - var subtract = load(subtract$1); - var multiply = load(multiply$1); - var divide = load(divide$1); - var pow = load(pow$1); - var factorial = load(factorial$1); - var combinations = load(combinations$1); - var isNegative = load(isNegative$1); - var isInteger = load(isInteger$22); - var larger$$1 = load(larger); - - /** - * The Stirling numbers of the second kind, counts the number of ways to partition - * a set of n labelled objects into k nonempty unlabelled subsets. - * stirlingS2 only takes integer arguments. - * The following condition must be enforced: k <= n. - * - * If n = k or k = 1, then s(n,k) = 1 - * - * Syntax: - * - * math.stirlingS2(n, k) - * - * Examples: - * - * math.stirlingS2(5, 3); //returns 25 - * - * See also: - * - * Bell numbers - * - * @param {Number | BigNumber} n Total number of objects in the set - * @param {Number | BigNumber} k Number of objects in the subset - * @return {Number | BigNumber} S(n,k) - */ - var stirlingS2 = typed('stirlingS2', { - 'number | BigNumber, number | BigNumber': function (n, k) { - if (!isInteger(n) || isNegative(n) || !isInteger(k) || isNegative(k)) { - throw new TypeError('Non-negative integer value expected in function stirlingS2'); - } - else if (larger$$1(k, n)) { - throw new TypeError('k must be less than or equal to n in function stirlingS2'); - } - - // 1/k! Sum(i=0 -> k) [(-1)^(k-i)*C(k,j)* i^n] - var kFactorial = factorial(k); - var result = 0; - for(var i = 0; i <= k; i++) { - var negativeOne = pow(-1, subtract(k,i)); - var kChooseI = combinations(k,i); - var iPower = pow(i,n); - - result = add$$1(result, multiply(multiply(kChooseI, iPower), negativeOne)); - } - - return divide(result, kFactorial); - } - }); - - stirlingS2.toTex = {2: '\\mathrm{S}\\left(${args}\\right)'}; - - return stirlingS2; - } - - var name$172 = 'stirlingS2'; - var factory_1$183 = factory$184; - - var stirlingS2$1 = { - name: name$172, - factory: factory_1$183 - }; - - function factory$185 (type, config, load, typed) { - var add$$1 = load(add); - var stirlingS2 = load(stirlingS2$1); - var isNegative = load(isNegative$1); - var isInteger = load(isInteger$22); - - /** - * The Bell Numbers count the number of partitions of a set. A partition is a pairwise disjoint subset of S whose union is S. - * bellNumbers only takes integer arguments. - * The following condition must be enforced: n >= 0 - * - * Syntax: - * - * math.bellNumbers(n) - * - * Examples: - * - * math.bellNumbers(3); // returns 5; - * math.bellNumbers(8); // returns 4140; - * - * See also: - * - * stirlingS2 - * - * @param {Number | BigNumber} n Total number of objects in the set - * @return {Number | BigNumber} B(n) - */ - var bellNumbers = typed('bellNumbers', { - 'number | BigNumber': function (n) { - - if (!isInteger(n) || isNegative(n)) { - throw new TypeError('Non-negative integer value expected in function bellNumbers'); - } - - // Sum (k=0, n) S(n,k). - var result = 0; - for(var i = 0; i <= n; i++) { - result = add$$1(result, stirlingS2(n, i)); - } - - return result; - } - }); - - bellNumbers.toTex = {1: '\\mathrm{B}_{${args[0]}}'}; - - return bellNumbers; - } - - var name$173 = 'bellNumbers'; - var factory_1$184 = factory$185; - - var bellNumbers$1 = { - name: name$173, - factory: factory_1$184 - }; - - function factory$186 (type, config, load, typed) { - var combinations = load(combinations$1); - var add = load(addScalar); - var isPositive = load(isPositive$1); - var isInteger = load(isInteger$22); - var larger$$1 = load(larger); - - /** - * The composition counts of n into k parts. - * - * composition only takes integer arguments. - * The following condition must be enforced: k <= n. - * - * Syntax: - * - * math.composition(n, k) - * - * Examples: - * - * math.composition(5, 3); // returns 6 - * - * See also: - * - * combinations - * - * @param {Number | BigNumber} n Total number of objects in the set - * @param {Number | BigNumber} k Number of objects in the subset - * @return {Number | BigNumber} Returns the composition counts of n into k parts. - */ - var composition = typed('composition', { - 'number | BigNumber, number | BigNumber': function (n, k) { - if (!isInteger(n) || !isPositive(n) || !isInteger(k) || !isPositive(k)) { - throw new TypeError('Positive integer value expected in function composition'); - } - else if (larger$$1(k, n)) { - throw new TypeError('k must be less than or equal to n in function composition'); - } - - return combinations(add(n, -1), add(k, -1)); - } - }); - - composition.toTex = undefined; // use default template - - return composition; - } - - var name$174 = 'composition'; - var factory_1$185 = factory$186; - - var composition$1 = { - name: name$174, - factory: factory_1$185 - }; - - function factory$187 (type, config, load, typed) { - var add$$1 = load(add); - var divide = load(divide$1); - var multiply = load(multiply$1); - var combinations = load(combinations$1); - var isNegative = load(isNegative$1); - var isInteger = load(isInteger$22); - - - /** - * The Catalan Numbers enumerate combinatorial structures of many different types. - * catalan only takes integer arguments. - * The following condition must be enforced: n >= 0 - * - * Syntax: - * - * math.catalan(n) - * - * Examples: - * - * math.catalan(3); // returns 5; - * math.catalan(8); // returns 1430; - * - * See also: - * - * bellNumbers - * - * @param {Number | BigNumber} n nth Catalan number - * @return {Number | BigNumber} Cn(n) - */ - var catalan = typed('catalan', { - 'number | BigNumber': function (n) { - - if (!isInteger(n) || isNegative(n)) { - throw new TypeError('Non-negative integer value expected in function catalan'); - } - - return divide(combinations(multiply(n,2), n), add$$1(n,1)); - - } - }); - - catalan.toTex = {1: '\\mathrm{C}_{${args[0]}}'}; - - return catalan; - } - - var name$175 = 'catalan'; - var factory_1$186 = factory$187; - - var catalan$1 = { - name: name$175, - factory: factory_1$186 - }; - - var combinatorics = [ - bellNumbers$1, - composition$1, - stirlingS2$1, - catalan$1 - ]; - - function factory$188 (type, config, load, typed) { - /** - * Compute the argument of a complex value. - * For a complex number `a + bi`, the argument is computed as `atan2(b, a)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.arg(x) - * - * Examples: - * - * var a = math.complex(2, 2); - * math.arg(a) / math.pi; // returns number 0.25 - * - * var b = math.complex('2 + 3i'); - * math.arg(b); // returns number 0.982793723247329 - * math.atan2(3, 2); // returns number 0.982793723247329 - * - * See also: - * - * re, im, conj, abs - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * A complex number or array with complex numbers - * @return {number | BigNumber | Array | Matrix} The argument of x - */ - var arg = typed('arg', { - 'number': function (x) { - return Math.atan2(0, x); - }, - - 'BigNumber': function (x) { - return type.BigNumber.atan2(0, x); - }, - - 'Complex': function (x) { - return x.arg(); - }, - - // TODO: implement BigNumber support for function arg - - 'Array | Matrix': function (x) { - return deepMap(x, arg); - } - }); - - arg.toTex = {1: '\\arg\\left(${args[0]}\\right)'}; - - return arg; - } - - var name$176 = 'arg'; - var factory_1$187 = factory$188; - - var arg$1 = { - name: name$176, - factory: factory_1$187 - }; - - function factory$189 (type, config, load, typed) { - /** - * Get the imaginary part of a complex number. - * For a complex number `a + bi`, the function returns `b`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.im(x) - * - * Examples: - * - * var a = math.complex(2, 3); - * math.re(a); // returns number 2 - * math.im(a); // returns number 3 - * - * math.re(math.complex('-5.2i')); // returns number -5.2 - * math.re(math.complex(2.4)); // returns number 0 - * - * See also: - * - * re, conj, abs, arg - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * A complex number or array with complex numbers - * @return {number | BigNumber | Array | Matrix} The imaginary part of x - */ - var im = typed('im', { - 'number': function (x) { - return 0; - }, - - 'BigNumber': function (x) { - return new type.BigNumber(0); - }, - - 'Complex': function (x) { - return x.im; - }, - - 'Array | Matrix': function (x) { - return deepMap(x, im); - } - }); - - im.toTex = {1: '\\Im\\left\\lbrace${args[0]}\\right\\rbrace'}; - - return im; - } - - var name$177 = 'im'; - var factory_1$188 = factory$189; - - var im$1 = { - name: name$177, - factory: factory_1$188 - }; - - function factory$190 (type, config, load, typed) { - /** - * Get the real part of a complex number. - * For a complex number `a + bi`, the function returns `a`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.re(x) - * - * Examples: - * - * var a = math.complex(2, 3); - * math.re(a); // returns number 2 - * math.im(a); // returns number 3 - * - * math.re(math.complex('-5.2i')); // returns number 0 - * math.re(math.complex(2.4)); // returns number 2.4 - * - * See also: - * - * im, conj, abs, arg - * - * @param {number | BigNumber | Complex | Array | Matrix} x - * A complex number or array with complex numbers - * @return {number | BigNumber | Array | Matrix} The real part of x - */ - var re = typed('re', { - 'number': function (x) { - return x; - }, - - 'BigNumber': function (x) { - return x; - }, - - 'Complex': function (x) { - return x.re; - }, - - 'Array | Matrix': function (x) { - return deepMap(x, re); - } - }); - - re.toTex = {1: '\\Re\\left\\lbrace${args[0]}\\right\\rbrace'}; - - return re; - } - - var name$178 = 're'; - var factory_1$189 = factory$190; - - var re$1 = { - name: name$178, - factory: factory_1$189 - }; - - var complex$5 = [ - arg$1, - conj$1, - im$1, - re$1 - ]; - - function factory$191 (type, config, load, typed) { - - var abs = load(abs$1); - var add$$1 = load(add); - var addScalar$$1 = load(addScalar); - var matrix$$1 = load(matrix); - var multiply = load(multiply$1); - var multiplyScalar$$1 = load(multiplyScalar); - var divideScalar$$1 = load(divideScalar); - var subtract = load(subtract$1); - var smaller$$1 = load(smaller); - var equalScalar$$1 = load(equalScalar); - - /** - * Calculates the point of intersection of two lines in two or three dimensions - * and of a line and a plane in three dimensions. The inputs are in the form of - * arrays or 1 dimensional matrices. The line intersection functions return null - * if the lines do not meet. - * - * Note: Fill the plane coefficients as `x + y + z = c` and not as `x + y + z + c = 0`. - * - * Syntax: - * - * math.intersect(endPoint1Line1, endPoint2Line1, endPoint1Line2, endPoint2Line2) - * math.intersect(endPoint1, endPoint2, planeCoefficients) - * - * Examples: - * - * math.intersect([0, 0], [10, 10], [10, 0], [0, 10]); // Returns [5, 5] - * math.intersect([0, 0, 0], [10, 10, 0], [10, 0, 0], [0, 10, 0]); // Returns [5, 5, 0] - * math.intersect([1, 0, 1], [4, -2, 2], [1, 1, 1, 6]); // Returns [7, -4, 3] - * - * @param {Array | Matrix} w Co-ordinates of first end-point of first line - * @param {Array | Matrix} x Co-ordinates of second end-point of first line - * @param {Array | Matrix} y Co-ordinates of first end-point of second line - * OR Co-efficients of the plane's equation - * @param {Array | Matrix} z Co-ordinates of second end-point of second line - * OR null if the calculation is for line and plane - * @return {Array} Returns the point of intersection of lines/lines-planes - */ - var intersect = typed('intersect', { - 'Array, Array, Array': function (x, y, plane) { - if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } - if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - if (!_4d(plane)) { throw new TypeError('Array with 4 numbers expected as third argument'); } - - return _intersectLinePlane(x[0], x[1], x[2], y[0], y[1], y[2], plane[0], plane[1], plane[2], plane[3]); - }, - - 'Array, Array, Array, Array': function (w, x, y, z) { - if (w.length === 2) { - if (!_2d(w)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } - if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } - if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for third argument'); } - if (!_2d(z)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for fourth argument'); } - - return _intersect2d(w, x, y, z); - } - else if (w.length === 3) { - if (!_3d(w)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } - if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for third argument'); } - if (!_3d(z)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for fourth argument'); } - - return _intersect3d(w[0], w[1], w[2], x[0], x[1], x[2], y[0], y[1], y[2], z[0], z[1], z[2]); - } - else { - throw new TypeError('Arrays with two or thee dimensional points expected'); - } - }, - - 'Matrix, Matrix, Matrix': function (x, y, plane) { - return matrix$$1(intersect(x.valueOf(), y.valueOf(), plane.valueOf())); - }, - - 'Matrix, Matrix, Matrix, Matrix': function (w, x, y, z) { - // TODO: output matrix type should match input matrix type - return matrix$$1(intersect(w.valueOf(), x.valueOf(), y.valueOf(), z.valueOf())); - } - }); - - function _isNumber(a) { - // intersect supports numbers and bignumbers - return (typeof a === 'number' || type.isBigNumber(a)); - } - - function _2d(x) { - return x.length === 2 && _isNumber(x[0]) && _isNumber(x[1]); - } - - function _3d(x) { - return x.length === 3 && _isNumber(x[0]) && _isNumber(x[1]) && _isNumber(x[2]); - } - - function _4d(x) { - return x.length === 4 && _isNumber(x[0]) && _isNumber(x[1]) && _isNumber(x[2]) && _isNumber(x[3]); - } - - function _intersect2d(p1a, p1b, p2a, p2b){ - var o1 = p1a; - var o2 = p2a; - var d1 = subtract(o1, p1b); - var d2 = subtract(o2, p2b); - var det = subtract(multiplyScalar$$1(d1[0], d2[1]), multiplyScalar$$1(d2[0], d1[1])); - if (smaller$$1(abs(det), config.epsilon)) { - return null; - } - var d20o11 = multiplyScalar$$1(d2[0], o1[1]); - var d21o10 = multiplyScalar$$1(d2[1], o1[0]); - var d20o21 = multiplyScalar$$1(d2[0], o2[1]); - var d21o20 = multiplyScalar$$1(d2[1], o2[0]); - var t = divideScalar$$1(addScalar$$1(subtract(subtract(d20o11, d21o10), d20o21), d21o20), det); - return add$$1(multiply(d1, t), o1); - } - - function _intersect3dHelper(a, b, c, d, e, f, g, h, i, j, k, l){ - // (a - b)*(c - d) + (e - f)*(g - h) + (i - j)*(k - l) - var add1 = multiplyScalar$$1(subtract(a, b), subtract(c, d)); - var add2 = multiplyScalar$$1(subtract(e, f), subtract(g, h)); - var add3 = multiplyScalar$$1(subtract(i, j), subtract(k, l)); - return addScalar$$1(addScalar$$1(add1, add2), add3); - } - - function _intersect3d(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4){ - var d1343 = _intersect3dHelper(x1, x3, x4, x3, y1, y3, y4, y3, z1, z3, z4, z3); - var d4321 = _intersect3dHelper(x4, x3, x2, x1, y4, y3, y2, y1, z4, z3, z2, z1); - var d1321 = _intersect3dHelper(x1, x3, x2, x1, y1, y3, y2, y1, z1, z3, z2, z1); - var d4343 = _intersect3dHelper(x4, x3, x4, x3, y4, y3, y4, y3, z4, z3, z4, z3); - var d2121 = _intersect3dHelper(x2, x1, x2, x1, y2, y1, y2, y1, z2, z1, z2, z1); - var ta = divideScalar$$1( - subtract(multiplyScalar$$1(d1343, d4321), multiplyScalar$$1(d1321, d4343)), - subtract(multiplyScalar$$1(d2121, d4343), multiplyScalar$$1(d4321, d4321))); - var tb = divideScalar$$1(addScalar$$1(d1343, multiplyScalar$$1(ta, d4321)), d4343); - - var pax = addScalar$$1(x1, multiplyScalar$$1(ta, subtract(x2, x1))); - var pay = addScalar$$1(y1, multiplyScalar$$1(ta, subtract(y2, y1))); - var paz = addScalar$$1(z1, multiplyScalar$$1(ta, subtract(z2, z1))); - var pbx = addScalar$$1(x3, multiplyScalar$$1(tb, subtract(x4, x3))); - var pby = addScalar$$1(y3, multiplyScalar$$1(tb, subtract(y4, y3))); - var pbz = addScalar$$1(z3, multiplyScalar$$1(tb, subtract(z4, z3))); - if (equalScalar$$1(pax, pbx) && equalScalar$$1(pay, pby) && equalScalar$$1(paz, pbz)){ - return [pax, pay, paz]; - } - else{ - return null; - } - } - - function _intersectLinePlane(x1, y1, z1, x2, y2, z2, x, y, z, c){ - var x1x = multiplyScalar$$1(x1, x); - var x2x = multiplyScalar$$1(x2, x); - var y1y = multiplyScalar$$1(y1, y); - var y2y = multiplyScalar$$1(y2, y); - var z1z = multiplyScalar$$1(z1, z); - var z2z = multiplyScalar$$1(z2, z); - var t = divideScalar$$1( - subtract(subtract(subtract(c, x1x), y1y), z1z), - subtract(subtract(subtract(addScalar$$1(addScalar$$1(x2x, y2y), z2z), x1x), y1y), z1z)); - var px = addScalar$$1(x1, multiplyScalar$$1(t, subtract(x2, x1))); - var py = addScalar$$1(y1, multiplyScalar$$1(t, subtract(y2, y1))); - var pz = addScalar$$1(z1, multiplyScalar$$1(t, subtract(z2, z1))); - return [px, py, pz]; - // TODO: Add cases when line is parallel to the plane: - // (a) no intersection, - // (b) line contained in plane - } - - return intersect; - } - - var name$179 = 'intersect'; - var factory_1$190 = factory$191; - - var intersect$1 = { - name: name$179, - factory: factory_1$190 - }; - - function factory$192 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var add = load(addScalar); - var subtract = load(subtract$1); - var multiply = load(multiplyScalar); - var divide = load(divideScalar); - var negate = load(unaryMinus$1); - var sqrt = load(sqrt$1); - var abs = load(abs$1); - - /** - * Calculates: - * The eucledian distance between two points in 2 and 3 dimensional spaces. - * Distance between point and a line in 2 and 3 dimensional spaces. - * Pairwise distance between a set of 2D or 3D points - * NOTE: - * When substituting coefficients of a line(a, b and c), use ax + by + c = 0 instead of ax + by = c - * For parametric equation of a 3D line, x0, y0, z0, a, b, c are from: (x−x0, y−y0, z−z0) = t(a, b, c) - * - * Syntax: - * math.distance([x1, y1], [x2, y2]) - *- math.distance({pointOneX: 4, pointOneY: 5}, {pointTwoX: 2, pointTwoY: 7}) - * math.distance([x1, y1, z1], [x2, y2, z2]) - * math.distance({pointOneX: 4, pointOneY: 5, pointOneZ: 8}, {pointTwoX: 2, pointTwoY: 7, pointTwoZ: 9}) - * math.distance([[A], [B], [C]...]) - * math.distance([x1, y1], [LinePtX1, LinePtY1], [LinePtX2, LinePtY2]) - * math.distance({pointX: 1, pointY: 4}, {lineOnePtX: 6, lineOnePtY: 3}, {lineTwoPtX: 2, lineTwoPtY: 8}) - * math.distance([x1, y1, z1], [LinePtX1, LinePtY1, LinePtZ1], [LinePtX2, LinePtY2, LinePtZ2]) - * math.distance({pointX: 1, pointY: 4, pointZ: 7}, {lineOnePtX: 6, lineOnePtY: 3, lineOnePtZ: 4}, {lineTwoPtX: 2, lineTwoPtY: 8, lineTwoPtZ: 5}) - * math.distance([x1, y1], [xCoeffLine, yCoeffLine, constant]) - * math.distance({pointX: 10, pointY: 10}, {xCoeffLine: 8, yCoeffLine: 1, constant: 3}) - * math.distance([x1, y1, z1], [x0, y0, z0, a-tCoeff, b-tCoeff, c-tCoeff]) point and parametric equation of 3D line - * math.distance([x, y, z], [x0, y0, z0, a, b, c]) - * math.distance({pointX: 2, pointY: 5, pointZ: 9}, {x0: 4, y0: 6, z0: 3, a: 4, b: 2, c: 0}) - * - * Examples: - * math.distance([0,0], [4,4]) // Returns 5.6569 - * math.distance( - * {pointOneX: 0, pointOneY: 0}, - * {pointTwoX: 10, pointTwoY: 10}) // Returns 14.142135623730951 - * math.distance([1, 0, 1], [4, -2, 2]) // Returns 3.74166 - * math.distance( - * {pointOneX: 4, pointOneY: 5, pointOneZ: 8}, - * {pointTwoX: 2, pointTwoY: 7, pointTwoZ: 9}) // Returns 3 - * math.distance([[1, 2], [1, 2], [1, 3]]) // Returns [0, 1, 1] - * math.distance([[1,2,4], [1,2,6], [8,1,3]]) // Returns [2, 7.14142842854285, 7.681145747868608] - * math.distance([10, 10], [8, 1, 3]) // Returns 11.535230316796387 - * math.distance([10, 10], [2, 3], [-8, 0]) // Returns 8.759953130362847 - * math.distance( - * {pointX: 1, pointY: 4}, - * {lineOnePtX: 6, lineOnePtY: 3}, - * {lineTwoPtX: 2, lineTwoPtY: 8}) // Returns 2.720549372624744 - * math.distance([2, 3, 1], [1, 1, 2, 5, 0, 1]) // Returns 2.3204774044612857 - * math.distance( - * {pointX: 2, pointY: 3, pointZ: 1}, - * {x0: 1, y0: 1, z0: 2, a: 5, b: 0, c: 1} // Returns 2.3204774044612857 - * - * @param {Array | Matrix | Object} x Co-ordinates of first point - * @param {Array | Matrix | Object} y Co-ordinates of second point - * @return {Number | BigNumber} Returns the distance from two/three points - */ - - var distance = typed('distance', { - 'Array, Array, Array': function(x, y, z){ - // Point to Line 2D; (x=Point, y=LinePoint1, z=LinePoint2) - if (x.length == 2 && y.length == 2 && z.length == 2){ - if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } - if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } - if (!_2d(z)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for third argument'); } - var m = divide(subtract(z[1], z[0]), subtract(y[1], y[0])); - var xCoeff = multiply(multiply(m, m), y[0]); - var yCoeff = negate(multiply(m, y[0])); - var constant = x[1]; - - return _distancePointLine2D(x[0], x[1], xCoeff, yCoeff, constant); - } - else{ - throw new TypeError('Invalid Arguments: Try again'); - } - }, - 'Object, Object, Object': function(x, y, z){ - if (Object.keys(x).length == 2 && Object.keys(y).length == 2 && Object.keys(z).length == 2){ - if (!_2d(x)) { throw new TypeError('Values of pointX and pointY should be numbers or BigNumbers'); } - if (!_2d(y)) { throw new TypeError('Values of lineOnePtX and lineOnePtY should be numbers or BigNumbers'); } - if (!_2d(z)) { throw new TypeError('Values of lineTwoPtX and lineTwoPtY should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('lineOnePtX') && - y.hasOwnProperty('lineOnePtY') && z.hasOwnProperty('lineTwoPtX') && z.hasOwnProperty('lineTwoPtY')){ - var m = divide(subtract(z.lineTwoPtY, z.lineTwoPtX), subtract(y.lineOnePtY, y.lineOnePtX)); - var xCoeff = multiply(multiply(m, m), y.lineOnePtX); - var yCoeff = negate(multiply(m, y.lineOnePtX)); - var constant = x.pointX; - - return _distancePointLine2D(x.pointX, x.pointY, xCoeff, yCoeff, constant); - } - else{ - throw new TypeError('Key names do not match'); - } - } - else{ - throw new TypeError('Invalid Arguments: Try again'); - } - }, - 'Array, Array': function(x, y){ - // Point to Line 2D; (x=[pointX, pointY], y=[x-coeff, y-coeff, const]) - if (x.length == 2 && y.length == 3){ - if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } - if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - - return _distancePointLine2D(x[0], x[1], y[0], y[1], y[2]); - } - // Point to Line 3D - else if (x.length == 3 && y.length == 6){ - if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } - if (!_parametricLine(y)) { throw new TypeError('Array with 6 numbers or BigNumbers expected for second argument'); } - - return _distancePointLine3D(x[0], x[1], x[2], y[0], y[1], y[2], y[3], y[4], y[5]); - } - // Point to Point 2D - else if (x.length == 2 && y.length == 2){ - if (!_2d(x)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for first argument'); } - if (!_2d(y)) { throw new TypeError('Array with 2 numbers or BigNumbers expected for second argument'); } - - return _distance2d(x[0], x[1], y[0], y[1]); - } - // Point to Point 3D - else if(x.length == 3 && y.length == 3){ - if (!_3d(x)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for first argument'); } - if (!_3d(y)) { throw new TypeError('Array with 3 numbers or BigNumbers expected for second argument'); } - - return _distance3d(x[0], x[1], x[2], y[0], y[1], y[2]); - } - else{ - throw new TypeError('Invalid Arguments: Try again'); - } - }, - 'Object, Object': function(x, y){ - if (Object.keys(x).length == 2 && Object.keys(y).length == 3){ - if (!_2d(x)) { throw new TypeError('Values of pointX and pointY should be numbers or BigNumbers'); } - if (!_3d(y)) { throw new TypeError('Values of xCoeffLine, yCoeffLine and constant should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('xCoeffLine') && - y.hasOwnProperty('yCoeffLine') && y.hasOwnProperty('constant')){ - - return _distancePointLine2D(x.pointX, x.pointY, y.xCoeffLine, y.yCoeffLine, y.constant); - } - else{ - throw new TypeError('Key names do not match'); - } - } - // Point to Line 3D - else if (Object.keys(x).length == 3 && Object.keys(y).length == 6){ - if (!_3d(x)) { throw new TypeError('Values of pointX, pointY and pointZ should be numbers or BigNumbers'); } - if (!_parametricLine(y)) { throw new TypeError('Values of x0, y0, z0, a, b and c should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointX') && x.hasOwnProperty('pointY') && y.hasOwnProperty('x0') && - y.hasOwnProperty('y0') && y.hasOwnProperty('z0') && y.hasOwnProperty('a') && - y.hasOwnProperty('b') && y.hasOwnProperty('c')){ - - return _distancePointLine3D(x.pointX, x.pointY, x.pointZ, y.x0, y.y0, y.z0, y.a, y.b, y.c); - } - else{ - throw new TypeError('Key names do not match'); - } - } - // Point to Point 2D - else if (Object.keys(x).length == 2 && Object.keys(y).length == 2){ - if (!_2d(x)) { throw new TypeError('Values of pointOneX and pointOneY should be numbers or BigNumbers'); } - if (!_2d(y)) { throw new TypeError('Values of pointTwoX and pointTwoY should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointOneX') && x.hasOwnProperty('pointOneY') && - y.hasOwnProperty('pointTwoX') && y.hasOwnProperty('pointTwoY')){ - - return _distance2d(x.pointOneX, x.pointOneY, y.pointTwoX, y.pointTwoY); - } - else{ - throw new TypeError('Key names do not match'); - } - } - // Point to Point 3D - else if(Object.keys(x).length == 3 && Object.keys(y).length == 3){ - if (!_3d(x)) { throw new TypeError('Values of pointOneX, pointOneY and pointOneZ should be numbers or BigNumbers'); } - if (!_3d(y)) { throw new TypeError('Values of pointTwoX, pointTwoY and pointTwoZ should be numbers or BigNumbers'); } - if (x.hasOwnProperty('pointOneX') && x.hasOwnProperty('pointOneY') && x.hasOwnProperty('pointOneZ') && - y.hasOwnProperty('pointTwoX') && y.hasOwnProperty('pointTwoY') && y.hasOwnProperty('pointTwoZ')){ - - return _distance3d(x.pointOneX, x.pointOneY, x.pointOneZ, y.pointTwoX, y.pointTwoY, y.pointTwoZ); - } - else { - throw new TypeError('Key names do not match'); - } - } - else{ - throw new TypeError('Invalid Arguments: Try again'); - } - }, - 'Array': function(arr){ - if (!_pairwise(arr)) { throw new TypeError('Incorrect array format entered for pairwise distance calculation'); } - - return _distancePairwise(arr); - } - }); - - function _isNumber(a) { - // distance supports numbers and bignumbers - return (typeof a === 'number' || type.isBigNumber(a)); - } - - function _2d(a){ - // checks if the number of arguments are correct in count and are valid (should be numbers) - if (a.constructor !== Array){ - a = _objectToArray(a); - } - return _isNumber(a[0]) && _isNumber(a[1]); - } - - function _3d(a){ - // checks if the number of arguments are correct in count and are valid (should be numbers) - if (a.constructor !== Array){ - a = _objectToArray(a); - } - return _isNumber(a[0]) && _isNumber(a[1]) && _isNumber(a[2]); - } - - function _parametricLine(a){ - if (a.constructor !== Array){ - a = _objectToArray(a); - } - return _isNumber(a[0]) && _isNumber(a[1]) && _isNumber(a[2]) && - _isNumber(a[3]) && _isNumber(a[4]) && _isNumber(a[5]); - } - - function _objectToArray(o){ - var keys = Object.keys(o); - var a = []; - for (var i = 0; i < keys.length; i++) { - a.push(o[keys[i]]); - } - return a; - } - - function _pairwise(a){ - //checks for valid arguments passed to _distancePairwise(Array) - if (a[0].length == 2 && _isNumber(a[0][0]) && _isNumber(a[0][1])){ - for(var i in a){ - if (a[i].length != 2 || !_isNumber(a[i][0]) || !_isNumber(a[i][1])){ - return false; - } - } - } - else if (a[0].length == 3 && _isNumber(a[0][0]) && _isNumber(a[0][1]) && _isNumber(a[0][2])){ - for(var i in a){ - if (a[i].length != 3 || !_isNumber(a[i][0]) || !_isNumber(a[i][1]) || !_isNumber(a[i][2])){ - return false; - } - } - } - else{ - return false; - } - return true; - } - - function _distancePointLine2D(x, y, a, b, c){ - var num = abs(add(add(multiply(a, x), multiply(b, y)), c)); - var den = sqrt(add(multiply(a, a), multiply(b, b))); - var result = divide(num, den); - return result; - } - - function _distancePointLine3D(x, y, z, x0, y0, z0, a, b, c){ - var num = [ subtract(multiply(subtract(y0, y), c), multiply(subtract(z0, z), b)), - subtract(multiply(subtract(z0, z), a), multiply(subtract(x0, x), c)), - subtract(multiply(subtract(x0, x), b), multiply(subtract(y0, y), a)) ]; - num = sqrt(add(add(multiply(num[0], num[0]), multiply(num[1], num[1])), multiply(num[2], num[2]))); - var den = sqrt(add(add(multiply(a, a), multiply(b, b)), multiply(c, c))); - var result = divide(num, den); - return result; - } - - function _distance2d(x1, y1, x2, y2){ - var yDiff = subtract(y2, y1); - var xDiff = subtract(x2, x1); - var radicant = add(multiply(yDiff, yDiff), multiply(xDiff, xDiff)); - var result = sqrt(radicant); - return result; - } - - function _distance3d(x1, y1, z1, x2, y2, z2){ - var zDiff = subtract(z2, z1); - var yDiff = subtract(y2, y1); - var xDiff = subtract(x2, x1); - var radicant = add(add(multiply(zDiff, zDiff), multiply(yDiff, yDiff)), multiply(xDiff, xDiff)); - var result = sqrt(radicant); - return result; - } - - function _distancePairwise(a){ - var result = []; - for(var i = 0; i < a.length-1; i++){ - for(var j = i+1; j < a.length; j++){ - if (a[0].length == 2){ - result.push(_distance2d(a[i][0], a[i][1], a[j][0], a[j][1])); - } - else if (a[0].length == 3){ - result.push(_distance3d(a[i][0], a[i][1], a[i][2], a[j][0], a[j][1], a[j][2])); - } - } - } - return result; - } - - return distance; - } - - var name$180 = 'distance'; - var factory_1$191 = factory$192; - - var distance$1 = { - name: name$180, - factory: factory_1$191 - }; - - var geometry = [ - intersect$1, - distance$1 - ]; - - function factory$193 (type, config, load, typed) { - var latex$$1 = latex; - - /** - * Logical `not`. Flips boolean value of a given parameter. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.not(x) - * - * Examples: - * - * math.not(2); // returns false - * math.not(0); // returns true - * math.not(true); // returns false - * - * a = [2, -7, 0]; - * math.not(a); // returns [false, false, true] - * - * See also: - * - * and, or, xor - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @return {boolean | Array | Matrix} - * Returns true when input is a zero or empty value. - */ - var not = typed('not', { - 'number': function (x) { - return !x; - }, - - 'Complex': function (x) { - return x.re === 0 && x.im === 0; - }, - - 'BigNumber': function (x) { - return x.isZero() || x.isNaN(); - }, - - 'Unit': function (x) { - return x.value !== null ? not(x.value) : true; - }, - - 'Array | Matrix': function (x) { - return deepMap(x, not); - } - }); - - not.toTex = { - 1: latex$$1.operators['not'] + '\\left(${args[0]}\\right)' - }; - - return not; - } - - var name$181 = 'not'; - var factory_1$192 = factory$193; - - var not$1 = { - name: name$181, - factory: factory_1$192 - }; - - function factory$194 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - var zeros = load(zeros$1); - var not = load(not$1); - var isZero = load(isZero$1); - - var algorithm02$$1 = load(algorithm02); - var algorithm06$$1 = load(algorithm06); - var algorithm11$$1 = load(algorithm11); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Logical `and`. Test whether two values are both defined with a nonzero/nonempty value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.and(x, y) - * - * Examples: - * - * math.and(2, 4); // returns true - * - * a = [2, 0, 0]; - * b = [3, 7, 0]; - * c = 0; - * - * math.and(a, b); // returns [true, false, false] - * math.and(a, c); // returns [false, false, false] - * - * See also: - * - * not, or, xor - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check - * @return {boolean | Array | Matrix} - * Returns true when both inputs are defined with a nonzero/nonempty value. - */ - var and = typed('and', { - - 'number, number': function (x, y) { - return !!(x && y); - }, - - 'Complex, Complex': function (x, y) { - return (x.re !== 0 || x.im !== 0) && (y.re !== 0 || y.im !== 0); - }, - - 'BigNumber, BigNumber': function (x, y) { - return !x.isZero() && !y.isZero() && !x.isNaN() && !y.isNaN(); - }, - - 'Unit, Unit': function (x, y) { - return and(x.value || 0, y.value || 0); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm06$$1(x, y, and, false); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm02$$1(y, x, and, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm02$$1(x, y, and, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, and); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return and(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return and(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return and(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - // check scalar - if (not(y)) { - // return zero matrix - return zeros(x.size(), x.storage()); - } - return algorithm11$$1(x, y, and, false); - }, - - 'DenseMatrix, any': function (x, y) { - // check scalar - if (not(y)) { - // return zero matrix - return zeros(x.size(), x.storage()); - } - return algorithm14$$1(x, y, and, false); - }, - - 'any, SparseMatrix': function (x, y) { - // check scalar - if (not(x)) { - // return zero matrix - return zeros(x.size(), x.storage()); - } - return algorithm11$$1(y, x, and, true); - }, - - 'any, DenseMatrix': function (x, y) { - // check scalar - if (not(x)) { - // return zero matrix - return zeros(x.size(), x.storage()); - } - return algorithm14$$1(y, x, and, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return and(matrix$$1(x), y).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return and(x, matrix$$1(y)).valueOf(); - } - }); - - and.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['and'] + '${args[1]}\\right)' - }; - - return and; - } - - var name$182 = 'and'; - var factory_1$193 = factory$194; - - var and$1 = { - name: name$182, - factory: factory_1$193 - }; - - function factory$195 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm05$$1 = load(algorithm05); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Logical `or`. Test if at least one value is defined with a nonzero/nonempty value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.or(x, y) - * - * Examples: - * - * math.or(2, 4); // returns true - * - * a = [2, 5, 0]; - * b = [0, 22, 0]; - * c = 0; - * - * math.or(a, b); // returns [true, true, false] - * math.or(b, c); // returns [false, true, false] - * - * See also: - * - * and, not, xor - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check - * @return {boolean | Array | Matrix} - * Returns true when one of the inputs is defined with a nonzero/nonempty value. - */ - var or = typed('or', { - - 'number, number': function (x, y) { - return !!(x || y); - }, - - 'Complex, Complex': function (x, y) { - return (x.re !== 0 || x.im !== 0) || (y.re !== 0 || y.im !== 0); - }, - - 'BigNumber, BigNumber': function (x, y) { - return (!x.isZero() && !x.isNaN()) || (!y.isZero() && !y.isNaN()); - }, - - 'Unit, Unit': function (x, y) { - return or(x.value || 0, y.value || 0); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm05$$1(x, y, or); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, or, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, or, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, or); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return or(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return or(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return or(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, or, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, or, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, or, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, or, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, or, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, or, true).valueOf(); - } - }); - - or.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['or'] + '${args[1]}\\right)' - }; - - return or; - } - - var name$183 = 'or'; - var factory_1$194 = factory$195; - - var or$1 = { - name: name$183, - factory: factory_1$194 - }; - - function factory$196 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Logical `xor`. Test whether one and only one value is defined with a nonzero/nonempty value. - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.xor(x, y) - * - * Examples: - * - * math.xor(2, 4); // returns false - * - * a = [2, 0, 0]; - * b = [2, 7, 0]; - * c = 0; - * - * math.xor(a, b); // returns [false, true, false] - * math.xor(a, c); // returns [true, false, false] - * - * See also: - * - * and, not, or - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x First value to check - * @param {number | BigNumber | Complex | Unit | Array | Matrix} y Second value to check - * @return {boolean | Array | Matrix} - * Returns true when one and only one input is defined with a nonzero/nonempty value. - */ - var xor = typed('xor', { - - 'number, number': function (x, y) { - return !!x !== !!y; - }, - - 'Complex, Complex': function (x, y) { - return ((x.re !== 0 || x.im !== 0) !== (y.re !== 0 || y.im !== 0)); - }, - - 'BigNumber, BigNumber': function (x, y) { - return ((!x.isZero() && !x.isNaN()) !== (!y.isZero() && !y.isNaN())); - }, - - 'Unit, Unit': function (x, y) { - return xor(x.value || 0, y.value || 0); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, xor); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, xor, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, xor, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, xor); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return xor(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return xor(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return xor(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, xor, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, xor, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, xor, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, xor, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, xor, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, xor, true).valueOf(); - } - }); - - xor.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['xor'] + '${args[1]}\\right)' - }; - - return xor; - } - - var name$184 = 'xor'; - var factory_1$195 = factory$196; - - var xor$1 = { - name: name$184, - factory: factory_1$195 - }; - - var logical = [ - and$1, - not$1, - or$1, - xor$1 - ]; - - function factory$197 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var subtract = load(subtract$1); - var multiply = load(multiply$1); - - /** - * Calculate the cross product for two vectors in three dimensional space. - * The cross product of `A = [a1, a2, a3]` and `B = [b1, b2, b3]` is defined - * as: - * - * cross(A, B) = [ - * a2 * b3 - a3 * b2, - * a3 * b1 - a1 * b3, - * a1 * b2 - a2 * b1 - * ] - * - * If one of the input vectors has a dimension greater than 1, the output - * vector will be a 1x3 (2-dimensional) matrix. - * - * Syntax: - * - * math.cross(x, y) - * - * Examples: - * - * math.cross([1, 1, 0], [0, 1, 1]); // Returns [1, -1, 1] - * math.cross([3, -3, 1], [4, 9, 2]); // Returns [-15, -2, 39] - * math.cross([2, 3, 4], [5, 6, 7]); // Returns [-3, 6, -3] - * math.cross([[1, 2, 3]], [[4], [5], [6]]); // Returns [[-3, 6, -3]] - * - * See also: - * - * dot, multiply - * - * @param {Array | Matrix} x First vector - * @param {Array | Matrix} y Second vector - * @return {Array | Matrix} Returns the cross product of `x` and `y` - */ - var cross = typed('cross', { - 'Matrix, Matrix': function (x, y) { - return matrix$$1(_cross(x.toArray(), y.toArray())); - }, - - 'Matrix, Array': function (x, y) { - return matrix$$1(_cross(x.toArray(), y)); - }, - - 'Array, Matrix': function (x, y) { - return matrix$$1(_cross(x, y.toArray())); - }, - - 'Array, Array': _cross - }); - - cross.toTex = { - 2: '\\left(${args[0]}\\right)\\times\\left(${args[1]}\\right)' - }; - - return cross; - - /** - * Calculate the cross product for two arrays - * @param {Array} x First vector - * @param {Array} y Second vector - * @returns {Array} Returns the cross product of x and y - * @private - */ - function _cross(x, y) { - var highestDimension = Math.max(array.size(x).length, array.size(y).length); - - x = array.squeeze(x); - y = array.squeeze(y); - - var xSize = array.size(x); - var ySize = array.size(y); - - if (xSize.length != 1 || ySize.length != 1 || xSize[0] != 3 || ySize[0] != 3) { - throw new RangeError('Vectors with length 3 expected ' + - '(Size A = [' + xSize.join(', ') + '], B = [' + ySize.join(', ') + '])'); - } - - var product = [ - subtract(multiply(x[1], y[2]), multiply(x[2], y[1])), - subtract(multiply(x[2], y[0]), multiply(x[0], y[2])), - subtract(multiply(x[0], y[1]), multiply(x[1], y[0])) - ]; - - if (highestDimension > 1) { - return [product]; - } else { - return product; - } - } - } - - var name$185 = 'cross'; - var factory_1$196 = factory$197; - - var cross$1 = { - name: name$185, - factory: factory_1$196 - }; - - var clone$8 = object.clone; - var isInteger$23 = number.isInteger; - - function factory$198 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - /** - * Create a diagonal matrix or retrieve the diagonal of a matrix - * - * When `x` is a vector, a matrix with vector `x` on the diagonal will be returned. - * When `x` is a two dimensional matrix, the matrixes `k`th diagonal will be returned as vector. - * When k is positive, the values are placed on the super diagonal. - * When k is negative, the values are placed on the sub diagonal. - * - * Syntax: - * - * math.diag(X) - * math.diag(X, format) - * math.diag(X, k) - * math.diag(X, k, format) - * - * Examples: - * - * // create a diagonal matrix - * math.diag([1, 2, 3]); // returns [[1, 0, 0], [0, 2, 0], [0, 0, 3]] - * math.diag([1, 2, 3], 1); // returns [[0, 1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]] - * math.diag([1, 2, 3], -1); // returns [[0, 0, 0], [1, 0, 0], [0, 2, 0], [0, 0, 3]] - * - * // retrieve the diagonal from a matrix - * var a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; - * math.diag(a); // returns [1, 5, 9] - * - * See also: - * - * ones, zeros, eye - * - * @param {Matrix | Array} x A two dimensional matrix or a vector - * @param {number | BigNumber} [k=0] The diagonal where the vector will be filled - * in or retrieved. - * @param {string} [format='dense'] The matrix storage format. - * - * @returns {Matrix | Array} Diagonal matrix from input vector, or diagonal from input matrix. - */ - var diag = typed('diag', { - // FIXME: simplify this huge amount of signatures as soon as typed-function supports optional arguments - - 'Array': function (x) { - return _diag(x, 0, array.size(x), null); - }, - - 'Array, number': function (x, k) { - return _diag(x, k, array.size(x), null); - }, - - 'Array, BigNumber': function (x, k) { - return _diag(x, k.toNumber(), array.size(x), null); - }, - - 'Array, string': function (x, format) { - return _diag(x, 0, array.size(x), format); - }, - - 'Array, number, string': function (x, k, format) { - return _diag(x, k, array.size(x), format); - }, - - 'Array, BigNumber, string': function (x, k, format) { - return _diag(x, k.toNumber(), array.size(x), format); - }, - - 'Matrix': function (x) { - return _diag(x, 0, x.size(), x.storage()); - }, - - 'Matrix, number': function (x, k) { - return _diag(x, k, x.size(), x.storage()); - }, - - 'Matrix, BigNumber': function (x, k) { - return _diag(x, k.toNumber(), x.size(), x.storage()); - }, - - 'Matrix, string': function (x, format) { - return _diag(x, 0, x.size(), format); - }, - - 'Matrix, number, string': function (x, k, format) { - return _diag(x, k, x.size(), format); - }, - - 'Matrix, BigNumber, string': function (x, k, format) { - return _diag(x, k.toNumber(), x.size(), format); - } - }); - - diag.toTex = undefined; // use default template - - return diag; - - /** - * Creeate diagonal matrix from a vector or vice versa - * @param {Array | Matrix} x - * @param {number} k - * @param {string} format Storage format for matrix. If null, - * an Array is returned - * @returns {Array | Matrix} - * @private - */ - function _diag (x, k, size, format) { - if (!isInteger$23(k)) { - throw new TypeError ('Second parameter in function diag must be an integer'); - } - - var kSuper = k > 0 ? k : 0; - var kSub = k < 0 ? -k : 0; - - // check dimensions - switch (size.length) { - case 1: - return _createDiagonalMatrix(x, k, format, size[0], kSub, kSuper); - case 2: - return _getDiagonal(x, k, format, size, kSub, kSuper); - } - throw new RangeError('Matrix for function diag must be 2 dimensional'); - } - - function _createDiagonalMatrix(x, k, format, l, kSub, kSuper) { - // matrix size - var ms = [l + kSub, l + kSuper]; - // get matrix constructor - var F = type.Matrix.storage(format || 'dense'); - // create diagonal matrix - var m = F.diagonal(ms, x, k); - // check we need to return a matrix - return format !== null ? m : m.valueOf(); - } - - function _getDiagonal(x, k, format, s, kSub, kSuper) { - // check x is a Matrix - if (type.isMatrix(x)) { - // get diagonal matrix - var dm = x.diagonal(k); - // check we need to return a matrix - if (format !== null) { - // check we need to change matrix format - if (format !== dm.storage()) - return matrix$$1(dm, format); - return dm; - } - return dm.valueOf(); - } - // vector size - var n = Math.min(s[0] - kSub, s[1] - kSuper); - // diagonal values - var vector = []; - // loop diagonal - for (var i = 0; i < n; i++) { - vector[i] = x[i + kSub][i + kSuper]; - } - // check we need to return a matrix - return format !== null ? matrix$$1(vector) : vector; - } - } - - var name$186 = 'diag'; - var factory_1$197 = factory$198; - - var diag$1 = { - name: name$186, - factory: factory_1$197 - }; - - var size$3 = array.size; - - function factory$199 (type, config, load, typed) { - var add$$1 = load(add); - var multiply = load(multiply$1); - - /** - * Calculate the dot product of two vectors. The dot product of - * `A = [a1, a2, a3, ..., an]` and `B = [b1, b2, b3, ..., bn]` is defined as: - * - * dot(A, B) = a1 * b1 + a2 * b2 + a3 * b3 + ... + an * bn - * - * Syntax: - * - * math.dot(x, y) - * - * Examples: - * - * math.dot([2, 4, 1], [2, 2, 3]); // returns number 15 - * math.multiply([2, 4, 1], [2, 2, 3]); // returns number 15 - * - * See also: - * - * multiply, cross - * - * @param {Array | Matrix} x First vector - * @param {Array | Matrix} y Second vector - * @return {number} Returns the dot product of `x` and `y` - */ - var dot = typed('dot', { - 'Matrix, Matrix': function (x, y) { - return _dot(x.toArray(), y.toArray()); - }, - - 'Matrix, Array': function (x, y) { - return _dot(x.toArray(), y); - }, - - 'Array, Matrix': function (x, y) { - return _dot(x, y.toArray()); - }, - - 'Array, Array': _dot - }); - - dot.toTex = {2: '\\left(${args[0]}\\cdot${args[1]}\\right)'}; - - return dot; - - /** - * Calculate the dot product for two arrays - * @param {Array} x First vector - * @param {Array} y Second vector - * @returns {number} Returns the dot product of x and y - * @private - */ - // TODO: double code with math.multiply - function _dot(x, y) { - var xSize= size$3(x); - var ySize = size$3(y); - var len = xSize[0]; - - if (xSize.length !== 1 || ySize.length !== 1) throw new RangeError('Vector expected'); // TODO: better error message - if (xSize[0] != ySize[0]) throw new RangeError('Vectors must have equal length (' + xSize[0] + ' != ' + ySize[0] + ')'); - if (len == 0) throw new RangeError('Cannot calculate the dot product of empty vectors'); - - var prod = 0; - for (var i = 0; i < len; i++) { - prod = add$$1(prod, multiply(x[i], y[i])); - } - - return prod; - } - } - - var name$187 = 'dot'; - var factory_1$198 = factory$199; - - var dot$1 = { - name: name$187, - factory: factory_1$198 - }; - - var format$6 = string.format; - - function factory$200 (type, config, load, typed) { - - var abs = load(abs$1); - var add$$1 = load(add); - var eye = load(eye$1); - var inv = load(inv$1); - var multiply = load(multiply$1); - - var SparseMatrix = type.SparseMatrix; - - /** - * Compute the matrix exponential, expm(A) = e^A. The matrix must be square. - * Not to be confused with exp(a), which performs element-wise - * exponentiation. - * - * The exponential is calculated using the Padé approximant with scaling and - * squaring; see "Nineteen Dubious Ways to Compute the Exponential of a - * Matrix," by Moler and Van Loan. - * - * Syntax: - * - * math.expm(x) - * - * Examples: - * - * var A = [[0,2],[0,0]] - * math.expm(A); // returns [[1,2],[0,1]] - * - * See also: - * - * exp - * - * @param {Matrix} x A square Matrix - * @return {Matrix} The exponential of x - */ - var expm = typed('expm', { - - 'Matrix': function (A) { - - // Check matrix size - var size = A.size(); - - if(size.length !== 2 || size[0] !== size[1]) { - throw new RangeError('Matrix must be square ' + - '(size: ' + format$6(size) + ')'); - } - - var n = size[0]; - - // Desired accuracy of the approximant (The actual accuracy - // will be affected by round-off error) - var eps = 1e-15; - - // The Padé approximant is not so accurate when the values of A - // are "large", so scale A by powers of two. Then compute the - // exponential, and square the result repeatedly according to - // the identity e^A = (e^(A/m))^m - - // Compute infinity-norm of A, ||A||, to see how "big" it is - var infNorm = infinityNorm(A); - - // Find the optimal scaling factor and number of terms in the - // Padé approximant to reach the desired accuracy - var params = findParams(infNorm, eps); - var q = params.q; - var j = params.j; - - // The Pade approximation to e^A is: - // Rqq(A) = Dqq(A) ^ -1 * Nqq(A) - // where - // Nqq(A) = sum(i=0, q, (2q-i)!p! / [ (2q)!i!(q-i)! ] A^i - // Dqq(A) = sum(i=0, q, (2q-i)!q! / [ (2q)!i!(q-i)! ] (-A)^i - - // Scale A by 1 / 2^j - var Apos = multiply(A, Math.pow(2, -j)); - - // The i=0 term is just the identity matrix - var N = eye(n); - var D = eye(n); - - // Initialization (i=0) - var factor = 1; - - // Initialization (i=1) - var Apos_to_i = Apos; // Cloning not necessary - var alternate = -1; - - for(var i=1; i<=q; i++) { - if(i>1) { - Apos_to_i = multiply(Apos_to_i, Apos); - alternate = -alternate; - } - factor = factor*(q-i+1)/((2*q-i+1)*i); - - N = add$$1(N, multiply(factor, Apos_to_i)); - D = add$$1(D, multiply(factor*alternate, Apos_to_i)); - } - - var R = multiply(inv(D), N); - - // Square j times - for(var i=0; i 0; - * } - * math.filter([6, -2, -1, 4, 3], isPositive); // returns [6, 4, 3] - * - * math.filter(["23", "foo", "100", "55", "bar"], /[0-9]+/); // returns ["23", "100", "55"] - * - * See also: - * - * forEach, map, sort - * - * @param {Matrix | Array} x A one dimensional matrix or array to filter - * @param {Function | RegExp} test - * A function or regular expression to test items. - * All entries for which `test` returns true are returned. - * When `test` is a function, it is invoked with three parameters: - * the value of the element, the index of the element, and the - * matrix/array being traversed. The function must return a boolean. - * @return {Matrix | Array} Returns the filtered matrix. - */ - var filter = typed('filter', { - 'Array, function': _filterCallback, - - 'Matrix, function': function (x, test) { - return matrix$$1(_filterCallback(x.toArray(), test)); - }, - - 'Array, RegExp': filterRegExp$1, - - 'Matrix, RegExp': function (x, test) { - return matrix$$1(filterRegExp$1(x.toArray(), test)); - } - }); - - filter.toTex = undefined; // use default template - - return filter; - } - - /** - * Filter values in a callback given a callback function - * @param {Array} x - * @param {Function} callback - * @return {Array} Returns the filtered array - * @private - */ - function _filterCallback (x, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$4(callback); - - return filter$2(x, function (value, index, array$$1) { - // invoke the callback function with the right number of arguments - if (args === 1) { - return callback(value); - } - else if (args === 2) { - return callback(value, [index]); - } - else { // 3 or -1 - return callback(value, [index], array$$1); - } - }); - } - - var name$189 = 'filter'; - var factory_1$200 = factory$201; - - var filter_1 = { - name: name$189, - factory: factory_1$200 - }; - - var clone$9 = object.clone; - var _flatten = array.flatten; - - function factory$202 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Flatten a multi dimensional matrix into a single dimensional matrix. - * - * Syntax: - * - * math.flatten(x) - * - * Examples: - * - * math.flatten([[1,2], [3,4]]); // returns [1, 2, 3, 4] - * - * See also: - * - * concat, resize, size, squeeze - * - * @param {Matrix | Array} x Matrix to be flattened - * @return {Matrix | Array} Returns the flattened matrix - */ - var flatten = typed('flatten', { - 'Array': function (x) { - return _flatten(clone$9(x)); - }, - - 'Matrix': function (x) { - var flat = _flatten(clone$9(x.toArray())); - // TODO: return the same matrix type as x - return matrix$$1(flat); - } - }); - - flatten.toTex = undefined; // use default template - - return flatten; - } - - var name$190 = 'flatten'; - var factory_1$201 = factory$202; - - var flatten$3 = { - name: name$190, - factory: factory_1$201 - }; - - var maxArgumentCount$5 = _function.maxArgumentCount; - var forEach$4 = array.forEach; - - function factory$203 (type, config, load, typed) { - /** - * Iterate over all elements of a matrix/array, and executes the given callback function. - * - * Syntax: - * - * math.forEach(x, callback) - * - * Examples: - * - * math.forEach([1, 2, 3], function(value) { - * console.log(value); - * }); - * // outputs 1, 2, 3 - * - * See also: - * - * filter, map, sort - * - * @param {Matrix | Array} x The matrix to iterate on. - * @param {Function} callback The callback function is invoked with three - * parameters: the value of the element, the index - * of the element, and the Matrix/array being traversed. - */ - var forEach = typed('forEach', { - 'Array, function': _forEach, - - 'Matrix, function': function (x, callback) { - return x.forEach(callback); - } - }); - - forEach.toTex = undefined; // use default template - - return forEach; - } - - /** - * forEach for a multi dimensional array - * @param {Array} array - * @param {Function} callback - * @private - */ - function _forEach (array$$1, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$5(callback); - - var recurse = function (value, index) { - if (Array.isArray(value)) { - forEach$4(value, function (child, i) { - // we create a copy of the index array and append the new index value - recurse(child, index.concat(i)); - }); - } - else { - // invoke the callback function with the right number of arguments - if (args === 1) { - callback(value); - } - else if (args === 2) { - callback(value, index); - } - else { // 3 or -1 - callback(value, index, array$$1); - } - } - }; - recurse(array$$1, []); - } - - var name$191 = 'forEach'; - var factory_1$202 = factory$203; - - var forEach_1 = { - name: name$191, - factory: factory_1$202 - }; - - var size$4 = array.size; - - function factory$204(type, config, load, typed) { - var matrix$$1 = load(matrix); - var multiplyScalar$$1 = load(multiplyScalar); - /** - * Calculates the kronecker product of 2 matrices or vectors. - * - * NOTE: If a one dimensional vector / matrix is given, it will be - * wrapped so its two dimensions. - * See the examples. - * - * Syntax: - * - * math.kron(x, y) - * - * Examples: - * - * math.kron([[1, 0], [0, 1]], [[1, 2], [3, 4]]); - * // returns [ [ 1, 2, 0, 0 ], [ 3, 4, 0, 0 ], [ 0, 0, 1, 2 ], [ 0, 0, 3, 4 ] ] - * - * math.kron([1,1], [2,3,4]); - * // returns [ [ 2, 3, 4, 2, 3, 4 ] ] - * - * See also: - * - * multiply, dot, cross - * - * @param {Array | Matrix} x First vector - * @param {Array | Matrix} y Second vector - * @return {Array | Matrix} Returns the kronecker product of `x` and `y` - */ - var kron = typed('kron', { - 'Matrix, Matrix': function(x, y) { - return matrix$$1(_kron(x.toArray(), y.toArray())); - }, - - 'Matrix, Array': function(x, y) { - return matrix$$1(_kron(x.toArray(), y)); - }, - - 'Array, Matrix': function(x, y) { - return matrix$$1(_kron(x, y.toArray())); - }, - - 'Array, Array': _kron - }); - - return kron; - - /** - * Calculate the kronecker product of two matrices / vectors - * @param {Array} a First vector - * @param {Array} b Second vector - * @returns {Array} Returns the kronecker product of x and y - * @private - */ - function _kron(a, b) { - // Deal with the dimensions of the matricies. - if (size$4(a).length === 1) { - // Wrap it in a 2D Matrix - a = [a]; - } - if (size$4(b).length === 1) { - // Wrap it in a 2D Matrix - b = [b]; - } - if (size$4(a).length > 2 || size$4(b).length > 2) { - throw new RangeError('Vectors with dimensions greater then 2 are not supported expected ' + - '(Size x = ' + JSON.stringify(a.length) + ', y = ' + JSON.stringify(b.length) + ')'); - } - var t = []; - var r = []; - - return a.map(function(a) { - return b.map(function(b) { - return a.map(function(y) { - return b.map(function(x) { - return r.push(multiplyScalar$$1(y, x)); - }); - }, t.push(r = [])); - }); - }, t = []) && t; - } - } - - var name$192 = 'kron'; - var factory_1$203 = factory$204; - - var kron$1 = { - name: name$192, - factory: factory_1$203 - }; - - var maxArgumentCount$6 = _function.maxArgumentCount; - - function factory$205 (type, config, load, typed) { - /** - * Create a new matrix or array with the results of the callback function executed on - * each entry of the matrix/array. - * - * Syntax: - * - * math.map(x, callback) - * - * Examples: - * - * math.map([1, 2, 3], function(value) { - * return value * value; - * }); // returns [1, 4, 9] - * - * See also: - * - * filter, forEach, sort - * - * @param {Matrix | Array} x The matrix to iterate on. - * @param {Function} callback The callback method is invoked with three - * parameters: the value of the element, the index - * of the element, and the matrix being traversed. - * @return {Matrix | array} Transformed map of x - */ - var map = typed('map', { - 'Array, function': _map$1, - - 'Matrix, function': function (x, callback) { - return x.map(callback); - } - }); - - map.toTex = undefined; // use default template - - return map; - } - - /** - * Map for a multi dimensional array - * @param {Array} array - * @param {Function} callback - * @return {Array} - * @private - */ - function _map$1 (array, callback) { - // figure out what number of arguments the callback function expects - var args = maxArgumentCount$6(callback); - - var recurse = function (value, index) { - if (Array.isArray(value)) { - return value.map(function (child, i) { - // we create a copy of the index array and append the new index value - return recurse(child, index.concat(i)); - }); - } - else { - // invoke the callback function with the right number of arguments - if (args === 1) { - return callback(value); - } - else if (args === 2) { - return callback(value, index); - } - else { // 3 or -1 - return callback(value, index, array); - } - } - }; - - return recurse(array, []); - } - - var name$193 = 'map'; - var factory_1$204 = factory$205; - - var map$7 = { - name: name$193, - factory: factory_1$204 - }; - - var isInteger$24 = number.isInteger; - var resize$2 = array.resize; - - function factory$206 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Create a matrix filled with ones. The created matrix can have one or - * multiple dimensions. - * - * Syntax: - * - * math.ones(m) - * math.ones(m, format) - * math.ones(m, n) - * math.ones(m, n, format) - * math.ones([m, n]) - * math.ones([m, n], format) - * math.ones([m, n, p, ...]) - * math.ones([m, n, p, ...], format) - * - * Examples: - * - * math.ones(3); // returns [1, 1, 1] - * math.ones(3, 2); // returns [[1, 1], [1, 1], [1, 1]] - * math.ones(3, 2, 'dense'); // returns Dense Matrix [[1, 1], [1, 1], [1, 1]] - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.ones(math.size(A)); // returns [[1, 1, 1], [1, 1, 1]] - * - * See also: - * - * zeros, eye, size, range - * - * @param {...number | Array} size The size of each dimension of the matrix - * @param {string} [format] The Matrix storage format - * - * @return {Array | Matrix | number} A matrix filled with ones - */ - var ones = typed('ones', { - '': function () { - return (config.matrix === 'Array') - ? _ones([]) - : _ones([], 'default'); - }, - - // math.ones(m, n, p, ..., format) - // TODO: more accurate signature '...number | BigNumber, string' as soon as typed-function supports this - '...number | BigNumber | string': function (size) { - var last = size[size.length - 1]; - if (typeof last === 'string') { - var format = size.pop(); - return _ones(size, format); - } - else if (config.matrix === 'Array') { - return _ones(size); - } - else { - return _ones(size, 'default'); - } - }, - - 'Array': _ones, - - 'Matrix': function (size) { - var format = size.storage(); - return _ones(size.valueOf(), format); - }, - - 'Array | Matrix, string': function (size, format) { - return _ones (size.valueOf(), format); - } - }); - - ones.toTex = undefined; // use default template - - return ones; - - /** - * Create an Array or Matrix with ones - * @param {Array} size - * @param {string} [format='default'] - * @return {Array | Matrix} - * @private - */ - function _ones(size, format) { - var hasBigNumbers = _normalize(size); - var defaultValue = hasBigNumbers ? new type.BigNumber(1) : 1; - _validate(size); - - if (format) { - // return a matrix - var m = matrix$$1(format); - if (size.length > 0) { - return m.resize(size, defaultValue); - } - return m; - } - else { - // return an Array - var arr = []; - if (size.length > 0) { - return resize$2(arr, size, defaultValue); - } - return arr; - } - } - - // replace BigNumbers with numbers, returns true if size contained BigNumbers - function _normalize(size) { - var hasBigNumbers = false; - size.forEach(function (value, index, arr) { - if (type.isBigNumber(value)) { - hasBigNumbers = true; - arr[index] = value.toNumber(); - } - }); - return hasBigNumbers; - } - - // validate arguments - function _validate (size) { - size.forEach(function (value) { - if (typeof value !== 'number' || !isInteger$24(value) || value < 0) { - throw new Error('Parameters in function ones must be positive integers'); - } - }); - } - } - - var name$194 = 'ones'; - var factory_1$205 = factory$206; - - var ones$1 = { - name: name$194, - factory: factory_1$205 - }; - - var nearlyEqual$6 = number.nearlyEqual; - - - function factory$207 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm05$$1 = load(algorithm05); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Compare two values. Returns 1 when x > y, -1 when x < y, and 0 when x == y. - * - * x and y are considered equal when the relative difference between x and y - * is smaller than the configured epsilon. The function cannot be used to - * compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.compare(x, y) - * - * Examples: - * - * math.compare(6, 1); // returns 1 - * math.compare(2, 3); // returns -1 - * math.compare(7, 7); // returns 0 - * math.compare('10', '2'); // returns 1 - * math.compare('1000', '1e3'); // returns 0 - * - * var a = math.unit('5 cm'); - * var b = math.unit('40 mm'); - * math.compare(a, b); // returns 1 - * - * math.compare(2, [1, 2, 3]); // returns [1, 0, -1] - * - * See also: - * - * equal, unequal, smaller, smallerEq, larger, largerEq, compareNatural, compareText - * - * @param {number | BigNumber | Fraction | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | Unit | string | Array | Matrix} y Second value to compare - * @return {number | BigNumber | Fraction | Array | Matrix} Returns the result of the comparison: - * 1 when x > y, -1 when x < y, and 0 when x == y. - */ - var compare = typed('compare', { - - 'boolean, boolean': function (x, y) { - return x === y ? 0 : (x > y ? 1 : -1); - }, - - 'number, number': function (x, y) { - return (x === y || nearlyEqual$6(x, y, config.epsilon)) - ? 0 - : (x > y ? 1 : -1); - }, - - 'BigNumber, BigNumber': function (x, y) { - return (x.eq(y) || nearlyEqual(x, y, config.epsilon)) - ? new type.BigNumber(0) - : new type.BigNumber(x.cmp(y)); - }, - - 'Fraction, Fraction': function (x, y) { - return new type.Fraction(x.compare(y)); - }, - - 'Complex, Complex': function () { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return compare(x.value, y.value); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm05$$1(x, y, compare); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, compare, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, compare, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, compare); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return compare(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return compare(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return compare(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, compare, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, compare, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, compare, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, compare, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, compare, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, compare, true).valueOf(); - } - }); - - compare.toTex = undefined; // use default template - - return compare; - } - - var name$195 = 'compare'; - var factory_1$206 = factory$207; - - var compare$1 = { - name: name$195, - factory: factory_1$206 - }; - - var isInteger$25 = number.isInteger; - - function factory$208 (type, config, load, typed) { - var asc = load(compare$1); - function desc(a, b) { - return -asc(a, b); - } - - /** - * Partition-based selection of an array or 1D matrix. - * Will find the kth smallest value, and mutates the input array. - * Uses Quickselect. - * - * Syntax: - * - * math.partitionSelect(x, k) - * math.partitionSelect(x, k, compare) - * - * Examples: - * - * math.partitionSelect([5, 10, 1], 2); // returns 10 - * math.partitionSelect(['C', 'B', 'A', 'D'], 1); // returns 'B' - * - * function sortByLength (a, b) { - * return a.length - b.length; - * } - * math.partitionSelect(['Langdon', 'Tom', 'Sara'], 2, sortByLength); // returns 'Langdon' - * - * See also: - * - * sort - * - * @param {Matrix | Array} x A one dimensional matrix or array to sort - * @param {Number} k The kth smallest value to be retrieved; zero-based index - * @param {Function | 'asc' | 'desc'} [compare='asc'] - * An optional comparator function. The function is called as - * `compare(a, b)`, and must return 1 when a > b, -1 when a < b, - * and 0 when a == b. - * @return {*} Returns the kth lowest value. - */ - return typed('partitionSelect', { - 'Array | Matrix, number': function (x, k) { - return _partitionSelect(x, k, asc); - }, - - 'Array | Matrix, number, string': function (x, k, compare) { - if (compare === 'asc') { - return _partitionSelect(x, k, asc); - } - else if (compare === 'desc') { - return _partitionSelect(x, k, desc); - } - else { - throw new Error('Compare string must be "asc" or "desc"'); - } - }, - - 'Array | Matrix, number, function': _partitionSelect - }); - - function _partitionSelect(x, k, compare) { - if (!isInteger$25(k) || k < 0) { - throw new Error('k must be a non-negative integer'); - } - - if (type.isMatrix(x)) { - var size = x.size(); - if (size.length > 1) { - throw new Error('Only one dimensional matrices supported'); - } - return quickSelect(x.valueOf(), k, compare); - } - - if (Array.isArray(x)) { - return quickSelect(x, k, compare); - } - } - - /** - * Quickselect algorithm. - * Code adapted from: - * http://blog.teamleadnet.com/2012/07/quick-select-algorithm-find-kth-element.html - * - * @param {Array} arr - * @param {Number} k - * @param {Function} compare - * @private - */ - function quickSelect(arr, k, compare) { - if (k >= arr.length) { - throw new Error('k out of bounds'); - } - - var from = 0; - var to = arr.length - 1; - - // if from == to we reached the kth element - while (from < to) { - var r = from; - var w = to; - var pivot = arr[Math.floor(Math.random() * (to - from + 1)) + from]; - - // stop if the reader and writer meets - while (r < w) { - // arr[r] >= pivot - if (compare(arr[r], pivot) >= 0) { // put the large values at the end - var tmp = arr[w]; - arr[w] = arr[r]; - arr[r] = tmp; - --w; - } else { // the value is smaller than the pivot, skip - ++r; - } - } - - // if we stepped up (r++) we need to step one down (arr[r] > pivot) - if (compare(arr[r], pivot) > 0) { - --r; - } - - // the r pointer is on the end of the first k elements - if (k <= r) { - to = r; - } else { - from = r + 1; - } - } - - return arr[k]; - } - } - - var name$196 = 'partitionSelect'; - var factory_1$207 = factory$208; - - var partitionSelect$1 = { - name: name$196, - factory: factory_1$207 - }; - - var isInteger$26 = number.isInteger; - - - function factory$209 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Reshape a multi dimensional array to fit the specified dimensions - * - * Syntax: - * - * math.reshape(x, sizes) - * - * Examples: - * - * math.reshape([1, 2, 3, 4, 5, 6], [2, 3]); - * // returns Array [[1, 2, 3], [4, 5, 6]] - * - * math.reshape([[1, 2], [3, 4]], [1, 4]); - * // returns Array [[1, 2, 3, 4]] - * - * math.reshape([[1, 2], [3, 4]], [4]); - * // returns Array [1, 2, 3, 4] - * - * var x = math.matrix([1, 2, 3, 4, 5, 6, 7, 8]); - * math.reshape(x, [2, 2, 2]); - * // returns Matrix [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] - * - * See also: - * - * size, squeeze, resize - * - * @param {Array | Matrix | *} x Matrix to be reshaped - * @param {number[]} sizes One dimensional array with integral sizes for - * each dimension - * - * @return {* | Array | Matrix} A reshaped clone of matrix `x` - * - * @throws {TypeError} If `sizes` does not contain solely integers - * @throws {DimensionError} If the product of the new dimension sizes does - * not equal that of the old ones - */ - var reshape = typed('reshape', { - - 'Matrix, Array': function (x, sizes) { - if(x.reshape) { - return x.reshape(sizes); - } else { - return matrix$$1(array.reshape(x.valueOf(), sizes)); - } - }, - - 'Array, Array': function (x, sizes) { - sizes.forEach(function (size) { - if (!isInteger$26(size)) { - throw new TypeError('Invalid size for dimension: ' + size); - } - }); - return array.reshape(x, sizes); - } - - }); - - reshape.toTex = undefined; // use default template - - return reshape; - } - - var name$197 = 'reshape'; - var factory_1$208 = factory$209; - - var reshape$1 = { - name: name$197, - factory: factory_1$208 - }; - - var isInteger$27 = number.isInteger; - var format$7 = string.format; - var clone$10 = object.clone; - - - function factory$210 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Resize a matrix - * - * Syntax: - * - * math.resize(x, size) - * math.resize(x, size, defaultValue) - * - * Examples: - * - * math.resize([1, 2, 3, 4, 5], [3]); // returns Array [1, 2, 3] - * math.resize([1, 2, 3], [5], 0); // returns Array [1, 2, 3, 0, 0] - * math.resize(2, [2, 3], 0); // returns Matrix [[2, 0, 0], [0, 0, 0]] - * math.resize("hello", [8], "!"); // returns string 'hello!!!' - * - * See also: - * - * size, squeeze, subset, reshape - * - * @param {Array | Matrix | *} x Matrix to be resized - * @param {Array | Matrix} size One dimensional array with numbers - * @param {number | string} [defaultValue=0] Zero by default, except in - * case of a string, in that case - * defaultValue = ' ' - * @return {* | Array | Matrix} A resized clone of matrix `x` - */ - // TODO: rework resize to a typed-function - var resize = function resize (x, size, defaultValue) { - if (arguments.length != 2 && arguments.length != 3) { - throw new ArgumentsError_1('resize', arguments.length, 2, 3); - } - - if (type.isMatrix(size)) { - size = size.valueOf(); // get Array - } - - if (type.isBigNumber(size[0])) { - // convert bignumbers to numbers - size = size.map(function (value) { - return type.isBigNumber(value) ? value.toNumber() : value; - }); - } - - // check x is a Matrix - if (type.isMatrix(x)) { - // use optimized matrix implementation, return copy - return x.resize(size, defaultValue, true); - } - - if (typeof x === 'string') { - // resize string - return _resizeString(x, size, defaultValue); - } - - // check result should be a matrix - var asMatrix = Array.isArray(x) ? false : (config.matrix !== 'Array'); - - if (size.length == 0) { - // output a scalar - while (Array.isArray(x)) { - x = x[0]; - } - - return clone$10(x); - } - else { - // output an array/matrix - if (!Array.isArray(x)) { - x = [x]; - } - x = clone$10(x); - - var res = array.resize(x, size, defaultValue); - return asMatrix ? matrix$$1(res) : res; - } - }; - - resize.toTex = undefined; // use default template - - return resize; - - /** - * Resize a string - * @param {string} str - * @param {number[]} size - * @param {string} [defaultChar=' '] - * @private - */ - function _resizeString(str, size, defaultChar) { - if (defaultChar !== undefined) { - if (typeof defaultChar !== 'string' || defaultChar.length !== 1) { - throw new TypeError('Single character expected as defaultValue'); - } - } - else { - defaultChar = ' '; - } - - if (size.length !== 1) { - throw new DimensionError_1(size.length, 1); - } - var len = size[0]; - if (typeof len !== 'number' || !isInteger$27(len)) { - throw new TypeError('Invalid size, must contain positive integers ' + - '(size: ' + format$7(size) + ')'); - } - - if (str.length > len) { - return str.substring(0, len); - } - else if (str.length < len) { - var res = str; - for (var i = 0, ii = len - str.length; i < ii; i++) { - res += defaultChar; - } - return res; - } - else { - return str; - } - } - } - - var name$198 = 'resize'; - var factory_1$209 = factory$210; - - var resize$3 = { - name: name$198, - factory: factory_1$209 - }; - - function factory$211 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Calculate the size of a matrix or scalar. - * - * Syntax: - * - * math.size(x) - * - * Examples: - * - * math.size(2.3); // returns [] - * math.size('hello world'); // returns [11] - * - * var A = [[1, 2, 3], [4, 5, 6]]; - * math.size(A); // returns [2, 3] - * math.size(math.range(1,6)); // returns [5] - * - * See also: - * - * resize, squeeze, subset - * - * @param {boolean | number | Complex | Unit | string | Array | Matrix} x A matrix - * @return {Array | Matrix} A vector with size of `x`. - */ - var size = typed('size', { - 'Matrix': function (x) { - // TODO: return the same matrix type as the input - return matrix$$1(x.size()); - }, - - 'Array': array.size, - - 'string': function (x) { - return (config.matrix === 'Array') ? [x.length] : matrix$$1([x.length]); - }, - - 'number | Complex | BigNumber | Unit | boolean | null': function (x) { - // scalar - return (config.matrix === 'Array') ? [] : matrix$$1([]); - } - }); - - size.toTex = undefined; // use default template - - return size; - } - - var name$199 = 'size'; - var factory_1$210 = factory$211; - - var size$5 = { - name: name$199, - factory: factory_1$210 - }; - - /* - * Natural Sort algorithm for Javascript - Version 0.7 - Released under MIT license - * Author: Jim Palmer (based on chunking idea from Dave Koelle) - */ - /*jshint unused:false */ - var naturalSort = function naturalSort (a, b) { - var re = /(^([+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi, - sre = /(^[ ]*|[ ]*$)/g, - dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/, - hre = /^0x[0-9a-f]+$/i, - ore = /^0/, - i = function(s) { return naturalSort.insensitive && ('' + s).toLowerCase() || '' + s; }, - // convert all to strings strip whitespace - x = i(a).replace(sre, '') || '', - y = i(b).replace(sre, '') || '', - // chunk/tokenize - xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), - yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'), - // numeric, hex or date detection - xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && x.match(dre) && Date.parse(x)), - yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null, - oFxNcL, oFyNcL; - // first try and sort Hex codes or Dates - if (yD) { - if ( xD < yD ) { return -1; } - else if ( xD > yD ) { return 1; } - } - // natural sorting through split numeric strings and default strings - for(var cLoc=0, numS=Math.max(xN.length, yN.length); cLoc < numS; cLoc++) { - // find floats not starting with '0', string or 0 if not defined (Clint Priest) - oFxNcL = !(xN[cLoc] || '').match(ore) && parseFloat(xN[cLoc]) || xN[cLoc] || 0; - oFyNcL = !(yN[cLoc] || '').match(ore) && parseFloat(yN[cLoc]) || yN[cLoc] || 0; - // handle numeric vs string comparison - number < string - (Kyle Adams) - if (isNaN(oFxNcL) !== isNaN(oFyNcL)) { return (isNaN(oFxNcL)) ? 1 : -1; } - // rely on string comparison if different types - i.e. '02' < 2 != '02' < '2' - else if (typeof oFxNcL !== typeof oFyNcL) { - oFxNcL += ''; - oFyNcL += ''; - } - if (oFxNcL < oFyNcL) { return -1; } - if (oFxNcL > oFyNcL) { return 1; } - } - return 0; - }; - - function factory$212 (type, config, load, typed) { - var getTypeOf = load(_typeof$1); - var compare = load(compare$1); - - var compareBooleans = compare.signatures['boolean,boolean']; - - /** - * Compare two values of any type in a deterministic, natural way. - * - * For numeric values, the function works the same as `math.compare`. - * For types of values that can't be compared mathematically, - * the function compares in a natural way. - * - * For numeric values, x and y are considered equal when the relative - * difference between x and y is smaller than the configured epsilon. - * The function cannot be used to compare values smaller than - * approximately 2.22e-16. - * - * For Complex numbers, first the real parts are compared. If equal, - * the imaginary parts are compared. - * - * Strings are compared with a natural sorting algorithm, which - * orders strings in a "logic" way following some heuristics. - * This differs from the function `compare`, which converts the string - * into a numeric value and compares that. The function `compareText` - * on the other hand compares text lexically. - * - * Arrays and Matrices are compared value by value until there is an - * unequal pair of values encountered. Objects are compared by sorted - * keys until the keys or their values are unequal. - * - * Syntax: - * - * math.compareNatural(x, y) - * - * Examples: - * - * math.compareNatural(6, 1); // returns 1 - * math.compareNatural(2, 3); // returns -1 - * math.compareNatural(7, 7); // returns 0 - * - * math.compareNatural('10', '2'); // returns 1 - * math.compareText('10', '2'); // returns -1 - * math.compare('10', '2'); // returns 1 - * - * math.compareNatural('Answer: 10', 'Answer: 2'); // returns 1 - * math.compareText('Answer: 10', 'Answer: 2'); // returns -1 - * math.compare('Answer: 10', 'Answer: 2'); - * // Error: Cannot convert "Answer: 10" to a number - * - * var a = math.unit('5 cm'); - * var b = math.unit('40 mm'); - * math.compareNatural(a, b); // returns 1 - * - * var c = math.complex('2 + 3i'); - * var d = math.complex('2 + 4i'); - * math.compareNatural(c, d); // returns -1 - * - * math.compareNatural([1, 2, 4], [1, 2, 3]); // returns 1 - * math.compareNatural([1, 2, 3], [1, 2]); // returns 1 - * math.compareNatural([1, 5], [1, 2, 3]); // returns 1 - * math.compareNatural([1, 2], [1, 2]); // returns 0 - * - * math.compareNatural({a: 2}, {a: 4}); // returns -1 - * - * See also: - * - * compare, compareText - * - * @param {*} x First value to compare - * @param {*} y Second value to compare - * @return {number} Returns the result of the comparison: - * 1 when x > y, -1 when x < y, and 0 when x == y. - */ - var compareNatural = typed('compareNatural', { - 'any, any': function (x, y) { - var typeX = getTypeOf(x); - var typeY = getTypeOf(y); - var c; - - // numeric types - if ((typeX === 'number' || typeX === 'BigNumber' || typeX === 'Fraction') && - (typeY === 'number' || typeY === 'BigNumber' || typeY === 'Fraction')) { - c = compare(x, y); - if (c.toString() !== '0') { - // c can be number, BigNumber, or Fraction - return c > 0 ? 1 : -1; // return a number - } - else { - return naturalSort(typeX, typeY); - } - } - - // matrix types - if (typeX === 'Array' || typeX === 'Matrix' || - typeY === 'Array' || typeY === 'Matrix') { - c = compareMatricesAndArrays (x, y); - if (c !== 0) { - return c; - } - else { - return naturalSort(typeX, typeY); - } - } - - // in case of different types, order by name of type, i.e. 'BigNumber' < 'Complex' - if (typeX !== typeY) { - return naturalSort(typeX, typeY); - } - - if (typeX === 'Complex') { - return compareComplexNumbers(x, y); - } - - if (typeX === 'Unit') { - if (x.equalBase(y)) { - return compareNatural(x.value, y.value); - } - - // compare by units - return compareArrays(x.formatUnits(), y.formatUnits()); - } - - if (typeX === 'boolean') { - return compareBooleans(x, y); - } - - if (typeX === 'string') { - return naturalSort(x, y); - } - - if (typeX === 'Object') { - return compareObjects(x, y); - } - - if (typeX === 'null') { - return 0; - } - - if (typeX === 'undefined') { - return 0; - } - - // this should not occur... - throw new TypeError('Unsupported type of value "' + typeX + '"'); - } - }); - - compareNatural.toTex = undefined; // use default template - - /** - * Compare mixed matrix/array types, by converting to same-shaped array. - * This comparator is non-deterministic regarding input types. - * @param {Array | SparseMatrix | DenseMatrix | *} x - * @param {Array | SparseMatrix | DenseMatrix | *} y - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ - function compareMatricesAndArrays (x, y) { - if (type.isSparseMatrix(x) && type.isSparseMatrix(y)) { - return compareArrays(x.toJSON().values, y.toJSON().values); - } - if (type.isSparseMatrix(x)) { - // note: convert to array is expensive - return compareMatricesAndArrays(x.toArray(), y); - } - if (type.isSparseMatrix(y)) { - // note: convert to array is expensive - return compareMatricesAndArrays(x, y.toArray()); - } - - // convert DenseArray into Array - if (type.isDenseMatrix(x)) { - return compareMatricesAndArrays(x.toJSON().data, y); - } - if (type.isDenseMatrix(y)) { - return compareMatricesAndArrays(x, y.toJSON().data); - } - - // convert scalars to array - if (!Array.isArray(x)) { - return compareMatricesAndArrays([x], y); - } - if (!Array.isArray(y)) { - return compareMatricesAndArrays(x, [y]); - } - - return compareArrays(x, y); - } - - /** - * Compare two Arrays - * - * - First, compares value by value - * - Next, if all corresponding values are equal, - * look at the length: longest array will be considered largest - * - * @param {Array} x - * @param {Array} y - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ - function compareArrays (x, y) { - // compare each value - for (var i = 0, ii = Math.min(x.length, y.length); i < ii; i++) { - var v = compareNatural(x[i], y[i]); - if (v !== 0) { - return v; - } - } - - // compare the size of the arrays - if (x.length > y.length) { return 1; } - if (x.length < y.length) { return -1; } - - // both Arrays have equal size and content - return 0; - } - - /** - * Compare two objects - * - * - First, compare sorted property names - * - Next, compare the property values - * - * @param {Object} x - * @param {Object} y - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ - function compareObjects (x, y) { - var keysX = Object.keys(x); - var keysY = Object.keys(y); - - // compare keys - keysX.sort(naturalSort); - keysY.sort(naturalSort); - var c = compareArrays(keysX, keysY); - if (c !== 0) { - return c; - } - - // compare values - for (var i = 0; i < keysX.length; i++) { - var v = compareNatural(x[keysX[i]], y[keysY[i]]); - if (v !== 0) { - return v; - } - } - - return 0; - } - - return compareNatural; - } - - /** - * Compare two complex numbers, `x` and `y`: - * - * - First, compare the real values of `x` and `y` - * - If equal, compare the imaginary values of `x` and `y` - * - * @params {Complex} x - * @params {Complex} y - * @returns {number} Returns the comparison result: -1, 0, or 1 - */ - function compareComplexNumbers (x, y) { - if (x.re > y.re) { return 1; } - if (x.re < y.re) { return -1; } - - if (x.im > y.im) { return 1; } - if (x.im < y.im) { return -1; } - - return 0; - } - - var name$200 = 'compareNatural'; - var factory_1$211 = factory$212; - - var compareNatural$1 = { - name: name$200, - factory: factory_1$211 - }; - - var size$6 = array.size; - - function factory$213 (type, config, load, typed) { - var matrix$$1 = load(matrix); - var compareAsc = load(compare$1); - var compareDesc = function (a, b) { - return -compareAsc(a, b); - }; - var compareNatural = load(compareNatural$1); - - /** - * Sort the items in a matrix. - * - * Syntax: - * - * math.sort(x) - * math.sort(x, compare) - * - * Examples: - * - * math.sort([5, 10, 1]); // returns [1, 5, 10] - * math.sort(['C', 'B', 'A', 'D'], math.compareNatural); - * // returns ['A', 'B', 'C', 'D'] - * - * function sortByLength (a, b) { - * return a.length - b.length; - * } - * math.sort(['Langdon', 'Tom', 'Sara'], sortByLength); - * // returns ['Tom', 'Sara', 'Langdon'] - * - * See also: - * - * filter, forEach, map, compare, compareNatural - * - * @param {Matrix | Array} x A one dimensional matrix or array to sort - * @param {Function | 'asc' | 'desc' | 'natural'} [compare='asc'] - * An optional _comparator function or name. The function is called as - * `compare(a, b)`, and must return 1 when a > b, -1 when a < b, - * and 0 when a == b. - * @return {Matrix | Array} Returns the sorted matrix. - */ - var sort = typed('sort', { - 'Array': function (x) { - _arrayIsVector(x); - return x.sort(compareAsc); - }, - - 'Matrix': function (x) { - _matrixIsVector(x); - return matrix$$1(x.toArray().sort(compareAsc), x.storage()); - }, - - 'Array, function': function (x, _comparator) { - _arrayIsVector(x); - return x.sort(_comparator); - }, - - 'Matrix, function': function (x, _comparator) { - _matrixIsVector(x); - return matrix$$1(x.toArray().sort(_comparator), x.storage()); - }, - - 'Array, string': function (x, order) { - _arrayIsVector(x); - return x.sort(_comparator(order)); - }, - - 'Matrix, string': function (x, order) { - _matrixIsVector(x); - return matrix$$1(x.toArray().sort(_comparator(order)), x.storage()); - } - }); - - sort.toTex = undefined; // use default template - - /** - * Get the comparator for given order ('asc', 'desc', 'natural') - * @param {'asc' | 'desc' | 'natural'} order - * @return {Function} Returns a _comparator function - */ - function _comparator (order) { - if (order === 'asc') { - return compareAsc; - } - else if (order === 'desc') { - return compareDesc; - } - else if (order === 'natural') { - return compareNatural; - } - else { - throw new Error('String "asc", "desc", or "natural" expected'); - } - } - - /** - * Validate whether an array is one dimensional - * Throws an error when this is not the case - * @param {Array} array - * @private - */ - function _arrayIsVector (array$$1) { - if (size$6(array$$1).length !== 1) { - throw new Error('One dimensional array expected'); - } - } - - /** - * Validate whether a matrix is one dimensional - * Throws an error when this is not the case - * @param {Matrix} matrix - * @private - */ - function _matrixIsVector (matrix$$1) { - if (matrix$$1.size().length !== 1) { - throw new Error('One dimensional matrix expected'); - } - } - - return sort; - } - - var name$201 = 'sort'; - var factory_1$212 = factory$213; - - var sort$1 = { - name: name$201, - factory: factory_1$212 - }; - - function factory$214(type, config, load, typed) { - var matrix$$1 = load(matrix); - var abs = load(abs$1); - var add$$1 = load(add); - var divide = load(divide$1); - var multiply = load(multiply$1); - var sqrt = load(sqrt$1); - var subtract = load(subtract$1); - var inv = load(inv$1); - var size = load(size$5); - var max = load(max$1); - var eye = load(eye$1); - - /** - * Calculate the principal square root of a square matrix. - * The principal square root matrix `X` of another matrix `A` is such that `X * X = A`. - * - * https://en.wikipedia.org/wiki/Square_root_of_a_matrix - * - * Syntax: - * - * X = math.sqrtm(A) - * - * Examples: - * - * math.sqrtm([[1, 2], [3, 4]]); // returns [[-2, 1], [1.5, -0.5]] - * - * See also: - * - * sqrt, pow - * - * @param {Array | Matrix} A The square matrix `A` - * @return {Array | Matrix} The principal square root of matrix `A` - */ - var sqrtm = typed('sqrtm', { - 'Array | Matrix': function (A) { - var size = type.isMatrix(A) ? A.size() : array.size(A); - switch (size.length) { - case 1: - // Single element Array | Matrix - if (size[0] == 1) { - return sqrt(A); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); - } - - case 2: - // Two-dimensional Array | Matrix - var rows = size[0]; - var cols = size[1]; - if (rows == cols) { - return _denmanBeavers(A); - } - else { - throw new RangeError('Matrix must be square ' + - '(size: ' + string.format(size) + ')'); - } - } - } - }); - - var _maxIterations = 1e3; - var _tolerance = 1e-6; - - /** - * Calculate the principal square root matrix using the Denman–Beavers iterative method - * - * https://en.wikipedia.org/wiki/Square_root_of_a_matrix#By_Denman–Beavers_iteration - * - * @param {Array | Matrix} A The square matrix `A` - * @return {Array | Matrix} The principal square root of matrix `A` - * @private - */ - function _denmanBeavers(A) { - var error; - var iterations = 0; - - var Y = A; - var Z = eye(size(A)); - - do { - var Y_k = Y; - Y = multiply(0.5, add$$1(Y_k, inv(Z))); - Z = multiply(0.5, add$$1(Z, inv(Y_k))); - - error = max(abs(subtract(Y, Y_k))); - - if (error > _tolerance && ++iterations > _maxIterations) { - throw new Error('computing square root of matrix: iterative method could not converge'); - } - } while (error > _tolerance); - - return Y; - } - - sqrtm.toTex = {1: '{${args[0]}}' + latex.operators['pow'] + '{\\frac{1}{2}}'}; - - return sqrtm; - } - - var name$202 = 'sqrtm'; - var factory_1$213 = factory$214; - - var sqrtm$1 = { - name: name$202, - factory: factory_1$213 - }; - - function factory$215 (type, config, load, typed) { - var matrix$$1 = load(matrix); - - /** - * Squeeze a matrix, remove inner and outer singleton dimensions from a matrix. - * - * Syntax: - * - * math.squeeze(x) - * - * Examples: - * - * math.squeeze([3]); // returns 3 - * math.squeeze([[3]]); // returns 3 - * - * var A = math.zeros(3, 1); // returns [[0], [0], [0]] (size 3x1) - * math.squeeze(A); // returns [0, 0, 0] (size 3) - * - * var B = math.zeros(1, 3); // returns [[0, 0, 0]] (size 1x3) - * math.squeeze(B); // returns [0, 0, 0] (size 3) - * - * // only inner and outer dimensions are removed - * var C = math.zeros(2, 1, 3); // returns [[[0, 0, 0]], [[0, 0, 0]]] (size 2x1x3) - * math.squeeze(C); // returns [[[0, 0, 0]], [[0, 0, 0]]] (size 2x1x3) - * - * See also: - * - * subset - * - * @param {Matrix | Array} x Matrix to be squeezed - * @return {Matrix | Array} Squeezed matrix - */ - var squeeze = typed('squeeze', { - 'Array': function (x) { - return array.squeeze(object.clone(x)); - }, - - 'Matrix': function (x) { - var res = array.squeeze(x.toArray()); - // FIXME: return the same type of matrix as the input - return Array.isArray(res) ? matrix$$1(res) : res; - }, - - 'any': function (x) { - // scalar - return object.clone(x); - } - }); - - squeeze.toTex = undefined; // use default template - - return squeeze; - } - - var name$203 = 'squeeze'; - var factory_1$214 = factory$215; - - var squeeze$1 = { - name: name$203, - factory: factory_1$214 - }; - - var matrix$3 = [ - concat$1, - cross$1, - det$1, - diag$1, - dot$1, - eye$1, - expm$1, - filter_1, - flatten$3, - forEach_1, - inv$1, - kron$1, - map$7, - ones$1, - partitionSelect$1, - range$1, - reshape$1, - resize$3, - size$5, - sort$1, - sqrtm$1, - squeeze$1, - subset$1, - trace$1, - transpose$1, - zeros$1 - ]; - - function factory$216 (type, config, load, typed) { - var add = load(addScalar); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the sum of a matrix or a list with values. - * In case of a (multi dimensional) array or matrix, the sum of all - * elements will be calculated. - * - * Syntax: - * - * math.sum(a, b, c, ...) - * math.sum(A) - * - * Examples: - * - * math.sum(2, 1, 4, 3); // returns 10 - * math.sum([2, 1, 4, 3]); // returns 10 - * math.sum([[2, 5], [4, 3], [1, 7]]); // returns 22 - * - * See also: - * - * mean, median, min, max, prod, std, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The sum of all values - */ - var sum = typed('sum', { - 'Array | Matrix': function (args) { - // sum([a, b, c, d, ...]) - return _sum(args); - }, - - 'Array | Matrix, number | BigNumber': function () { - // sum([a, b, c, d, ...], dim) - // TODO: implement sum(A, dim) - throw new Error('sum(A, dim) is not yet supported'); - }, - - '...': function (args) { - // sum(a, b, c, d, ...) - return _sum(args); - } - }); - - sum.toTex = undefined; // use default template - - return sum; - - /** - * Recursively calculate the sum of an n-dimensional array - * @param {Array} array - * @return {number} sum - * @private - */ - function _sum(array) { - var sum = undefined; - - deepForEach(array, function (value) { - try { - sum = (sum === undefined) ? value : add(sum, value); - } - catch (err) { - throw improveErrorMessage$$1(err, 'sum', value); - } - }); - - if (sum === undefined) { - switch (config.number) { - case 'number': - return 0; - case 'BigNumber': - return new type.BigNumber(0); - case 'Fraction': - return new type.Fraction(0); - default: - return 0; - } - } - - return sum; - } - } - - var name$204 = 'sum'; - var factory_1$215 = factory$216; - - var sum$1 = { - name: name$204, - factory: factory_1$215 - }; - - function factory$217(type, config, load, typed) { - var matrix$$1 = load(matrix); - var divide = load(divide$1); - var sum = load(sum$1); - var multiply = load(multiply$1); - var dotDivide = load(dotDivide$1); - var log = load(log$1); - var isNumeric = load(isNumeric$1); - - /** - * Calculate the Kullback-Leibler (KL) divergence between two distributions - * - * Syntax: - * - * math.kldivergence(x, y) - * - * Examples: - * - * math.kldivergence([0.7,0.5,0.4], [0.2,0.9,0.5]); //returns 0.24376698773121153 - * - * - * @param {Array | Matrix} q First vector - * @param {Array | Matrix} p Second vector - * @return {number} Returns distance between q and p - */ - var kldivergence = typed('kldivergence', { - 'Array, Array': function(q, p) { - return _kldiv(matrix$$1(q), matrix$$1(p)); - }, - - 'Matrix, Array': function(q, p) { - return _kldiv(q, matrix$$1(p)); - }, - - 'Array, Matrix': function(q, p){ - return _kldiv(matrix$$1(q), p); - }, - - 'Matrix, Matrix': function(q, p){ - return _kldiv(q, p); - } - - }); - - function _kldiv(q, p) { - var plength = p.size().length; - var qlength = q.size().length; - if (plength > 1) { - throw new Error('first object must be one dimensional'); - } - - if (qlength > 1) { - throw new Error('second object must be one dimensional'); - } - - if(plength !== qlength){ - throw new Error("Length of two vectors must be equal"); - } - - //Before calculation, apply normalization - var sumq = sum(q); - if (sumq === 0) { - throw new Error("Sum of elements in first object must be non zero"); - } - - var sump = sum(p); - if (sump === 0) { - throw new Error("Sum of elements in second object must be non zero"); - } - var qnorm = divide(q, sum(q)); - var pnorm = divide(p, sum(p)); - - var result = sum(multiply(qnorm, log(dotDivide(qnorm, pnorm)))); - if (isNumeric(result)) { - return result; - } - else { - return Number.NaN; - } - } - - return kldivergence; - } - - - var name$205 = 'kldivergence'; - var factory_1$216 = factory$217; - - var kldivergence$1 = { - name: name$205, - factory: factory_1$216 - }; - - function factory$218 (type, config, load, typed) { - var add$$1 = load(add); - var multiply = load(multiply$1); - var divide = load(divide$1); - var factorial = load(factorial$1); - var isInteger = load(isInteger$22); - var isPositive = load(isPositive$1); - - /** - * Multinomial Coefficients compute the number of ways of picking a1, a2, ..., ai unordered outcomes from `n` possibilities. - * - * multinomial takes one array of integers as an argument. - * The following condition must be enforced: every ai <= 0 - * - * Syntax: - * - * math.multinomial(a) // a is an array type - * - * Examples: - * - * math.multinomial([1,2,1]); // returns 12 - * - * See also: - * - * combinations, factorial - * - * @param {number[] | BigNumber[]} a Integer numbers of objects in the subset - * @return {Number | BigNumber} Multinomial coefficient. - */ - return typed('multinomial', { - 'Array | Matrix': function (a) { - var sum = 0; - var denom = 1; - - deepForEach(a, function(ai) { - if(!isInteger(ai) || !isPositive(ai)) { - throw new TypeError('Positive integer value expected in function multinomial'); - } - sum = add$$1(sum, ai); - denom = multiply(denom, factorial(ai)); - }); - - return divide(factorial(sum), denom); - } - }); - } - - var name$206 = 'multinomial'; - var factory_1$217 = factory$218; - - var multinomial$1 = { - name: name$206, - factory: factory_1$217 - }; - - var isInteger$28 = number.isInteger; - - function factory$219 (type, config, load, typed) { - var factorial = load(factorial$1); - - /** - * Compute the number of ways of obtaining an ordered subset of `k` elements - * from a set of `n` elements. - * - * Permutations only takes integer arguments. - * The following condition must be enforced: k <= n. - * - * Syntax: - * - * math.permutations(n) - * math.permutations(n, k) - * - * Examples: - * - * math.permutations(5); // 120 - * math.permutations(5, 3); // 60 - * - * See also: - * - * combinations, factorial - * - * @param {number | BigNumber} n The number of objects in total - * @param {number | BigNumber} [k] The number of objects in the subset - * @return {number | BigNumber} The number of permutations - */ - var permutations = typed('permutations', { - 'number | BigNumber': factorial, - - 'number, number': function (n, k) { - var result, i; - - if (!isInteger$28(n) || n < 0) { - throw new TypeError('Positive integer value expected in function permutations'); - } - if (!isInteger$28(k) || k < 0) { - throw new TypeError('Positive integer value expected in function permutations'); - } - if (k > n) { - throw new TypeError('second argument k must be less than or equal to first argument n'); - } - - // Permute n objects, k at a time - result = 1; - for (i = n - k + 1; i <= n; i++) { - result = result * i; - } - - return result; - }, - - 'BigNumber, BigNumber': function (n, k) { - var result, i; - - if (!isPositiveInteger$1(n) || !isPositiveInteger$1(k)) { - throw new TypeError('Positive integer value expected in function permutations'); - } - if (k.gt(n)) { - throw new TypeError('second argument k must be less than or equal to first argument n'); - } - - result = new type.BigNumber(1); - for (i = n.minus(k).plus(1); i.lte(n); i = i.plus(1)) { - result = result.times(i); - } - - return result; - } - - // TODO: implement support for collection in permutations - }); - - permutations.toTex = undefined; // use default template - - return permutations; - } - - /** - * Test whether BigNumber n is a positive integer - * @param {BigNumber} n - * @returns {boolean} isPositiveInteger - */ - function isPositiveInteger$1(n) { - return n.isInteger() && n.gte(0); - } - - var name$207 = 'permutations'; - var factory_1$218 = factory$219; - - var permutations$1 = { - name: name$207, - factory: factory_1$218 - }; - - var seedRandom = createCommonjsModule(function (module) { - - var width = 256;// each RC4 output is 0 <= x < 256 - var chunks = 6;// at least six RC4 outputs for each double - var digits = 52;// there are 52 significant digits in a double - var pool = [];// pool: entropy pool starts empty - var GLOBAL = typeof commonjsGlobal === 'undefined' ? window : commonjsGlobal; - - // - // The following constants are related to IEEE 754 limits. - // - var startdenom = Math.pow(width, chunks), - significance = Math.pow(2, digits), - overflow = significance * 2, - mask = width - 1; - - - var oldRandom = Math.random; - - // - // seedrandom() - // This is the seedrandom function described above. - // - module.exports = function(seed, options) { - if (options && options.global === true) { - options.global = false; - Math.random = module.exports(seed, options); - options.global = true; - return Math.random; - } - var use_entropy = (options && options.entropy) || false; - var key = []; - - // Flatten the seed string or build one from local entropy if needed. - var shortseed = mixkey(flatten( - use_entropy ? [seed, tostring(pool)] : - 0 in arguments ? seed : autoseed(), 3), key); - - // Use the seed to initialize an ARC4 generator. - var arc4 = new ARC4(key); - - // Mix the randomness into accumulated entropy. - mixkey(tostring(arc4.S), pool); - - // Override Math.random - - // This function returns a random double in [0, 1) that contains - // randomness in every bit of the mantissa of the IEEE 754 value. - - return function() { // Closure to return a random double: - var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 - d = startdenom, // and denominator d = 2 ^ 48. - x = 0; // and no 'extra last byte'. - while (n < significance) { // Fill up all significant digits by - n = (n + x) * width; // shifting numerator and - d *= width; // denominator and generating a - x = arc4.g(1); // new least-significant-byte. - } - while (n >= overflow) { // To avoid rounding up, before adding - n /= 2; // last byte, shift everything - d /= 2; // right using integer Math until - x >>>= 1; // we have exactly the desired bits. - } - return (n + x) / d; // Form the number within [0, 1). - }; - }; - - module.exports.resetGlobal = function () { - Math.random = oldRandom; - }; - - // - // ARC4 - // - // An ARC4 implementation. The constructor takes a key in the form of - // an array of at most (width) integers that should be 0 <= x < (width). - // - // The g(count) method returns a pseudorandom integer that concatenates - // the next (count) outputs from ARC4. Its return value is a number x - // that is in the range 0 <= x < (width ^ count). - // - /** @constructor */ - function ARC4(key) { - var t, keylen = key.length, - me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; - - // The empty key [] is treated as [0]. - if (!keylen) { key = [keylen++]; } - - // Set up S using the standard key scheduling algorithm. - while (i < width) { - s[i] = i++; - } - for (i = 0; i < width; i++) { - s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; - s[j] = t; - } - - // The "g" method returns the next (count) outputs as one number. - (me.g = function(count) { - // Using instance members instead of closure state nearly doubles speed. - var t, r = 0, - i = me.i, j = me.j, s = me.S; - while (count--) { - t = s[i = mask & (i + 1)]; - r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; - } - me.i = i; me.j = j; - return r; - // For robust unpredictability discard an initial batch of values. - // See http://www.rsa.com/rsalabs/node.asp?id=2009 - })(width); - } - - // - // flatten() - // Converts an object tree to nested arrays of strings. - // - function flatten(obj, depth) { - var result = [], typ = (typeof obj)[0], prop; - if (depth && typ == 'o') { - for (prop in obj) { - try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} - } - } - return (result.length ? result : typ == 's' ? obj : obj + '\0'); - } - - // - // mixkey() - // Mixes a string seed into a key that is an array of integers, and - // returns a shortened string seed that is equivalent to the result key. - // - function mixkey(seed, key) { - var stringseed = seed + '', smear, j = 0; - while (j < stringseed.length) { - key[mask & j] = - mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); - } - return tostring(key); - } - - // - // autoseed() - // Returns an object for autoseeding, using window.crypto if available. - // - /** @param {Uint8Array=} seed */ - function autoseed(seed) { - try { - GLOBAL.crypto.getRandomValues(seed = new Uint8Array(width)); - return tostring(seed); - } catch (e) { - return [+new Date, GLOBAL, GLOBAL.navigator && GLOBAL.navigator.plugins, - GLOBAL.screen, tostring(pool)]; - } - } - - // - // tostring() - // Converts an array of charcodes to a string - // - function tostring(a) { - return String.fromCharCode.apply(0, a); - } - - // - // When seedrandom.js is loaded, we immediately mix a few bits - // from the built-in RNG into the entropy pool. Because we do - // not want to intefere with determinstic PRNG state later, - // seedrandom will not call Math.random on its own again after - // initialization. - // - mixkey(Math.random(), pool); - }); - var seedRandom_1 = seedRandom.resetGlobal; - - // create a random seed here to prevent an infinite loop from seed-random - // inside the factory. Reason is that math.random is defined as a getter/setter - // and seed-random generates a seed from the local entropy by reading every - // defined object including `math` itself. That means that whilst getting - // math.random, it tries to get math.random, etc... an infinite loop. - // See https://github.com/ForbesLindesay/seed-random/issues/6 - var singletonRandom = seedRandom(); - - function factory$220 (type, config, load, typed, math) { - var random; - - // create a new random generator with given seed - function setSeed (seed) { - random = seed === null ? singletonRandom : seedRandom(String(seed)); - } - - // initialize a seeded pseudo random number generator with config's random seed - setSeed(config.randomSeed); - - // wrapper function so the rng can be updated via generator - function rng() { - return random(); - } - - // updates generator with a new instance of a seeded pseudo random number generator - math.on('config', function (curr, prev, changes) { - // if the user specified a randomSeed - if(changes.randomSeed !== undefined) { - // update generator with a new instance of a seeded pseudo random number generator - setSeed(curr.randomSeed); - } - }); - - return rng; - } - - var factory_1$219 = factory$220; - var math$17 = true; - - var seededRNG = { - factory: factory_1$219, - math: math$17 - }; - - var isNumber$3 = number.isNumber; - - // TODO: rethink math.distribution - // TODO: rework to a typed function - function factory$221 (type, config, load, typed, math) { - var matrix$$1 = load(matrix); - var array$$1 = array; - - // seeded pseudo random number generator - var rng = load(seededRNG); - - /** - * Create a distribution object with a set of random functions for given - * random distribution. - * - * Syntax: - * - * math.distribution(name) - * - * Examples: - * - * var normalDist = math.distribution('normal'); // create a normal distribution - * normalDist.random(0, 10); // get a random value between 0 and 10 - * - * See also: - * - * random, randomInt, pickRandom - * - * @param {string} name Name of a distribution. Choose from 'uniform', 'normal'. - * @return {Object} Returns a distribution object containing functions: - * `random([size] [, min] [, max])`, - * `randomInt([min] [, max])`, - * `pickRandom(array)` - */ - function distribution(name) { - if (!distributions.hasOwnProperty(name)) - throw new Error('Unknown distribution ' + name); - - var args = Array.prototype.slice.call(arguments, 1), - distribution = distributions[name].apply(this, args); - - return (function(distribution) { - - // This is the public API for all distributions - var randFunctions = { - - random: function(arg1, arg2, arg3) { - var size, min, max; - - if (arguments.length > 3) { - throw new ArgumentsError_1('random', arguments.length, 0, 3); - } else if (arguments.length === 1) { - // `random(max)` or `random(size)` - if (isCollection(arg1)) { - size = arg1; - } else { - max = arg1; - } - } else if (arguments.length === 2) { - // `random(min, max)` or `random(size, max)` - if (isCollection(arg1)) { - size = arg1; - max = arg2; - } else { - min = arg1; - max = arg2; - } - } else { - // `random(size, min, max)` - size = arg1; - min = arg2; - max = arg3; - } - - // TODO: validate type of size - if ((min !== undefined && !isNumber$3(min)) || (max !== undefined && !isNumber$3(max))) { - throw new TypeError('Invalid argument in function random'); - } - - if (max === undefined) max = 1; - if (min === undefined) min = 0; - if (size !== undefined) { - var res = _randomDataForMatrix(size.valueOf(), min, max, _random); - return type.isMatrix(size) ? matrix$$1(res) : res; - } - return _random(min, max); - }, - - randomInt: typed({ - 'number | Array': function(arg) { - var min = 0; - - if (isCollection(arg)) { - var size = arg; - var max = 1; - var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); - return type.isMatrix(size) ? matrix$$1(res) : res; - } else { - var max = arg; - return _randomInt(min, max); - } - }, - 'number | Array, number': function(arg1, arg2) { - if (isCollection(arg1)) { - var size = arg1; - var max = arg2; - var min = 0; - var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); - return type.isMatrix(size) ? matrix$$1(res) : res; - } - else { - var min = arg1; - var max = arg2; - return _randomInt(min, max); - } - }, - 'Array, number, number': function(size, min, max) { - var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); - return (size && size.isMatrix === true) ? matrix$$1(res) : res; - } - }), - - pickRandom: typed({ - 'Array': function(possibles) { - return _pickRandom(possibles); - }, - 'Array, number | Array': function(possibles, arg2) { - var number$$1, weights; - - if (Array.isArray(arg2)) { - weights = arg2; - } else if (isNumber$3(arg2)) { - number$$1 = arg2; - } else { - throw new TypeError('Invalid argument in function pickRandom') - } - - return _pickRandom(possibles, number$$1, weights); - }, - 'Array, number | Array, Array | number': function(possibles, arg2, arg3) { - var number$$1, weights; - - if (Array.isArray(arg2)) { - weights = arg2; - number$$1 = arg3; - } else { - weights = arg3; - number$$1 = arg2; - } - - if (!Array.isArray(weights) || !isNumber$3(number$$1)) { - throw new TypeError('Invalid argument in function pickRandom'); - } - - return _pickRandom(possibles, number$$1, weights); - } - }) - }; - - var _pickRandom = function(possibles, number$$1, weights) { - var single = (typeof number$$1 === 'undefined'); - - if (single) { - number$$1 = 1; - } - - if (type.isMatrix(possibles)) { - possibles = possibles.valueOf(); // get Array - } else if (!Array.isArray(possibles)) { - throw new TypeError('Unsupported type of value in function pickRandom'); - } - - if (array$$1.size(possibles).length > 1) { - throw new Error('Only one dimensional vectors supported'); - } - - if (typeof weights !== 'undefined') { - if (weights.length != possibles.length) { - throw new Error('Weights must have the same length as possibles'); - } - - var totalWeights = 0; - - for (var i = 0, len = weights.length; i < len; i++) { - if (!isNumber$3(weights[i]) || weights[i] < 0) { - throw new Error('Weights must be an array of positive numbers'); - } - - totalWeights += weights[i]; - } - } - - var length = possibles.length; - - if (length == 0) { - return []; - } else if (number$$1 >= length) { - return number$$1 > 1 ? possibles : possibles[0]; - } - - var result = []; - var pick; - - while (result.length < number$$1) { - if (typeof weights === 'undefined') { - pick = possibles[Math.floor(rng() * length)]; - } else { - var randKey = rng() * totalWeights; - - for (var i = 0, len = possibles.length; i < len; i++) { - randKey -= weights[i]; - - if (randKey < 0) { - pick = possibles[i]; - break; - } - } - } - - if (result.indexOf(pick) == -1) { - result.push(pick); - } - } - - return single ? result[0] : result; - - // TODO: add support for multi dimensional matrices - }; - - var _random = function(min, max) { - return min + distribution() * (max - min); - }; - - var _randomInt = function(min, max) { - return Math.floor(min + distribution() * (max - min)); - }; - - // This is a function for generating a random matrix recursively. - var _randomDataForMatrix = function(size, min, max, randFunc) { - var data = [], length, i; - size = size.slice(0); - - if (size.length > 1) { - for (var i = 0, length = size.shift(); i < length; i++) { - data.push(_randomDataForMatrix(size, min, max, randFunc)); - } - } else { - for (var i = 0, length = size.shift(); i < length; i++) { - data.push(randFunc(min, max)); - } - } - - return data; - }; - - return randFunctions; - - })(distribution); - } - - // Each distribution is a function that takes no argument and when called returns - // a number between 0 and 1. - var distributions = { - - uniform: function() { - return rng; - }, - - // Implementation of normal distribution using Box-Muller transform - // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform - // We take : mean = 0.5, standard deviation = 1/6 - // so that 99.7% values are in [0, 1]. - normal: function() { - return function() { - var u1, u2, - picked = -1; - // We reject values outside of the interval [0, 1] - // TODO: check if it is ok to do that? - while (picked < 0 || picked > 1) { - u1 = rng(); - u2 = rng(); - picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; - } - return picked; - } - } - }; - - distribution.toTex = undefined; // use default template - - return distribution; - } - - var name$208 = 'distribution'; - var factory_1$220 = factory$221; - - var distribution = { - name: name$208, - factory: factory_1$220 - }; - - function factory$222 (type, config, load, typed) { - var distribution$$1 = load(distribution); - - /** - * Random pick one or more values from a one dimensional array. - * Array elements are picked using a random function with uniform or weighted distribution. - * - * Syntax: - * - * math.pickRandom(array) - * math.pickRandom(array, number) - * math.pickRandom(array, weights) - * math.pickRandom(array, number, weights) - * math.pickRandom(array, weights, number) - * - * Examples: - * - * math.pickRandom([3, 6, 12, 2]); // returns one of the values in the array - * math.pickRandom([3, 6, 12, 2], 2); // returns an array of two of the values in the array - * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1]); // returns one of the values in the array with weighted distribution - * math.pickRandom([3, 6, 12, 2], 2, [1, 3, 2, 1]); // returns an array of two of the values in the array with weighted distribution - * math.pickRandom([3, 6, 12, 2], [1, 3, 2, 1], 2); // returns an array of two of the values in the array with weighted distribution - * - * See also: - * - * random, randomInt - * - * @param {Array} array A one dimensional array - * @param {Int} number An int or float - * @param {Array} weights An array of ints or floats - * @return {number | Array} Returns a single random value from array when number is 1 or undefined. - * Returns an array with the configured number of elements when number is > 1. - */ - // TODO: rework pickRandom to a typed-function - var pickRandom = distribution$$1('uniform').pickRandom; - - pickRandom.toTex = undefined; // use default template - - return pickRandom; - } - - var name$209 = 'pickRandom'; - var factory_1$221 = factory$222; - - var pickRandom$1 = { - name: name$209, - factory: factory_1$221 - }; - - function factory$223 (type, config, load, typed) { - var distribution$$1 = load(distribution); - - /** - * Return a random number larger or equal to `min` and smaller than `max` - * using a uniform distribution. - * - * Syntax: - * - * math.random() // generate a random number between 0 and 1 - * math.random(max) // generate a random number between 0 and max - * math.random(min, max) // generate a random number between min and max - * math.random(size) // generate a matrix with random numbers between 0 and 1 - * math.random(size, max) // generate a matrix with random numbers between 0 and max - * math.random(size, min, max) // generate a matrix with random numbers between min and max - * - * Examples: - * - * math.random(); // returns a random number between 0 and 1 - * math.random(100); // returns a random number between 0 and 100 - * math.random(30, 40); // returns a random number between 30 and 40 - * math.random([2, 3]); // returns a 2x3 matrix with random numbers between 0 and 1 - * - * See also: - * - * randomInt, pickRandom - * - * @param {Array | Matrix} [size] If provided, an array or matrix with given - * size and filled with random values is returned - * @param {number} [min] Minimum boundary for the random value, included - * @param {number} [max] Maximum boundary for the random value, excluded - * @return {number | Array | Matrix} A random number - */ - // TODO: rework random to a typed-function - var random = distribution$$1('uniform').random; - - random.toTex = undefined; // use default template - - return random; - } - - var name$210 = 'random'; - var factory_1$222 = factory$223; - - var random$1 = { - name: name$210, - factory: factory_1$222 - }; - - function factory$224 (type, config, load, typed) { - var distribution$$1 = load(distribution); - - /** - * Return a random integer number larger or equal to `min` and smaller than `max` - * using a uniform distribution. - * - * Syntax: - * - * math.randomInt(max) // generate a random integer between 0 and max - * math.randomInt(min, max) // generate a random integer between min and max - * math.randomInt(size) // generate a matrix with random integer between 0 and 1 - * math.randomInt(size, max) // generate a matrix with random integer between 0 and max - * math.randomInt(size, min, max) // generate a matrix with random integer between min and max - * - * Examples: - * - * math.randomInt(100); // returns a random integer between 0 and 100 - * math.randomInt(30, 40); // returns a random integer between 30 and 40 - * math.randomInt([2, 3]); // returns a 2x3 matrix with random integers between 0 and 1 - * - * See also: - * - * random, pickRandom - * - * @param {Array | Matrix} [size] If provided, an array or matrix with given - * size and filled with random values is returned - * @param {number} [min] Minimum boundary for the random value, included - * @param {number} [max] Maximum boundary for the random value, excluded - * @return {number | Array | Matrix} A random integer value - */ - // TODO: rework randomInt to a typed-function - var randomInt = distribution$$1('uniform').randomInt; - - randomInt.toTex = undefined; // use default template - - return randomInt; - } - - var name$211 = 'randomInt'; - var factory_1$223 = factory$224; - - var randomInt$1 = { - name: name$211, - factory: factory_1$223 - }; - - var probability = [ - //require('./distribution'), // TODO: rethink math.distribution - combinations$1, - factorial$1, - gamma$1, - kldivergence$1, - multinomial$1, - permutations$1, - pickRandom$1, - random$1, - randomInt$1 - ]; - - function factory$225 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - var _typeof = load(_typeof$1); - - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Compare two strings lexically. Comparison is case sensitive. - * Returns 1 when x > y, -1 when x < y, and 0 when x == y. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.compareText(x, y) - * - * Examples: - * - * math.compareText('B', 'A'); // returns 1 - * math.compareText('2', '10'); // returns 1 - * math.compare('2', '10'); // returns -1 - * math.compareNatural('2', '10'); // returns -1 - * - * math.compareText('B', ['A', 'B', 'C']); // returns [1, 0, -1] - * - * See also: - * - * equal, equalText, compare, compareNatural - * - * @param {string | Array | DenseMatrix} x First string to compare - * @param {string | Array | DenseMatrix} y Second string to compare - * @return {number | Array | DenseMatrix} Returns the result of the comparison: - * 1 when x > y, -1 when x < y, and 0 when x == y. - */ - var compareText = typed('compareText', { - - 'any, any': _compareText, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, _compareText); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return compareText(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return compareText(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return compareText(x, matrix$$1(y)); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, _compareText, false); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, _compareText, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, _compareText, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, _compareText, true).valueOf(); - } - }); - - /** - * Compare two strings - * @param {string} x - * @param {string} y - * @returns {number} - * @private - */ - function _compareText(x, y) { - // we don't want to convert numbers to string, only accept string input - if (!type.isString(x)) { - throw new TypeError('Unexpected type of argument in function compareText ' + - '(expected: string or Array or Matrix, actual: ' + _typeof(x) + ', index: 0)'); - } - if (!type.isString(y)) { - throw new TypeError('Unexpected type of argument in function compareText ' + - '(expected: string or Array or Matrix, actual: ' + _typeof(y) + ', index: 1)'); - } - - return (x === y) - ? 0 - : (x > y ? 1 : -1); - } - - compareText.toTex = undefined; // use default template - - return compareText; - } - - var name$212 = 'compareText'; - var factory_1$224 = factory$225; - - var compareText$1 = { - name: name$212, - factory: factory_1$224 - }; - - function factory$226 (type, config, load, typed) { - var equal = load(equal$1); - - /** - * Test element wise whether two matrices are equal. - * The function accepts both matrices and scalar values. - * - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.deepEqual(x, y) - * - * Examples: - * - * math.deepEqual(2, 4); // returns false - * - * a = [2, 5, 1]; - * b = [2, 7, 1]; - * - * math.deepEqual(a, b); // returns false - * math.equal(a, b); // returns [true, false, true] - * - * See also: - * - * equal, unequal - * - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} x First matrix to compare - * @param {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} y Second matrix to compare - * @return {number | BigNumber | Fraction | Complex | Unit | Array | Matrix} - * Returns true when the input matrices have the same size and each of their elements is equal. - */ - var deepEqual = typed('deepEqual', { - 'any, any': function (x, y) { - return _deepEqual(x.valueOf(), y.valueOf()); - } - }); - - deepEqual.toTex = undefined; // use default template - - return deepEqual; - - /** - * Test whether two arrays have the same size and all elements are equal - * @param {Array | *} x - * @param {Array | *} y - * @return {boolean} Returns true if both arrays are deep equal - */ - function _deepEqual(x, y) { - if (Array.isArray(x)) { - if (Array.isArray(y)) { - var len = x.length; - if (len !== y.length) { - return false; - } - - for (var i = 0; i < len; i++) { - if (!_deepEqual(x[i], y[i])) { - return false; - } - } - - return true; - } - else { - return false; - } - } - else { - if (Array.isArray(y)) { - return false; - } - else { - return equal(x, y); - } - } - } - } - - var name$213 = 'deepEqual'; - var factory_1$225 = factory$226; - - var deepEqual$2 = { - name: name$213, - factory: factory_1$225 - }; - - function factory$227 (type, config, load, typed) { - var compareText = load(compareText$1); - var isZero = load(isZero$1); - - /** - * Check equality of two strings. Comparison is case sensitive. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.equalText(x, y) - * - * Examples: - * - * math.equalText('Hello', 'Hello'); // returns true - * math.equalText('a', 'A'); // returns false - * math.equal('2e3', '2000'); // returns true - * math.equalText('2e3', '2000'); // returns false - * - * math.equalText('B', ['A', 'B', 'C']); // returns [false, true, false] - * - * See also: - * - * equal, compareText, compare, compareNatural - * - * @param {string | Array | DenseMatrix} x First string to compare - * @param {string | Array | DenseMatrix} y Second string to compare - * @return {number | Array | DenseMatrix} Returns true if the values are equal, and false if not. - */ - var equalText = typed('equalText', { - - 'any, any': function (x, y) { - return isZero(compareText(x, y)); - } - - }); - - equalText.toTex = undefined; // use default template - - return equalText; - } - - var name$214 = 'equalText'; - var factory_1$226 = factory$227; - - var equalText$1 = { - name: name$214, - factory: factory_1$226 - }; - - var nearlyEqual$7 = number.nearlyEqual; - - - function factory$228 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm03$$1 = load(algorithm03); - var algorithm07$$1 = load(algorithm07); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - var latex$$1 = latex; - - /** - * Test whether value x is smaller or equal to y. - * - * The function returns true when x is smaller than y or the relative - * difference between x and y is smaller than the configured epsilon. The - * function cannot be used to compare values smaller than approximately 2.22e-16. - * - * For matrices, the function is evaluated element wise. - * Strings are compared by their numerical value. - * - * Syntax: - * - * math.smallerEq(x, y) - * - * Examples: - * - * math.smaller(1 + 2, 3); // returns false - * math.smallerEq(1 + 2, 3); // returns true - * - * See also: - * - * equal, unequal, smaller, larger, largerEq, compare - * - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} x First value to compare - * @param {number | BigNumber | Fraction | boolean | Unit | string | Array | Matrix} y Second value to compare - * @return {boolean | Array | Matrix} Returns true when the x is smaller than y, else returns false - */ - var smallerEq = typed('smallerEq', { - - 'boolean, boolean': function (x, y) { - return x <= y; - }, - - 'number, number': function (x, y) { - return x <= y || nearlyEqual$7(x, y, config.epsilon); - }, - - 'BigNumber, BigNumber': function (x, y) { - return x.lte(y) || nearlyEqual(x, y, config.epsilon); - }, - - 'Fraction, Fraction': function (x, y) { - return x.compare(y) !== 1; - }, - - 'Complex, Complex': function () { - throw new TypeError('No ordering relation is defined for complex numbers'); - }, - - 'Unit, Unit': function (x, y) { - if (!x.equalBase(y)) { - throw new Error('Cannot compare units with different base'); - } - return smallerEq(x.value, y.value); - }, - - 'SparseMatrix, SparseMatrix': function(x, y) { - return algorithm07$$1(x, y, smallerEq); - }, - - 'SparseMatrix, DenseMatrix': function(x, y) { - return algorithm03$$1(y, x, smallerEq, true); - }, - - 'DenseMatrix, SparseMatrix': function(x, y) { - return algorithm03$$1(x, y, smallerEq, false); - }, - - 'DenseMatrix, DenseMatrix': function(x, y) { - return algorithm13$$1(x, y, smallerEq); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return smallerEq(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return smallerEq(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return smallerEq(x, matrix$$1(y)); - }, - - 'SparseMatrix, any': function (x, y) { - return algorithm12$$1(x, y, smallerEq, false); - }, - - 'DenseMatrix, any': function (x, y) { - return algorithm14$$1(x, y, smallerEq, false); - }, - - 'any, SparseMatrix': function (x, y) { - return algorithm12$$1(y, x, smallerEq, true); - }, - - 'any, DenseMatrix': function (x, y) { - return algorithm14$$1(y, x, smallerEq, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, smallerEq, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, smallerEq, true).valueOf(); - } - }); - - smallerEq.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['smallerEq'] + '${args[1]}\\right)' - }; - - return smallerEq; - } - - var name$215 = 'smallerEq'; - var factory_1$227 = factory$228; - - var smallerEq$1 = { - name: name$215, - factory: factory_1$227 - }; - - var relational = [ - compare$1, - compareNatural$1, - compareText$1, - deepEqual$2, - equal$1, - equalText$1, - larger, - largerEq$1, - smaller, - smallerEq$1, - unequal$1 - ]; - - var flatten$4 = array.flatten; - - function factory$229 (type, config, load, typed) { - var index = load(MatrixIndex); - var matrix = load(DenseMatrix); - var size = load(size$5); - var subset = load(subset$1); - var compareNatural = load(compareNatural$1); - - /** - * Create the cartesian product of two (multi)sets. - * Multi-dimension arrays will be converted to single-dimension arrays before the operation. - * - * Syntax: - * - * math.setCartesian(set1, set2) - * - * Examples: - * - * math.setCartesian([1, 2], [3, 4]); // returns [[1, 3], [1, 4], [2, 3], [2, 4]] - * - * See also: - * - * setUnion, setIntersect, setDifference, setPowerset - * - * @param {Array | Matrix} a1 A (multi)set - * @param {Array | Matrix} a2 A (multi)set - * @return {Array | Matrix} The cartesian product of two (multi)sets - */ - var setCartesian = typed('setCartesian', { - 'Array | Matrix, Array | Matrix': function (a1, a2) { - if (subset(size(a1), new index(0)) === 0 || subset(size(a2), new index(0)) === 0) { // if any of them is empty, return empty - var result = []; - } - else { - var b1 = flatten$4(Array.isArray(a1) ? a1 : a1.toArray()).sort(compareNatural); - var b2 = flatten$4(Array.isArray(a2) ? a2 : a2.toArray()).sort(compareNatural); - var result = []; - for (var i=0; i0; i--) { - for (var j=0; j array$$1[j+1].length) { - temp = array$$1[j]; - array$$1[j] = array$$1[j+1]; - array$$1[j+1] = temp; - } - } - } - return array$$1; - } - } - - var name$222 = 'setPowerset'; - var factory_1$234 = factory$235; - - var setPowerset$1 = { - name: name$222, - factory: factory_1$234 - }; - - var flatten$11 = array.flatten; - - function factory$236 (type, config, load, typed) { - var compareNatural = load(compareNatural$1); - - /** - * Count the number of elements of a (multi)set. When a second parameter is 'true', count only the unique values. - * A multi-dimension array will be converted to a single-dimension array before the operation. - * - * Syntax: - * - * math.setSize(set) - * math.setSize(set, unique) - * - * Examples: - * - * math.setSize([1, 2, 2, 4]); // returns 4 - * math.setSize([1, 2, 2, 4], true); // returns 3 - * - * See also: - * - * setUnion, setIntersect, setDifference - * - * @param {Array | Matrix} a A multiset - * @return {number} The number of elements of the (multi)set - */ - var setSize = typed('setSize', { - 'Array | Matrix': function (a) { - return Array.isArray(a) ? flatten$11(a).length : flatten$11(a.toArray()).length; - }, - 'Array | Matrix, boolean': function (a, unique) { - if (unique === false || a.length === 0) { - return Array.isArray(a) ? flatten$11(a).length : flatten$11(a.toArray()).length; - } - else { - var b = flatten$11(Array.isArray(a) ? a : a.toArray()).sort(compareNatural); - var count = 1; - for (var i=1; i= MAX_NUM) { - return sign$2(x); - } - if (y <= THRESH) { - return sign$2(x) * erf1(y); - } - if (y <= 4.0) { - return sign$2(x) * (1 - erfc2(y)); - } - return sign$2(x) * (1 - erfc3(y)); - }, - - // TODO: Not sure if there's a way to guarantee some degree of accuracy here. - // Perhaps it would be best to set the precision of the number to that which - // is guaranteed by erf() - 'BigNumber': function (n) { - return new type.BigNumber(erf(n.toNumber())); - }, - - 'Array | Matrix': function (n) { - return deepMap(n, erf); - } - - // TODO: For complex numbers, use the approximation for the Faddeeva function - // from "More Efficient Computation of the Complex Error Function" (AMS) - - }); - - /** - * Approximates the error function erf() for x <= 0.46875 using this function: - * n - * erf(x) = x * sum (p_j * x^(2j)) / (q_j * x^(2j)) - * j=0 - */ - function erf1(y) { - var ysq = y * y; - var xnum = P[0][4]*ysq; - var xden = ysq; - var i; - - for (i = 0; i < 3; i += 1) { - xnum = (xnum + P[0][i]) * ysq; - xden = (xden + Q[0][i]) * ysq; - } - return y * (xnum + P[0][3]) / (xden + Q[0][3]); - } - - /** - * Approximates the complement of the error function erfc() for - * 0.46875 <= x <= 4.0 using this function: - * n - * erfc(x) = e^(-x^2) * sum (p_j * x^j) / (q_j * x^j) - * j=0 - */ - function erfc2(y) { - var xnum = P[1][8] * y; - var xden = y; - var i; - - for (i = 0; i < 7; i += 1) { - xnum = (xnum + P[1][i]) * y; - xden = (xden + Q[1][i]) * y; - } - var result = (xnum + P[1][7]) / (xden + Q[1][7]); - var ysq = parseInt(y * 16) / 16; - var del = (y - ysq) * (y + ysq); - return Math.exp(-ysq*ysq) * Math.exp(-del) * result; - } - - /** - * Approximates the complement of the error function erfc() for x > 4.0 using - * this function: - * - * erfc(x) = (e^(-x^2) / x) * [ 1/sqrt(pi) + - * n - * 1/(x^2) * sum (p_j * x^(-2j)) / (q_j * x^(-2j)) ] - * j=0 - */ - function erfc3(y) { - var ysq = 1 / (y * y); - var xnum = P[2][5] * ysq; - var xden = ysq; - var i; - - for (i = 0; i < 4; i += 1) { - xnum = (xnum + P[2][i]) * ysq; - xden = (xden + Q[2][i]) * ysq; - } - var result = ysq * (xnum + P[2][4]) / (xden + Q[2][4]); - result = (SQRPI - result) / y; - ysq = parseInt(y * 16) / 16; - var del = (y - ysq) * (y + ysq); - return Math.exp(-ysq*ysq) * Math.exp(-del) * result; - } - - erf.toTex = {1: 'erf\\left(${args[0]}\\right)'}; - - return erf; - } - - /** - * Upper bound for the first approximation interval, 0 <= x <= THRESH - * @constant - */ - var THRESH = 0.46875; - - /** - * Constant used by W. J. Cody's Fortran77 implementation to denote sqrt(pi) - * @constant - */ - var SQRPI = 5.6418958354775628695e-1; - - /** - * Coefficients for each term of the numerator sum (p_j) for each approximation - * interval (see W. J. Cody's paper for more details) - * @constant - */ - var P = [[ - 3.16112374387056560e00, 1.13864154151050156e02, - 3.77485237685302021e02, 3.20937758913846947e03, - 1.85777706184603153e-1 - ], [ - 5.64188496988670089e-1, 8.88314979438837594e00, - 6.61191906371416295e01, 2.98635138197400131e02, - 8.81952221241769090e02, 1.71204761263407058e03, - 2.05107837782607147e03, 1.23033935479799725e03, - 2.15311535474403846e-8 - ], [ - 3.05326634961232344e-1, 3.60344899949804439e-1, - 1.25781726111229246e-1, 1.60837851487422766e-2, - 6.58749161529837803e-4, 1.63153871373020978e-2 - ]]; - - /** - * Coefficients for each term of the denominator sum (q_j) for each approximation - * interval (see W. J. Cody's paper for more details) - * @constant - */ - var Q = [[ - 2.36012909523441209e01, 2.44024637934444173e02, - 1.28261652607737228e03, 2.84423683343917062e03 - ], [ - 1.57449261107098347e01, 1.17693950891312499e02, - 5.37181101862009858e02, 1.62138957456669019e03, - 3.29079923573345963e03, 4.36261909014324716e03, - 3.43936767414372164e03, 1.23033935480374942e03 - ], [ - 2.56852019228982242e00, 1.87295284992346047e00, - 5.27905102951428412e-1, 6.05183413124413191e-2, - 2.33520497626869185e-3 - ]]; - - /** - * Maximum/minimum safe numbers to input to erf() (in ES6+, this number is - * Number.[MAX|MIN]_SAFE_INTEGER). erf() for all numbers beyond this limit will - * return 1 - */ - var MAX_NUM = Math.pow(2, 53); - - - var name$226 = 'erf'; - var factory_1$238 = factory$239; - - var erf$1 = { - name: name$226, - factory: factory_1$238 - }; - - var special = [ - erf$1 - ]; - - var flatten$14 = array.flatten; - - - function factory$240 (type, config, load, typed) { - var add = load(addScalar); - var divide = load(divideScalar); - var compare = load(compare$1); - var partitionSelect = load(partitionSelect$1); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the median of a matrix or a list with values. The values are - * sorted and the middle value is returned. In case of an even number of - * values, the average of the two middle values is returned. - * Supported types of values are: Number, BigNumber, Unit - * - * In case of a (multi dimensional) array or matrix, the median of all - * elements will be calculated. - * - * Syntax: - * - * math.median(a, b, c, ...) - * math.median(A) - * - * Examples: - * - * math.median(5, 2, 7); // returns 5 - * math.median([3, -1, 5, 7]); // returns 4 - * - * See also: - * - * mean, min, max, sum, prod, std, var, quantileSeq - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The median - */ - var median = typed('median', { - // median([a, b, c, d, ...]) - 'Array | Matrix': _median, - - // median([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': function (array$$1, dim) { - // TODO: implement median(A, dim) - throw new Error('median(A, dim) is not yet supported'); - //return reduce(arguments[0], arguments[1], ...); - }, - - // median(a, b, c, d, ...) - '...': function (args) { - if (containsCollections(args)) { - throw new TypeError('Scalar values expected in function median'); - } - - return _median(args); - } - }); - - - /** - * Recursively calculate the median of an n-dimensional array - * @param {Array} array - * @return {Number} median - * @private - */ - function _median(array$$1) { - try { - array$$1 = flatten$14(array$$1.valueOf()); - - var num = array$$1.length; - if (num == 0) { - throw new Error('Cannot calculate median of an empty array'); - } - - if (num % 2 == 0) { - // even: return the average of the two middle values - var mid = num / 2 - 1; - var right = partitionSelect(array$$1, mid + 1); - - // array now partitioned at mid + 1, take max of left part - var left = array$$1[mid]; - for (var i = 0; i < mid; ++i) { - if (compare(array$$1[i], left) > 0) { - left = array$$1[i]; - } - } - - return middle2(left, right); - } - else { - // odd: return the middle value - var m = partitionSelect(array$$1, (num - 1) / 2); - - return middle(m); - } - } - catch (err) { - throw improveErrorMessage$$1(err, 'median'); - } - } - - // helper function to type check the middle value of the array - var middle = typed({ - 'number | BigNumber | Complex | Unit': function (value) { - return value; - } - }); - - // helper function to type check the two middle value of the array - var middle2 = typed({ - 'number | BigNumber | Complex | Unit, number | BigNumber | Complex | Unit': function (left, right) { - return divide(add(left, right), 2); - } - }); - - median.toTex = undefined; // use default template - - return median; - } - - var name$227 = 'median'; - var factory_1$239 = factory$240; - - var median$1 = { - name: name$227, - factory: factory_1$239 - }; - - var flatten$15 = array.flatten; - - function factory$241 (type, config, load, typed) { - var abs = load(abs$1); - var map = load(map$7); - var median = load(median$1); - var subtract = load(subtract$1); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the median absolute deviation of a matrix or a list with values. - * The median absolute deviation is defined as the median of the absolute - * deviations from the median. - * - * Syntax: - * - * math.mad(a, b, c, ...) - * math.mad(A) - * - * Examples: - * - * math.mad(10, 20, 30); // returns 10 - * math.mad([1, 2, 3]); // returns 1 - * math.mad([[1, 2, 3], [4, 5, 6]]); // returns 1.5 - * - * See also: - * - * median, mean, std, abs - * - * @param {Array | Matrix} array - * A single matrix or multiple scalar values. - * @return {*} The median absolute deviation. - */ - var mad = typed('mad', { - // mad([a, b, c, d, ...]) - 'Array | Matrix': _mad, - - // mad(a, b, c, d, ...) - '...': function (args) { - return _mad(args); - } - }); - - mad.toTex = undefined; // use default template - - return mad; - - function _mad(array$$1) { - array$$1 = flatten$15(array$$1.valueOf()); - - if (array$$1.length === 0) { - throw new Error('Cannot calculate median absolute deviation (mad) of an empty array'); - } - - try { - var med = median(array$$1); - return median(map(array$$1, function (value) { - return abs(subtract(value, med)); - })); - } - catch (err) { - if (err instanceof TypeError && err.message.indexOf('median') !== -1) { - throw new TypeError(err.message.replace('median', 'mad')); - } - else { - throw improveErrorMessage$$1(err, 'mad'); - } - } - } - } - - var name$228 = 'mad'; - var factory_1$240 = factory$241; - - var mad$1 = { - name: name$228, - factory: factory_1$240 - }; - - var flatten$16 = array.flatten; - - function factory$242 (type, config, load, typed) { - - /** - * Computes the mode of a set of numbers or a list with values(numbers or characters). - * If there are more than one modes, it returns a list of those values. - * - * Syntax: - * - * math.mode(a, b, c, ...) - * math.mode(A) - * - * Examples: - * - * math.mode(2, 1, 4, 3, 1); // returns [1] - * math.mode([1, 2.7, 3.2, 4, 2.7]); // returns [2.7] - * math.mode(1, 4, 6, 1, 6) // returns [1, 6] - * math.mode('a','a','b','c') // returns ["a"] - * math.mode(1, 1.5, 'abc') // returns [1, 1.5, "abc"] - * - * See also: - * - * median, - * mean - * - * @param {... *} args A single matrix - * @return {*} The mode of all values - */ - - var mode = typed('mode', { - 'Array | Matrix' : _mode, - - '...': function (args) { - return _mode(args); - } - }); - - return mode; - - /** - * Calculates the mode in an 1-dimensional array - * @param {Array} values - * @return {number} mode - * @private - */ - function _mode(values) { - values = flatten$16(values.valueOf()); - var num = values.length; - if (num == 0) { - throw new Error('Cannot calculate mode of an empty array'); - } - - var count = {}, - mode = [], - max = 0; - for (var i in values) { - if (!(values[i] in count)){ - count[values[i]] = 0; - } - count[values[i]]++; - if (count[values[i]] == max){ - mode.push(values[i]); - } - else if (count[values[i]] > max) { - max = count[values[i]]; - mode = [values[i]]; - } - } - return mode; - }} - - var name$229 = 'mode'; - var factory_1$241 = factory$242; - - var mode$1 = { - name: name$229, - factory: factory_1$241 - }; - - function factory$243 (type, config, load, typed) { - var multiply = load(multiplyScalar); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the product of a matrix or a list with values. - * In case of a (multi dimensional) array or matrix, the sum of all - * elements will be calculated. - * - * Syntax: - * - * math.prod(a, b, c, ...) - * math.prod(A) - * - * Examples: - * - * math.multiply(2, 3); // returns 6 - * math.prod(2, 3); // returns 6 - * math.prod(2, 3, 4); // returns 24 - * math.prod([2, 3, 4]); // returns 24 - * math.prod([[2, 5], [4, 3]]); // returns 120 - * - * See also: - * - * mean, median, min, max, sum, std, var - * - * @param {... *} args A single matrix or or multiple scalar values - * @return {*} The product of all values - */ - var prod = typed('prod', { - // prod([a, b, c, d, ...]) - 'Array | Matrix': _prod, - - // prod([a, b, c, d, ...], dim) - 'Array | Matrix, number | BigNumber': function (array, dim) { - // TODO: implement prod(A, dim) - throw new Error('prod(A, dim) is not yet supported'); - //return reduce(arguments[0], arguments[1], math.prod); - }, - - // prod(a, b, c, d, ...) - '...': function (args) { - return _prod(args); - } - }); - - prod.toTex = undefined; // use default template - - return prod; - - /** - * Recursively calculate the product of an n-dimensional array - * @param {Array} array - * @return {number} prod - * @private - */ - function _prod(array) { - var prod = undefined; - - deepForEach(array, function (value) { - try { - prod = (prod === undefined) ? value : multiply(prod, value); - } - catch (err) { - throw improveErrorMessage$$1(err, 'prod', value); - } - }); - - if (prod === undefined) { - throw new Error('Cannot calculate prod of an empty array'); - } - - return prod; - } - } - - var name$230 = 'prod'; - var factory_1$242 = factory$243; - - var prod$1 = { - name: name$230, - factory: factory_1$242 - }; - - var isInteger$29 = number.isInteger; - var isNumber$4 = number.isNumber; - var flatten$17 = array.flatten; - - - function factory$244 (type, config, load, typed) { - var add$$1 = load(add); - var multiply = load(multiply$1); - var partitionSelect = load(partitionSelect$1); - var compare = load(compare$1); - - /** - * Compute the prob order quantile of a matrix or a list with values. - * The sequence is sorted and the middle value is returned. - * Supported types of sequence values are: Number, BigNumber, Unit - * Supported types of probability are: Number, BigNumber - * - * In case of a (multi dimensional) array or matrix, the prob order quantile - * of all elements will be calculated. - * - * Syntax: - * - * math.quantileSeq(A, prob[, sorted]) - * math.quantileSeq(A, [prob1, prob2, ...][, sorted]) - * math.quantileSeq(A, N[, sorted]) - * - * Examples: - * - * math.quantileSeq([3, -1, 5, 7], 0.5); // returns 4 - * math.quantileSeq([3, -1, 5, 7], [1/3, 2/3]); // returns [3, 5] - * math.quantileSeq([3, -1, 5, 7], 2); // returns [3, 5] - * math.quantileSeq([-1, 3, 5, 7], 0.5, true); // returns 4 - * - * See also: - * - * median, mean, min, max, sum, prod, std, var - * - * @param {Array, Matrix} data A single matrix or Array - * @param {Number, BigNumber, Array} probOrN prob is the order of the quantile, while N is - * the amount of evenly distributed steps of - * probabilities; only one of these options can - * be provided - * @param {Boolean} sorted=false is data sorted in ascending order - * @return {Number, BigNumber, Unit, Array} Quantile(s) - */ - function quantileSeq(data, probOrN, sorted) { - var probArr, dataArr, one; - - if (arguments.length < 2 || arguments.length > 3) { - throw new SyntaxError('Function quantileSeq requires two or three parameters'); - } - - if (isCollection(data)) { - sorted = sorted || false; - if (typeof sorted === 'boolean') { - dataArr = data.valueOf(); - if (isNumber$4(probOrN)) { - if (probOrN < 0) { - throw new Error('N/prob must be non-negative'); - } - - if (probOrN <= 1) { - // quantileSeq([a, b, c, d, ...], prob[,sorted]) - return _quantileSeq(dataArr, probOrN, sorted); - } - - if (probOrN > 1) { - // quantileSeq([a, b, c, d, ...], N[,sorted]) - if (!isInteger$29(probOrN)) { - throw new Error('N must be a positive integer'); - } - - var nPlusOne = probOrN + 1; - probArr = new Array(probOrN); - for (var i = 0; i < probOrN;) { - probArr[i] = _quantileSeq(dataArr, (++i) / nPlusOne, sorted); - } - return probArr; - } - } - - if (type.isBigNumber(probOrN)) { - if (probOrN.isNegative()) { - throw new Error('N/prob must be non-negative'); - } - - one = new probOrN.constructor(1); - - if (probOrN.lte(one)) { - // quantileSeq([a, b, c, d, ...], prob[,sorted]) - return _quantileSeq(dataArr, probOrN, sorted); - } - - if (probOrN.gt(one)) { - // quantileSeq([a, b, c, d, ...], N[,sorted]) - if (!probOrN.isInteger()) { - throw new Error('N must be a positive integer'); - } - - // largest possible Array length is 2^32-1; - // 2^32 < 10^15, thus safe conversion guaranteed - var intN = probOrN.toNumber(); - if (intN > 4294967295) { - throw new Error('N must be less than or equal to 2^32-1, as that is the maximum length of an Array'); - } - - var nPlusOne = new type.BigNumber(intN + 1); - probArr = new Array(intN); - for (var i = 0; i < intN;) { - probArr[i] = _quantileSeq(dataArr, new type.BigNumber(++i).div(nPlusOne), sorted); - } - return probArr; - } - } - - if (Array.isArray(probOrN)) { - // quantileSeq([a, b, c, d, ...], [prob1, prob2, ...][,sorted]) - probArr = new Array(probOrN.length); - for (var i = 0; i < probArr.length; ++i) { - var currProb = probOrN[i]; - if (isNumber$4(currProb)) { - if (currProb < 0 || currProb > 1) { - throw new Error('Probability must be between 0 and 1, inclusive'); - } - } else if (type.isBigNumber(currProb)) { - one = new currProb.constructor(1); - if (currProb.isNegative() || currProb.gt(one)) { - throw new Error('Probability must be between 0 and 1, inclusive'); - } - } else { - throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function - } - - probArr[i] = _quantileSeq(dataArr, currProb, sorted); - } - return probArr; - } - - throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function - } - - throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function - } - - throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function - } - - /** - * Calculate the prob order quantile of an n-dimensional array. - * - * @param {Array} array - * @param {Number, BigNumber} prob - * @param {Boolean} sorted - * @return {Number, BigNumber, Unit} prob order quantile - * @private - */ - function _quantileSeq(array$$1, prob, sorted) { - var flat = flatten$17(array$$1); - var len = flat.length; - if (len === 0) { - throw new Error('Cannot calculate quantile of an empty sequence'); - } - - if (isNumber$4(prob)) { - var index = prob * (len-1); - var fracPart = index % 1; - if (fracPart === 0) { - var value = sorted ? flat[index] : partitionSelect(flat, index); - - validate(value); - - return value; - } - - var integerPart = Math.floor(index); - - var left, right; - if (sorted) { - left = flat[integerPart]; - right = flat[integerPart+1]; - } else { - right = partitionSelect(flat, integerPart+1); - - // max of partition is kth largest - left = flat[integerPart]; - for (var i = 0; i < integerPart; ++i) { - if (compare(flat[i], left) > 0) { - left = flat[i]; - } - } - } - - validate(left); - validate(right); - - // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1] - return add$$1(multiply(left, 1 - fracPart), multiply(right, fracPart)); - } - - // If prob is a BigNumber - var index = prob.times(len-1); - if (index.isInteger()) { - index = index.toNumber(); - var value = sorted ? flat[index] : partitionSelect(flat, index); - - validate(value); - - return value; - } - - var integerPart = index.floor(); - var fracPart = index.minus(integerPart); - var integerPartNumber = integerPart.toNumber(); - - var left, right; - if (sorted) { - left = flat[integerPartNumber]; - right = flat[integerPartNumber+1]; - } else { - right = partitionSelect(flat, integerPartNumber+1); - - // max of partition is kth largest - left = flat[integerPartNumber]; - for (var i = 0; i < integerPartNumber; ++i) { - if (compare(flat[i], left) > 0) { - left = flat[i]; - } - } - } - - validate(left); - validate(right); - - // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1] - var one = new fracPart.constructor(1); - return add$$1(multiply(left, one.minus(fracPart)), multiply(right, fracPart)); - } - - /** - * Check if array value types are valid, throw error otherwise. - * @param {number | BigNumber | Unit} x - * @param {number | BigNumber | Unit} x - * @private - */ - var validate = typed({ - 'number | BigNumber | Unit': function (x) { - return x; - } - }); - - return quantileSeq; - } - - var name$231 = 'quantileSeq'; - var factory_1$243 = factory$244; - - var quantileSeq$1 = { - name: name$231, - factory: factory_1$243 - }; - - var DEFAULT_NORMALIZATION = 'unbiased'; - - - - function factory$245 (type, config, load, typed) { - var add = load(addScalar); - var subtract = load(subtract$1); - var multiply = load(multiplyScalar); - var divide = load(divideScalar); - var improveErrorMessage$$1 = load(improveErrorMessage); - - /** - * Compute the variance of a matrix or a list with values. - * In case of a (multi dimensional) array or matrix, the variance over all - * elements will be calculated. - * - * Optionally, the type of normalization can be specified as second - * parameter. The parameter `normalization` can be one of the following values: - * - * - 'unbiased' (default) The sum of squared errors is divided by (n - 1) - * - 'uncorrected' The sum of squared errors is divided by n - * - 'biased' The sum of squared errors is divided by (n + 1) - * - * Note that older browser may not like the variable name `var`. In that - * case, the function can be called as `math['var'](...)` instead of - * `math.var(...)`. - * - * Syntax: - * - * math.var(a, b, c, ...) - * math.var(A) - * math.var(A, normalization) - * - * Examples: - * - * math.var(2, 4, 6); // returns 4 - * math.var([2, 4, 6, 8]); // returns 6.666666666666667 - * math.var([2, 4, 6, 8], 'uncorrected'); // returns 5 - * math.var([2, 4, 6, 8], 'biased'); // returns 4 - * - * math.var([[1, 2, 3], [4, 5, 6]]); // returns 3.5 - * - * See also: - * - * mean, median, max, min, prod, std, sum - * - * @param {Array | Matrix} array - * A single matrix or or multiple scalar values - * @param {string} [normalization='unbiased'] - * Determines how to normalize the variance. - * Choose 'unbiased' (default), 'uncorrected', or 'biased'. - * @return {*} The variance - */ - var variance = typed('variance', { - // var([a, b, c, d, ...]) - 'Array | Matrix': function (array) { - return _var(array, DEFAULT_NORMALIZATION); - }, - - // var([a, b, c, d, ...], normalization) - 'Array | Matrix, string': _var, - - // var(a, b, c, d, ...) - '...': function (args) { - return _var(args, DEFAULT_NORMALIZATION); - } - }); - - variance.toTex = '\\mathrm{Var}\\left(${args}\\right)'; - - return variance; - - /** - * Recursively calculate the variance of an n-dimensional array - * @param {Array} array - * @param {string} normalization - * Determines how to normalize the variance: - * - 'unbiased' The sum of squared errors is divided by (n - 1) - * - 'uncorrected' The sum of squared errors is divided by n - * - 'biased' The sum of squared errors is divided by (n + 1) - * @return {number | BigNumber} variance - * @private - */ - function _var(array, normalization) { - var sum = 0; - var num = 0; - - if (array.length == 0) { - throw new SyntaxError('Function var requires one or more parameters (0 provided)'); - } - - // calculate the mean and number of elements - deepForEach(array, function (value) { - try { - sum = add(sum, value); - num++; - } - catch (err) { - throw improveErrorMessage$$1(err, 'var', value); - } - }); - if (num === 0) throw new Error('Cannot calculate var of an empty array'); - - var mean = divide(sum, num); - - // calculate the variance - sum = 0; - deepForEach(array, function (value) { - var diff = subtract(value, mean); - sum = add(sum, multiply(diff, diff)); - }); - - switch (normalization) { - case 'uncorrected': - return divide(sum, num); - - case 'biased': - return divide(sum, num + 1); - - case 'unbiased': - var zero = type.isBigNumber(sum) ? new type.BigNumber(0) : 0; - return (num == 1) ? zero : divide(sum, num - 1); - - default: - throw new Error('Unknown normalization "' + normalization + '". ' + - 'Choose "unbiased" (default), "uncorrected", or "biased".'); - } - } - } - - var name$232 = 'var'; - var factory_1$244 = factory$245; - - var _var$1 = { - name: name$232, - factory: factory_1$244 - }; - - function factory$246 (type, config, load, typed) { - var sqrt = load(sqrt$1); - var variance = load(_var$1); - - /** - * Compute the standard deviation of a matrix or a list with values. - * The standard deviations is defined as the square root of the variance: - * `std(A) = sqrt(var(A))`. - * In case of a (multi dimensional) array or matrix, the standard deviation - * over all elements will be calculated. - * - * Optionally, the type of normalization can be specified as second - * parameter. The parameter `normalization` can be one of the following values: - * - * - 'unbiased' (default) The sum of squared errors is divided by (n - 1) - * - 'uncorrected' The sum of squared errors is divided by n - * - 'biased' The sum of squared errors is divided by (n + 1) - * - * Syntax: - * - * math.std(a, b, c, ...) - * math.std(A) - * math.std(A, normalization) - * - * Examples: - * - * math.std(2, 4, 6); // returns 2 - * math.std([2, 4, 6, 8]); // returns 2.581988897471611 - * math.std([2, 4, 6, 8], 'uncorrected'); // returns 2.23606797749979 - * math.std([2, 4, 6, 8], 'biased'); // returns 2 - * - * math.std([[1, 2, 3], [4, 5, 6]]); // returns 1.8708286933869707 - * - * See also: - * - * mean, median, max, min, prod, sum, var - * - * @param {Array | Matrix} array - * A single matrix or or multiple scalar values - * @param {string} [normalization='unbiased'] - * Determines how to normalize the variance. - * Choose 'unbiased' (default), 'uncorrected', or 'biased'. - * @return {*} The standard deviation - */ - var std = typed('std', { - // std([a, b, c, d, ...]) - 'Array | Matrix': _std, - - // std([a, b, c, d, ...], normalization) - 'Array | Matrix, string': _std, - - // std(a, b, c, d, ...) - '...': function (args) { - return _std(args); - } - }); - - std.toTex = undefined; // use default template - - return std; - - function _std(array, normalization) { - if (array.length == 0) { - throw new SyntaxError('Function std requires one or more parameters (0 provided)'); - } - - try { - return sqrt(variance.apply(null, arguments)); - } - catch (err) { - if (err instanceof TypeError && err.message.indexOf(' var') !== -1) { - throw new TypeError(err.message.replace(' var', ' std')); - } - else { - throw err; - } - } - } - } - - var name$233 = 'std'; - var factory_1$245 = factory$246; - - var std$1 = { - name: name$233, - factory: factory_1$245 - }; - - var statistics = [ - mad$1, - max$1, - mean$1, - median$1, - min$1, - mode$1, - prod$1, - quantileSeq$1, - std$1, - sum$1, - _var$1 - ]; - - function factory$247 (type, config, load, typed) { - /** - * Format a value of any type into a string. - * - * Syntax: - * - * math.format(value) - * math.format(value, options) - * math.format(value, precision) - * math.format(value, callback) - * - * Where: - * - * - `value: *` - * The value to be formatted - * - `options: Object` - * An object with formatting options. Available options: - * - `notation: string` - * 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 - * `lower` and `upper` bounds, and uses exponential notation elsewhere. - * Lower bound is included, upper bound is excluded. - * For example '123.4' and '1.4e7'. - * - `precision: number` - * A number between 0 and 16 to round the digits of the number. In case - * of notations 'exponential' 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. - * - `lowerExp: number` - * Exponent determining the lower boundary for formatting a value with - * an exponent when `notation='auto`. Default value is `-3`. - * - `upperExp: number` - * Exponent determining the upper boundary for formatting a value with - * an exponent when `notation='auto`. Default value is `5`. - * - `fraction: string`. Available values: 'ratio' (default) or 'decimal'. - * For example `format(fraction(1, 3))` will output '1/3' when 'ratio' is - * configured, and will output `0.(3)` when 'decimal' is configured. - * - `callback: function` - * A custom formatting function, invoked for all numeric elements in `value`, - * for example all elements of a matrix, or the real and imaginary - * parts of a complex number. This callback can be used to override the - * built-in numeric notation with any type of formatting. Function `callback` - * is called with `value` as parameter and must return a string. - * - * When `value` is an Object: - * - * - When the object contains a property `format` being a function, this function - * is invoked as `value.format(options)` and the result is returned. - * - When the object has its own `toString` method, this method is invoked - * and the result is returned. - * - In other cases the function will loop over all object properties and - * return JSON object notation like '{"a": 2, "b": 3}'. - * - * When value is a function: - * - * - When the function has a property `syntax`, it returns this - * syntax description. - * - In other cases, a string `'function'` is returned. - * - * Examples: - * - * math.format(6.4); // returns '6.4' - * math.format(1240000); // returns '1.24e6' - * math.format(1/3); // returns '0.3333333333333333' - * math.format(1/3, 3); // returns '0.333' - * math.format(21385, 2); // returns '21000' - * math.format(12e8, {notation: 'fixed'}); // returns '1200000000' - * math.format(2.3, {notation: 'fixed', precision: 4}); // returns '2.3000' - * math.format(52.8, {notation: 'exponential'}); // returns '5.28e+1' - * math.format(12400,{notation: 'engineering'}); // returns '12.400e+3' - * math.format(2000, {lowerExp: -2, upperExp: 2}); // returns '2e+3' - * - * function formatCurrency(value) { - * // return currency notation with two digits: - * return '$' + value.toFixed(2); - * - * // you could also use math.format inside the callback: - * // return '$' + math.format(value, {notation: 'fixed', precision: 2}); - * } - * math.format([2.1, 3, 0.016], formatCurrency}; // returns '[$2.10, $3.00, $0.02]' - * - * See also: - * - * print - * - * @param {*} value Value to be stringified - * @param {Object | Function | number} [options] Formatting options - * @return {string} The formatted value - */ - var format = typed('format', { - 'any': string.format, - 'any, Object | function | number': string.format - }); - - format.toTex = undefined; // use default template - - return format; - } - - var name$234 = 'format'; - var factory_1$246 = factory$247; - - var format$8 = { - name: name$234, - factory: factory_1$246 - }; - - var isString$5 = string.isString; - var format$9 = string.format; - - function factory$248 (type, config, load, typed) { - /** - * Interpolate values into a string template. - * - * Syntax: - * - * math.print(template, values) - * math.print(template, values, precision) - * math.print(template, values, options) - * - * Example usage: - * - * // the following outputs: 'Lucy is 5 years old' - * math.print('Lucy is $age years old', {age: 5}); - * - * // the following outputs: 'The value of pi is 3.141592654' - * math.print('The value of pi is $pi', {pi: math.pi}, 10); - * - * // the following outputs: 'hello Mary! The date is 2013-03-23' - * math.print('Hello $user.name! The date is $date', { - * user: { - * name: 'Mary', - * }, - * date: new Date(2013, 2, 23).toISOString().substring(0, 10) - * }); - * - * // the following outputs: 'My favorite fruits are apples and bananas !' - * math.print('My favorite fruits are $0 and $1 !', [ - * 'apples', - * 'bananas' - * ]); - * - * See also: - * - * format - * - * @param {string} template A string containing variable placeholders. - * @param {Object | Array | Matrix} values An object or array containing variables - * which will be filled in in the template. - * @param {number | Object} [options] Formatting options, - * or the number of digits to format numbers. - * See function math.format for a description - * of all options. - * @return {string} Interpolated string - */ - var print = typed ('print', { - // note: Matrix will be converted automatically to an Array - 'string, Object | Array': _print, - 'string, Object | Array, number | Object': _print - }); - - print.toTex = undefined; // use default template - - return print; - } - - /** - * Interpolate values into a string template. - * @param {string} template - * @param {Object} values - * @param {number | Object} [options] - * @returns {string} Interpolated string - * @private - */ - function _print(template, values, options) { - return template.replace(/\$([\w\.]+)/g, function (original, key) { - var keys = key.split('.'); - var value = values[keys.shift()]; - while (keys.length && value !== undefined) { - var k = keys.shift(); - value = k ? value[k] : value + '.'; - } - - if (value !== undefined) { - if (!isString$5(value)) { - return format$9(value, options); - } - else { - return value; - } - } - - return original; - } - ); - } - - var name$235 = 'print'; - var factory_1$247 = factory$248; - - var print = { - name: name$235, - factory: factory_1$247 - }; - - var string$10 = [ - format$8, - print - ]; - - function factory$249 (type, config, load, typed) { - - /** - * Calculate the inverse cosine of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acos(x) - * - * Examples: - * - * math.acos(0.5); // returns number 1.0471975511965979 - * math.acos(math.cos(1.5)); // returns number 1.5 - * - * math.acos(2); // returns Complex 0 + 1.3169578969248166 i - * - * See also: - * - * cos, atan, asin - * - * @param {number | BigNumber | Complex | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} The arc cosine of x - */ - var acos = typed('acos', { - 'number': function (x) { - if ((x >= -1 && x <= 1) || config.predictable) { - return Math.acos(x); - } - else { - return new type.Complex(x, 0).acos(); - } - }, - - 'Complex': function (x) { - return x.acos(); - }, - - 'BigNumber': function (x) { - return x.acos(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, acos); - } - }); - - acos.toTex = {1: '\\cos^{-1}\\left(${args[0]}\\right)'}; - - return acos; - } - - var name$236 = 'acos'; - var factory_1$248 = factory$249; - - var acos$1 = { - name: name$236, - factory: factory_1$248 - }; - - function factory$250 (type, config, load, typed) { - - /** - * Calculate the hyperbolic arccos of a value, - * defined as `acosh(x) = ln(sqrt(x^2 - 1) + x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acosh(x) - * - * Examples: - * - * math.acosh(1.5); // returns 0.9624236501192069 - * - * See also: - * - * cosh, asinh, atanh - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arccosine of x - */ - var acosh = typed('acosh', { - 'number': function (x) { - if (x >= 1 || config.predictable) { - return _acosh(x); - } - if (x <= -1) { - return new type.Complex(Math.log(Math.sqrt(x*x - 1) - x), Math.PI); - } - return new type.Complex(x, 0).acosh(); - }, - - 'Complex': function (x) { - return x.acosh(); - }, - - 'BigNumber': function (x) { - return x.acosh(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, acosh); - } - }); - - acosh.toTex = {1: '\\cosh^{-1}\\left(${args[0]}\\right)'}; - - return acosh; - } - - /** - * Calculate the hyperbolic arccos of a number - * @param {number} x - * @return {number} - * @private - */ - var _acosh = Math.acosh || function (x) { - return Math.log(Math.sqrt(x*x - 1) + x) - }; - - var name$237 = 'acosh'; - var factory_1$249 = factory$250; - - var acosh$1 = { - name: name$237, - factory: factory_1$249 - }; - - function factory$251 (type, config, load, typed) { - - /** - * Calculate the inverse cotangent of a value, defined as `acot(x) = atan(1/x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acot(x) - * - * Examples: - * - * math.acot(0.5); // returns number 0.4636476090008061 - * math.acot(math.cot(1.5)); // returns number 1.5 - * - * math.acot(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * cot, atan - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} The arc cotangent of x - */ - var acot = typed('acot', { - 'number': function (x) { - return Math.atan(1 / x); - }, - - 'Complex': function (x) { - return x.acot(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).atan(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, acot); - } - }); - - acot.toTex = {1: '\\cot^{-1}\\left(${args[0]}\\right)'}; - - return acot; - } - - var name$238 = 'acot'; - var factory_1$250 = factory$251; - - var acot$1 = { - name: name$238, - factory: factory_1$250 - }; - - function factory$252 (type, config, load, typed) { - - /** - * Calculate the hyperbolic arccotangent of a value, - * defined as `acoth(x) = atanh(1/x) = (ln((x+1)/x) + ln(x/(x-1))) / 2`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acoth(x) - * - * Examples: - * - * math.acoth(0.5); // returns 0.8047189562170503 - * - * See also: - * - * acsch, asech - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arccotangent of x - */ - var acoth = typed('acoth', { - 'number': function (x) { - if (x >= 1 || x <= -1 || config.predictable) { - return isFinite(x) ? (Math.log((x+1)/x) + Math.log(x/(x-1))) / 2 : 0; - } - return new type.Complex(x, 0).acoth(); - }, - - 'Complex': function (x) { - return x.acoth(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).atanh(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, acoth); - } - }); - - acoth.toTex = {1: '\\coth^{-1}\\left(${args[0]}\\right)'}; - - return acoth; - } - - var name$239 = 'acoth'; - var factory_1$251 = factory$252; - - var acoth$1 = { - name: name$239, - factory: factory_1$251 - }; - - function factory$253 (type, config, load, typed) { - - /** - * Calculate the inverse cosecant of a value, defined as `acsc(x) = asin(1/x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acsc(x) - * - * Examples: - * - * math.acsc(0.5); // returns number 0.5235987755982989 - * math.acsc(math.csc(1.5)); // returns number ~1.5 - * - * math.acsc(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * csc, asin, asec - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} The arc cosecant of x - */ - var acsc = typed('acsc', { - 'number': function (x) { - if (x <= -1 || x >= 1 || config.predictable) { - return Math.asin(1 / x); - } - return new type.Complex(x, 0).acsc(); - }, - - 'Complex': function (x) { - return x.acsc(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).asin(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, acsc); - } - }); - - acsc.toTex = {1: '\\csc^{-1}\\left(${args[0]}\\right)'}; - - return acsc; - } - - var name$240 = 'acsc'; - var factory_1$252 = factory$253; - - var acsc$1 = { - name: name$240, - factory: factory_1$252 - }; - - function factory$254 (type, config, load, typed) { - - /** - * Calculate the hyperbolic arccosecant of a value, - * defined as `acsch(x) = asinh(1/x) = ln(1/x + sqrt(1/x^2 + 1))`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.acsch(x) - * - * Examples: - * - * math.acsch(0.5); // returns 1.4436354751788103 - * - * See also: - * - * asech, acoth - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arccosecant of x - */ - var acsch = typed('acsch', { - 'number': function (x) { - x = 1 / x; - return Math.log(x + Math.sqrt(x*x + 1)); - }, - - 'Complex': function (x) { - return x.acsch(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).asinh(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, acsch); - } - }); - - acsch.toTex = {1: '\\mathrm{csch}^{-1}\\left(${args[0]}\\right)'}; - - return acsch; - } - - var name$241 = 'acsch'; - var factory_1$253 = factory$254; - - var acsch$1 = { - name: name$241, - factory: factory_1$253 - }; - - function factory$255 (type, config, load, typed) { - - /** - * Calculate the inverse secant of a value. Defined as `asec(x) = acos(1/x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.asec(x) - * - * Examples: - * - * math.asec(0.5); // returns 1.0471975511965979 - * math.asec(math.sec(1.5)); // returns 1.5 - * - * math.asec(2); // returns 0 + 1.3169578969248166 i - * - * See also: - * - * acos, acot, acsc - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} The arc secant of x - */ - var asec = typed('asec', { - 'number': function (x) { - if (x <= -1 || x >= 1 || config.predictable) { - return Math.acos(1 / x); - } - return new type.Complex(x, 0).asec(); - }, - - 'Complex': function (x) { - return x.asec(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).acos(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, asec); - } - }); - - asec.toTex = {1: '\\sec^{-1}\\left(${args[0]}\\right)'}; - - return asec; - } - - var name$242 = 'asec'; - var factory_1$254 = factory$255; - - var asec$1 = { - name: name$242, - factory: factory_1$254 - }; - - function factory$256 (type, config, load, typed) { - var acosh = typed.find(load(acosh$1), ['Complex']); - - /** - * Calculate the hyperbolic arcsecant of a value, - * defined as `asech(x) = acosh(1/x) = ln(sqrt(1/x^2 - 1) + 1/x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.asech(x) - * - * Examples: - * - * math.asech(0.5); // returns 1.3169578969248166 - * - * See also: - * - * acsch, acoth - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arcsecant of x - */ - var asech = typed('asech', { - 'number': function (x) { - if ((x <= 1 && x >= -1) || config.predictable) { - x = 1 / x; - - var ret = Math.sqrt(x*x - 1); - if (x > 0 || config.predictable) { - return Math.log(ret + x); - } - - return new type.Complex(Math.log(ret - x), Math.PI); - } - - return new type.Complex(x, 0).asech(); - }, - - 'Complex': function (x) { - return x.asech() - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x).acosh(); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, asech); - } - }); - - asech.toTex = {1: '\\mathrm{sech}^{-1}\\left(${args[0]}\\right)'}; - - return asech; - } - - var name$243 = 'asech'; - var factory_1$255 = factory$256; - - var asech$1 = { - name: name$243, - factory: factory_1$255 - }; - - function factory$257 (type, config, load, typed) { - - /** - * Calculate the inverse sine of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.asin(x) - * - * Examples: - * - * math.asin(0.5); // returns number 0.5235987755982989 - * math.asin(math.sin(1.5)); // returns number ~1.5 - * - * math.asin(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * sin, atan, acos - * - * @param {number | BigNumber | Complex | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} The arc sine of x - */ - var asin = typed('asin', { - 'number': function (x) { - if ((x >= -1 && x <= 1) || config.predictable) { - return Math.asin(x); - } - else { - return new type.Complex(x, 0).asin(); - } - }, - - 'Complex': function (x) { - return x.asin(); - }, - - 'BigNumber': function (x) { - return x.asin(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since asin(0) = 0 - return deepMap(x, asin, true); - } - }); - - asin.toTex = {1: '\\sin^{-1}\\left(${args[0]}\\right)'}; - - return asin; - } - - var name$244 = 'asin'; - var factory_1$256 = factory$257; - - var asin$1 = { - name: name$244, - factory: factory_1$256 - }; - - function factory$258 (type, config, load, typed) { - - /** - * Calculate the hyperbolic arcsine of a value, - * defined as `asinh(x) = ln(x + sqrt(x^2 + 1))`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.asinh(x) - * - * Examples: - * - * math.asinh(0.5); // returns 0.48121182505960347 - * - * See also: - * - * acosh, atanh - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arcsine of x - */ - var asinh = typed('asinh', { - 'number': Math.asinh || function (x) { - return Math.log(Math.sqrt(x*x + 1) + x); - }, - - 'Complex': function (x) { - return x.asinh(); - }, - - 'BigNumber': function (x) { - return x.asinh(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since asinh(0) = 0 - return deepMap(x, asinh, true); - } - }); - - asinh.toTex = {1: '\\sinh^{-1}\\left(${args[0]}\\right)'}; - - return asinh; - } - - var name$245 = 'asinh'; - var factory_1$257 = factory$258; - - var asinh$1 = { - name: name$245, - factory: factory_1$257 - }; - - function factory$259 (type, config, load, typed) { - - /** - * Calculate the inverse tangent of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.atan(x) - * - * Examples: - * - * math.atan(0.5); // returns number 0.4636476090008061 - * math.atan(math.tan(1.5)); // returns number 1.5 - * - * math.atan(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * tan, asin, acos - * - * @param {number | BigNumber | Complex | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} The arc tangent of x - */ - var atan = typed('atan', { - 'number': function (x) { - return Math.atan(x); - }, - - 'Complex': function (x) { - return x.atan(); - }, - - 'BigNumber': function (x) { - return x.atan(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since atan(0) = 0 - return deepMap(x, atan, true); - } - }); - - atan.toTex = {1: '\\tan^{-1}\\left(${args[0]}\\right)'}; - - return atan; - } - - var name$246 = 'atan'; - var factory_1$258 = factory$259; - - var atan$1 = { - name: name$246, - factory: factory_1$258 - }; - - function factory$260 (type, config, load, typed) { - - var matrix$$1 = load(matrix); - - var algorithm02$$1 = load(algorithm02); - var algorithm03$$1 = load(algorithm03); - var algorithm09$$1 = load(algorithm09); - var algorithm11$$1 = load(algorithm11); - var algorithm12$$1 = load(algorithm12); - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Calculate the inverse tangent function with two arguments, y/x. - * By providing two arguments, the right quadrant of the computed angle can be - * determined. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.atan2(y, x) - * - * Examples: - * - * math.atan2(2, 2) / math.pi; // returns number 0.25 - * - * var angle = math.unit(60, 'deg'); // returns Unit 60 deg - * var x = math.cos(angle); - * var y = math.sin(angle); - * - * math.atan(2); // returns Complex 1.5707963267948966 -1.3169578969248166 i - * - * See also: - * - * tan, atan, sin, cos - * - * @param {number | Array | Matrix} y Second dimension - * @param {number | Array | Matrix} x First dimension - * @return {number | Array | Matrix} Four-quadrant inverse tangent - */ - var atan2 = typed('atan2', { - - 'number, number': Math.atan2, - - // Complex numbers doesn't seem to have a reasonable implementation of - // atan2(). Even Matlab removed the support, after they only calculated - // the atan only on base of the real part of the numbers and ignored the imaginary. - - 'BigNumber, BigNumber': function (y, x) { - return type.BigNumber.atan2(y, x); - }, - - 'SparseMatrix, SparseMatrix': function (x, y) { - return algorithm09$$1(x, y, atan2, false); - }, - - 'SparseMatrix, DenseMatrix': function (x, y) { - // mind the order of y and x! - return algorithm02$$1(y, x, atan2, true); - }, - - 'DenseMatrix, SparseMatrix': function (x, y) { - return algorithm03$$1(x, y, atan2, false); - }, - - 'DenseMatrix, DenseMatrix': function (x, y) { - return algorithm13$$1(x, y, atan2); - }, - - 'Array, Array': function (x, y) { - return atan2(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - return atan2(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - return atan2(x, matrix$$1(y)); - }, - - 'SparseMatrix, number | BigNumber': function (x, y) { - return algorithm11$$1(x, y, atan2, false); - }, - - 'DenseMatrix, number | BigNumber': function (x, y) { - return algorithm14$$1(x, y, atan2, false); - }, - - 'number | BigNumber, SparseMatrix': function (x, y) { - // mind the order of y and x - return algorithm12$$1(y, x, atan2, true); - }, - - 'number | BigNumber, DenseMatrix': function (x, y) { - // mind the order of y and x - return algorithm14$$1(y, x, atan2, true); - }, - - 'Array, number | BigNumber': function (x, y) { - return algorithm14$$1(matrix$$1(x), y, atan2, false).valueOf(); - }, - - 'number | BigNumber, Array': function (x, y) { - return algorithm14$$1(matrix$$1(y), x, atan2, true).valueOf(); - } - }); - - atan2.toTex = {2: '\\mathrm{atan2}\\left(${args}\\right)'}; - - return atan2; - } - - var name$247 = 'atan2'; - var factory_1$259 = factory$260; - - var atan2$1 = { - name: name$247, - factory: factory_1$259 - }; - - function factory$261 (type, config, load, typed) { - /** - * Calculate the hyperbolic arctangent of a value, - * defined as `atanh(x) = ln((1 + x)/(1 - x)) / 2`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.atanh(x) - * - * Examples: - * - * math.atanh(0.5); // returns 0.5493061443340549 - * - * See also: - * - * acosh, asinh - * - * @param {number | Complex | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic arctangent of x - */ - var atanh = typed('atanh', { - 'number': function (x) { - if ((x <= 1 && x >= -1) || config.predictable) { - return _atanh(x); - } - return new type.Complex(x, 0).atanh(); - }, - - 'Complex': function (x) { - return x.atanh(); - }, - - 'BigNumber': function (x) { - return x.atanh(); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since atanh(0) = 0 - return deepMap(x, atanh, true); - } - }); - - atanh.toTex = {1: '\\tanh^{-1}\\left(${args[0]}\\right)'}; - - return atanh; - } - - /** - * Calculate the hyperbolic arctangent of a number - * @param {number} x - * @return {number} - * @private - */ - var _atanh = Math.atanh || function (x) { - return Math.log((1 + x)/(1 - x)) / 2 - }; - - var name$248 = 'atanh'; - var factory_1$260 = factory$261; - - var atanh$1 = { - name: name$248, - factory: factory_1$260 - }; - - function factory$262 (type, config, load, typed) { - - /** - * Calculate the cosine of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cos(x) - * - * Examples: - * - * math.cos(2); // returns number -0.4161468365471422 - * math.cos(math.pi / 4); // returns number 0.7071067811865475 - * math.cos(math.unit(180, 'deg')); // returns number -1 - * math.cos(math.unit(60, 'deg')); // returns number 0.5 - * - * var angle = 0.2; - * math.pow(math.sin(angle), 2) + math.pow(math.cos(angle), 2); // returns number ~1 - * - * See also: - * - * cos, tan - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Cosine of x - */ - var cos = typed('cos', { - 'number': Math.cos, - - 'Complex': function (x) { - return x.cos(); - }, - - 'BigNumber': function (x) { - return x.cos(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cos is no angle'); - } - return cos(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, cos); - } - }); - - cos.toTex = {1: '\\cos\\left(${args[0]}\\right)'}; - - return cos; - } - - var name$249 = 'cos'; - var factory_1$261 = factory$262; - - var cos$1 = { - name: name$249, - factory: factory_1$261 - }; - - function factory$263 (type, config, load, typed) { - /** - * Calculate the hyperbolic cosine of a value, - * defined as `cosh(x) = 1/2 * (exp(x) + exp(-x))`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cosh(x) - * - * Examples: - * - * math.cosh(0.5); // returns number 1.1276259652063807 - * - * See also: - * - * sinh, tanh - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic cosine of x - */ - var cosh = typed('cosh', { - 'number': _cosh, - - 'Complex': function (x) { - return x.cosh(); - }, - - 'BigNumber': function (x) { - return x.cosh(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cosh is no angle'); - } - return cosh(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, cosh); - } - }); - - cosh.toTex = {1: '\\cosh\\left(${args[0]}\\right)'}; - - return cosh; - } - - /** - * Calculate the hyperbolic cosine of a number - * @param {number} x - * @returns {number} - * @private - */ - var _cosh = Math.cosh || function (x) { - return (Math.exp(x) + Math.exp(-x)) / 2; - }; - - var name$250 = 'cosh'; - var factory_1$262 = factory$263; - - var cosh$1 = { - name: name$250, - factory: factory_1$262 - }; - - function factory$264 (type, config, load, typed) { - /** - * Calculate the cotangent of a value. Defined as `cot(x) = 1 / tan(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.cot(x) - * - * Examples: - * - * math.cot(2); // returns number -0.45765755436028577 - * 1 / math.tan(2); // returns number -0.45765755436028577 - * - * See also: - * - * tan, sec, csc - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Cotangent of x - */ - var cot = typed('cot', { - 'number': function (x) { - return 1 / Math.tan(x); - }, - - 'Complex': function (x) { - return x.cot(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.tan()); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function cot is no angle'); - } - return cot(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, cot); - } - }); - - cot.toTex = {1: '\\cot\\left(${args[0]}\\right)'}; - - return cot; - } - - var name$251 = 'cot'; - var factory_1$263 = factory$264; - - var cot$1 = { - name: name$251, - factory: factory_1$263 - }; - - function factory$265 (type, config, load, typed) { - /** - * Calculate the hyperbolic cotangent of a value, - * defined as `coth(x) = 1 / tanh(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.coth(x) - * - * Examples: - * - * // coth(x) = 1 / tanh(x) - * math.coth(2); // returns 1.0373147207275482 - * 1 / math.tanh(2); // returns 1.0373147207275482 - * - * See also: - * - * sinh, tanh, cosh - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic cotangent of x - */ - var coth = typed('coth', { - 'number': _coth, - - 'Complex': function (x) { - return x.coth(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.tanh()); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function coth is no angle'); - } - return coth(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, coth); - } - }); - - coth.toTex = {1: '\\coth\\left(${args[0]}\\right)'}; - - return coth; - } - - /** - * Calculate the hyperbolic cosine of a number - * @param {number} x - * @returns {number} - * @private - */ - function _coth(x) { - var e = Math.exp(2 * x); - return (e + 1) / (e - 1); - } - - var name$252 = 'coth'; - var factory_1$264 = factory$265; - - var coth$1 = { - name: name$252, - factory: factory_1$264 - }; - - function factory$266 (type, config, load, typed) { - /** - * Calculate the cosecant of a value, defined as `csc(x) = 1/sin(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.csc(x) - * - * Examples: - * - * math.csc(2); // returns number 1.099750170294617 - * 1 / math.sin(2); // returns number 1.099750170294617 - * - * See also: - * - * sin, sec, cot - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Cosecant of x - */ - var csc = typed('csc', { - 'number': function (x) { - return 1 / Math.sin(x); - }, - - 'Complex': function (x) { - return x.csc(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.sin()); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function csc is no angle'); - } - return csc(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, csc); - } - }); - - csc.toTex = {1: '\\csc\\left(${args[0]}\\right)'}; - - return csc; - } - - var name$253 = 'csc'; - var factory_1$265 = factory$266; - - var csc$1 = { - name: name$253, - factory: factory_1$265 - }; - - var sign$3 = number.sign; - - function factory$267 (type, config, load, typed) { - /** - * Calculate the hyperbolic cosecant of a value, - * defined as `csch(x) = 1 / sinh(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.csch(x) - * - * Examples: - * - * // csch(x) = 1/ sinh(x) - * math.csch(0.5); // returns 1.9190347513349437 - * 1 / math.sinh(0.5); // returns 1.9190347513349437 - * - * See also: - * - * sinh, sech, coth - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic cosecant of x - */ - var csch = typed('csch', { - 'number': _csch, - - 'Complex': function (x) { - return x.csch(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.sinh()); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function csch is no angle'); - } - return csch(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, csch); - } - }); - - csch.toTex = {1: '\\mathrm{csch}\\left(${args[0]}\\right)'}; - - return csch; - } - - /** - * Calculate the hyperbolic cosecant of a number - * @param {number} x - * @returns {number} - * @private - */ - function _csch(x) { - // consider values close to zero (+/-) - if (x == 0) { - return Number.POSITIVE_INFINITY; - } - else { - return Math.abs(2 / (Math.exp(x) - Math.exp(-x))) * sign$3(x); - } - } - - var name$254 = 'csch'; - var factory_1$266 = factory$267; - - var csch$1 = { - name: name$254, - factory: factory_1$266 - }; - - function factory$268 (type, config, load, typed) { - /** - * Calculate the secant of a value, defined as `sec(x) = 1/cos(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sec(x) - * - * Examples: - * - * math.sec(2); // returns number -2.4029979617223822 - * 1 / math.cos(2); // returns number -2.4029979617223822 - * - * See also: - * - * cos, csc, cot - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Secant of x - */ - var sec = typed('sec', { - 'number': function (x) { - return 1 / Math.cos(x); - }, - - 'Complex': function (x) { - return x.sec(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.cos()); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sec is no angle'); - } - return sec(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, sec); - } - }); - - sec.toTex = {1: '\\sec\\left(${args[0]}\\right)'}; - - return sec; - } - - var name$255 = 'sec'; - var factory_1$267 = factory$268; - - var sec$1 = { - name: name$255, - factory: factory_1$267 - }; - - function factory$269 (type, config, load, typed) { - /** - * Calculate the hyperbolic secant of a value, - * defined as `sech(x) = 1 / cosh(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sech(x) - * - * Examples: - * - * // sech(x) = 1/ cosh(x) - * math.sech(0.5); // returns 0.886818883970074 - * 1 / math.cosh(0.5); // returns 0.886818883970074 - * - * See also: - * - * cosh, csch, coth - * - * @param {number | Complex | Unit | Array | Matrix} x Function input - * @return {number | Complex | Array | Matrix} Hyperbolic secant of x - */ - var sech = typed('sech', { - 'number': _sech, - - 'Complex': function (x) { - return x.sech(); - }, - - 'BigNumber': function (x) { - return new type.BigNumber(1).div(x.cosh()); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sech is no angle'); - } - return sech(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, sech); - } - }); - - sech.toTex = {1: '\\mathrm{sech}\\left(${args[0]}\\right)'}; - - return sech; - } - - /** - * Calculate the hyperbolic secant of a number - * @param {number} x - * @returns {number} - * @private - */ - function _sech(x) { - return 2 / (Math.exp(x) + Math.exp(-x)); - } - - var name$256 = 'sech'; - var factory_1$268 = factory$269; - - var sech$1 = { - name: name$256, - factory: factory_1$268 - }; - - function factory$270 (type, config, load, typed) { - - /** - * Calculate the sine of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sin(x) - * - * Examples: - * - * math.sin(2); // returns number 0.9092974268256813 - * math.sin(math.pi / 4); // returns number 0.7071067811865475 - * math.sin(math.unit(90, 'deg')); // returns number 1 - * math.sin(math.unit(30, 'deg')); // returns number 0.5 - * - * var angle = 0.2; - * math.pow(math.sin(angle), 2) + math.pow(math.cos(angle), 2); // returns number ~1 - * - * See also: - * - * cos, tan - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Sine of x - */ - var sin = typed('sin', { - 'number': Math.sin, - - 'Complex': function (x) { - return x.sin(); - }, - - 'BigNumber': function (x) { - return x.sin(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sin is no angle'); - } - return sin(x.value); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since sin(0) = 0 - return deepMap(x, sin, true); - } - }); - - sin.toTex = {1: '\\sin\\left(${args[0]}\\right)'}; - - return sin; - } - - var name$257 = 'sin'; - var factory_1$269 = factory$270; - - var sin$1 = { - name: name$257, - factory: factory_1$269 - }; - - function factory$271 (type, config, load, typed) { - /** - * Calculate the hyperbolic sine of a value, - * defined as `sinh(x) = 1/2 * (exp(x) - exp(-x))`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.sinh(x) - * - * Examples: - * - * math.sinh(0.5); // returns number 0.5210953054937474 - * - * See also: - * - * cosh, tanh - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic sine of x - */ - var sinh = typed('sinh', { - 'number': _sinh, - - 'Complex': function (x) { - return x.sinh(); - }, - - 'BigNumber': function (x) { - return x.sinh(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function sinh is no angle'); - } - return sinh(x.value); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since sinh(0) = 0 - return deepMap(x, sinh, true); - } - }); - - sinh.toTex = {1: '\\sinh\\left(${args[0]}\\right)'}; - - return sinh; - } - - /** - * Calculate the hyperbolic sine of a number - * @param {number} x - * @returns {number} - * @private - */ - var _sinh = Math.sinh || function (x) { - return (Math.exp(x) - Math.exp(-x)) / 2; - }; - - var name$258 = 'sinh'; - var factory_1$270 = factory$271; - - var sinh$1 = { - name: name$258, - factory: factory_1$270 - }; - - function factory$272 (type, config, load, typed) { - /** - * Calculate the tangent of a value. `tan(x)` is equal to `sin(x) / cos(x)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.tan(x) - * - * Examples: - * - * math.tan(0.5); // returns number 0.5463024898437905 - * math.sin(0.5) / math.cos(0.5); // returns number 0.5463024898437905 - * math.tan(math.pi / 4); // returns number 1 - * math.tan(math.unit(45, 'deg')); // returns number 1 - * - * See also: - * - * atan, sin, cos - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Tangent of x - */ - var tan = typed('tan', { - 'number': Math.tan, - - 'Complex': function (x) { - return x.tan(); - }, - - 'BigNumber': function (x) { - return x.tan(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function tan is no angle'); - } - return tan(x.value); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since tan(0) = 0 - return deepMap(x, tan, true); - } - }); - - tan.toTex = {1: '\\tan\\left(${args[0]}\\right)'}; - - return tan; - } - - var name$259 = 'tan'; - var factory_1$271 = factory$272; - - var tan$1 = { - name: name$259, - factory: factory_1$271 - }; - - function factory$273 (type, config, load, typed) { - /** - * Calculate the hyperbolic tangent of a value, - * defined as `tanh(x) = (exp(2 * x) - 1) / (exp(2 * x) + 1)`. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.tanh(x) - * - * Examples: - * - * // tanh(x) = sinh(x) / cosh(x) = 1 / coth(x) - * math.tanh(0.5); // returns 0.46211715726000974 - * math.sinh(0.5) / math.cosh(0.5); // returns 0.46211715726000974 - * 1 / math.coth(0.5); // returns 0.46211715726000974 - * - * See also: - * - * sinh, cosh, coth - * - * @param {number | BigNumber | Complex | Unit | Array | Matrix} x Function input - * @return {number | BigNumber | Complex | Array | Matrix} Hyperbolic tangent of x - */ - var tanh = typed('tanh', { - 'number': _tanh, - - 'Complex': function (x) { - return x.tanh(); - }, - - 'BigNumber': function (x) { - return x.tanh(); - }, - - 'Unit': function (x) { - if (!x.hasBase(type.Unit.BASE_UNITS.ANGLE)) { - throw new TypeError ('Unit in function tanh is no angle'); - } - return tanh(x.value); - }, - - 'Array | Matrix': function (x) { - // deep map collection, skip zeros since tanh(0) = 0 - return deepMap(x, tanh, true); - } - }); - - tanh.toTex = {1: '\\tanh\\left(${args[0]}\\right)'}; - - return tanh; - } - - /** - * Calculate the hyperbolic tangent of a number - * @param {number} x - * @returns {number} - * @private - */ - var _tanh = Math.tanh || function (x) { - var e = Math.exp(2 * x); - return (e - 1) / (e + 1); - }; - - var name$260 = 'tanh'; - var factory_1$272 = factory$273; - - var tanh$1 = { - name: name$260, - factory: factory_1$272 - }; - - var trigonometry = [ - acos$1, - acosh$1, - acot$1, - acoth$1, - acsc$1, - acsch$1, - asec$1, - asech$1, - asin$1, - asinh$1, - atan$1, - atan2$1, - atanh$1, - cos$1, - cosh$1, - cot$1, - coth$1, - csc$1, - csch$1, - sec$1, - sech$1, - sin$1, - sinh$1, - tan$1, - tanh$1 - ]; - - function factory$274 (type, config, load, typed) { - var latex$$1 = latex; - - var matrix$$1 = load(matrix); - - var algorithm13$$1 = load(algorithm13); - var algorithm14$$1 = load(algorithm14); - - /** - * Change the unit of a value. - * - * For matrices, the function is evaluated element wise. - * - * Syntax: - * - * math.to(x, unit) - * - * Examples: - * - * math.to(math.unit('2 inch'), 'cm'); // returns Unit 5.08 cm - * math.to(math.unit('2 inch'), math.unit(null, 'cm')); // returns Unit 5.08 cm - * math.to(math.unit(16, 'bytes'), 'bits'); // returns Unit 128 bits - * - * See also: - * - * unit - * - * @param {Unit | Array | Matrix} x The unit to be converted. - * @param {Unit | Array | Matrix} unit New unit. Can be a string like "cm" - * or a unit without value. - * @return {Unit | Array | Matrix} value with changed, fixed unit. - */ - var to = typed('to', { - - 'Unit, Unit | string': function (x, unit) { - return x.to(unit); - }, - - 'Matrix, Matrix': function (x, y) { - // SparseMatrix does not support Units - return algorithm13$$1(x, y, to); - }, - - 'Array, Array': function (x, y) { - // use matrix implementation - return to(matrix$$1(x), matrix$$1(y)).valueOf(); - }, - - 'Array, Matrix': function (x, y) { - // use matrix implementation - return to(matrix$$1(x), y); - }, - - 'Matrix, Array': function (x, y) { - // use matrix implementation - return to(x, matrix$$1(y)); - }, - - 'Matrix, any': function (x, y) { - // SparseMatrix does not support Units - return algorithm14$$1(x, y, to, false); - }, - - 'any, Matrix': function (x, y) { - // SparseMatrix does not support Units - return algorithm14$$1(y, x, to, true); - }, - - 'Array, any': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(x), y, to, false).valueOf(); - }, - - 'any, Array': function (x, y) { - // use matrix implementation - return algorithm14$$1(matrix$$1(y), x, to, true).valueOf(); - } - }); - - to.toTex = { - 2: '\\left(${args[0]}' + latex$$1.operators['to'] + '${args[1]}\\right)' - }; - - return to; - } - - var name$261 = 'to'; - var factory_1$273 = factory$274; - - var to$1 = { - name: name$261, - factory: factory_1$273 - }; - - var unit$1 = [ - to$1 - ]; - - function factory$275 (type, config, load, typed) { - /** - * Test whether a value is prime: has no divisors other than itself and one. - * The function supports type `number`, `bignumber`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isPrime(x) - * - * Examples: - * - * math.isPrime(3); // returns true - * math.isPrime(-2); // returns false - * math.isPrime(0); // returns false - * math.isPrime(-0); // returns false - * math.isPrime(0.5); // returns false - * math.isPrime('2'); // returns true - * math.isPrime([2, 17, 100]); // returns [true, true, false] - * - * See also: - * - * isNumeric, isZero, isNegative, isInteger - * - * @param {number | BigNumber | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is larger than zero. - * Throws an error in case of an unknown data type. - */ - var isPrime = typed('isPrime', { - 'number': function (x) { - if (x < 2){ - return false; - } - if (x == 2){ - return true; - } - if (x % 2 == 0){ - return false; - } - for (var i = 3; i * i <= x; i += 2){ - if (x % i == 0){ - return false; - } - } - return true; - }, - - 'BigNumber': function (x) { - if (x.lt(2)){ - return false; - } - if (x.equals(2)){ - return true; - } - if (x.mod(2).isZero()){ - return false; - } - for(var i = type.BigNumber(3); i.times(i).lte(x); i = i.plus(1)){ - if (x.mod(i).isZero()){ - return false; - } - } - return true; - }, - - 'Array | Matrix': function (x) { - return deepMap(x, isPrime); - } - }); - - return isPrime; - } - - var name$262 = 'isPrime'; - var factory_1$274 = factory$275; - - var isPrime$1 = { - name: name$262, - factory: factory_1$274 - }; - - function factory$276 (type, config, load, typed) { - /** - * Test whether a value is NaN (not a number). - * The function supports types `number`, `BigNumber`, `Fraction`, `Unit` and `Complex`. - * - * The function is evaluated element-wise in case of Array or Matrix input. - * - * Syntax: - * - * math.isNaN(x) - * - * Examples: - * - * math.isNaN(3); // returns false - * math.isNaN(NaN); // returns true - * math.isNaN(0); // returns false - * math.isNaN(math.bignumber(NaN)); // returns true - * math.isNaN(math.bignumber(0)); // returns false - * math.isNaN(math.fraction(-2, 5)); // returns false - * math.isNaN('-2'); // returns false - * math.isNaN([2, 0, -3, NaN]'); // returns [false, false, false, true] - * - * See also: - * - * isNumeric, isNegative, isPositive, isZero, isInteger - * - * @param {number | BigNumber | Fraction | Unit | Array | Matrix} x Value to be tested - * @return {boolean} Returns true when `x` is NaN. - * Throws an error in case of an unknown data type. - */ - var isNaN = typed('isNaN', { - 'number': function (x) { - return Number.isNaN(x); - }, - - 'BigNumber': function (x) { - return x.isNaN(); - }, - - 'Fraction': function (x) { - return false; - }, - - 'Complex': function (x) { - return x.isNaN(); - }, - - 'Unit': function (x) { - return Number.isNaN(x.value); - }, - - 'Array | Matrix': function (x) { - return deepMap(x, Number.isNaN); - } - }); - - return isNaN; - } - - var name$263 = 'isNaN'; - var factory_1$275 = factory$276; - - var _isNaN$1 = { - name: name$263, - factory: factory_1$275 - }; - - var utils$1 = [ - clone$5, - isInteger$22, - isNegative$1, - isNumeric$1, - isPositive$1, - isPrime$1, - isZero$1, - _isNaN$1, - _typeof$1 - ]; - - var _function$3 = [ - algebra, - arithmetic, - bitwise$1, - combinatorics, - complex$5, - geometry, - logical, - matrix$3, - probability, - relational, - set, - special, - statistics, - string$10, - trigonometry, - unit$1, - utils$1 - ]; - - function factory$277 (type, config, load, typed, math) { - /** - * Instantiate mathjs data types from their JSON representation - * @param {string} key - * @param {*} value - * @returns {*} Returns the revived object - */ - return function reviver(key, value) { - var constructor = type[value && value.mathjs] || - (math.expression && math.expression.node[value && value.mathjs]); - // TODO: instead of checking math.expression.node, expose all Node classes on math.type too - - if (constructor && typeof constructor.fromJSON === 'function') { - return constructor.fromJSON(value); - } - - return value; - } - } - - var name$264 = 'reviver'; - var path$64 = 'json'; - var factory_1$276 = factory$277; - var math$18 = true; // request the math namespace as fifth argument - - var reviver = { - name: name$264, - path: path$64, - factory: factory_1$276, - math: math$18 - }; - - var json = [ - reviver - ]; - - var error = [ - { - name: 'ArgumentsError', path: 'error', - factory: function () { - return ArgumentsError_1; - } - }, - { - name: 'DimensionError', - path: 'error', - factory: function () { - return DimensionError_1; - } - }, - { - name: 'IndexError', - path: 'error', - factory: function () { - return IndexError_1; - } - } - ]; - - // import customized constants file - - var lib = [ - type, // data types (Matrix, Complex, Unit, ...) - constants$1, // constants - expression, // expression parsing - _function$3, // functions - json, // serialization utility (math.json.reviver) - error // errors - ]; - - var numeric1_2_6 = createCommonjsModule(function (module, exports) { - - var numeric = exports; - if(typeof commonjsGlobal !== "undefined") { commonjsGlobal.numeric = numeric; } - - numeric.version = "1.2.6"; - - // 1. Utility functions - numeric.bench = function bench (f,interval) { - var t1,t2,n,i; - if(typeof interval === "undefined") { interval = 15; } - n = 0.5; - t1 = new Date(); - while(1) { - n*=2; - for(i=n;i>3;i-=4) { f(); f(); f(); f(); } - while(i>0) { f(); i--; } - t2 = new Date(); - if(t2-t1 > interval) break; - } - for(i=n;i>3;i-=4) { f(); f(); f(); f(); } - while(i>0) { f(); i--; } - t2 = new Date(); - return 1000*(3*n-1)/(t2-t1); - }; - - numeric._myIndexOf = (function _myIndexOf(w) { - var n = this.length,k; - for(k=0;k numeric.largeArray) { ret.push('...Large Array...'); return true; } - var flag = false; - ret.push('['); - for(k=0;k0) { ret.push(','); if(flag) ret.push('\n '); } flag = foo(x[k]); } - ret.push(']'); - return true; - } - ret.push('{'); - var flag = false; - for(k in x) { if(x.hasOwnProperty(k)) { if(flag) ret.push(',\n'); flag = true; ret.push(k); ret.push(': \n'); foo(x[k]); } } - ret.push('}'); - return true; - } - foo(x); - return ret.join(''); - }; - - numeric.parseDate = function parseDate(d) { - function foo(d) { - if(typeof d === 'string') { return Date.parse(d.replace(/-/g,'/')); } - if(!(d instanceof Array)) { throw new Error("parseDate: parameter must be arrays of strings"); } - var ret = [],k; - for(k=0;k0) { - ret[count] = []; - for(j=0;j> 2; - q = ((x & 3) << 4) + (y >> 4); - r = ((y & 15) << 2) + (z >> 6); - s = z & 63; - if(i+1>=n) { r = s = 64; } - else if(i+2>=n) { s = 64; } - ret += key.charAt(p) + key.charAt(q) + key.charAt(r) + key.charAt(s); - } - return ret; - } - function crc32Array (a,from,to) { - if(typeof from === "undefined") { from = 0; } - if(typeof to === "undefined") { to = a.length; } - var table = [0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, - 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, - 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, - 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, - 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, - 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, - 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, - 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, - 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, - 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, - 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, - 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, - 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, - 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, - 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, - 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, - 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, - 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, - 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, - 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, - 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, - 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, - 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, - 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, - 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, - 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D]; - - var crc = -1, y = 0, n = a.length,i; - - for (i = from; i < to; i++) { - y = (crc ^ a[i]) & 0xFF; - crc = (crc >>> 8) ^ table[y]; - } - - return crc ^ (-1); - } - - var h = img[0].length, w = img[0][0].length, s1, s2, k,length,a,b,i,j,adler32,crc32; - var stream = [ - 137, 80, 78, 71, 13, 10, 26, 10, // 0: PNG signature - 0,0,0,13, // 8: IHDR Chunk length - 73, 72, 68, 82, // 12: "IHDR" - (w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w&255, // 16: Width - (h >> 24) & 255, (h >> 16) & 255, (h >> 8) & 255, h&255, // 20: Height - 8, // 24: bit depth - 2, // 25: RGB - 0, // 26: deflate - 0, // 27: no filter - 0, // 28: no interlace - -1,-2,-3,-4, // 29: CRC - -5,-6,-7,-8, // 33: IDAT Chunk length - 73, 68, 65, 84, // 37: "IDAT" - // RFC 1950 header starts here - 8, // 41: RFC1950 CMF - 29 // 42: RFC1950 FLG - ]; - crc32 = crc32Array(stream,12,29); - stream[29] = (crc32>>24)&255; - stream[30] = (crc32>>16)&255; - stream[31] = (crc32>>8)&255; - stream[32] = (crc32)&255; - s1 = 1; - s2 = 0; - for(i=0;i>8)&255; - stream.push(a); stream.push(b); - stream.push((~a)&255); stream.push((~b)&255); - if(i===0) stream.push(0); - for(j=0;j255) a = 255; - else if(a<0) a=0; - else a = Math.round(a); - s1 = (s1 + a )%65521; - s2 = (s2 + s1)%65521; - stream.push(a); - } - } - stream.push(0); - } - adler32 = (s2<<16)+s1; - stream.push((adler32>>24)&255); - stream.push((adler32>>16)&255); - stream.push((adler32>>8)&255); - stream.push((adler32)&255); - length = stream.length - 41; - stream[33] = (length>>24)&255; - stream[34] = (length>>16)&255; - stream[35] = (length>>8)&255; - stream[36] = (length)&255; - crc32 = crc32Array(stream,37); - stream.push((crc32>>24)&255); - stream.push((crc32>>16)&255); - stream.push((crc32>>8)&255); - stream.push((crc32)&255); - stream.push(0); - stream.push(0); - stream.push(0); - stream.push(0); - // a = stream.length; - stream.push(73); // I - stream.push(69); // E - stream.push(78); // N - stream.push(68); // D - stream.push(174); // CRC1 - stream.push(66); // CRC2 - stream.push(96); // CRC3 - stream.push(130); // CRC4 - return 'data:image/png;base64,'+base64(stream); - }; - - // 2. Linear algebra with Arrays. - numeric._dim = function _dim(x) { - var ret = []; - while(typeof x === "object") { ret.push(x.length); x = x[0]; } - return ret; - }; - - numeric.dim = function dim(x) { - var y,z; - if(typeof x === "object") { - y = x[0]; - if(typeof y === "object") { - z = y[0]; - if(typeof z === "object") { - return numeric._dim(x); - } - return [x.length,y.length]; - } - return [x.length]; - } - return []; - }; - - numeric.mapreduce = function mapreduce(body,init) { - return Function('x','accum','_s','_k', - 'if(typeof accum === "undefined") accum = '+init+';\n'+ - 'if(typeof x === "number") { var xi = x; '+body+'; return accum; }\n'+ - 'if(typeof _s === "undefined") _s = numeric.dim(x);\n'+ - 'if(typeof _k === "undefined") _k = 0;\n'+ - 'var _n = _s[_k];\n'+ - 'var i,xi;\n'+ - 'if(_k < _s.length-1) {\n'+ - ' for(i=_n-1;i>=0;i--) {\n'+ - ' accum = arguments.callee(x[i],accum,_s,_k+1);\n'+ - ' }'+ - ' return accum;\n'+ - '}\n'+ - 'for(i=_n-1;i>=1;i-=2) { \n'+ - ' xi = x[i];\n'+ - ' '+body+';\n'+ - ' xi = x[i-1];\n'+ - ' '+body+';\n'+ - '}\n'+ - 'if(i === 0) {\n'+ - ' xi = x[i];\n'+ - ' '+body+'\n'+ - '}\n'+ - 'return accum;' - ); - }; - numeric.mapreduce2 = function mapreduce2(body,setup) { - return Function('x', - 'var n = x.length;\n'+ - 'var i,xi;\n'+setup+';\n'+ - 'for(i=n-1;i!==-1;--i) { \n'+ - ' xi = x[i];\n'+ - ' '+body+';\n'+ - '}\n'+ - 'return accum;' - ); - }; - - - numeric.same = function same(x,y) { - var i,n; - if(!(x instanceof Array) || !(y instanceof Array)) { return false; } - n = x.length; - if(n !== y.length) { return false; } - for(i=0;i=0;i-=2) { ret[i+1] = v; ret[i] = v; } - if(i===-1) { ret[0] = v; } - return ret; - } - for(i=n-1;i>=0;i--) { ret[i] = numeric.rep(s,v,k+1); } - return ret; - }; - - - numeric.dotMMsmall = function dotMMsmall(x,y) { - var i,j,k,p,q,r,ret,foo,bar,woo,i0; - p = x.length; q = y.length; r = y[0].length; - ret = Array(p); - for(i=p-1;i>=0;i--) { - foo = Array(r); - bar = x[i]; - for(k=r-1;k>=0;k--) { - woo = bar[q-1]*y[q-1][k]; - for(j=q-2;j>=1;j-=2) { - i0 = j-1; - woo += bar[j]*y[j][k] + bar[i0]*y[i0][k]; - } - if(j===0) { woo += bar[0]*y[0][k]; } - foo[k] = woo; - } - ret[i] = foo; - } - return ret; - }; - numeric._getCol = function _getCol(A,j,x) { - var n = A.length, i; - for(i=n-1;i>0;--i) { - x[i] = A[i][j]; - --i; - x[i] = A[i][j]; - } - if(i===0) x[0] = A[0][j]; - }; - numeric.dotMMbig = function dotMMbig(x,y){ - var gc = numeric._getCol, p = y.length, v = Array(p); - var m = x.length, n = y[0].length, A = new Array(m), xj; - var VV = numeric.dotVV; - var i,j; - --p; - --m; - for(i=m;i!==-1;--i) A[i] = Array(n); - --n; - for(i=n;i!==-1;--i) { - gc(y,i,v); - for(j=m;j!==-1;--j) { - xj = x[j]; - A[j][i] = VV(xj,v); - } - } - return A; - }; - - numeric.dotMV = function dotMV(x,y) { - var p = x.length, q = y.length,i; - var ret = Array(p), dotVV = numeric.dotVV; - for(i=p-1;i>=0;i--) { ret[i] = dotVV(x[i],y); } - return ret; - }; - - numeric.dotVM = function dotVM(x,y) { - var j,k,p,q,ret,woo,i0; - p = x.length; q = y[0].length; - ret = Array(q); - for(k=q-1;k>=0;k--) { - woo = x[p-1]*y[p-1][k]; - for(j=p-2;j>=1;j-=2) { - i0 = j-1; - woo += x[j]*y[j][k] + x[i0]*y[i0][k]; - } - if(j===0) { woo += x[0]*y[0][k]; } - ret[k] = woo; - } - return ret; - }; - - numeric.dotVV = function dotVV(x,y) { - var i,n=x.length,i1,ret = x[n-1]*y[n-1]; - for(i=n-2;i>=1;i-=2) { - i1 = i-1; - ret += x[i]*y[i] + x[i1]*y[i1]; - } - if(i===0) { ret += x[0]*y[0]; } - return ret; - }; - - numeric.dot = function dot(x,y) { - var d = numeric.dim; - switch(d(x).length*1000+d(y).length) { - case 2002: - if(y.length < 10) return numeric.dotMMsmall(x,y); - else return numeric.dotMMbig(x,y); - case 2001: return numeric.dotMV(x,y); - case 1002: return numeric.dotVM(x,y); - case 1001: return numeric.dotVV(x,y); - case 1000: return numeric.mulVS(x,y); - case 1: return numeric.mulSV(x,y); - case 0: return x*y; - default: throw new Error('numeric.dot only works on vectors and matrices'); - } - }; - - numeric.diag = function diag(d) { - var i,i1,j,n = d.length, A = Array(n), Ai; - for(i=n-1;i>=0;i--) { - Ai = Array(n); - i1 = i+2; - for(j=n-1;j>=i1;j-=2) { - Ai[j] = 0; - Ai[j-1] = 0; - } - if(j>i) { Ai[j] = 0; } - Ai[i] = d[i]; - for(j=i-1;j>=1;j-=2) { - Ai[j] = 0; - Ai[j-1] = 0; - } - if(j===0) { Ai[0] = 0; } - A[i] = Ai; - } - return A; - }; - numeric.getDiag = function(A) { - var n = Math.min(A.length,A[0].length),i,ret = Array(n); - for(i=n-1;i>=1;--i) { - ret[i] = A[i][i]; - --i; - ret[i] = A[i][i]; - } - if(i===0) { - ret[0] = A[0][0]; - } - return ret; - }; - - numeric.identity = function identity(n) { return numeric.diag(numeric.rep([n],1)); }; - numeric.pointwise = function pointwise(params,body,setup) { - if(typeof setup === "undefined") { setup = ""; } - var fun = []; - var k; - var avec = /\[i\]$/,p,thevec = ''; - var haveret = false; - for(k=0;k=0;i--) ret[i] = arguments.callee('+params.join(',')+',_s,_k+1);\n'+ - ' return ret;\n'+ - '}\n'+ - setup+'\n'+ - 'for(i=_n-1;i!==-1;--i) {\n'+ - ' '+body+'\n'+ - '}\n'+ - 'return ret;' - ); - return Function.apply(null,fun); - }; - numeric.pointwise2 = function pointwise2(params,body,setup) { - if(typeof setup === "undefined") { setup = ""; } - var fun = []; - var k; - var avec = /\[i\]$/,p,thevec = ''; - var haveret = false; - for(k=0;k=0;i--) { _biforeach(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } - }); - numeric._biforeach2 = (function _biforeach2(x,y,s,k,f) { - if(k === s.length-1) { return f(x,y); } - var i,n=s[k],ret = Array(n); - for(i=n-1;i>=0;--i) { ret[i] = _biforeach2(typeof x==="object"?x[i]:x,typeof y==="object"?y[i]:y,s,k+1,f); } - return ret; - }); - numeric._foreach = (function _foreach(x,s,k,f) { - if(k === s.length-1) { f(x); return; } - var i,n=s[k]; - for(i=n-1;i>=0;i--) { _foreach(x[i],s,k+1,f); } - }); - numeric._foreach2 = (function _foreach2(x,s,k,f) { - if(k === s.length-1) { return f(x); } - var i,n=s[k], ret = Array(n); - for(i=n-1;i>=0;i--) { ret[i] = _foreach2(x[i],s,k+1,f); } - return ret; - }); - - /*numeric.anyV = numeric.mapreduce('if(xi) return true;','false'); - numeric.allV = numeric.mapreduce('if(!xi) return false;','true'); - numeric.any = function(x) { if(typeof x.length === "undefined") return x; return numeric.anyV(x); } - numeric.all = function(x) { if(typeof x.length === "undefined") return x; return numeric.allV(x); }*/ - - numeric.ops2 = { - add: '+', - sub: '-', - mul: '*', - div: '/', - mod: '%', - and: '&&', - or: '||', - eq: '===', - neq: '!==', - lt: '<', - gt: '>', - leq: '<=', - geq: '>=', - band: '&', - bor: '|', - bxor: '^', - lshift: '<<', - rshift: '>>', - rrshift: '>>>' - }; - numeric.opseq = { - addeq: '+=', - subeq: '-=', - muleq: '*=', - diveq: '/=', - modeq: '%=', - lshifteq: '<<=', - rshifteq: '>>=', - rrshifteq: '>>>=', - bandeq: '&=', - boreq: '|=', - bxoreq: '^=' - }; - numeric.mathfuns = ['abs','acos','asin','atan','ceil','cos', - 'exp','floor','log','round','sin','sqrt','tan', - 'isNaN','isFinite']; - numeric.mathfuns2 = ['atan2','pow','max','min']; - numeric.ops1 = { - neg: '-', - not: '!', - bnot: '~', - clone: '' - }; - numeric.mapreducers = { - any: ['if(xi) return true;','var accum = false;'], - all: ['if(!xi) return false;','var accum = true;'], - sum: ['accum += xi;','var accum = 0;'], - prod: ['accum *= xi;','var accum = 1;'], - norm2Squared: ['accum += xi*xi;','var accum = 0;'], - norminf: ['accum = max(accum,abs(xi));','var accum = 0, max = Math.max, abs = Math.abs;'], - norm1: ['accum += abs(xi)','var accum = 0, abs = Math.abs;'], - sup: ['accum = max(accum,xi);','var accum = -Infinity, max = Math.max;'], - inf: ['accum = min(accum,xi);','var accum = Infinity, min = Math.min;'] - }; - - (function () { - var i,o; - for(i=0;iv0) { i0 = i; v0 = k; } } - Aj = A[i0]; A[i0] = A[j]; A[j] = Aj; - Ij = I[i0]; I[i0] = I[j]; I[j] = Ij; - x = Aj[j]; - for(k=j;k!==n;++k) Aj[k] /= x; - for(k=n-1;k!==-1;--k) Ij[k] /= x; - for(i=m-1;i!==-1;--i) { - if(i!==j) { - Ai = A[i]; - Ii = I[i]; - x = Ai[j]; - for(k=j+1;k!==n;++k) Ai[k] -= Aj[k]*x; - for(k=n-1;k>0;--k) { Ii[k] -= Ij[k]*x; --k; Ii[k] -= Ij[k]*x; } - if(k===0) Ii[0] -= Ij[0]*x; - } - } - } - return I; - }; - - numeric.det = function det(x) { - var s = numeric.dim(x); - if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: det() only works on square matrices'); } - var n = s[0], ret = 1,i,j,k,A = numeric.clone(x),Aj,Ai,alpha,temp,k1; - for(j=0;j Math.abs(A[k][j])) { k = i; } } - if(k !== j) { - temp = A[k]; A[k] = A[j]; A[j] = temp; - ret *= -1; - } - Aj = A[j]; - for(i=j+1;i=1;i-=2) { - A1 = x[i]; - A0 = x[i-1]; - for(j=n-1;j>=1;--j) { - Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; - --j; - Bj = ret[j]; Bj[i] = A1[j]; Bj[i-1] = A0[j]; - } - if(j===0) { - Bj = ret[0]; Bj[i] = A1[0]; Bj[i-1] = A0[0]; - } - } - if(i===0) { - A0 = x[0]; - for(j=n-1;j>=1;--j) { - ret[j][0] = A0[j]; - --j; - ret[j][0] = A0[j]; - } - if(j===0) { ret[0][0] = A0[0]; } - } - return ret; - }; - numeric.negtranspose = function negtranspose(x) { - var i,j,m = x.length,n = x[0].length, ret=Array(n),A0,A1,Bj; - for(j=0;j=1;i-=2) { - A1 = x[i]; - A0 = x[i-1]; - for(j=n-1;j>=1;--j) { - Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; - --j; - Bj = ret[j]; Bj[i] = -A1[j]; Bj[i-1] = -A0[j]; - } - if(j===0) { - Bj = ret[0]; Bj[i] = -A1[0]; Bj[i-1] = -A0[0]; - } - } - if(i===0) { - A0 = x[0]; - for(j=n-1;j>=1;--j) { - ret[j][0] = -A0[j]; - --j; - ret[j][0] = -A0[j]; - } - if(j===0) { ret[0][0] = -A0[0]; } - } - return ret; - }; - - numeric._random = function _random(s,k) { - var i,n=s[k],ret=Array(n), rnd; - if(k === s.length-1) { - rnd = Math.random; - for(i=n-1;i>=1;i-=2) { - ret[i] = rnd(); - ret[i-1] = rnd(); - } - if(i===0) { ret[0] = rnd(); } - return ret; - } - for(i=n-1;i>=0;i--) ret[i] = _random(s,k+1); - return ret; - }; - numeric.random = function random(s) { return numeric._random(s,0); }; - - numeric.norm2 = function norm2(x) { return Math.sqrt(numeric.norm2Squared(x)); }; - - numeric.linspace = function linspace(a,b,n) { - if(typeof n === "undefined") n = Math.max(Math.round(b-a)+1,1); - if(n<2) { return n===1?[a]:[]; } - var i,ret = Array(n); - n--; - for(i=n;i>=0;i--) { ret[i] = (i*b+(n-i)*a)/n; } - return ret; - }; - - numeric.getBlock = function getBlock(x,from,to) { - var s = numeric.dim(x); - function foo(x,k) { - var i,a = from[k], n = to[k]-a, ret = Array(n); - if(k === s.length-1) { - for(i=n;i>=0;i--) { ret[i] = x[i+a]; } - return ret; - } - for(i=n;i>=0;i--) { ret[i] = foo(x[i+a],k+1); } - return ret; - } - return foo(x,0); - }; - - numeric.setBlock = function setBlock(x,from,to,B) { - var s = numeric.dim(x); - function foo(x,y,k) { - var i,a = from[k], n = to[k]-a; - if(k === s.length-1) { for(i=n;i>=0;i--) { x[i+a] = y[i]; } } - for(i=n;i>=0;i--) { foo(x[i+a],y[i],k+1); } - } - foo(x,B,0); - return x; - }; - - numeric.getRange = function getRange(A,I,J) { - var m = I.length, n = J.length; - var i,j; - var B = Array(m), Bi, AI; - for(i=m-1;i!==-1;--i) { - B[i] = Array(n); - Bi = B[i]; - AI = A[I[i]]; - for(j=n-1;j!==-1;--j) Bi[j] = AI[J[j]]; - } - return B; - }; - - numeric.blockMatrix = function blockMatrix(X) { - var s = numeric.dim(X); - if(s.length<4) return numeric.blockMatrix([X]); - var m=s[0],n=s[1],M,N,i,j,Xij; - M = 0; N = 0; - for(i=0;i=0;i--) { - Ai = Array(n); - xi = x[i]; - for(j=n-1;j>=3;--j) { - Ai[j] = xi * y[j]; - --j; - Ai[j] = xi * y[j]; - --j; - Ai[j] = xi * y[j]; - --j; - Ai[j] = xi * y[j]; - } - while(j>=0) { Ai[j] = xi * y[j]; --j; } - A[i] = Ai; - } - return A; - }; - - // 3. The Tensor type T - numeric.T = function T(x,y) { this.x = x; this.y = y; }; - numeric.t = function t(x,y) { return new numeric.T(x,y); }; - - numeric.Tbinop = function Tbinop(rr,rc,cr,cc,setup) { - var io = numeric.indexOf; - if(typeof setup !== "string") { - var k; - setup = ''; - for(k in numeric) { - if(numeric.hasOwnProperty(k) && (rr.indexOf(k)>=0 || rc.indexOf(k)>=0 || cr.indexOf(k)>=0 || cc.indexOf(k)>=0) && k.length>1) { - setup += 'var '+k+' = numeric.'+k+';\n'; - } - } - } - return Function(['y'], - 'var x = this;\n'+ - 'if(!(y instanceof numeric.T)) { y = new numeric.T(y); }\n'+ - setup+'\n'+ - 'if(x.y) {'+ - ' if(y.y) {'+ - ' return new numeric.T('+cc+');\n'+ - ' }\n'+ - ' return new numeric.T('+cr+');\n'+ - '}\n'+ - 'if(y.y) {\n'+ - ' return new numeric.T('+rc+');\n'+ - '}\n'+ - 'return new numeric.T('+rr+');\n' - ); - }; - - numeric.T.prototype.add = numeric.Tbinop( - 'add(x.x,y.x)', - 'add(x.x,y.x),y.y', - 'add(x.x,y.x),x.y', - 'add(x.x,y.x),add(x.y,y.y)'); - numeric.T.prototype.sub = numeric.Tbinop( - 'sub(x.x,y.x)', - 'sub(x.x,y.x),neg(y.y)', - 'sub(x.x,y.x),x.y', - 'sub(x.x,y.x),sub(x.y,y.y)'); - numeric.T.prototype.mul = numeric.Tbinop( - 'mul(x.x,y.x)', - 'mul(x.x,y.x),mul(x.x,y.y)', - 'mul(x.x,y.x),mul(x.y,y.x)', - 'sub(mul(x.x,y.x),mul(x.y,y.y)),add(mul(x.x,y.y),mul(x.y,y.x))'); - - numeric.T.prototype.reciprocal = function reciprocal() { - var mul = numeric.mul, div = numeric.div; - if(this.y) { - var d = numeric.add(mul(this.x,this.x),mul(this.y,this.y)); - return new numeric.T(div(this.x,d),div(numeric.neg(this.y),d)); - } - return new T(div(1,this.x)); - }; - numeric.T.prototype.div = function div(y) { - if(!(y instanceof numeric.T)) y = new numeric.T(y); - if(y.y) { return this.mul(y.reciprocal()); } - var div = numeric.div; - if(this.y) { return new numeric.T(div(this.x,y.x),div(this.y,y.x)); } - return new numeric.T(div(this.x,y.x)); - }; - numeric.T.prototype.dot = numeric.Tbinop( - 'dot(x.x,y.x)', - 'dot(x.x,y.x),dot(x.x,y.y)', - 'dot(x.x,y.x),dot(x.y,y.x)', - 'sub(dot(x.x,y.x),dot(x.y,y.y)),add(dot(x.x,y.y),dot(x.y,y.x))' - ); - numeric.T.prototype.transpose = function transpose() { - var t = numeric.transpose, x = this.x, y = this.y; - if(y) { return new numeric.T(t(x),t(y)); } - return new numeric.T(t(x)); - }; - numeric.T.prototype.transjugate = function transjugate() { - var t = numeric.transpose, x = this.x, y = this.y; - if(y) { return new numeric.T(t(x),numeric.negtranspose(y)); } - return new numeric.T(t(x)); - }; - numeric.Tunop = function Tunop(r,c,s) { - if(typeof s !== "string") { s = ''; } - return Function( - 'var x = this;\n'+ - s+'\n'+ - 'if(x.y) {'+ - ' '+c+';\n'+ - '}\n'+ - r+';\n' - ); - }; - - numeric.T.prototype.exp = numeric.Tunop( - 'return new numeric.T(ex)', - 'return new numeric.T(mul(cos(x.y),ex),mul(sin(x.y),ex))', - 'var ex = numeric.exp(x.x), cos = numeric.cos, sin = numeric.sin, mul = numeric.mul;'); - numeric.T.prototype.conj = numeric.Tunop( - 'return new numeric.T(x.x);', - 'return new numeric.T(x.x,numeric.neg(x.y));'); - numeric.T.prototype.neg = numeric.Tunop( - 'return new numeric.T(neg(x.x));', - 'return new numeric.T(neg(x.x),neg(x.y));', - 'var neg = numeric.neg;'); - numeric.T.prototype.sin = numeric.Tunop( - 'return new numeric.T(numeric.sin(x.x))', - 'return x.exp().sub(x.neg().exp()).div(new numeric.T(0,2));'); - numeric.T.prototype.cos = numeric.Tunop( - 'return new numeric.T(numeric.cos(x.x))', - 'return x.exp().add(x.neg().exp()).div(2);'); - numeric.T.prototype.abs = numeric.Tunop( - 'return new numeric.T(numeric.abs(x.x));', - 'return new numeric.T(numeric.sqrt(numeric.add(mul(x.x,x.x),mul(x.y,x.y))));', - 'var mul = numeric.mul;'); - numeric.T.prototype.log = numeric.Tunop( - 'return new numeric.T(numeric.log(x.x));', - 'var theta = new numeric.T(numeric.atan2(x.y,x.x)), r = x.abs();\n'+ - 'return new numeric.T(numeric.log(r.x),theta.x);'); - numeric.T.prototype.norm2 = numeric.Tunop( - 'return numeric.norm2(x.x);', - 'var f = numeric.norm2Squared;\n'+ - 'return Math.sqrt(f(x.x)+f(x.y));'); - numeric.T.prototype.inv = function inv() { - var A = this; - if(typeof A.y === "undefined") { return new numeric.T(numeric.inv(A.x)); } - var n = A.x.length, i, j, k; - var Rx = numeric.identity(n),Ry = numeric.rep([n,n],0); - var Ax = numeric.clone(A.x), Ay = numeric.clone(A.y); - var Aix, Aiy, Ajx, Ajy, Rix, Riy, Rjx, Rjy; - var i,j,k,d,d1,ax,ay,bx,by,temp; - for(i=0;i d) { k=j; d = d1; } - } - if(k!==i) { - temp = Ax[i]; Ax[i] = Ax[k]; Ax[k] = temp; - temp = Ay[i]; Ay[i] = Ay[k]; Ay[k] = temp; - temp = Rx[i]; Rx[i] = Rx[k]; Rx[k] = temp; - temp = Ry[i]; Ry[i] = Ry[k]; Ry[k] = temp; - } - Aix = Ax[i]; Aiy = Ay[i]; - Rix = Rx[i]; Riy = Ry[i]; - ax = Aix[i]; ay = Aiy[i]; - for(j=i+1;j0;i--) { - Rix = Rx[i]; Riy = Ry[i]; - for(j=i-1;j>=0;j--) { - Rjx = Rx[j]; Rjy = Ry[j]; - ax = Ax[j][i]; ay = Ay[j][i]; - for(k=n-1;k>=0;k--) { - bx = Rix[k]; by = Riy[k]; - Rjx[k] -= ax*bx - ay*by; - Rjy[k] -= ax*by + ay*bx; - } - } - } - return new numeric.T(Rx,Ry); - }; - numeric.T.prototype.get = function get(i) { - var x = this.x, y = this.y, k = 0, ik, n = i.length; - if(y) { - while(k= 0 ? 1 : -1; - var alpha = s*numeric.norm2(x); - v[0] += alpha; - var foo = numeric.norm2(v); - if(foo === 0) { /* this should not happen */ throw new Error('eig: internal error'); } - return numeric.div(v,foo); - }; - - numeric.toUpperHessenberg = function toUpperHessenberg(me) { - var s = numeric.dim(me); - if(s.length !== 2 || s[0] !== s[1]) { throw new Error('numeric: toUpperHessenberg() only works on square matrices'); } - var m = s[0], i,j,k,x,v,A = numeric.clone(me),B,C,Ai,Ci,Q = numeric.identity(m),Qi; - for(j=0;j0) { - v = numeric.house(x); - B = numeric.getBlock(A,[j+1,j],[m-1,m-1]); - C = numeric.tensor(v,numeric.dot(v,B)); - for(i=j+1;i=4*det) { - var s1,s2; - s1 = 0.5*(tr+Math.sqrt(tr*tr-4*det)); - s2 = 0.5*(tr-Math.sqrt(tr*tr-4*det)); - Hloc = numeric.add(numeric.sub(numeric.dot(Hloc,Hloc), - numeric.mul(Hloc,s1+s2)), - numeric.diag(numeric.rep([3],s1*s2))); - } else { - Hloc = numeric.add(numeric.sub(numeric.dot(Hloc,Hloc), - numeric.mul(Hloc,tr)), - numeric.diag(numeric.rep([3],det))); - } - x = [Hloc[0][0],Hloc[1][0],Hloc[2][0]]; - v = numeric.house(x); - B = [H[0],H[1],H[2]]; - C = numeric.tensor(v,numeric.dot(v,B)); - for(i=0;i<3;i++) { Hi = H[i]; Ci = C[i]; for(k=0;k=0) { - if(p1<0) x = -0.5*(p1-sqrt(disc)); - else x = -0.5*(p1+sqrt(disc)); - n1 = (a-x)*(a-x)+b*b; - n2 = c*c+(d-x)*(d-x); - if(n1>n2) { - n1 = sqrt(n1); - p = (a-x)/n1; - q = b/n1; - } else { - n2 = sqrt(n2); - p = c/n2; - q = (d-x)/n2; - } - Q0 = new T([[q,-p],[p,q]]); - Q.setRows(i,j,Q0.dot(Q.getRows(i,j))); - } else { - x = -0.5*p1; - y = 0.5*sqrt(-disc); - n1 = (a-x)*(a-x)+b*b; - n2 = c*c+(d-x)*(d-x); - if(n1>n2) { - n1 = sqrt(n1+y*y); - p = (a-x)/n1; - q = b/n1; - x = 0; - y /= n1; - } else { - n2 = sqrt(n2+y*y); - p = c/n2; - q = (d-x)/n2; - x = y/n2; - y = 0; - } - Q0 = new T([[q,-p],[p,q]],[[x,y],[y,-x]]); - Q.setRows(i,j,Q0.dot(Q.getRows(i,j))); - } - } - } - var R = Q.dot(A).dot(Q.transjugate()), n = A.length, E = numeric.T.identity(n); - for(j=0;j0) { - for(k=j-1;k>=0;k--) { - var Rk = R.get([k,k]), Rj = R.get([j,j]); - if(numeric.neq(Rk.x,Rj.x) || numeric.neq(Rk.y,Rj.y)) { - x = R.getRow(k).getBlock([k],[j-1]); - y = E.getRow(j).getBlock([k],[j-1]); - E.set([j,k],(R.get([k,j]).neg().sub(x.dot(y))).div(Rk.sub(Rj))); - } else { - E.setRow(j,E.getRow(k)); - continue; - } - } - } - } - for(j=0;j=counts.length) counts[counts.length] = 0; - if(foo[j]!==0) counts[j]++; - } - } - var n = counts.length; - var Ai = Array(n+1); - Ai[0] = 0; - for(i=0;i= k11) { - xj[n] = j[m]; - if(m===0) return; - ++n; - --m; - km = k[m]; - k11 = k1[m]; - } else { - foo = Pinv[Aj[km]]; - if(x[foo] === 0) { - x[foo] = 1; - k[m] = km; - ++m; - j[m] = foo; - km = Ai[foo]; - k1[m] = k11 = Ai[foo+1]; - } else ++km; - } - } - }; - numeric.ccsLPSolve = function ccsLPSolve(A,B,x,xj,I,Pinv,dfs) { - var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1; - var Bi = B[0], Bj = B[1], Bv = B[2]; - - var i,i0,i1,j,j0,j1,k,l,a; - i0 = Bi[I]; - i1 = Bi[I+1]; - xj.length = 0; - for(i=i0;i a) { e = k; a = c; } - } - if(abs(x[i])= k11) { - xj[n] = Pinv[j[m]]; - if(m===0) return; - ++n; - --m; - km = k[m]; - k11 = k1[m]; - } else { - foo = Aj[km]; - if(x[foo] === 0) { - x[foo] = 1; - k[m] = km; - ++m; - j[m] = foo; - foo = Pinv[foo]; - km = Ai[foo]; - k1[m] = k11 = Ai[foo+1]; - } else ++km; - } - } - }; - numeric.ccsLPSolve0 = function ccsLPSolve0(A,B,y,xj,I,Pinv,P,dfs) { - var Ai = A[0], Aj = A[1], Av = A[2],m = Ai.length-1; - var Bi = B[0], Bj = B[1], Bv = B[2]; - - var i,i0,i1,j,j0,j1,k,l,a; - i0 = Bi[I]; - i1 = Bi[I+1]; - xj.length = 0; - for(i=i0;i a) { e = k; a = c; } - } - if(abs(y[P[i]]) ret[k]) ret[k] = A.length; - var i; - for(i in A) { - if(A.hasOwnProperty(i)) dim(A[i],ret,k+1); - } - return ret; - }; - - numeric.sclone = function clone(A,k,n) { - if(typeof k === "undefined") { k=0; } - if(typeof n === "undefined") { n = numeric.sdim(A).length; } - var i,ret = Array(A.length); - if(k === n-1) { - for(i in A) { if(A.hasOwnProperty(i)) ret[i] = A[i]; } - return ret; - } - for(i in A) { - if(A.hasOwnProperty(i)) ret[i] = clone(A[i],k+1,n); - } - return ret; - }; - - numeric.sdiag = function diag(d) { - var n = d.length,i,ret = Array(n),i1; - for(i=n-1;i>=1;i-=2) { - i1 = i-1; - ret[i] = []; ret[i][i] = d[i]; - ret[i1] = []; ret[i1][i1] = d[i1]; - } - if(i===0) { ret[0] = []; ret[0][0] = d[i]; } - return ret; - }; - - numeric.sidentity = function identity(n) { return numeric.sdiag(numeric.rep([n],1)); }; - - numeric.stranspose = function transpose(A) { - var ret = [], n = A.length, i,j,Ai; - for(i in A) { - if(!(A.hasOwnProperty(i))) continue; - Ai = A[i]; - for(j in Ai) { - if(!(Ai.hasOwnProperty(j))) continue; - if(typeof ret[j] !== "object") { ret[j] = []; } - ret[j][i] = Ai[j]; - } - } - return ret; - }; - - numeric.sLUP = function LUP(A,tol) { - throw new Error("The function numeric.sLUP had a bug in it and has been removed. Please use the new numeric.ccsLUP function instead."); - }; - - numeric.sdotMM = function dotMM(A,B) { - var p = A.length, q = B.length, BT = numeric.stranspose(B), r = BT.length, Ai, BTk; - var i,j,k,accum; - var ret = Array(p),reti; - for(i=p-1;i>=0;i--) { - reti = []; - Ai = A[i]; - for(k=r-1;k>=0;k--) { - accum = 0; - BTk = BT[k]; - for(j in Ai) { - if(!(Ai.hasOwnProperty(j))) continue; - if(j in BTk) { accum += Ai[j]*BTk[j]; } - } - if(accum) reti[k] = accum; - } - ret[i] = reti; - } - return ret; - }; - - numeric.sdotMV = function dotMV(A,x) { - var p = A.length, Ai, i,j; - var ret = Array(p), accum; - for(i=p-1;i>=0;i--) { - Ai = A[i]; - accum = 0; - for(j in Ai) { - if(!(Ai.hasOwnProperty(j))) continue; - if(x[j]) accum += Ai[j]*x[j]; - } - if(accum) ret[i] = accum; - } - return ret; - }; - - numeric.sdotVM = function dotMV(x,A) { - var i,j,Ai,alpha; - var ret = []; - for(i in x) { - if(!x.hasOwnProperty(i)) continue; - Ai = A[i]; - alpha = x[i]; - for(j in Ai) { - if(!Ai.hasOwnProperty(j)) continue; - if(!ret[j]) { ret[j] = 0; } - ret[j] += alpha*Ai[j]; - } - } - return ret; - }; - - numeric.sdotVV = function dotVV(x,y) { - var i,ret=0; - for(i in x) { if(x[i] && y[i]) ret+= x[i]*y[i]; } - return ret; - }; - - numeric.sdot = function dot(A,B) { - var m = numeric.sdim(A).length, n = numeric.sdim(B).length; - var k = m*1000+n; - switch(k) { - case 0: return A*B; - case 1001: return numeric.sdotVV(A,B); - case 2001: return numeric.sdotMV(A,B); - case 1002: return numeric.sdotVM(A,B); - case 2002: return numeric.sdotMM(A,B); - default: throw new Error('numeric.sdot not implemented for tensors of order '+m+' and '+n); - } - }; - - numeric.sscatter = function scatter(V) { - var n = V[0].length, Vij, i, j, m = V.length, A = [], Aj; - for(i=n-1;i>=0;--i) { - if(!V[m-1][i]) continue; - Aj = A; - for(j=0;j=0;--i) ret[i] = []; - } - for(i=n;i>=0;--i) ret[i].push(k[i]); - ret[n+1].push(Ai); - } - } else gather(Ai,ret,k); - } - } - if(k.length>n) k.pop(); - return ret; - }; - - // 6. Coordinate matrices - numeric.cLU = function LU(A) { - var I = A[0], J = A[1], V = A[2]; - var p = I.length, m=0, i,j,k,a,b,c; - for(i=0;im) m=I[i]; - m++; - var L = Array(m), U = Array(m), left = numeric.rep([m],Infinity), right = numeric.rep([m],-Infinity); - var Ui, Uj,alpha; - for(k=0;kright[i]) right[i] = j; - } - for(i=0;i right[i+1]) right[i+1] = right[i]; } - for(i=m-1;i>=1;i--) { if(left[i]=0;i--) { - while(Uj[k] > i) { - ret[i] -= Uv[k]*ret[Uj[k]]; - k--; - } - ret[i] /= Uv[k]; - k--; - } - return ret; - }; - - numeric.cgrid = function grid(n,shape) { - if(typeof n === "number") n = [n,n]; - var ret = numeric.rep(n,-1); - var i,j,count; - if(typeof shape !== "function") { - switch(shape) { - case 'L': - shape = function(i,j) { return (i>=n[0]/2 || jN) N = Ai[k]; } - N++; - ret = numeric.rep([N],0); - for(k=0;k1) { - mid = floor((p+q)/2); - if(x[mid] <= x0) p = mid; - else q = mid; - } - return this._at(x0,p); - } - var n = x0.length, i, ret = Array(n); - for(i=n-1;i!==-1;--i) ret[i] = this.at(x0[i]); - return ret; - }; - numeric.Spline.prototype.diff = function diff() { - var x = this.x; - var yl = this.yl; - var yr = this.yr; - var kl = this.kl; - var kr = this.kr; - var n = yl.length; - var i,dx,dy; - var zl = kl, zr = kr, pl = Array(n), pr = Array(n); - var add = numeric.add, mul = numeric.mul, div = numeric.div, sub = numeric.sub; - for(i=n-1;i!==-1;--i) { - dx = x[i+1]-x[i]; - dy = sub(yr[i+1],yl[i]); - pl[i] = div(add(mul(dy, 6),mul(kl[i],-4*dx),mul(kr[i+1],-2*dx)),dx*dx); - pr[i+1] = div(add(mul(dy,-6),mul(kl[i], 2*dx),mul(kr[i+1], 4*dx)),dx*dx); - } - return new numeric.Spline(x,zl,zr,pl,pr); - }; - numeric.Spline.prototype.roots = function roots() { - function sqr(x) { return x*x; } - var ret = []; - var x = this.x, yl = this.yl, yr = this.yr, kl = this.kl, kr = this.kr; - if(typeof yl[0] === "number") { - yl = [yl]; - yr = [yr]; - kl = [kl]; - kr = [kr]; - } - var m = yl.length,n=x.length-1,i,j,k; - var ai,bi,ci,di, ret = Array(m),ri,k0,k1,y0,y1,A,B,D,dx,cx,stops,z0,z1,zm,t0,t1,tm; - var sqrt = Math.sqrt; - for(i=0;i!==m;++i) { - ai = yl[i]; - bi = yr[i]; - ci = kl[i]; - di = kr[i]; - ri = []; - for(j=0;j!==n;j++) { - if(j>0 && bi[j]*ai[j]<0) ri.push(x[j]); - dx = (x[j+1]-x[j]); - cx = x[j]; - y0 = ai[j]; - y1 = bi[j+1]; - k0 = ci[j]/dx; - k1 = di[j+1]/dx; - D = sqr(k0-k1+3*(y0-y1)) + 12*k1*y0; - A = k1+3*y0+2*k0-3*y1; - B = 3*(k1+k0+2*(y0-y1)); - if(D<=0) { - z0 = A/B; - if(z0>x[j] && z0x[j] && z0x[j] && z10) { - t0 = t1; - z0 = z1; - continue; - } - var side = 0; - while(1) { - tm = (z0*t1-z1*t0)/(z0-z1); - if(tm <= t0 || tm >= t1) { break; } - zm = this._at(tm,j); - if(zm*z1>0) { - t1 = tm; - z1 = zm; - if(side === -1) z0*=0.5; - side = -1; - } else if(zm*z0>0) { - t0 = tm; - z0 = zm; - if(side === 1) z1*=0.5; - side = 1; - } else break; - } - ri.push(tm); - t0 = stops[k+1]; - z0 = this._at(t0, j); - } - if(z1 === 0) ri.push(t1); - } - ret[i] = ri; - } - if(typeof this.yl[0] === "number") return ret[0]; - return ret; - }; - numeric.spline = function spline(x,y,k1,kn) { - var n = x.length, b = [], dx = [], dy = []; - var i; - var sub = numeric.sub,mul = numeric.mul,add = numeric.add; - for(i=n-2;i>=0;i--) { dx[i] = x[i+1]-x[i]; dy[i] = sub(y[i+1],y[i]); } - if(typeof k1 === "string" || typeof kn === "string") { - k1 = kn = "periodic"; - } - // Build sparse tridiagonal system - var T = [[],[],[]]; - switch(typeof k1) { - case "undefined": - b[0] = mul(3/(dx[0]*dx[0]),dy[0]); - T[0].push(0,0); - T[1].push(0,1); - T[2].push(2/dx[0],1/dx[0]); - break; - case "string": - b[0] = add(mul(3/(dx[n-2]*dx[n-2]),dy[n-2]),mul(3/(dx[0]*dx[0]),dy[0])); - T[0].push(0,0,0); - T[1].push(n-2,0,1); - T[2].push(1/dx[n-2],2/dx[n-2]+2/dx[0],1/dx[0]); - break; - default: - b[0] = k1; - T[0].push(0); - T[1].push(0); - T[2].push(1); - break; - } - for(i=1;i20) { throw new Error("Numerical gradient fails"); } - x0[i] = x[i]+h; - f1 = f(x0); - x0[i] = x[i]-h; - f2 = f(x0); - x0[i] = x[i]; - if(isNaN(f1) || isNaN(f2)) { h/=16; continue; } - J[i] = (f1-f2)/(2*h); - t0 = x[i]-h; - t1 = x[i]; - t2 = x[i]+h; - d1 = (f1-f0)/h; - d2 = (f0-f2)/h; - N = max(abs(J[i]),abs(f0),abs(f1),abs(f2),abs(t0),abs(t1),abs(t2),1e-8); - errest = min(max(abs(d1-J[i]),abs(d2-J[i]),abs(d1-d2))/N,h/N); - if(errest>eps) { h/=16; } - else break; - } - } - return J; - }; - - numeric.uncmin = function uncmin(f,x0,tol,gradient,maxit,callback,options) { - var grad = numeric.gradient; - if(typeof options === "undefined") { options = {}; } - if(typeof tol === "undefined") { tol = 1e-8; } - if(typeof gradient === "undefined") { gradient = function(x) { return grad(f,x); }; } - if(typeof maxit === "undefined") maxit = 1000; - x0 = numeric.clone(x0); - var n = x0.length; - var f0 = f(x0),f1,df0; - if(isNaN(f0)) throw new Error('uncmin: f(x0) is a NaN!'); - var max = Math.max, norm2 = numeric.norm2; - tol = max(tol,numeric.epsilon); - var step,g0,g1,H1 = options.Hinv || numeric.identity(n); - var dot = numeric.dot, inv = numeric.inv, sub = numeric.sub, add = numeric.add, ten = numeric.tensor, div = numeric.div, mul = numeric.mul; - var all = numeric.all, isfinite = numeric.isFinite, neg = numeric.neg; - var it=0,s,x1,y,Hy,ys,t,nstep; - var msg = ""; - g0 = gradient(x0); - while(it= 0.1*t*df0 || isNaN(f1)) { - t *= 0.5; - ++it; - continue; - } - break; - } - if(t*nstep < tol) { msg = "Line search step size smaller than tol"; break; } - if(it === maxit) { msg = "maxit reached during line search"; break; } - g1 = gradient(x1); - y = sub(g1,g0); - ys = dot(y,s); - Hy = dot(H1,y); - H1 = sub(add(H1, - mul( - (ys+dot(y,Hy))/(ys*ys), - ten(s,s) )), - div(add(ten(Hy,s),ten(s,Hy)),ys)); - x0 = x1; - f0 = f1; - g0 = g1; - ++it; - } - return {solution: x0, f: f0, gradient: g0, invHessian: H1, iterations:it, message: msg}; - }; - - // 10. Ode solver (Dormand-Prince) - numeric.Dopri = function Dopri(x,y,f,ymid,iterations,msg,events) { - this.x = x; - this.y = y; - this.f = f; - this.ymid = ymid; - this.iterations = iterations; - this.events = events; - this.message = msg; - }; - numeric.Dopri.prototype._at = function _at(xi,j) { - function sqr(x) { return x*x; } - var sol = this; - var xs = sol.x; - var ys = sol.y; - var k1 = sol.f; - var ymid = sol.ymid; - var n = xs.length; - var x0,x1,xh,y0,y1,yh,xi; - var h; - var c = 0.5; - var add = numeric.add, mul = numeric.mul,sub = numeric.sub, p,q,w; - x0 = xs[j]; - x1 = xs[j+1]; - y0 = ys[j]; - y1 = ys[j+1]; - h = x1-x0; - xh = x0+c*h; - yh = ymid[j]; - p = sub(k1[j ],mul(y0,1/(x0-xh)+2/(x0-x1))); - q = sub(k1[j+1],mul(y1,1/(x1-xh)+2/(x1-x0))); - w = [sqr(xi - x1) * (xi - xh) / sqr(x0 - x1) / (x0 - xh), - sqr(xi - x0) * sqr(xi - x1) / sqr(x0 - xh) / sqr(x1 - xh), - sqr(xi - x0) * (xi - xh) / sqr(x1 - x0) / (x1 - xh), - (xi - x0) * sqr(xi - x1) * (xi - xh) / sqr(x0-x1) / (x0 - xh), - (xi - x1) * sqr(xi - x0) * (xi - xh) / sqr(x0-x1) / (x1 - xh)]; - return add(add(add(add(mul(y0,w[0]), - mul(yh,w[1])), - mul(y1,w[2])), - mul( p,w[3])), - mul( q,w[4])); - }; - numeric.Dopri.prototype.at = function at(x) { - var i,j,k,floor = Math.floor; - if(typeof x !== "number") { - var n = x.length, ret = Array(n); - for(i=n-1;i!==-1;--i) { - ret[i] = this.at(x[i]); - } - return ret; - } - var x0 = this.x; - i = 0; j = x0.length-1; - while(j-i>1) { - k = floor(0.5*(i+j)); - if(x0[k] <= x) i = k; - else j = k; - } - return this._at(x,i); - }; - - numeric.dopri = function dopri(x0,x1,y0,f,tol,maxit,event) { - if(typeof tol === "undefined") { tol = 1e-6; } - if(typeof maxit === "undefined") { maxit = 1000; } - var xs = [x0], ys = [y0], k1 = [f(x0,y0)], k2,k3,k4,k5,k6,k7, ymid = []; - var A2 = 1/5; - var A3 = [3/40,9/40]; - var A4 = [44/45,-56/15,32/9]; - var A5 = [19372/6561,-25360/2187,64448/6561,-212/729]; - var A6 = [9017/3168,-355/33,46732/5247,49/176,-5103/18656]; - var b = [35/384,0,500/1113,125/192,-2187/6784,11/84]; - var bm = [0.5*6025192743/30085553152, - 0, - 0.5*51252292925/65400821598, - 0.5*-2691868925/45128329728, - 0.5*187940372067/1594534317056, - 0.5*-1776094331/19743644256, - 0.5*11237099/235043384]; - var c = [1/5,3/10,4/5,8/9,1,1]; - var e = [-71/57600,0,71/16695,-71/1920,17253/339200,-22/525,1/40]; - var i = 0,er,j; - var h = (x1-x0)/10; - var it = 0; - var add = numeric.add, mul = numeric.mul, y1,erinf; - var min = Math.min, abs = Math.abs, norminf = numeric.norminf,pow = Math.pow; - var any = numeric.any, lt = numeric.lt, and = numeric.and, sub = numeric.sub; - var e0, e1, ev; - var ret = new numeric.Dopri(xs,ys,k1,ymid,-1,""); - if(typeof event === "function") e0 = event(x0,y0); - while(x0x1) h = x1-x0; - k2 = f(x0+c[0]*h, add(y0,mul( A2*h,k1[i]))); - k3 = f(x0+c[1]*h, add(add(y0,mul(A3[0]*h,k1[i])),mul(A3[1]*h,k2))); - k4 = f(x0+c[2]*h, add(add(add(y0,mul(A4[0]*h,k1[i])),mul(A4[1]*h,k2)),mul(A4[2]*h,k3))); - k5 = f(x0+c[3]*h, add(add(add(add(y0,mul(A5[0]*h,k1[i])),mul(A5[1]*h,k2)),mul(A5[2]*h,k3)),mul(A5[3]*h,k4))); - k6 = f(x0+c[4]*h,add(add(add(add(add(y0,mul(A6[0]*h,k1[i])),mul(A6[1]*h,k2)),mul(A6[2]*h,k3)),mul(A6[3]*h,k4)),mul(A6[4]*h,k5))); - y1 = add(add(add(add(add(y0,mul(k1[i],h*b[0])),mul(k3,h*b[2])),mul(k4,h*b[3])),mul(k5,h*b[4])),mul(k6,h*b[5])); - k7 = f(x0+h,y1); - er = add(add(add(add(add(mul(k1[i],h*e[0]),mul(k3,h*e[2])),mul(k4,h*e[3])),mul(k5,h*e[4])),mul(k6,h*e[5])),mul(k7,h*e[6])); - if(typeof er === "number") erinf = abs(er); - else erinf = norminf(er); - if(erinf > tol) { // reject - h = 0.2*h*pow(tol/erinf,0.25); - if(x0+h === x0) { - ret.msg = "Step size became too small"; - break; - } - continue; - } - ymid[i] = add(add(add(add(add(add(y0, - mul(k1[i],h*bm[0])), - mul(k3 ,h*bm[2])), - mul(k4 ,h*bm[3])), - mul(k5 ,h*bm[4])), - mul(k6 ,h*bm[5])), - mul(k7 ,h*bm[6])); - ++i; - xs[i] = x0+h; - ys[i] = y1; - k1[i] = k7; - if(typeof event === "function") { - var yi,xl = x0,xr = x0+0.5*h,xi; - e1 = event(xr,ymid[i-1]); - ev = and(lt(e0,0),lt(0,e1)); - if(!any(ev)) { xl = xr; xr = x0+h; e0 = e1; e1 = event(xr,y1); ev = and(lt(e0,0),lt(0,e1)); } - if(any(ev)) { - var en,ei; - var side=0, sl = 1.0, sr = 1.0; - while(1) { - if(typeof e0 === "number") xi = (sr*e1*xl-sl*e0*xr)/(sr*e1-sl*e0); - else { - xi = xr; - for(j=e0.length-1;j!==-1;--j) { - if(e0[j]<0 && e1[j]>0) xi = min(xi,(sr*e1[j]*xl-sl*e0[j]*xr)/(sr*e1[j]-sl*e0[j])); - } - } - if(xi <= xl || xi >= xr) break; - yi = ret._at(xi, i-1); - ei = event(xi,yi); - en = and(lt(e0,0),lt(0,ei)); - if(any(en)) { - xr = xi; - e1 = ei; - ev = en; - sr = 1.0; - if(side === -1) sl *= 0.5; - else sl = 1.0; - side = -1; - } else { - xl = xi; - e0 = ei; - sl = 1.0; - if(side === 1) sr *= 0.5; - else sr = 1.0; - side = 1; - } - } - y1 = ret._at(0.5*(x0+xi),i-1); - ret.f[i] = f(xi,yi); - ret.x[i] = xi; - ret.y[i] = yi; - ret.ymid[i-1] = y1; - ret.events = ev; - ret.iterations = it; - return ret; - } - } - x0 += h; - y0 = y1; - e0 = e1; - h = min(0.8*h*pow(tol/erinf,0.25),4*h); - } - ret.iterations = it; - return ret; - }; - - // 11. Ax = b - numeric.LU = function(A, fast) { - fast = fast || false; - - var abs = Math.abs; - var i, j, k, absAjk, Akk, Ak, Pk, Ai; - var max; - var n = A.length, n1 = n-1; - var P = new Array(n); - if(!fast) A = numeric.clone(A); - - for (k = 0; k < n; ++k) { - Pk = k; - Ak = A[k]; - max = abs(Ak[k]); - for (j = k + 1; j < n; ++j) { - absAjk = abs(A[j][k]); - if (max < absAjk) { - max = absAjk; - Pk = j; - } - } - P[k] = Pk; - - if (Pk != k) { - A[k] = A[Pk]; - A[Pk] = Ak; - Ak = A[k]; - } - - Akk = Ak[k]; - - for (i = k + 1; i < n; ++i) { - A[i][k] /= Akk; - } - - for (i = k + 1; i < n; ++i) { - Ai = A[i]; - for (j = k + 1; j < n1; ++j) { - Ai[j] -= Ai[k] * Ak[j]; - ++j; - Ai[j] -= Ai[k] * Ak[j]; - } - if(j===n1) Ai[j] -= Ai[k] * Ak[j]; - } - } - - return { - LU: A, - P: P - }; - }; - - numeric.LUsolve = function LUsolve(LUP, b) { - var i, j; - var LU = LUP.LU; - var n = LU.length; - var x = numeric.clone(b); - var P = LUP.P; - var Pi, LUi, tmp; - - for (i=n-1;i!==-1;--i) x[i] = b[i]; - for (i = 0; i < n; ++i) { - Pi = P[i]; - if (P[i] !== i) { - tmp = x[i]; - x[i] = x[Pi]; - x[Pi] = tmp; - } - - LUi = LU[i]; - for (j = 0; j < i; ++j) { - x[i] -= x[j] * LUi[j]; - } - } - - for (i = n - 1; i >= 0; --i) { - LUi = LU[i]; - for (j = i + 1; j < n; ++j) { - x[i] -= x[j] * LUi[j]; - } - - x[i] /= LUi[i]; - } - - return x; - }; - - numeric.solve = function solve(A,b,fast) { return numeric.LUsolve(numeric.LU(A,fast), b); }; - - // 12. Linear programming - numeric.echelonize = function echelonize(A) { - var s = numeric.dim(A), m = s[0], n = s[1]; - var I = numeric.identity(m); - var P = Array(m); - var i,j,k,l,Ai,Ii,Z,a; - var abs = Math.abs; - var diveq = numeric.diveq; - A = numeric.clone(A); - for(i=0;ia1) alpha = a1; - g = add(c,mul(alpha,p)); - H = dot(A1,A0); - for(i=m-1;i!==-1;--i) H[i][i] += 1; - d = solve(H,div(g,alpha),true); - var t0 = div(z,dot(A,d)); - var t = 1.0; - for(i=n-1;i!==-1;--i) if(t0[i]<0) t = min(t,-0.999*t0[i]); - y = sub(x,mul(d,t)); - z = sub(b,dot(A,y)); - if(!all(gt(z,0))) return { solution: x, message: "", iterations: count }; - x = y; - if(alpha=0) unbounded = false; - else unbounded = true; - } - if(unbounded) return { solution: y, message: "Unbounded", iterations: count }; - } - return { solution: x, message: "maximum iteration count exceeded", iterations:count }; - }; - - numeric._solveLP = function _solveLP(c,A,b,tol,maxit) { - var m = c.length, n = b.length,y; - var sum = numeric.sum, log = numeric.log, mul = numeric.mul, sub = numeric.sub, dot = numeric.dot, div = numeric.div, add = numeric.add; - var c0 = numeric.rep([m],0).concat([1]); - var J = numeric.rep([n,1],-1); - var A0 = numeric.blockMatrix([[A , J ]]); - var b0 = b; - var y = numeric.rep([m],0).concat(Math.max(0,numeric.sup(numeric.neg(b)))+1); - var x0 = numeric.__solveLP(c0,A0,b0,tol,maxit,y,false); - var x = numeric.clone(x0.solution); - x.length = m; - var foo = numeric.inf(sub(b,dot(A,x))); - if(foo<0) { return { solution: NaN, message: "Infeasible", iterations: x0.iterations }; } - var ret = numeric.__solveLP(c, A, b, tol, maxit-x0.iterations, x, true); - ret.iterations += x0.iterations; - return ret; - }; - - numeric.solveLP = function solveLP(c,A,b,Aeq,beq,tol,maxit) { - if(typeof maxit === "undefined") maxit = 1000; - if(typeof tol === "undefined") tol = numeric.epsilon; - if(typeof Aeq === "undefined") return numeric._solveLP(c,A,b,tol,maxit); - var m = Aeq.length, n = Aeq[0].length, o = A.length; - var B = numeric.echelonize(Aeq); - var flags = numeric.rep([n],0); - var P = B.P; - var Q = []; - var i; - for(i=P.length-1;i!==-1;--i) flags[P[i]] = 1; - for(i=n-1;i!==-1;--i) if(flags[i]===0) Q.push(i); - var g = numeric.getRange; - var I = numeric.linspace(0,m-1), J = numeric.linspace(0,o-1); - var Aeq2 = g(Aeq,I,Q), A1 = g(A,J,P), A2 = g(A,J,Q), dot = numeric.dot, sub = numeric.sub; - var A3 = dot(A1,B.I); - var A4 = sub(A2,dot(A3,Aeq2)), b4 = sub(b,dot(A3,beq)); - var c1 = Array(P.length), c2 = Array(Q.length); - for(i=P.length-1;i!==-1;--i) c1[i] = c[P[i]]; - for(i=Q.length-1;i!==-1;--i) c2[i] = c[Q[i]]; - var c4 = sub(c2,dot(c1,dot(B.I,Aeq2))); - var S = numeric._solveLP(c4,A4,b4,tol,maxit); - var x2 = S.solution; - if(x2!==x2) return S; - var x1 = dot(B.I,sub(beq,dot(Aeq2,x2))); - var x = Array(c.length); - for(i=P.length-1;i!==-1;--i) x[P[i]] = x1[i]; - for(i=Q.length-1;i!==-1;--i) x[Q[i]] = x2[i]; - return { solution: x, message:S.message, iterations: S.iterations }; - }; - - numeric.MPStoLP = function MPStoLP(MPS) { - if(MPS instanceof String) { MPS.split('\n'); } - var state = 0; - var states = ['Initial state','NAME','ROWS','COLUMNS','RHS','BOUNDS','ENDATA']; - var n = MPS.length; - var i,j,z,N=0,rows = {}, sign = [], rl = 0, vars = {}, nv = 0; - var name; - var c = [], A = [], b = []; - function err(e) { throw new Error('MPStoLP: '+e+'\nLine '+i+': '+MPS[i]+'\nCurrent state: '+states[state]+'\n'); } - for(i=0;i - // - // Math.seedrandom('yipee'); Sets Math.random to a function that is - // initialized using the given explicit seed. - // - // Math.seedrandom(); Sets Math.random to a function that is - // seeded using the current time, dom state, - // and other accumulated local entropy. - // The generated seed string is returned. - // - // Math.seedrandom('yowza', true); - // Seeds using the given explicit seed mixed - // together with accumulated entropy. - // - // - // Seeds using physical random bits downloaded - // from random.org. - // - // Seeds using urandom bits from call.jsonlib.com, - // which is faster than random.org. - // - // Examples: - // - // Math.seedrandom("hello"); // Use "hello" as the seed. - // document.write(Math.random()); // Always 0.5463663768140734 - // document.write(Math.random()); // Always 0.43973793770592234 - // var rng1 = Math.random; // Remember the current prng. - // - // var autoseed = Math.seedrandom(); // New prng with an automatic seed. - // document.write(Math.random()); // Pretty much unpredictable. - // - // Math.random = rng1; // Continue "hello" prng sequence. - // document.write(Math.random()); // Always 0.554769432473455 - // - // Math.seedrandom(autoseed); // Restart at the previous seed. - // document.write(Math.random()); // Repeat the 'unpredictable' value. - // - // Notes: - // - // Each time seedrandom('arg') is called, entropy from the passed seed - // is accumulated in a pool to help generate future seeds for the - // zero-argument form of Math.seedrandom, so entropy can be injected over - // time by calling seedrandom with explicit data repeatedly. - // - // On speed - This javascript implementation of Math.random() is about - // 3-10x slower than the built-in Math.random() because it is not native - // code, but this is typically fast enough anyway. Seeding is more expensive, - // especially if you use auto-seeding. Some details (timings on Chrome 4): - // - // Our Math.random() - avg less than 0.002 milliseconds per call - // seedrandom('explicit') - avg less than 0.5 milliseconds per call - // seedrandom('explicit', true) - avg less than 2 milliseconds per call - // seedrandom() - avg about 38 milliseconds per call - // - // LICENSE (BSD): - // - // Copyright 2010 David Bau, all rights reserved. - // - // Redistribution and use in source and binary forms, with or without - // modification, are permitted provided that the following conditions are met: - // - // 1. Redistributions of source code must retain the above copyright - // notice, this list of conditions and the following disclaimer. - // - // 2. Redistributions in binary form must reproduce the above copyright - // notice, this list of conditions and the following disclaimer in the - // documentation and/or other materials provided with the distribution. - // - // 3. Neither the name of this module nor the names of its contributors may - // be used to endorse or promote products derived from this software - // without specific prior written permission. - // - // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // - /** - * All code is in an anonymous closure to keep the global namespace clean. - * - * @param {number=} overflow - * @param {number=} startdenom - */ - - // Patched by Seb so that seedrandom.js does not pollute the Math object. - // My tests suggest that doing Math.trouble = 1 makes Math lookups about 5% - // slower. - numeric.seedrandom = { pow:Math.pow, random:Math.random }; - - (function (pool, math, width, chunks, significance, overflow, startdenom) { - - - // - // seedrandom() - // This is the seedrandom function described above. - // - math['seedrandom'] = function seedrandom(seed, use_entropy) { - var key = []; - var arc4; - - // Flatten the seed string or build one from local entropy if needed. - seed = mixkey(flatten( - use_entropy ? [seed, pool] : - arguments.length ? seed : - [new Date().getTime(), pool, window], 3), key); - - // Use the seed to initialize an ARC4 generator. - arc4 = new ARC4(key); - - // Mix the randomness into accumulated entropy. - mixkey(arc4.S, pool); - - // Override Math.random - - // This function returns a random double in [0, 1) that contains - // randomness in every bit of the mantissa of the IEEE 754 value. - - math['random'] = function random() { // Closure to return a random double: - var n = arc4.g(chunks); // Start with a numerator n < 2 ^ 48 - var d = startdenom; // and denominator d = 2 ^ 48. - var x = 0; // and no 'extra last byte'. - while (n < significance) { // Fill up all significant digits by - n = (n + x) * width; // shifting numerator and - d *= width; // denominator and generating a - x = arc4.g(1); // new least-significant-byte. - } - while (n >= overflow) { // To avoid rounding up, before adding - n /= 2; // last byte, shift everything - d /= 2; // right using integer math until - x >>>= 1; // we have exactly the desired bits. - } - return (n + x) / d; // Form the number within [0, 1). - }; - - // Return the seed that was used - return seed; - }; - - // - // ARC4 - // - // An ARC4 implementation. The constructor takes a key in the form of - // an array of at most (width) integers that should be 0 <= x < (width). - // - // The g(count) method returns a pseudorandom integer that concatenates - // the next (count) outputs from ARC4. Its return value is a number x - // that is in the range 0 <= x < (width ^ count). - // - /** @constructor */ - function ARC4(key) { - var t, u, me = this, keylen = key.length; - var i = 0, j = me.i = me.j = me.m = 0; - me.S = []; - me.c = []; - - // The empty key [] is treated as [0]. - if (!keylen) { key = [keylen++]; } - - // Set up S using the standard key scheduling algorithm. - while (i < width) { me.S[i] = i++; } - for (i = 0; i < width; i++) { - t = me.S[i]; - j = lowbits(j + t + key[i % keylen]); - u = me.S[j]; - me.S[i] = u; - me.S[j] = t; - } - - // The "g" method returns the next (count) outputs as one number. - me.g = function getnext(count) { - var s = me.S; - var i = lowbits(me.i + 1); var t = s[i]; - var j = lowbits(me.j + t); var u = s[j]; - s[i] = u; - s[j] = t; - var r = s[lowbits(t + u)]; - while (--count) { - i = lowbits(i + 1); t = s[i]; - j = lowbits(j + t); u = s[j]; - s[i] = u; - s[j] = t; - r = r * width + s[lowbits(t + u)]; - } - me.i = i; - me.j = j; - return r; - }; - // For robust unpredictability discard an initial batch of values. - // See http://www.rsa.com/rsalabs/node.asp?id=2009 - me.g(width); - } - - // - // flatten() - // Converts an object tree to nested arrays of strings. - // - /** @param {Object=} result - * @param {string=} prop - * @param {string=} typ */ - function flatten(obj, depth, result, prop, typ) { - result = []; - typ = typeof(obj); - if (depth && typ == 'object') { - for (prop in obj) { - if (prop.indexOf('S') < 5) { // Avoid FF3 bug (local/sessionStorage) - try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} - } - } - } - return (result.length ? result : obj + (typ != 'string' ? '\0' : '')); - } - - // - // mixkey() - // Mixes a string seed into a key that is an array of integers, and - // returns a shortened string seed that is equivalent to the result key. - // - /** @param {number=} smear - * @param {number=} j */ - function mixkey(seed, key, smear, j) { - seed += ''; // Ensure the seed is a string - smear = 0; - for (j = 0; j < seed.length; j++) { - key[lowbits(j)] = - lowbits((smear ^= key[lowbits(j)] * 19) + seed.charCodeAt(j)); - } - seed = ''; - for (j in key) { seed += String.fromCharCode(key[j]); } - return seed; - } - - // - // lowbits() - // A quick "n mod width" for width a power of 2. - // - function lowbits(n) { return n & (width - 1); } - - // - // The following constants are related to IEEE 754 limits. - // - startdenom = math.pow(width, chunks); - significance = math.pow(2, significance); - overflow = significance * 2; - - // - // When seedrandom.js is loaded, we immediately mix a few bits - // from the built-in RNG into the entropy pool. Because we do - // not want to intefere with determinstic PRNG state later, - // seedrandom will not call math.random on its own again after - // initialization. - // - mixkey(math.random(), pool); - - // End anonymous scope, and pass initial values. - }( - [], // pool: entropy pool starts empty - numeric.seedrandom, // math: package containing random, pow, and seedrandom - 256, // width: each RC4 output is 0 <= x < 256 - 6, // chunks: at least six RC4 outputs for each double - 52 // significance: there are 52 significant digits in a double - )); - /* This file is a slightly modified version of quadprog.js from Alberto Santini. - * It has been slightly modified by Sébastien Loisel to make sure that it handles - * 0-based Arrays instead of 1-based Arrays. - * License is in resources/LICENSE.quadprog */ - (function(exports) { - - function base0to1(A) { - if(typeof A !== "object") { return A; } - var ret = [], i,n=A.length; - for(i=0;i meq) { - work[l] = sum; - } else { - work[l] = -Math.abs(sum); - if (sum > 0) { - for (j = 1; j <= n; j = j + 1) { - amat[j][i] = -amat[j][i]; - } - bvec[i] = -bvec[i]; - } - } - } - - for (i = 1; i <= nact; i = i + 1) { - work[iwsv + iact[i]] = 0; - } - - nvl = 0; - temp = 0; - for (i = 1; i <= q; i = i + 1) { - if (work[iwsv + i] < temp * work[iwnbv + i]) { - nvl = i; - temp = work[iwsv + i] / work[iwnbv + i]; - } - } - if (nvl === 0) { - return 999; - } - - return 0; - } - - function fn_goto_55() { - for (i = 1; i <= n; i = i + 1) { - sum = 0; - for (j = 1; j <= n; j = j + 1) { - sum = sum + dmat[j][i] * amat[j][nvl]; - } - work[i] = sum; - } - - l1 = iwzv; - for (i = 1; i <= n; i = i + 1) { - work[l1 + i] = 0; - } - for (j = nact + 1; j <= n; j = j + 1) { - for (i = 1; i <= n; i = i + 1) { - work[l1 + i] = work[l1 + i] + dmat[i][j] * work[j]; - } - } - - t1inf = true; - for (i = nact; i >= 1; i = i - 1) { - sum = work[i]; - l = iwrm + (i * (i + 3)) / 2; - l1 = l - i; - for (j = i + 1; j <= nact; j = j + 1) { - sum = sum - work[l] * work[iwrv + j]; - l = l + j; - } - sum = sum / work[l1]; - work[iwrv + i] = sum; - if (iact[i] < meq) { - // continue; - break; - } - if (sum < 0) { - // continue; - break; - } - t1inf = false; - it1 = i; - } - - if (!t1inf) { - t1 = work[iwuv + it1] / work[iwrv + it1]; - for (i = 1; i <= nact; i = i + 1) { - if (iact[i] < meq) { - // continue; - break; - } - if (work[iwrv + i] < 0) { - // continue; - break; - } - temp = work[iwuv + i] / work[iwrv + i]; - if (temp < t1) { - t1 = temp; - it1 = i; - } - } - } - - sum = 0; - for (i = iwzv + 1; i <= iwzv + n; i = i + 1) { - sum = sum + work[i] * work[i]; - } - if (Math.abs(sum) <= vsmall) { - if (t1inf) { - ierr[1] = 1; - // GOTO 999 - return 999; - } else { - for (i = 1; i <= nact; i = i + 1) { - work[iwuv + i] = work[iwuv + i] - t1 * work[iwrv + i]; - } - work[iwuv + nact + 1] = work[iwuv + nact + 1] + t1; - // GOTO 700 - return 700; - } - } else { - sum = 0; - for (i = 1; i <= n; i = i + 1) { - sum = sum + work[iwzv + i] * amat[i][nvl]; - } - tt = -work[iwsv + nvl] / sum; - t2min = true; - if (!t1inf) { - if (t1 < tt) { - tt = t1; - t2min = false; - } - } - - for (i = 1; i <= n; i = i + 1) { - sol[i] = sol[i] + tt * work[iwzv + i]; - if (Math.abs(sol[i]) < vsmall) { - sol[i] = 0; - } - } - - crval[1] = crval[1] + tt * sum * (tt / 2 + work[iwuv + nact + 1]); - for (i = 1; i <= nact; i = i + 1) { - work[iwuv + i] = work[iwuv + i] - tt * work[iwrv + i]; - } - work[iwuv + nact + 1] = work[iwuv + nact + 1] + tt; - - if (t2min) { - nact = nact + 1; - iact[nact] = nvl; - - l = iwrm + ((nact - 1) * nact) / 2 + 1; - for (i = 1; i <= nact - 1; i = i + 1) { - work[l] = work[i]; - l = l + 1; - } - - if (nact === n) { - work[l] = work[n]; - } else { - for (i = n; i >= nact + 1; i = i - 1) { - if (work[i] === 0) { - // continue; - break; - } - gc = Math.max(Math.abs(work[i - 1]), Math.abs(work[i])); - gs = Math.min(Math.abs(work[i - 1]), Math.abs(work[i])); - if (work[i - 1] >= 0) { - temp = Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); - } else { - temp = -Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); - } - gc = work[i - 1] / temp; - gs = work[i] / temp; - - if (gc === 1) { - // continue; - break; - } - if (gc === 0) { - work[i - 1] = gs * temp; - for (j = 1; j <= n; j = j + 1) { - temp = dmat[j][i - 1]; - dmat[j][i - 1] = dmat[j][i]; - dmat[j][i] = temp; - } - } else { - work[i - 1] = temp; - nu = gs / (1 + gc); - for (j = 1; j <= n; j = j + 1) { - temp = gc * dmat[j][i - 1] + gs * dmat[j][i]; - dmat[j][i] = nu * (dmat[j][i - 1] + temp) - dmat[j][i]; - dmat[j][i - 1] = temp; - - } - } - } - work[l] = work[nact]; - } - } else { - sum = -bvec[nvl]; - for (j = 1; j <= n; j = j + 1) { - sum = sum + sol[j] * amat[j][nvl]; - } - if (nvl > meq) { - work[iwsv + nvl] = sum; - } else { - work[iwsv + nvl] = -Math.abs(sum); - if (sum > 0) { - for (j = 1; j <= n; j = j + 1) { - amat[j][nvl] = -amat[j][nvl]; - } - bvec[nvl] = -bvec[nvl]; - } - } - // GOTO 700 - return 700; - } - } - - return 0; - } - - function fn_goto_797() { - l = iwrm + (it1 * (it1 + 1)) / 2 + 1; - l1 = l + it1; - if (work[l1] === 0) { - // GOTO 798 - return 798; - } - gc = Math.max(Math.abs(work[l1 - 1]), Math.abs(work[l1])); - gs = Math.min(Math.abs(work[l1 - 1]), Math.abs(work[l1])); - if (work[l1 - 1] >= 0) { - temp = Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); - } else { - temp = -Math.abs(gc * Math.sqrt(1 + gs * gs / (gc * gc))); - } - gc = work[l1 - 1] / temp; - gs = work[l1] / temp; - - if (gc === 1) { - // GOTO 798 - return 798; - } - if (gc === 0) { - for (i = it1 + 1; i <= nact; i = i + 1) { - temp = work[l1 - 1]; - work[l1 - 1] = work[l1]; - work[l1] = temp; - l1 = l1 + i; - } - for (i = 1; i <= n; i = i + 1) { - temp = dmat[i][it1]; - dmat[i][it1] = dmat[i][it1 + 1]; - dmat[i][it1 + 1] = temp; - } - } else { - nu = gs / (1 + gc); - for (i = it1 + 1; i <= nact; i = i + 1) { - temp = gc * work[l1 - 1] + gs * work[l1]; - work[l1] = nu * (work[l1 - 1] + temp) - work[l1]; - work[l1 - 1] = temp; - l1 = l1 + i; - } - for (i = 1; i <= n; i = i + 1) { - temp = gc * dmat[i][it1] + gs * dmat[i][it1 + 1]; - dmat[i][it1 + 1] = nu * (dmat[i][it1] + temp) - dmat[i][it1 + 1]; - dmat[i][it1] = temp; - } - } - - return 0; - } - - function fn_goto_798() { - l1 = l - it1; - for (i = 1; i <= it1; i = i + 1) { - work[l1] = work[l]; - l = l + 1; - l1 = l1 + 1; - } - - work[iwuv + it1] = work[iwuv + it1 + 1]; - iact[it1] = iact[it1 + 1]; - it1 = it1 + 1; - if (it1 < nact) { - // GOTO 797 - return 797; - } - - return 0; - } - - function fn_goto_799() { - work[iwuv + nact] = work[iwuv + nact + 1]; - work[iwuv + nact + 1] = 0; - iact[nact] = 0; - nact = nact - 1; - iter[2] = iter[2] + 1; - - return 0; - } - - go = 0; - while (true) { - go = fn_goto_50(); - if (go === 999) { - return; - } - while (true) { - go = fn_goto_55(); - if (go === 0) { - break; - } - if (go === 999) { - return; - } - if (go === 700) { - if (it1 === nact) { - fn_goto_799(); - } else { - while (true) { - fn_goto_797(); - go = fn_goto_798(); - if (go !== 797) { - break; - } - } - fn_goto_799(); - } - } - } - } - - } - - function solveQP(Dmat, dvec, Amat, bvec, meq, factorized) { - Dmat = base0to1(Dmat); - dvec = base0to1(dvec); - Amat = base0to1(Amat); - var i, n, q, - nact, r, - crval = [], iact = [], sol = [], work = [], iter = [], - message; - - meq = meq || 0; - factorized = factorized ? base0to1(factorized) : [undefined, 0]; - bvec = bvec ? base0to1(bvec) : []; - - // In Fortran the array index starts from 1 - n = Dmat.length - 1; - q = Amat[1].length - 1; - - if (!bvec) { - for (i = 1; i <= q; i = i + 1) { - bvec[i] = 0; - } - } - for (i = 1; i <= q; i = i + 1) { - iact[i] = 0; - } - nact = 0; - r = Math.min(n, q); - for (i = 1; i <= n; i = i + 1) { - sol[i] = 0; - } - crval[1] = 0; - for (i = 1; i <= (2 * n + (r * (r + 5)) / 2 + 2 * q + 1); i = i + 1) { - work[i] = 0; - } - for (i = 1; i <= 2; i = i + 1) { - iter[i] = 0; - } - - qpgen2(Dmat, dvec, n, n, sol, crval, Amat, - bvec, n, q, meq, iact, nact, iter, work, factorized); - - message = ""; - if (factorized[1] === 1) { - message = "constraints are inconsistent, no solution!"; - } - if (factorized[1] === 2) { - message = "matrix D in quadratic function is not positive definite!"; - } - - return { - solution: base1to0(sol), - value: base1to0(crval), - unconstrained_solution: base1to0(dvec), - iterations: base1to0(iter), - iact: base1to0(iact), - message: message - }; - } - exports.solveQP = solveQP; - }(numeric)); - /* - Shanti Rao sent me this routine by private email. I had to modify it - slightly to work on Arrays instead of using a Matrix object. - It is apparently translated from http://stitchpanorama.sourceforge.net/Python/svd.py - */ - - numeric.svd= function svd(A) { - var temp; - //Compute the thin SVD from G. H. Golub and C. Reinsch, Numer. Math. 14, 403-420 (1970) - var prec= numeric.epsilon; //Math.pow(2,-52) // assumes double prec - var tolerance= 1.e-64/prec; - var itmax= 50; - var c=0; - var i=0; - var j=0; - var k=0; - var l=0; - - var u= numeric.clone(A); - var m= u.length; - - var n= u[0].length; - - if (m < n) throw "Need more rows than columns" - - var e = new Array(n); - var q = new Array(n); - for (i=0; i b) - return a*Math.sqrt(1.0+(b*b/a/a)) - else if (b == 0.0) - return a - return b*Math.sqrt(1.0+(a*a/b/b)) - } - - //Householder's reduction to bidiagonal form - - var f= 0.0; - var g= 0.0; - var h= 0.0; - var x= 0.0; - var y= 0.0; - var z= 0.0; - var s= 0.0; - - for (i=0; i < n; i++) - { - e[i]= g; - s= 0.0; - l= i+1; - for (j=i; j < m; j++) - s += (u[j][i]*u[j][i]); - if (s <= tolerance) - g= 0.0; - else - { - f= u[i][i]; - g= Math.sqrt(s); - if (f >= 0.0) g= -g; - h= f*g-s; - u[i][i]=f-g; - for (j=l; j < n; j++) - { - s= 0.0; - for (k=i; k < m; k++) - s += u[k][i]*u[k][j]; - f= s/h; - for (k=i; k < m; k++) - u[k][j]+=f*u[k][i]; - } - } - q[i]= g; - s= 0.0; - for (j=l; j < n; j++) - s= s + u[i][j]*u[i][j]; - if (s <= tolerance) - g= 0.0; - else - { - f= u[i][i+1]; - g= Math.sqrt(s); - if (f >= 0.0) g= -g; - h= f*g - s; - u[i][i+1] = f-g; - for (j=l; j < n; j++) e[j]= u[i][j]/h; - for (j=l; j < m; j++) - { - s=0.0; - for (k=l; k < n; k++) - s += (u[j][k]*u[i][k]); - for (k=l; k < n; k++) - u[j][k]+=s*e[k]; - } - } - y= Math.abs(q[i])+Math.abs(e[i]); - if (y>x) - x=y; - } - - // accumulation of right hand gtransformations - for (i=n-1; i != -1; i+= -1) - { - if (g != 0.0) - { - h= g*u[i][i+1]; - for (j=l; j < n; j++) - v[j][i]=u[i][j]/h; - for (j=l; j < n; j++) - { - s=0.0; - for (k=l; k < n; k++) - s += u[i][k]*v[k][j]; - for (k=l; k < n; k++) - v[k][j]+=(s*v[k][i]); - } - } - for (j=l; j < n; j++) - { - v[i][j] = 0; - v[j][i] = 0; - } - v[i][i] = 1; - g= e[i]; - l= i; - } - - // accumulation of left hand transformations - for (i=n-1; i != -1; i+= -1) - { - l= i+1; - g= q[i]; - for (j=l; j < n; j++) - u[i][j] = 0; - if (g != 0.0) - { - h= u[i][i]*g; - for (j=l; j < n; j++) - { - s=0.0; - for (k=l; k < m; k++) s += u[k][i]*u[k][j]; - f= s/h; - for (k=i; k < m; k++) u[k][j]+=f*u[k][i]; - } - for (j=i; j < m; j++) u[j][i] = u[j][i]/g; - } - else - for (j=i; j < m; j++) u[j][i] = 0; - u[i][i] += 1; - } - - // diagonalization of the bidiagonal form - prec= prec*x; - for (k=n-1; k != -1; k+= -1) - { - for (var iteration=0; iteration < itmax; iteration++) - { // test f splitting - var test_convergence = false; - for (l=k; l != -1; l+= -1) - { - if (Math.abs(e[l]) <= prec) - { test_convergence= true; - break - } - if (Math.abs(q[l-1]) <= prec) - break - } - if (!test_convergence) - { // cancellation of e[l] if l>0 - c= 0.0; - s= 1.0; - var l1= l-1; - for (i =l; i= itmax-1) - throw 'Error: no convergence.' - // shift from bottom 2x2 minor - x= q[l]; - y= q[k-1]; - g= e[k-1]; - h= e[k]; - f= ((y-z)*(y+z)+(g-h)*(g+h))/(2.0*h*y); - g= pythag(f,1.0); - if (f < 0.0) - f= ((x-z)*(x+z)+h*(y/(f-g)-h))/x; - else - f= ((x-z)*(x+z)+h*(y/(f+g)-h))/x; - // next QR transformation - c= 1.0; - s= 1.0; - for (i=l+1; i< k+1; i++) - { - g= e[i]; - y= q[i]; - h= s*g; - g= c*g; - z= pythag(f,h); - e[i-1]= z; - c= f/z; - s= h/z; - f= x*c+g*s; - g= -x*s+g*c; - h= y*s; - y= y*c; - for (j=0; j < n; j++) - { - x= v[j][i-1]; - z= v[j][i]; - v[j][i-1] = x*c+z*s; - v[j][i] = -x*s+z*c; - } - z= pythag(f,h); - q[i-1]= z; - c= f/z; - s= h/z; - f= c*g+s*y; - x= -s*g+c*y; - for (j=0; j < m; j++) - { - y= u[j][i-1]; - z= u[j][i]; - u[j][i-1] = y*c+z*s; - u[j][i] = -y*s+z*c; - } - } - e[l]= 0.0; - e[k]= f; - q[k]= x; - } - } - - //vt= transpose(v) - //return (u,q,vt) - for (i=0;i= 0; j--) - { - if (q[j] < q[i]) - { - // writeln(i,'-',j) - c = q[j]; - q[j] = q[i]; - q[i] = c; - for(k=0;k math.pow === pow_strict_f; - - Object.defineProperty(math, 'pow_strict', { - get: is_pow_strict, - set: set_pow_strict, - }); - - math.pow_strict = true; - - - function set_define_e(bool) { - if(bool) - math.config({define_e: true}); - else - math.config({define_e: false}); - } - var get_define_e = () => math.config().define_e!==false; - function set_define_i(bool) { - if(bool) - math.config({define_i: true}); - else - math.config({define_i: false}); - } - var get_define_i = () => math.config().define_i!==false; - function set_define_pi(bool) { - if(bool) - math.config({define_pi: true}); - else - math.config({define_pi: false}); - } - var get_define_pi = () => math.config().define_pi!==false; - - Object.defineProperty(math, 'define_e', { - get: get_define_e, - set: set_define_e, - }); - Object.defineProperty(math, 'define_i', { - get: get_define_i, - set: set_define_i, - }); - Object.defineProperty(math, 'define_pi', { - get: get_define_pi, - set: set_define_pi, - }); - - return math; - } - - // return a new instance of math.js - var math$19 = create$2(); - - function leaves( tree, include_subscripts ) { - if(!Array.isArray(tree)) - return [tree]; - - var operator = tree[0]; - var operands = tree.slice(1); - - if(include_subscripts && operator === '_') { - if(typeof operands[0] === "string" && - ((typeof operands[1] === "string") || (typeof operands[1] === "number"))) - return [operands[0] + "_"+ operands[1]]; - } - - if(operator === "apply") { - operands = tree.slice(2); - } - if(operands.length === 0) - return []; - - return operands.map( function(v,i) { return leaves(v, include_subscripts); } ) - .reduce( function(a,b) { return a.concat(b); } ); - - } - - function variables( expr_or_tree, include_subscripts = false ) { - - var tree = get_tree(expr_or_tree); - - var result = leaves( tree, include_subscripts ); - - result = result.filter( function(v,i) { - return (typeof v === 'string') && - (math$19.define_e || (v !== "e")) && - (math$19.define_pi || (v !== "pi")) && - (math$19.define_i || (v !== "i")); - }); - - result = result.filter(function(itm,i,a){ - return i === result.indexOf(itm); - }); - - return result; - } - - function operators_list( tree ) { - if (!Array.isArray(tree)) - return []; - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === "apply") { - operands = tree.slice(2); - } - if(operands.length === 0) - return [operator]; - - return [operator].concat( - operands.map( function(v,i) { return operators_list(v); } ) - .reduce( function(a,b) { return a.concat(b); } )); - - } - - function operators$1( expr_or_tree ) { - - var tree = get_tree(expr_or_tree); - - var result = operators_list( tree ); - - result = result.filter( function(v,i) { - return (v !== 'apply'); - }); - - result = result.filter(function(itm,i,a){ - return i === result.indexOf(itm); - }); - - return result; - } - - function functions_list( tree ) { - if (typeof tree === 'number') { - return []; - } - - if (typeof tree === 'string') { - return []; - } - - if (typeof tree === 'boolean') { - return []; - } - - var operator = tree[0]; - var operands = tree.slice(1); - - var functions = []; - if(operator === "apply") { - functions = [operands[0]]; - operands = tree.slice(2); - } - - return functions.concat( - operands.map( function(v,i) { return functions_list(v); } ) - .reduce( function(a,b) { return a.concat(b); } )); - - } - - function functions( expr_or_tree ) { - - var tree = get_tree(expr_or_tree); - - var result = functions_list( tree ); - - result = result.filter(function(itm,i,a){ - return i === result.indexOf(itm); - }); - - return result; - } - - var variables$1 = /*#__PURE__*/Object.freeze({ - variables: variables, - operators: operators$1, - functions: functions - }); - - var underscore = createCommonjsModule(function (module, exports) { - // Underscore.js 1.8.3 - // http://underscorejs.org - // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - // Underscore may be freely distributed under the MIT license. - - (function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `exports` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var - push = ArrayProto.push, - slice = ArrayProto.slice, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind, - nativeCreate = Object.create; - - // Naked function reference for surrogate-prototype-swapping. - var Ctor = function(){}; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { - if (obj instanceof _) return obj; - if (!(this instanceof _)) return new _(obj); - this._wrapped = obj; - }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object. - { - if ('object' !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } - - // Current version. - _.VERSION = '1.8.3'; - - // Internal function that returns an efficient (for current engines) version - // of the passed-in callback, to be repeatedly applied in other Underscore - // functions. - var optimizeCb = function(func, context, argCount) { - if (context === void 0) return func; - switch (argCount == null ? 3 : argCount) { - case 1: return function(value) { - return func.call(context, value); - }; - case 2: return function(value, other) { - return func.call(context, value, other); - }; - case 3: return function(value, index, collection) { - return func.call(context, value, index, collection); - }; - case 4: return function(accumulator, value, index, collection) { - return func.call(context, accumulator, value, index, collection); - }; - } - return function() { - return func.apply(context, arguments); - }; - }; - - // A mostly-internal function to generate callbacks that can be applied - // to each element in a collection, returning the desired result — either - // identity, an arbitrary callback, a property matcher, or a property accessor. - var cb = function(value, context, argCount) { - if (value == null) return _.identity; - if (_.isFunction(value)) return optimizeCb(value, context, argCount); - if (_.isObject(value)) return _.matcher(value); - return _.property(value); - }; - _.iteratee = function(value, context) { - return cb(value, context, Infinity); - }; - - // An internal function for creating assigner functions. - var createAssigner = function(keysFunc, undefinedOnly) { - return function(obj) { - var length = arguments.length; - if (length < 2 || obj == null) return obj; - for (var index = 1; index < length; index++) { - var source = arguments[index], - keys = keysFunc(source), - l = keys.length; - for (var i = 0; i < l; i++) { - var key = keys[i]; - if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; - } - } - return obj; - }; - }; - - // An internal function for creating a new object that inherits from another. - var baseCreate = function(prototype) { - if (!_.isObject(prototype)) return {}; - if (nativeCreate) return nativeCreate(prototype); - Ctor.prototype = prototype; - var result = new Ctor; - Ctor.prototype = null; - return result; - }; - - var property = function(key) { - return function(obj) { - return obj == null ? void 0 : obj[key]; - }; - }; - - // Helper for collection methods to determine whether a collection - // should be iterated as an array or as an object - // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength - // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094 - var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; - var getLength = property('length'); - var isArrayLike = function(collection) { - var length = getLength(collection); - return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; - }; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles raw objects in addition to array-likes. Treats all - // sparse array-likes as if they were dense. - _.each = _.forEach = function(obj, iteratee, context) { - iteratee = optimizeCb(iteratee, context); - var i, length; - if (isArrayLike(obj)) { - for (i = 0, length = obj.length; i < length; i++) { - iteratee(obj[i], i, obj); - } - } else { - var keys = _.keys(obj); - for (i = 0, length = keys.length; i < length; i++) { - iteratee(obj[keys[i]], keys[i], obj); - } - } - return obj; - }; - - // Return the results of applying the iteratee to each element. - _.map = _.collect = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length, - results = Array(length); - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - results[index] = iteratee(obj[currentKey], currentKey, obj); - } - return results; - }; - - // Create a reducing function iterating left or right. - function createReduce(dir) { - // Optimized iterator function as using arguments.length - // in the main function will deoptimize the, see #1991. - function iterator(obj, iteratee, memo, keys, index, length) { - for (; index >= 0 && index < length; index += dir) { - var currentKey = keys ? keys[index] : index; - memo = iteratee(memo, obj[currentKey], currentKey, obj); - } - return memo; - } - - return function(obj, iteratee, memo, context) { - iteratee = optimizeCb(iteratee, context, 4); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length, - index = dir > 0 ? 0 : length - 1; - // Determine the initial value if none is provided. - if (arguments.length < 3) { - memo = obj[keys ? keys[index] : index]; - index += dir; - } - return iterator(obj, iteratee, memo, keys, index, length); - }; - } - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. - _.reduce = _.foldl = _.inject = createReduce(1); - - // The right-associative version of reduce, also known as `foldr`. - _.reduceRight = _.foldr = createReduce(-1); - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, predicate, context) { - var key; - if (isArrayLike(obj)) { - key = _.findIndex(obj, predicate, context); - } else { - key = _.findKey(obj, predicate, context); - } - if (key !== void 0 && key !== -1) return obj[key]; - }; - - // Return all the elements that pass a truth test. - // Aliased as `select`. - _.filter = _.select = function(obj, predicate, context) { - var results = []; - predicate = cb(predicate, context); - _.each(obj, function(value, index, list) { - if (predicate(value, index, list)) results.push(value); - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, predicate, context) { - return _.filter(obj, _.negate(cb(predicate)), context); - }; - - // Determine whether all of the elements match a truth test. - // Aliased as `all`. - _.every = _.all = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length; - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - if (!predicate(obj[currentKey], currentKey, obj)) return false; - } - return true; - }; - - // Determine if at least one element in the object matches a truth test. - // Aliased as `any`. - _.some = _.any = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = !isArrayLike(obj) && _.keys(obj), - length = (keys || obj).length; - for (var index = 0; index < length; index++) { - var currentKey = keys ? keys[index] : index; - if (predicate(obj[currentKey], currentKey, obj)) return true; - } - return false; - }; - - // Determine if the array or object contains a given item (using `===`). - // Aliased as `includes` and `include`. - _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) { - if (!isArrayLike(obj)) obj = _.values(obj); - if (typeof fromIndex != 'number' || guard) fromIndex = 0; - return _.indexOf(obj, item, fromIndex) >= 0; - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - var isFunc = _.isFunction(method); - return _.map(obj, function(value) { - var func = isFunc ? method : value[method]; - return func == null ? func : func.apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, _.property(key)); - }; - - // Convenience version of a common use case of `filter`: selecting only objects - // containing specific `key:value` pairs. - _.where = function(obj, attrs) { - return _.filter(obj, _.matcher(attrs)); - }; - - // Convenience version of a common use case of `find`: getting the first object - // containing specific `key:value` pairs. - _.findWhere = function(obj, attrs) { - return _.find(obj, _.matcher(attrs)); - }; - - // Return the maximum element (or element-based computation). - _.max = function(obj, iteratee, context) { - var result = -Infinity, lastComputed = -Infinity, - value, computed; - if (iteratee == null && obj != null) { - obj = isArrayLike(obj) ? obj : _.values(obj); - for (var i = 0, length = obj.length; i < length; i++) { - value = obj[i]; - if (value > result) { - result = value; - } - } - } else { - iteratee = cb(iteratee, context); - _.each(obj, function(value, index, list) { - computed = iteratee(value, index, list); - if (computed > lastComputed || computed === -Infinity && result === -Infinity) { - result = value; - lastComputed = computed; - } - }); - } - return result; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iteratee, context) { - var result = Infinity, lastComputed = Infinity, - value, computed; - if (iteratee == null && obj != null) { - obj = isArrayLike(obj) ? obj : _.values(obj); - for (var i = 0, length = obj.length; i < length; i++) { - value = obj[i]; - if (value < result) { - result = value; - } - } - } else { - iteratee = cb(iteratee, context); - _.each(obj, function(value, index, list) { - computed = iteratee(value, index, list); - if (computed < lastComputed || computed === Infinity && result === Infinity) { - result = value; - lastComputed = computed; - } - }); - } - return result; - }; - - // Shuffle a collection, using the modern version of the - // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). - _.shuffle = function(obj) { - var set = isArrayLike(obj) ? obj : _.values(obj); - var length = set.length; - var shuffled = Array(length); - for (var index = 0, rand; index < length; index++) { - rand = _.random(0, index); - if (rand !== index) shuffled[index] = shuffled[rand]; - shuffled[rand] = set[index]; - } - return shuffled; - }; - - // Sample **n** random values from a collection. - // If **n** is not specified, returns a single random element. - // The internal `guard` argument allows it to work with `map`. - _.sample = function(obj, n, guard) { - if (n == null || guard) { - if (!isArrayLike(obj)) obj = _.values(obj); - return obj[_.random(obj.length - 1)]; - } - return _.shuffle(obj).slice(0, Math.max(0, n)); - }; - - // Sort the object's values by a criterion produced by an iteratee. - _.sortBy = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - return _.pluck(_.map(obj, function(value, index, list) { - return { - value: value, - index: index, - criteria: iteratee(value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria; - var b = right.criteria; - if (a !== b) { - if (a > b || a === void 0) return 1; - if (a < b || b === void 0) return -1; - } - return left.index - right.index; - }), 'value'); - }; - - // An internal function used for aggregate "group by" operations. - var group = function(behavior) { - return function(obj, iteratee, context) { - var result = {}; - iteratee = cb(iteratee, context); - _.each(obj, function(value, index) { - var key = iteratee(value, index, obj); - behavior(result, value, key); - }); - return result; - }; - }; - - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = group(function(result, value, key) { - if (_.has(result, key)) result[key].push(value); else result[key] = [value]; - }); - - // Indexes the object's values by a criterion, similar to `groupBy`, but for - // when you know that your index values will be unique. - _.indexBy = group(function(result, value, key) { - result[key] = value; - }); - - // Counts instances of an object that group by a certain criterion. Pass - // either a string attribute to count by, or a function that returns the - // criterion. - _.countBy = group(function(result, value, key) { - if (_.has(result, key)) result[key]++; else result[key] = 1; - }); - - // Safely create a real, live array from anything iterable. - _.toArray = function(obj) { - if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (isArrayLike(obj)) return _.map(obj, _.identity); - return _.values(obj); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - if (obj == null) return 0; - return isArrayLike(obj) ? obj.length : _.keys(obj).length; - }; - - // Split a collection into two arrays: one whose elements all satisfy the given - // predicate, and one whose elements all do not satisfy the predicate. - _.partition = function(obj, predicate, context) { - predicate = cb(predicate, context); - var pass = [], fail = []; - _.each(obj, function(value, key, obj) { - (predicate(value, key, obj) ? pass : fail).push(value); - }); - return [pass, fail]; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head` and `take`. The **guard** check - // allows it to work with `_.map`. - _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; - if (n == null || guard) return array[0]; - return _.initial(array, array.length - n); - }; - - // Returns everything but the last entry of the array. Especially useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. - _.initial = function(array, n, guard) { - return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); - }; - - // Get the last element of an array. Passing **n** will return the last N - // values in the array. - _.last = function(array, n, guard) { - if (array == null) return void 0; - if (n == null || guard) return array[array.length - 1]; - return _.rest(array, Math.max(0, array.length - n)); - }; - - // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. - // Especially useful on the arguments object. Passing an **n** will return - // the rest N values in the array. - _.rest = _.tail = _.drop = function(array, n, guard) { - return slice.call(array, n == null || guard ? 1 : n); - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, _.identity); - }; - - // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, strict, startIndex) { - var output = [], idx = 0; - for (var i = startIndex || 0, length = getLength(input); i < length; i++) { - var value = input[i]; - if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { - //flatten current level of array or arguments object - if (!shallow) value = flatten(value, shallow, strict); - var j = 0, len = value.length; - output.length += len; - while (j < len) { - output[idx++] = value[j++]; - } - } else if (!strict) { - output[idx++] = value; - } - } - return output; - }; - - // Flatten out an array, either recursively (by default), or just one level. - _.flatten = function(array, shallow) { - return flatten(array, shallow, false); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iteratee, context) { - if (!_.isBoolean(isSorted)) { - context = iteratee; - iteratee = isSorted; - isSorted = false; - } - if (iteratee != null) iteratee = cb(iteratee, context); - var result = []; - var seen = []; - for (var i = 0, length = getLength(array); i < length; i++) { - var value = array[i], - computed = iteratee ? iteratee(value, i, array) : value; - if (isSorted) { - if (!i || seen !== computed) result.push(value); - seen = computed; - } else if (iteratee) { - if (!_.contains(seen, computed)) { - seen.push(computed); - result.push(value); - } - } else if (!_.contains(result, value)) { - result.push(value); - } - } - return result; - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(flatten(arguments, true, true)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. - _.intersection = function(array) { - var result = []; - var argsLength = arguments.length; - for (var i = 0, length = getLength(array); i < length; i++) { - var item = array[i]; - if (_.contains(result, item)) continue; - for (var j = 1; j < argsLength; j++) { - if (!_.contains(arguments[j], item)) break; - } - if (j === argsLength) result.push(item); - } - return result; - }; - - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = flatten(arguments, true, true, 1); - return _.filter(array, function(value){ - return !_.contains(rest, value); - }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - return _.unzip(arguments); - }; - - // Complement of _.zip. Unzip accepts an array of arrays and groups - // each array's elements on shared indices - _.unzip = function(array) { - var length = array && _.max(array, getLength).length || 0; - var result = Array(length); - - for (var index = 0; index < length; index++) { - result[index] = _.pluck(array, index); - } - return result; - }; - - // Converts lists into objects. Pass either a single array of `[key, value]` - // pairs, or two parallel arrays of the same length -- one of keys, and one of - // the corresponding values. - _.object = function(list, values) { - var result = {}; - for (var i = 0, length = getLength(list); i < length; i++) { - if (values) { - result[list[i]] = values[i]; - } else { - result[list[i][0]] = list[i][1]; - } - } - return result; - }; - - // Generator function to create the findIndex and findLastIndex functions - function createPredicateIndexFinder(dir) { - return function(array, predicate, context) { - predicate = cb(predicate, context); - var length = getLength(array); - var index = dir > 0 ? 0 : length - 1; - for (; index >= 0 && index < length; index += dir) { - if (predicate(array[index], index, array)) return index; - } - return -1; - }; - } - - // Returns the first index on an array-like that passes a predicate test - _.findIndex = createPredicateIndexFinder(1); - _.findLastIndex = createPredicateIndexFinder(-1); - - // Use a comparator function to figure out the smallest index at which - // an object should be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iteratee, context) { - iteratee = cb(iteratee, context, 1); - var value = iteratee(obj); - var low = 0, high = getLength(array); - while (low < high) { - var mid = Math.floor((low + high) / 2); - if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; - } - return low; - }; - - // Generator function to create the indexOf and lastIndexOf functions - function createIndexFinder(dir, predicateFind, sortedIndex) { - return function(array, item, idx) { - var i = 0, length = getLength(array); - if (typeof idx == 'number') { - if (dir > 0) { - i = idx >= 0 ? idx : Math.max(idx + length, i); - } else { - length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1; - } - } else if (sortedIndex && idx && length) { - idx = sortedIndex(array, item); - return array[idx] === item ? idx : -1; - } - if (item !== item) { - idx = predicateFind(slice.call(array, i, length), _.isNaN); - return idx >= 0 ? idx + i : -1; - } - for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) { - if (array[idx] === item) return idx; - } - return -1; - }; - } - - // Return the position of the first occurrence of an item in an array, - // or -1 if the item is not included in the array. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex); - _.lastIndexOf = createIndexFinder(-1, _.findLastIndex); - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (stop == null) { - stop = start || 0; - start = 0; - } - step = step || 1; - - var length = Math.max(Math.ceil((stop - start) / step), 0); - var range = Array(length); - - for (var idx = 0; idx < length; idx++, start += step) { - range[idx] = start; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Determines whether to execute a function as a constructor - // or a normal function with the provided arguments - var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { - if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); - var self = baseCreate(sourceFunc.prototype); - var result = sourceFunc.apply(self, args); - if (_.isObject(result)) return result; - return self; - }; - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if - // available. - _.bind = function(func, context) { - if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); - var args = slice.call(arguments, 2); - var bound = function() { - return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); - }; - return bound; - }; - - // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. _ acts - // as a placeholder, allowing any combination of arguments to be pre-filled. - _.partial = function(func) { - var boundArgs = slice.call(arguments, 1); - var bound = function() { - var position = 0, length = boundArgs.length; - var args = Array(length); - for (var i = 0; i < length; i++) { - args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; - } - while (position < arguments.length) args.push(arguments[position++]); - return executeBound(func, bound, this, this, args); - }; - return bound; - }; - - // Bind a number of an object's methods to that object. Remaining arguments - // are the method names to be bound. Useful for ensuring that all callbacks - // defined on an object belong to it. - _.bindAll = function(obj) { - var i, length = arguments.length, key; - if (length <= 1) throw new Error('bindAll must be passed function names'); - for (i = 1; i < length; i++) { - key = arguments[i]; - obj[key] = _.bind(obj[key], obj); - } - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memoize = function(key) { - var cache = memoize.cache; - var address = '' + (hasher ? hasher.apply(this, arguments) : key); - if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); - return cache[address]; - }; - memoize.cache = {}; - return memoize; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ - return func.apply(null, args); - }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = _.partial(_.delay, _, 1); - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. Normally, the throttled function will run - // as much as it can, without ever going more than once per `wait` duration; - // but if you'd like to disable the execution on the leading edge, pass - // `{leading: false}`. To disable execution on the trailing edge, ditto. - _.throttle = function(func, wait, options) { - var context, args, result; - var timeout = null; - var previous = 0; - if (!options) options = {}; - var later = function() { - previous = options.leading === false ? 0 : _.now(); - timeout = null; - result = func.apply(context, args); - if (!timeout) context = args = null; - }; - return function() { - var now = _.now(); - if (!previous && options.leading === false) previous = now; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0 || remaining > wait) { - if (timeout) { - clearTimeout(timeout); - timeout = null; - } - previous = now; - result = func.apply(context, args); - if (!timeout) context = args = null; - } else if (!timeout && options.trailing !== false) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout, args, context, timestamp, result; - - var later = function() { - var last = _.now() - timestamp; - - if (last < wait && last >= 0) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) { - result = func.apply(context, args); - if (!timeout) context = args = null; - } - } - }; - - return function() { - context = this; - args = arguments; - timestamp = _.now(); - var callNow = immediate && !timeout; - if (!timeout) timeout = setTimeout(later, wait); - if (callNow) { - result = func.apply(context, args); - context = args = null; - } - - return result; - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return _.partial(wrapper, func); - }; - - // Returns a negated version of the passed-in predicate. - _.negate = function(predicate) { - return function() { - return !predicate.apply(this, arguments); - }; - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var args = arguments; - var start = args.length - 1; - return function() { - var i = start; - var result = args[start].apply(this, arguments); - while (i--) result = args[i].call(this, result); - return result; - }; - }; - - // Returns a function that will only be executed on and after the Nth call. - _.after = function(times, func) { - return function() { - if (--times < 1) { - return func.apply(this, arguments); - } - }; - }; - - // Returns a function that will only be executed up to (but not including) the Nth call. - _.before = function(times, func) { - var memo; - return function() { - if (--times > 0) { - memo = func.apply(this, arguments); - } - if (times <= 1) func = null; - return memo; - }; - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = _.partial(_.before, 2); - - // Object Functions - // ---------------- - - // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. - var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); - var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', - 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; - - function collectNonEnumProps(obj, keys) { - var nonEnumIdx = nonEnumerableProps.length; - var constructor = obj.constructor; - var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; - - // Constructor is a special case. - var prop = 'constructor'; - if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); - - while (nonEnumIdx--) { - prop = nonEnumerableProps[nonEnumIdx]; - if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { - keys.push(prop); - } - } - } - - // Retrieve the names of an object's own properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = function(obj) { - if (!_.isObject(obj)) return []; - if (nativeKeys) return nativeKeys(obj); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys.push(key); - // Ahem, IE < 9. - if (hasEnumBug) collectNonEnumProps(obj, keys); - return keys; - }; - - // Retrieve all the property names of an object. - _.allKeys = function(obj) { - if (!_.isObject(obj)) return []; - var keys = []; - for (var key in obj) keys.push(key); - // Ahem, IE < 9. - if (hasEnumBug) collectNonEnumProps(obj, keys); - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - var keys = _.keys(obj); - var length = keys.length; - var values = Array(length); - for (var i = 0; i < length; i++) { - values[i] = obj[keys[i]]; - } - return values; - }; - - // Returns the results of applying the iteratee to each element of the object - // In contrast to _.map it returns an object - _.mapObject = function(obj, iteratee, context) { - iteratee = cb(iteratee, context); - var keys = _.keys(obj), - length = keys.length, - results = {}, - currentKey; - for (var index = 0; index < length; index++) { - currentKey = keys[index]; - results[currentKey] = iteratee(obj[currentKey], currentKey, obj); - } - return results; - }; - - // Convert an object into a list of `[key, value]` pairs. - _.pairs = function(obj) { - var keys = _.keys(obj); - var length = keys.length; - var pairs = Array(length); - for (var i = 0; i < length; i++) { - pairs[i] = [keys[i], obj[keys[i]]]; - } - return pairs; - }; - - // Invert the keys and values of an object. The values must be serializable. - _.invert = function(obj) { - var result = {}; - var keys = _.keys(obj); - for (var i = 0, length = keys.length; i < length; i++) { - result[obj[keys[i]]] = keys[i]; - } - return result; - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = createAssigner(_.allKeys); - - // Assigns a given object with all the own properties in the passed-in object(s) - // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) - _.extendOwn = _.assign = createAssigner(_.keys); - - // Returns the first key on an object that passes a predicate test - _.findKey = function(obj, predicate, context) { - predicate = cb(predicate, context); - var keys = _.keys(obj), key; - for (var i = 0, length = keys.length; i < length; i++) { - key = keys[i]; - if (predicate(obj[key], key, obj)) return key; - } - }; - - // Return a copy of the object only containing the whitelisted properties. - _.pick = function(object, oiteratee, context) { - var result = {}, obj = object, iteratee, keys; - if (obj == null) return result; - if (_.isFunction(oiteratee)) { - keys = _.allKeys(obj); - iteratee = optimizeCb(oiteratee, context); - } else { - keys = flatten(arguments, false, false, 1); - iteratee = function(value, key, obj) { return key in obj; }; - obj = Object(obj); - } - for (var i = 0, length = keys.length; i < length; i++) { - var key = keys[i]; - var value = obj[key]; - if (iteratee(value, key, obj)) result[key] = value; - } - return result; - }; - - // Return a copy of the object without the blacklisted properties. - _.omit = function(obj, iteratee, context) { - if (_.isFunction(iteratee)) { - iteratee = _.negate(iteratee); - } else { - var keys = _.map(flatten(arguments, false, false, 1), String); - iteratee = function(value, key) { - return !_.contains(keys, key); - }; - } - return _.pick(obj, iteratee, context); - }; - - // Fill in a given object with default properties. - _.defaults = createAssigner(_.allKeys, true); - - // Creates an object that inherits from the given prototype object. - // If additional properties are provided then they will be added to the - // created object. - _.create = function(prototype, props) { - var result = baseCreate(prototype); - if (props) _.extendOwn(result, props); - return result; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Returns whether an object has a given set of `key:value` pairs. - _.isMatch = function(object, attrs) { - var keys = _.keys(attrs), length = keys.length; - if (object == null) return !length; - var obj = Object(object); - for (var i = 0; i < length; i++) { - var key = keys[i]; - if (attrs[key] !== obj[key] || !(key in obj)) return false; - } - return true; - }; - - - // Internal recursive comparison function for `isEqual`. - var eq = function(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). - if (a === b) return a !== 0 || 1 / a === 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a instanceof _) a = a._wrapped; - if (b instanceof _) b = b._wrapped; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className !== toString.call(b)) return false; - switch (className) { - // Strings, numbers, regular expressions, dates, and booleans are compared by value. - case '[object RegExp]': - // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return '' + a === '' + b; - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. - // Object(NaN) is equivalent to NaN - if (+a !== +a) return +b !== +b; - // An `egal` comparison is performed for other numeric values. - return +a === 0 ? 1 / +a === 1 / b : +a === +b; - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a === +b; - } - - var areArrays = className === '[object Array]'; - if (!areArrays) { - if (typeof a != 'object' || typeof b != 'object') return false; - - // Objects with different constructors are not equivalent, but `Object`s or `Array`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && - _.isFunction(bCtor) && bCtor instanceof bCtor) - && ('constructor' in a && 'constructor' in b)) { - return false; - } - } - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - - // Initializing stack of traversed objects. - // It's done here since we only need them for objects and arrays comparison. - aStack = aStack || []; - bStack = bStack || []; - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] === a) return bStack[length] === b; - } - - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - - // Recursively compare objects and arrays. - if (areArrays) { - // Compare array lengths to determine if a deep comparison is necessary. - length = a.length; - if (length !== b.length) return false; - // Deep compare the contents, ignoring non-numeric properties. - while (length--) { - if (!eq(a[length], b[length], aStack, bStack)) return false; - } - } else { - // Deep compare objects. - var keys = _.keys(a), key; - length = keys.length; - // Ensure that both objects contain the same number of properties before comparing deep equality. - if (_.keys(b).length !== length) return false; - while (length--) { - // Deep compare each member - key = keys[length]; - if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return true; - }; - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b); - }; - - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (obj == null) return true; - if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; - return _.keys(obj).length === 0; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType === 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) === '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - var type = typeof obj; - return type === 'function' || type === 'object' && !!obj; - }; - - // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. - _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { - _['is' + name] = function(obj) { - return toString.call(obj) === '[object ' + name + ']'; - }; - }); - - // Define a fallback version of the method in browsers (ahem, IE < 9), where - // there isn't any inspectable "Arguments" type. - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return _.has(obj, 'callee'); - }; - } - - // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, - // IE 11 (#1621), and in Safari 8 (#1929). - if (typeof /./ != 'function' && typeof Int8Array != 'object') { - _.isFunction = function(obj) { - return typeof obj == 'function' || false; - }; - } - - // Is a given object a finite number? - _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); - }; - - // Is the given value `NaN`? (NaN is the only number which does not equal itself). - _.isNaN = function(obj) { - return _.isNumber(obj) && obj !== +obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Shortcut function for checking if an object has a given property directly - // on itself (in other words, not on a prototype). - _.has = function(obj, key) { - return obj != null && hasOwnProperty.call(obj, key); - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iteratees. - _.identity = function(value) { - return value; - }; - - // Predicate-generating functions. Often useful outside of Underscore. - _.constant = function(value) { - return function() { - return value; - }; - }; - - _.noop = function(){}; - - _.property = property; - - // Generates a function for a given object that returns a given property. - _.propertyOf = function(obj) { - return obj == null ? function(){} : function(key) { - return obj[key]; - }; - }; - - // Returns a predicate for checking whether an object has a given set of - // `key:value` pairs. - _.matcher = _.matches = function(attrs) { - attrs = _.extendOwn({}, attrs); - return function(obj) { - return _.isMatch(obj, attrs); - }; - }; - - // Run a function **n** times. - _.times = function(n, iteratee, context) { - var accum = Array(Math.max(0, n)); - iteratee = optimizeCb(iteratee, context, 1); - for (var i = 0; i < n; i++) accum[i] = iteratee(i); - return accum; - }; - - // Return a random integer between min and max (inclusive). - _.random = function(min, max) { - if (max == null) { - max = min; - min = 0; - } - return min + Math.floor(Math.random() * (max - min + 1)); - }; - - // A (possibly faster) way to get the current timestamp as an integer. - _.now = Date.now || function() { - return new Date().getTime(); - }; - - // List of HTML entities for escaping. - var escapeMap = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '`': '`' - }; - var unescapeMap = _.invert(escapeMap); - - // Functions for escaping and unescaping strings to/from HTML interpolation. - var createEscaper = function(map) { - var escaper = function(match) { - return map[match]; - }; - // Regexes for identifying a key that needs to be escaped - var source = '(?:' + _.keys(map).join('|') + ')'; - var testRegexp = RegExp(source); - var replaceRegexp = RegExp(source, 'g'); - return function(string) { - string = string == null ? '' : '' + string; - return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; - }; - }; - _.escape = createEscaper(escapeMap); - _.unescape = createEscaper(unescapeMap); - - // If the value of the named `property` is a function then invoke it with the - // `object` as context; otherwise, return it. - _.result = function(object, property, fallback) { - var value = object == null ? void 0 : object[property]; - if (value === void 0) { - value = fallback; - } - return _.isFunction(value) ? value.call(object) : value; - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; - - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /(.)^/; - - // Certain characters need to be escaped so that they can be put into a - // string literal. - var escapes = { - "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - var escaper = /\\|'|\r|\n|\u2028|\u2029/g; - - var escapeChar = function(match) { - return '\\' + escapes[match]; - }; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - // NB: `oldSettings` only exists for backwards compatibility. - _.template = function(text, settings, oldSettings) { - if (!settings && oldSettings) settings = oldSettings; - settings = _.defaults({}, settings, _.templateSettings); - - // Combine delimiters into one regular expression via alternation. - var matcher = RegExp([ - (settings.escape || noMatch).source, - (settings.interpolate || noMatch).source, - (settings.evaluate || noMatch).source - ].join('|') + '|$', 'g'); - - // Compile the template source, escaping string literals appropriately. - var index = 0; - var source = "__p+='"; - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { - source += text.slice(index, offset).replace(escaper, escapeChar); - index = offset + match.length; - - if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; - } else if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; - } else if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; - } - - // Adobe VMs need the match returned to produce the correct offest. - return match; - }); - source += "';\n"; - - // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - - source = "var __t,__p='',__j=Array.prototype.join," + - "print=function(){__p+=__j.call(arguments,'');};\n" + - source + 'return __p;\n'; - - try { - var render = new Function(settings.variable || 'obj', '_', source); - } catch (e) { - e.source = source; - throw e; - } - - var template = function(data) { - return render.call(this, data, _); - }; - - // Provide the compiled source as a convenience for precompilation. - var argument = settings.variable || 'obj'; - template.source = 'function(' + argument + '){\n' + source + '}'; - - return template; - }; - - // Add a "chain" function. Start chaining a wrapped Underscore object. - _.chain = function(obj) { - var instance = _(obj); - instance._chain = true; - return instance; - }; - - // OOP - // --------------- - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - - // Helper function to continue chaining intermediate results. - var result = function(instance, obj) { - return instance._chain ? _(obj).chain() : obj; - }; - - // Add your own custom functions to the Underscore object. - _.mixin = function(obj) { - _.each(_.functions(obj), function(name) { - var func = _[name] = obj[name]; - _.prototype[name] = function() { - var args = [this._wrapped]; - push.apply(args, arguments); - return result(this, func.apply(_, args)); - }; - }); - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - var obj = this._wrapped; - method.apply(obj, arguments); - if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; - return result(this, obj); - }; - }); - - // Add all accessor Array functions to the wrapper. - _.each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - return result(this, method.apply(this._wrapped, arguments)); - }; - }); - - // Extracts the result from a wrapped and chained object. - _.prototype.value = function() { - return this._wrapped; - }; - - // Provide unwrapping proxy for some methods used in engine operations - // such as arithmetic and JSON stringification. - _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; - - _.prototype.toString = function() { - return '' + this._wrapped; - }; - - // AMD registration happens at the end for compatibility with AMD loaders - // that may not enforce next-turn semantics on modules. Even though general - // practice for AMD registration is to be anonymous, underscore registers - // as a named module because, like jQuery, it is a base library that is - // popular enough to be bundled in a third party lib, but not be part of - // an AMD load request. Those cases could generate an error when an - // anonymous define() is called outside of a loader request. - if (typeof undefined === 'function' && undefined.amd) { - undefined('underscore', [], function() { - return _; - }); - } - }.call(commonjsGlobal)); - }); - var underscore_1 = underscore._; - - function handleNaNInfinityStringify(key, value) { - if (value !== value) { - return '0/0'; - } - - if (value === 1/0) { - return '1/0'; - } - - if (value === -1/0) { - return '-1/0'; - } - - return value; - } - - function handleNaNInfinityParse(key, value) { - if (value === '0/0') { - return 0/0; - } - - if (value === '1/0') { - return Infinity; - } - - if (value === '-1/0') { - return -1/0; - } - - return value; - } - - function deepClone(s) { - return JSON.parse( - JSON.stringify(s, handleNaNInfinityStringify), - handleNaNInfinityParse); - } - - const equal$2 = function(left, right, { - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - }={}) { - /* - * Return true if left and right are syntactically equal. - * - */ - - if(!(Array.isArray(left) && Array.isArray(right))) { - if((typeof left) !== (typeof right)) - return false; - - if(typeof left === "number" && Number.isFinite(left)) { - let tol = 1E-14; - let minAbs = Math.min(Math.abs(left),Math.abs(right)); - if(allowed_error_is_absolute) { - tol *= minAbs; - if(allowed_error_in_numbers > tol) { - tol = allowed_error_in_numbers; - } - }else { - if(allowed_error_in_numbers > tol) { - tol = allowed_error_in_numbers; - } - tol *= minAbs; - } - return Math.abs(left-right) <= tol; - } - - return (left===right); - } - - var leftOperator = left[0]; - var leftOperands = left.slice(1); - - var rightOperator = right[0]; - var rightOperands = right.slice(1); - - if (leftOperator !== rightOperator) - return false; - - if (leftOperands.length !== rightOperands.length) - return false; - - if(allowed_error_in_numbers > 0 && !include_error_in_number_exponents && leftOperator === "^") { - let baseEqual = equal$2(leftOperands[0], rightOperands[0], { - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - }); - - if(!baseEqual) { - return false; - } - let exponentEqual = equal$2(leftOperands[1], rightOperands[1]); - return exponentEqual; - } - - return underscore.every( underscore.zip( leftOperands, rightOperands ), - function(pair) { - return equal$2(pair[0], pair[1], { - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - }); - }); - }; - - const match = function( tree, pattern, params) { - - /* - * Attempt to match the entire tree to given pattern - * - * Returns - * - object describing the bindings of pattern if the entire tree - * was matched with those bindings - * - false if a match was not found - * - * - * In a pattern: - * - operators much match exactly - * - strings that are designed as variables - * must be bound to a subtree - * - numbers and other strings much exactly match - * - * variables, if defined, specifies which strings in pattern are - * wildcards that can be matched to any subtree - * If defined, variables must be an object with - * key: string from pattern which is a wildcard - * values: must be one of the following - * - true: any subtree matches the wildcard - * - a regular expression: subtree must match regular expression - * (a non-string subtree is first passed to JSON.stringify) - * - a function: takes a tree as an argument and - * returns whether or not that tree is a valid match - * - * If variables is not defined, then all variables from pattern - * will be wildcards that match any subtree - * - * If defined, params is an object with keys - * - allow_permutations: if true, check all permutations of operators - * - allow_implicit_identities: an array of variables from pattern - * that can implicitly match the identity of their enclosing - * operator - * - allow_extended_match: if true, then some tree operands can be skipped - * otherwise, all tree operands must be matched - - */ - - var allow_extended_match=false; - - if(params === undefined) - params = {}; - else { - // don't let extended match parameter propagate - if(params.allow_extended_match) { - allow_extended_match=true; - // copy params to new object - params = Object.assign({}, params); - delete params["allow_extended_match"]; - } - - } - - var variables$$1 = params["variables"]; - if(variables$$1 === undefined) { - variables$$1 = {}; - let vip = variables(pattern); - for(let i=0; i < vip.length;i++ ) { - variables$$1[vip[i]] = true; - } - - // add to params, after copying to new object - params = Object.assign({}, params); - params["variables"] = variables$$1; - } - - if(pattern in variables$$1) { - // check if tree satisfies any conditions for pattern - let condition = variables$$1[pattern]; - if(condition !== true) { - if(condition instanceof RegExp) { - if(typeof tree === 'string') { - if(!tree.match(condition)) - return false; - } - else { - if(!JSON.stringify(tree).match(condition)) - return false; - } - } - else if(typeof variables$$1[pattern] === 'function') { - if(!variables$$1[pattern](tree)) - return false; - } - else { - return false; - } - } - - // record the whole tree as the match to pattern - let result = {}; - result[pattern] = tree; - return result; - } - - if(params.allow_permutations) { - // even though order doesn't matter with permutations - // normalize to default order as it orients operators - // such as inequalities and containments to a direction - // that won't be affected by permutations - tree = default_order(tree); - pattern = default_order(pattern); - } - - // if pattern isn't an array, the tree must be the pattern to match - // (As there are no variables, there is no binding) - if(!Array.isArray(pattern)) { - if (tree === pattern) - return {}; - else - return false; - } - - var treeOperands = allChildren(tree); - var operator=pattern[0]; - var patternOperands = pattern.slice(1); - - // Since pattern is an array, there is no match if tree isn't an array - // of the same or larger length with the same operator - // (unless some pattern variables can be implicitly set to identities) - if (!Array.isArray(tree) || (tree[0] !== operator) - || (treeOperands.length < patternOperands.length)) { - - if(Array.isArray(params.allow_implicit_identities)) { - - let result = matchImplicitIdentity(tree, pattern, params); - if(result) - return result; - } - - // if pattern is a multiplication and - // tree is a unary minus of a multiplication - // convert tree to a muliplication with unary minus on first factor - if(operator === '*' && Array.isArray(tree) && tree[0] === '-' - && Array.isArray(tree[1]) && tree[1][0] === '*') { - treeOperands = allChildren(tree[1]); - treeOperands[0] = ['-', treeOperands[0]]; - } - else - return false; - } - - let result = matchOperands(operator, treeOperands, patternOperands, - params, allow_extended_match); - - if(result) - return result; - - - if(Array.isArray(params.allow_implicit_identities)) - return matchImplicitIdentity([operator].concat(treeOperands), - pattern, params); - else - return false; - }; - - - - function matchOperands(operator, treeOperands, patternOperands, params, - allow_extended_match) { - - // treeOperands will match patternOperands only if - // - each pattern operand can be matched by a tree operand - // (or a group of tree operands) - // - if allow_extended_match, then some tree operands can be skipped - // otherwise, all tree operands must be matched - // - if permutations are allowed (calculated from params and operator) - // patterns can be matched in any order - // otherwise, patterns must be matched in order, possibly skipping - // beginning or ending tree operands (if allow_extended_match) - // - all the resulting bindings are consistent, - // meaning they assigned the same match to any - // repeated placeholder in pattern - - var previous_matches = patternOperands.map(v => Object()); - var nPars = patternOperands.length; - - // TODO: check if commutative - var allow_permutations = false; - if(params.allow_permutations && - (operator === "*" || operator === "+" || operator === "=" - || operator === "and" || operator === "or" || operator === "ne" - || operator === "union" || operator === "intersect")) - allow_permutations=true; - - - function matchOps(treeOpIndicesLeft, patternInd, matches) { - - // max group is the maximum number of tree operands that can be matched by a variable - let max_group = 1; - let max_last_group = 1; - - // only allow multiple matches by variables for associative operators - if(is_associative[operator]) { - max_group = treeOpIndicesLeft.length - (nPars-patternInd-1); - max_last_group = treeOpIndicesLeft.length; } - - if(params.max_group !== undefined) - max_group = (params.max_group < max_group) ? params.max_group - : max_group; - if(params.max_last_group !== undefined) - max_last_group = (params.max_last_group < max_last_group) ? params.max_last_group - : max_last_group; - - - let inds_set; - - if(!allow_extended_match && patternInd === nPars-1) { - // if no extended match, then the last pattern operand - // must match the remaining tree operands - if(treeOpIndicesLeft.length <= max_last_group) { - inds_set = [treeOpIndicesLeft]; - } - else { - return false; - } - } - else if(allow_permutations) { - inds_set = subsets(treeOpIndicesLeft, max_group); - } - else { - inds_set = []; - for(let i=1; i <= max_group; i++) - inds_set.push(treeOpIndicesLeft.slice(0, i)); - - } - - for(let inds of inds_set) { - - let m = previous_matches[patternInd][inds]; - - if(m === undefined) { - - let treeChunk = inds.reduce(function(a,b) { - return a.concat([treeOperands[b]]);}, []); - - if(treeChunk.length > 1) - treeChunk= [operator].concat(treeChunk); - else - treeChunk = treeChunk[0]; - - m = match(treeChunk, patternOperands[patternInd], params); - - previous_matches[patternInd][inds] = m; - - } - - if(!m) - continue; - - // Check consistency of bindings - if (!underscore.every( underscore.intersection( - Object.keys( matches ), - Object.keys( m ) ), - function(k) { - return equal$2(matches[k], m[k]); - })) { - continue; - } - - // combine matches - let combined_matches = Object.assign({}, m); - Object.assign( combined_matches, matches ); - - let treeOpIndices = treeOpIndicesLeft.filter( - v => !inds.includes(v)); - - // if last pattern operand, we're done - if(patternInd === nPars-1) { - let skipped = treeOpIndices.reduce(function(a,b) { - return a.concat([treeOperands[b]]);}, []); - - return {matches: combined_matches, skipped: skipped}; - } - - // attempt to match remaining treeOps - // with remaining pattern operands - let results = matchOps(treeOpIndices, patternInd+1, - combined_matches); - - if(results) { - return results; - } - } - - return false; - } - - var matches = {}; - - // create array of 0, 1, ...., treeOperands.length-1 - var treeIndices = [...Array(treeOperands.length).keys()]; - - if(allow_permutations) { - - let m = matchOps(treeIndices, 0, {}); - - if(!m) - return false; - - matches = m.matches; - if(m.skipped.length > 0) - matches['_skipped'] = m.skipped; - - return matches; - } - else { - let maxSkip = allow_extended_match ? treeOperands.length - nPars : 0; - let skipped_before = []; - let m; - - // without permutations, operands can only be skipped - // at beggining or end - // (matchOps will skip at end but not at beginning - // when permutations are not allowed) - for(let initialSkip=0; initialSkip <= maxSkip; initialSkip++ ) { - - m = matchOps(treeIndices, 0, {}); - - if(m) - break; - - treeIndices = treeIndices.slice(1); - skipped_before.push(treeOperands[initialSkip]); - } - - if(!m) - return false; - - matches = m.matches; - if(m.skipped.length > 0) - matches['_skipped'] = m.skipped; - if(skipped_before.length > 0) - matches['_skipped_before'] = skipped_before; - return matches; - - } - } - - function matchImplicitIdentity(tree, pattern, params) { - - var operator = pattern[0]; - var patternOperands = pattern.slice(1); - - // for now, implement implicit identities just - // for addition, multiplication, and exponents - if(!(operator === '+' || operator === '*' || operator === '^')) - return false; - - // find any pattern operand that is allowed to be an implicit identity - var implicit_identity = null; - for(let i=0; i < patternOperands.length; i++) { - let po = patternOperands[i]; - if(typeof po === 'string' && - params.allow_implicit_identities.includes(po)) { - implicit_identity = po; - break; - } - } - - if(implicit_identity === null) - return false; - - var matches = {}; - - // match implicit_identity to the identity of the operator - if(operator === '+') - matches[implicit_identity] = 0; - else - matches[implicit_identity] = 1; - - // special case where tree beings with unary - - // and pattern is a multiplication where implicit identity is a factor - if(operator === '*' && patternOperands.includes(implicit_identity) - && Array.isArray(tree) && tree[0] === '-') { - matches[implicit_identity] = -1; - tree = tree[1]; - } - - // remove matched variable from pattern - var matched_ind = patternOperands.indexOf(implicit_identity); - patternOperands.splice(matched_ind,1); - - // for exponentiation, only allow for identity in exponent - if(operator === '^' && matched_ind === 0) - return false; - - if(patternOperands.length === 1) { - pattern = patternOperands[0]; - } - else { - pattern = [operator].concat(patternOperands); - } - - var m = match(tree, pattern, params); - - if (m) { - // Check consistency of bindings - if(implicit_identity in m) { - if(!equal$2(m[implicit_identity], matches[implicit_identity])) - return false; - } - Object.assign( matches, m); - } else - return false; - - return matches; - } - - - const substitute = function( pattern, bindings ) { - if (typeof pattern === 'number' || typeof pattern === "boolean") { - return pattern; - } - - if (typeof pattern === 'string') { - if (bindings[pattern] !== undefined) - return deepClone(bindings[pattern]); - - return pattern; - } - - if (Array.isArray(pattern)) { - return [pattern[0]].concat( pattern.slice(1).map( function(p) { - return substitute(p, bindings); - }) ); - } - - return []; - }; - - const transform$2 = function( tree, F ) { - /* - * Transform the tree function F in a bottom-up fashion - * (calling F at children before parents) - * - * F must be be a function that returns a tree - */ - - if (Array.isArray(tree)) { - let new_tree = [tree[0]]; - for( let i=1; i 0; depth-- ) { - old_tree = new_tree; - for(let i=0; i 0 || add_right.length > 0) { - if(Array.isArray(result)) { - if(result[0]===pattern[0]) { - result = result.slice(1); - } - else { - result = [result]; - } - } - result=[pattern[0]].concat( - add_left, result, add_right); - } - - if(params.evaluate_numbers) - result = evaluate_numbers( - result, {max_digits: params.max_digits}); - - return result; - } - else { - return subtree; - } - }); - - } - - if(equal$2(old_tree, new_tree)) { - return new_tree; - } - } - - return new_tree; - }; - - var endsWith = string.endsWith; - var clone$11 = object.clone; - - - function factory$278 (type, config, load, typed, math) { - var add = load(addScalar); - var subtract = load(subtract$1); - var multiply = load(multiplyScalar); - var divide = load(divideScalar); - var pow = load(pow$1); - var abs = load(abs$1); - var fix = load(fix$1); - var round = load(round$1); - var equal = load(equal$1); - var isNumeric = load(isNumeric$1); - var format = load(format$8); - var getTypeOf = load(_typeof$1); - var toNumber = load(number$3); - var Complex = load(Complex_1); - - /** - * A unit can be constructed in the following ways: - * var a = new Unit(value, name); - * var b = new Unit(null, name); - * var c = Unit.parse(str); - * - * Example usage: - * var a = new Unit(5, 'cm'); // 50 mm - * var b = Unit.parse('23 kg'); // 23 kg - * var c = math.in(a, new Unit(null, 'm'); // 0.05 m - * var d = new Unit(9.81, "m/s^2"); // 9.81 m/s^2 - * - * @class Unit - * @constructor Unit - * @param {number | BigNumber | Fraction | Complex | boolean} [value] A value like 5.2 - * @param {string} [name] A unit name like "cm" or "inch", or a derived unit of the form: "u1[^ex1] [u2[^ex2] ...] [/ u3[^ex3] [u4[^ex4]]]", such as "kg m^2/s^2", where each unit appearing after the forward slash is taken to be in the denominator. "kg m^2 s^-2" is a synonym and is also acceptable. Any of the units can include a prefix. - */ - function Unit(value, name) { - if (!(this instanceof Unit)) { - throw new Error('Constructor must be called with the new operator'); - } - - if (!(value == undefined || isNumeric(value) || type.isComplex(value))) { - throw new TypeError('First parameter in Unit constructor must be number, BigNumber, Fraction, Complex, or undefined'); - } - if (name != undefined && (typeof name !== 'string' || name === '')) { - throw new TypeError('Second parameter in Unit constructor must be a string'); - } - - if (name != undefined) { - var u = Unit.parse(name); - this.units = u.units; - this.dimensions = u.dimensions; - } - else { - this.units = [ - { - unit: UNIT_NONE, - prefix: PREFIXES.NONE, // link to a list with supported prefixes - power: 0 - } - ]; - this.dimensions = []; - for(var i=0; i= '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') { - // The grammar branches here. This could either be part of an exponent or the start of a unit that begins with the letter e, such as "4exabytes" - - var tentativeNumber = ''; - var tentativeIndex = index; - - tentativeNumber += c; - next(); - - if (c == '+' || c == '-') { - tentativeNumber += c; - next(); - } - - // Scientific notation MUST be followed by an exponent (otherwise we assume it is not scientific notation) - if (!isDigit(c)) { - // The e or E must belong to something else, so return the number without the e or E. - revert(tentativeIndex); - return number; - } - - // We can now safely say that this is scientific notation. - number = number + tentativeNumber; - while (isDigit(c)) { - number += c; - next(); - } - } - - return number; - } - - function parseUnit() { - var unitName = ''; - - // Alphanumeric characters only; matches [a-zA-Z0-9] - var code = text.charCodeAt(index); - while ( (code >= 48 && code <= 57) || - (code >= 65 && code <= 90) || - (code >= 97 && code <= 122)) { - unitName += c; - next(); - code = text.charCodeAt(index); - } - - // Must begin with [a-zA-Z] - code = unitName.charCodeAt(0); - if ((code >= 65 && code <= 90) || - (code >= 97 && code <= 122)) { - return unitName || null; - } - else { - return null; - } - } - - function parseCharacter(toFind) { - if (c === toFind) { - next(); - return toFind; - } - else { - return null; - } - } - - /** - * Parse a string into a unit. The value of the unit is parsed as number, - * BigNumber, or Fraction depending on the math.js config setting `number`. - * - * Throws an exception if the provided string does not contain a valid unit or - * cannot be parsed. - * @memberof Unit - * @param {string} str A string like "5.2 inch", "4e2 cm/s^2" - * @return {Unit} unit - */ - Unit.parse = function (str, options) { - options = options || {}; - text = str; - index = -1; - c = ''; - - if (typeof text !== 'string') { - throw new TypeError('Invalid argument in Unit.parse, string expected'); - } - - var unit = new Unit(); - unit.units = []; - - var powerMultiplierCurrent = 1; - var expectingUnit = false; - - // A unit should follow this pattern: - // [number] ...[ [*/] unit[^number] ] - // unit[^number] ... [ [*/] unit[^number] ] - - // Rules: - // number is any floating point number. - // unit is any alphanumeric string beginning with an alpha. Units with names like e3 should be avoided because they look like the exponent of a floating point number! - // The string may optionally begin with a number. - // Each unit may optionally be followed by ^number. - // Whitespace or a forward slash is recommended between consecutive units, although the following technically is parseable: - // 2m^2kg/s^2 - // it is not good form. If a unit starts with e, then it could be confused as a floating point number: - // 4erg - - next(); - skipWhitespace(); - - // Optional number at the start of the string - var valueStr = parseNumber(); - var value = null; - if(valueStr) { - if (config.number === 'BigNumber') { - value = new type.BigNumber(valueStr); - } - else if (config.number === 'Fraction') { - value = new type.Fraction(valueStr); - } - else { // number - value = parseFloat(valueStr); - } - - skipWhitespace(); // Whitespace is not required here - - // handle multiplication or division right after the value, like '1/s' - if (parseCharacter('*')) { - powerMultiplierCurrent = 1; - expectingUnit = true; - } - else if (parseCharacter('/')) { - powerMultiplierCurrent = -1; - expectingUnit = true; - } - } - - // Stack to keep track of powerMultipliers applied to each parentheses group - var powerMultiplierStack = []; - - // Running product of all elements in powerMultiplierStack - var powerMultiplierStackProduct = 1; - - while (true) { - skipWhitespace(); - - // Check for and consume opening parentheses, pushing powerMultiplierCurrent to the stack - // A '(' will always appear directly before a unit. - while (c === '(') { - powerMultiplierStack.push(powerMultiplierCurrent); - powerMultiplierStackProduct *= powerMultiplierCurrent; - powerMultiplierCurrent = 1; - next(); - skipWhitespace(); - } - - // Is there something here? - if(c) { - var oldC = c; - var uStr = parseUnit(); - if(uStr == null) { - throw new SyntaxError('Unexpected "' + oldC + '" in "' + text + '" at index ' + index.toString()); - } - } - else { - // End of input. - break; - } - - // Verify the unit exists and get the prefix (if any) - var res = _findUnit(uStr); - if(res == null) { - // Unit not found. - throw new SyntaxError('Unit "' + uStr + '" not found.'); - } - - var power = powerMultiplierCurrent * powerMultiplierStackProduct; - // Is there a "^ number"? - skipWhitespace(); - if (parseCharacter('^')) { - skipWhitespace(); - var p = parseNumber(); - if(p == null) { - // No valid number found for the power! - throw new SyntaxError('In "' + str + '", "^" must be followed by a floating-point number'); - } - power *= p; - } - - // Add the unit to the list - unit.units.push( { - unit: res.unit, - prefix: res.prefix, - power: power - }); - for(var i=0; i 1 || Math.abs(this.units[0].power - 1.0) > 1e-15; - }; - - /** - * Normalize a value, based on its currently set unit(s) - * @memberof Unit - * @param {number | BigNumber | Fraction | boolean} value - * @return {number | BigNumber | Fraction | boolean} normalized value - * @private - */ - Unit.prototype._normalize = function (value) { - var unitValue, unitOffset, unitPower, unitPrefixValue; - var convert; - - if (value == null || this.units.length === 0) { - return value; - } - else if (this._isDerived()) { - // This is a derived unit, so do not apply offsets. - // For example, with J kg^-1 degC^-1 you would NOT want to apply the offset. - var res = value; - convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed - - for(var i=0; i < this.units.length; i++) { - unitValue = convert(this.units[i].unit.value); - unitPrefixValue = convert(this.units[i].prefix.value); - unitPower = convert(this.units[i].power); - res = multiply(res, pow(multiply(unitValue, unitPrefixValue), unitPower)); - } - - return res; - } - else { - // This is a single unit of power 1, like kg or degC - convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed - - unitValue = convert(this.units[0].unit.value); - unitOffset = convert(this.units[0].unit.offset); - unitPrefixValue = convert(this.units[0].prefix.value); - - return multiply(add(value, unitOffset), multiply(unitValue, unitPrefixValue)); - } - }; - - /** - * Denormalize a value, based on its currently set unit(s) - * @memberof Unit - * @param {number} value - * @param {number} [prefixValue] Optional prefix value to be used (ignored if this is a derived unit) - * @return {number} denormalized value - * @private - */ - Unit.prototype._denormalize = function (value, prefixValue) { - var unitValue, unitOffset, unitPower, unitPrefixValue; - var convert; - - if (value == null || this.units.length === 0) { - return value; - } - else if (this._isDerived()) { - // This is a derived unit, so do not apply offsets. - // For example, with J kg^-1 degC^-1 you would NOT want to apply the offset. - // Also, prefixValue is ignored--but we will still use the prefix value stored in each unit, since kg is usually preferable to g unless the user decides otherwise. - var res = value; - convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed - - for (var i = 0; i < this.units.length; i++) { - unitValue = convert(this.units[i].unit.value); - unitPrefixValue = convert(this.units[i].prefix.value); - unitPower = convert(this.units[i].power); - res = divide(res, pow(multiply(unitValue, unitPrefixValue), unitPower)); - } - - return res; - } - else { - // This is a single unit of power 1, like kg or degC - convert = Unit._getNumberConverter(getTypeOf(value)); // convert to Fraction or BigNumber if needed - - unitValue = convert(this.units[0].unit.value); - unitPrefixValue = convert(this.units[0].prefix.value); - unitOffset = convert(this.units[0].unit.offset); - - if (prefixValue == undefined) { - return subtract(divide(divide(value, unitValue), unitPrefixValue), unitOffset); - } - else { - return subtract(divide(divide(value, unitValue), prefixValue), unitOffset); - } - } - }; - - /** - * Find a unit from a string - * @memberof Unit - * @param {string} str A string like 'cm' or 'inch' - * @returns {Object | null} result When found, an object with fields unit and - * prefix is returned. Else, null is returned. - * @private - */ - function _findUnit(str) { - - // First, match units names exactly. For example, a user could define 'mm' as 10^-4 m, which is silly, but then we would want 'mm' to match the user-defined unit. - if(UNITS.hasOwnProperty(str)) { - var unit = UNITS[str]; - var prefix = unit.prefixes['']; - return { - unit: unit, - prefix: prefix - } - } - - for (var name in UNITS) { - if (UNITS.hasOwnProperty(name)) { - if (endsWith(str, name)) { - var unit = UNITS[name]; - var prefixLen = (str.length - name.length); - var prefixName = str.substring(0, prefixLen); - var prefix = unit.prefixes.hasOwnProperty(prefixName) - ? unit.prefixes[prefixName] - : undefined; - if (prefix !== undefined) { - // store unit, prefix, and value - return { - unit: unit, - prefix: prefix - }; - } - } - } - } - - return null; - } - - /** - * Test if the given expression is a unit. - * The unit can have a prefix but cannot have a value. - * @memberof Unit - * @param {string} name A string to be tested whether it is a value less unit. - * The unit can have prefix, like "cm" - * @return {boolean} true if the given string is a unit - */ - Unit.isValuelessUnit = function (name) { - return (_findUnit(name) != null); - }; - - /** - * check if this unit has given base unit - * If this unit is a derived unit, this will ALWAYS return false, since by definition base units are not derived. - * @memberof Unit - * @param {BASE_UNITS | string | undefined} base - */ - Unit.prototype.hasBase = function (base) { - - if(typeof(base) === "string") { - base = BASE_UNITS[base]; - } - - if(!base) - return false; - - - // All dimensions must be the same - for(var i=0; i 1e-12) { - return false; - } - } - return true; - - }; - - /** - * Check if this unit has a base or bases equal to another base or bases - * For derived units, the exponent on each base also must match - * @memberof Unit - * @param {Unit} other - * @return {boolean} true if equal base - */ - Unit.prototype.equalBase = function (other) { - // All dimensions must be the same - for(var i=0; i 1e-12) { - return false; - } - } - return true; - }; - - /** - * Check if this unit equals another unit - * @memberof Unit - * @param {Unit} other - * @return {boolean} true if both units are equal - */ - Unit.prototype.equals = function (other) { - return (this.equalBase(other) && equal(this.value, other.value)); - }; - - /** - * Multiply this unit with another one - * @memberof Unit - * @param {Unit} other - * @return {Unit} product of this unit and the other unit - */ - Unit.prototype.multiply = function (other) { - var res = this.clone(); - - for(var i = 0; i 1e-12) { - if(currentUnitSystem.hasOwnProperty(baseDim)) { - proposedUnitList.push({ - unit: currentUnitSystem[baseDim].unit, - prefix: currentUnitSystem[baseDim].prefix, - power: this.dimensions[i] || 0 - }); - } - else { - missingBaseDim = true; - } - } - } - - // Is the proposed unit list "simpler" than the existing one? - if(proposedUnitList.length < this.units.length && !missingBaseDim) { - // Replace this unit list with the proposed list - this.units = proposedUnitList; - } - } - } - - this.isUnitListSimplified = true; - }; - - Unit.prototype.toSI = function() { - - var ret = this.clone(); - - var proposedUnitList = []; - for(var i=0; i 1e-12) { - if(UNIT_SYSTEMS["si"].hasOwnProperty(baseDim)) { - proposedUnitList.push({ - unit: UNIT_SYSTEMS["si"][baseDim].unit, - prefix: UNIT_SYSTEMS["si"][baseDim].prefix, - power: ret.dimensions[i] || 0 - }); - } - else { - throw new Error("Cannot express custom unit " + baseDim + " in SI units"); - } - } - } - - // Replace this unit list with the proposed list - ret.units = proposedUnitList; - - ret.isUnitListSimplified = true; - - return ret; - }; - - /** - * Get a string representation of the units of this Unit, without the value. - * @memberof Unit - * @return {string} - */ - Unit.prototype.formatUnits = function () { - - // Lazy evaluation of the unit list - this.simplifyUnitListLazy(); - - var strNum = ""; - var strDen = ""; - var nNum = 0; - var nDen = 0; - - for(var i=0; i 0) { - nNum++; - strNum += " " + this.units[i].prefix.name + this.units[i].unit.name; - if(Math.abs(this.units[i].power - 1.0) > 1e-15) { - strNum += "^" + this.units[i].power; - } - } - else if(this.units[i].power < 0) { - nDen++; - } - } - - if(nDen > 0) { - for(var i=0; i 0) { - strDen += " " + this.units[i].prefix.name + this.units[i].unit.name; - if(Math.abs(this.units[i].power + 1.0) > 1e-15) { - strDen += "^" + (-this.units[i].power); - } - } - else { - strDen += " " + this.units[i].prefix.name + this.units[i].unit.name; - strDen += "^" + (this.units[i].power); - } - } - } - } - // Remove leading " " - strNum = strNum.substr(1); - strDen = strDen.substr(1); - - // Add parans for better copy/paste back into the eval, for example, or for better pretty print formatting - if(nNum > 1 && nDen > 0) { - strNum = "(" + strNum + ")"; - } - if(nDen > 1 && nNum > 0) { - strDen = "(" + strDen + ")"; - } - - var str = strNum; - if(nNum > 0 && nDen > 0) { - str += " / "; - } - str += strDen; - - return str; - }; - - /** - * Get a string representation of the Unit, with optional formatting options. - * @memberof Unit - * @param {Object | number | Function} [options] Formatting options. See - * lib/utils/number:format for a - * description of the available - * options. - * @return {string} - */ - Unit.prototype.format = function (options) { - - // Simplfy the unit list, if necessary - this.simplifyUnitListLazy(); - - // Apply some custom logic for handling VA and VAR. The goal is to express the value of the unit as a real value, if possible. Otherwise, use a real-valued unit instead of a complex-valued one. - var isImaginary = false; - var isReal = true; - if(typeof(this.value) !== 'undefined' && this.value !== null && type.isComplex(this.value)) { - // TODO: Make this better, for example, use relative magnitude of re and im rather than absolute - isImaginary = Math.abs(this.value.re) < 1e-14; - isReal = Math.abs(this.value.im) < 1e-14; - } - - for(var i in this.units) { - if(this.units[i].unit) { - if(this.units[i].unit.name === 'VA' && isImaginary) { - this.units[i].unit = UNITS["VAR"]; - } - else if(this.units[i].unit.name === 'VAR' && !isImaginary) { - this.units[i].unit = UNITS["VA"]; - } - } - } - - - // Now apply the best prefix - // Units must have only one unit and not have the fixPrefix flag set - if (this.units.length === 1 && !this.fixPrefix) { - // Units must have integer powers, otherwise the prefix will change the - // outputted value by not-an-integer-power-of-ten - if (Math.abs(this.units[0].power - Math.round(this.units[0].power)) < 1e-14) { - // Apply the best prefix - this.units[0].prefix = this._bestPrefix(); - } - } - - - var value = this._denormalize(this.value); - var str = (this.value !== null) ? format(value, options || {}) : ''; - var unitStr = this.formatUnits(); - if(this.value && type.isComplex(this.value)) { - str = "(" + str + ")"; // Surround complex values with ( ) to enable better parsing - } - if(unitStr.length > 0 && str.length > 0) { - str += " "; - } - str += unitStr; - - return str; - }; - - /** - * Calculate the best prefix using current value. - * @memberof Unit - * @returns {Object} prefix - * @private - */ - Unit.prototype._bestPrefix = function () { - if (this.units.length !== 1) { - throw new Error("Can only compute the best prefix for single units with integer powers, like kg, s^2, N^-1, and so forth!"); - } - if (Math.abs(this.units[0].power - Math.round(this.units[0].power)) >= 1e-14) { - throw new Error("Can only compute the best prefix for single units with integer powers, like kg, s^2, N^-1, and so forth!"); - } - - // find the best prefix value (resulting in the value of which - // the absolute value of the log10 is closest to zero, - // though with a little offset of 1.2 for nicer values: you get a - // sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ... - - // Note: the units value can be any numeric type, but to find the best - // prefix it's enough to work with limited precision of a regular number - // Update: using mathjs abs since we also allow complex numbers - var absValue = this.value !== null ? abs(this.value) : 0; - var absUnitValue = abs(this.units[0].unit.value); - var bestPrefix = this.units[0].prefix; - if (absValue === 0) { - return bestPrefix; - } - var power = this.units[0].power; - var bestDiff = Math.log(absValue / Math.pow(bestPrefix.value * absUnitValue, power)) / Math.LN10 - 1.2; - if(bestDiff > -2.200001 && bestDiff < 1.800001) return bestPrefix; // Allow the original prefix - bestDiff = Math.abs(bestDiff); - var prefixes = this.units[0].unit.prefixes; - for (var p in prefixes) { - if (prefixes.hasOwnProperty(p)) { - var prefix = prefixes[p]; - if (prefix.scientific) { - - var diff = Math.abs( - Math.log(absValue / Math.pow(prefix.value * absUnitValue, power)) / Math.LN10 - 1.2); - - if (diff < bestDiff - || (diff === bestDiff && prefix.name.length < bestPrefix.name.length)) { - // choose the prefix with the smallest diff, or if equal, choose the one - // with the shortest name (can happen with SHORTLONG for example) - bestPrefix = prefix; - bestDiff = diff; - } - } - } - } - - return bestPrefix; - }; - - /** - * Returns an array of units whose sum is equal to this unit - * @memberof Unit - * @param {Array} [parts] An array of strings or valueless units. - * - * Example: - * - * var u = new Unit(1, 'm'); - * u.splitUnit(['feet', 'inch']); - * [ 3 feet, 3.3700787401575 inch ] - * - * @return {Array} An array of units. - */ - Unit.prototype.splitUnit = function(parts) { - - var x = this.clone(); - var ret = []; - for(var i=0; i= '0' && c <= '9'); - }; - - if(i === 0 && !isValidAlpha(c)) - throw new Error('Invalid unit name (must begin with alpha character): "' + name + '"'); - - if(i > 0 && !( isValidAlpha(c) - || isDigit(c))) - throw new Error('Invalid unit name (only alphanumeric characters are allowed): "' + name + '"'); - - } - } - - /** - * Wrapper around createUnitSingle. - * Example: - * createUnit({ - * foo: { }, - * bar: { - * definition: 'kg/foo', - * aliases: ['ba', 'barr', 'bars'], - * offset: 200 - * }, - * baz: '4 bar' - * }, - * { - * override: true; - * }); - * @param {object} obj Object map. Each key becomes a unit which is defined by its value. - * @param {object} options - */ - Unit.createUnit = function(obj, options) { - - if(typeof(obj) !== 'object') { - throw new TypeError("createUnit expects first parameter to be of type 'Object'"); - } - - // Remove all units and aliases we are overriding - if(options && options.override) { - for(var key in obj) { - if(obj.hasOwnProperty(key)) { - Unit.deleteUnit(key); - } - if(obj[key].aliases) { - for(var i=0; i foo_STUFF, or the essence of foo - if(BASE_DIMENSIONS.indexOf(baseName) >= 0) { - throw new Error('Cannot create new base unit "' + name + '": a base unit with that name already exists (and cannot be overridden)'); - } - BASE_DIMENSIONS.push(baseName); - - // Push 0 onto existing base units - for(var b in BASE_UNITS) { - if(BASE_UNITS.hasOwnProperty(b)) { - BASE_UNITS[b].dimensions[BASE_DIMENSIONS.length-1] = 0; - } - } - - // Add the new base unit - var newBaseUnit = { dimensions: [] }; - for(var i=0; i 1e-12) { - match = false; - break; - } - } - if(match) { - anyMatch = true; - break; - } - } - } - if(!anyMatch) { - var baseName = name + "_STUFF"; // foo --> foo_STUFF, or the essence of foo - // Add the new base unit - var newBaseUnit = { dimensions: defUnit.dimensions.slice(0) }; - newBaseUnit.key = baseName; - BASE_UNITS[baseName] = newBaseUnit; - - currentUnitSystem[baseName] = { - unit: newUnit, - prefix: PREFIXES.NONE[''] - }; - - newUnit.base = baseName; - } - } - - Unit.UNITS[name] = newUnit; - - for (var i=0; i) - * - * Example: - * - * math.splitUnit(new Unit(1, 'm'), ['feet', 'inch']); - * // [ 3 feet, 3.3700787401575 inch ] - * - * See also: - * - * unit - * - * @param {Array} [parts] An array of strings or valueless units. - * @return {Array} An array of units. - */ - var splitUnit = typed('splitUnit', { - 'Unit, Array': function(unit, parts) { - return unit.splitUnit(parts); - } - }); - - return splitUnit; - - } - - var name$268 = 'splitUnit'; - var factory_1$280 = factory$281; - - var splitUnit$1 = { - name: name$268, - factory: factory_1$280 - }; - - var lazy$5 = object.lazy; - - - function factory$282 (type, config, load, typed, math) { - - // helper function to create a unit with a fixed prefix - function fixedUnit(str) { - var unit = type.Unit.parse(str); - unit.fixPrefix = true; - return unit; - } - - // Source: http://www.wikiwand.com/en/Physical_constant - - // Universal constants - setLazyConstant$1(math, 'speedOfLight', function () {return fixedUnit('299792458 m s^-1')}); - setLazyConstant$1(math, 'gravitationConstant', function () {return fixedUnit('6.6738480e-11 m^3 kg^-1 s^-2')}); - setLazyConstant$1(math, 'planckConstant', function () {return fixedUnit('6.626069311e-34 J s')}); - setLazyConstant$1(math, 'reducedPlanckConstant',function () {return fixedUnit('1.05457172647e-34 J s')}); - - // Electromagnetic constants - setLazyConstant$1(math, 'magneticConstant', function () {return fixedUnit('1.2566370614e-6 N A^-2')}); - setLazyConstant$1(math, 'electricConstant', function () {return fixedUnit('8.854187817e-12 F m^-1')}); - setLazyConstant$1(math, 'vacuumImpedance', function () {return fixedUnit('376.730313461 ohm')}); - setLazyConstant$1(math, 'coulomb', function () {return fixedUnit('8.9875517873681764e9 N m^2 C^-2')}); - setLazyConstant$1(math, 'elementaryCharge', function () {return fixedUnit('1.60217656535e-19 C')}); - setLazyConstant$1(math, 'bohrMagneton', function () {return fixedUnit('9.2740096820e-24 J T^-1')}); - setLazyConstant$1(math, 'conductanceQuantum', function () {return fixedUnit('7.748091734625e-5 S')}); - setLazyConstant$1(math, 'inverseConductanceQuantum', function () {return fixedUnit('12906.403721742 ohm')}); - setLazyConstant$1(math, 'magneticFluxQuantum', function () {return fixedUnit('2.06783375846e-15 Wb')}); - setLazyConstant$1(math, 'nuclearMagneton', function () {return fixedUnit('5.0507835311e-27 J T^-1')}); - setLazyConstant$1(math, 'klitzing', function () {return fixedUnit('25812.807443484 ohm')}); - //setLazyConstant(math, 'josephson', function () {return fixedUnit('4.8359787011e-14 Hz V^-1')}); // TODO: support for Hz needed - - // Atomic and nuclear constants - setLazyConstant$1(math, 'bohrRadius', function () {return fixedUnit('5.291772109217e-11 m')}); - setLazyConstant$1(math, 'classicalElectronRadius', function () {return fixedUnit('2.817940326727e-15 m')}); - setLazyConstant$1(math, 'electronMass', function () {return fixedUnit('9.1093829140e-31 kg')}); - setLazyConstant$1(math, 'fermiCoupling', function () {return fixedUnit('1.1663645e-5 GeV^-2')}); - setLazyConstant$1(math, 'fineStructure', function () {return 7.297352569824e-3}); - setLazyConstant$1(math, 'hartreeEnergy', function () {return fixedUnit('4.3597443419e-18 J')}); - setLazyConstant$1(math, 'protonMass', function () {return fixedUnit('1.67262177774e-27 kg')}); - setLazyConstant$1(math, 'deuteronMass', function () {return fixedUnit('3.3435830926e-27 kg')}); - setLazyConstant$1(math, 'neutronMass', function () {return fixedUnit('1.6749271613e-27 kg')}); - setLazyConstant$1(math, 'quantumOfCirculation', function () {return fixedUnit('3.636947552024e-4 m^2 s^-1')}); - setLazyConstant$1(math, 'rydberg', function () {return fixedUnit('10973731.56853955 m^-1')}); - setLazyConstant$1(math, 'thomsonCrossSection', function () {return fixedUnit('6.65245873413e-29 m^2')}); - setLazyConstant$1(math, 'weakMixingAngle', function () {return 0.222321}); - setLazyConstant$1(math, 'efimovFactor', function () {return 22.7}); - - // Physico-chemical constants - setLazyConstant$1(math, 'atomicMass', function () {return fixedUnit('1.66053892173e-27 kg')}); - setLazyConstant$1(math, 'avogadro', function () {return fixedUnit('6.0221412927e23 mol^-1')}); - setLazyConstant$1(math, 'boltzmann', function () {return fixedUnit('1.380648813e-23 J K^-1')}); - setLazyConstant$1(math, 'faraday', function () {return fixedUnit('96485.336521 C mol^-1')}); - setLazyConstant$1(math, 'firstRadiation', function () {return fixedUnit('3.7417715317e-16 W m^2')}); - // setLazyConstant(math, 'spectralRadiance', function () {return fixedUnit('1.19104286953e-16 W m^2 sr^-1')}); // TODO spectralRadiance - setLazyConstant$1(math, 'loschmidt', function () {return fixedUnit('2.686780524e25 m^-3')}); - setLazyConstant$1(math, 'gasConstant', function () {return fixedUnit('8.314462175 J K^-1 mol^-1')}); - setLazyConstant$1(math, 'molarPlanckConstant', function () {return fixedUnit('3.990312717628e-10 J s mol^-1')}); - setLazyConstant$1(math, 'molarVolume', function () {return fixedUnit('2.241396820e-10 m^3 mol^-1')}); - setLazyConstant$1(math, 'sackurTetrode', function () {return -1.164870823}); - setLazyConstant$1(math, 'secondRadiation', function () {return fixedUnit('1.438777013e-2 m K')}); - setLazyConstant$1(math, 'stefanBoltzmann', function () {return fixedUnit('5.67037321e-8 W m^-2 K^-4')}); - setLazyConstant$1(math, 'wienDisplacement', function () {return fixedUnit('2.897772126e-3 m K')}); - - // Adopted values - setLazyConstant$1(math, 'molarMass', function () {return fixedUnit('1e-3 kg mol^-1')}); - setLazyConstant$1(math, 'molarMassC12', function () {return fixedUnit('1.2e-2 kg mol^-1')}); - setLazyConstant$1(math, 'gravity', function () {return fixedUnit('9.80665 m s^-2')}); - // atm is defined in Unit.js - - // Natural units - setLazyConstant$1(math, 'planckLength', function () {return fixedUnit('1.61619997e-35 m')}); - setLazyConstant$1(math, 'planckMass', function () {return fixedUnit('2.1765113e-8 kg')}); - setLazyConstant$1(math, 'planckTime', function () {return fixedUnit('5.3910632e-44 s')}); - setLazyConstant$1(math, 'planckCharge', function () {return fixedUnit('1.87554595641e-18 C')}); - setLazyConstant$1(math, 'planckTemperature', function () {return fixedUnit('1.41683385e+32 K')}); - - } - - // create a lazy constant in both math and mathWithTransform - function setLazyConstant$1 (math, name, resolver) { - lazy$5(math, name, resolver); - lazy$5(math.expression.mathWithTransform, name, resolver); - } - - var factory_1$281 = factory$282; - var lazy_1$2 = false; // no lazy loading of constants, the constants themselves are lazy when needed - var math$21 = true; // request access to the math namespace - - var physicalConstants = { - factory: factory_1$281, - lazy: lazy_1$2, - math: math$21 - }; - - var unit$3 = [ - // type - Unit, - - // construction function - unit$2, - - // create new units - createUnit$1, - - // split units - splitUnit$1, - - // physical constants - physicalConstants - ]; - - var type$1 = [ - bignumber$1, - boolean_1, - chain$1, - complex$3, - fraction$3, - matrix$1, - number$3, - resultset, - string$6, - unit$3 - ]; - - var version$1 = '4.4.2'; - - function factory$283 (type, config, load, typed, math) { - // listen for changed in the configuration, automatically reload - // constants when needed - math.on('config', function (curr, prev) { - if (curr.number !== prev.number) { - factory$283(type, config, load, typed, math); - } - }); - - setConstant$1(math, 'true', true); - setConstant$1(math, 'false', false); - setConstant$1(math, 'null', null); - setConstant$1(math, 'uninitialized', 'Error: Constant uninitialized is removed since v4.0.0. Use null instead'); - - if (config.number === 'BigNumber') { - setConstant$1(math, 'Infinity', new type.BigNumber(Infinity)); - setConstant$1(math, 'NaN', new type.BigNumber(NaN)); - - setLazyConstant$2(math, 'pi', function () {return constants.pi(type.BigNumber)}); - setLazyConstant$2(math, 'tau', function () {return constants.tau(type.BigNumber)}); - setLazyConstant$2(math, 'e', function () {return constants.e(type.BigNumber)}); - setLazyConstant$2(math, 'phi', function () {return constants.phi(type.BigNumber)}); // golden ratio, (1+sqrt(5))/2 - - // uppercase constants (for compatibility with built-in Math) - setLazyConstant$2(math, 'E', function () {return math.e;}); - setLazyConstant$2(math, 'LN2', function () {return new type.BigNumber(2).ln();}); - setLazyConstant$2(math, 'LN10', function () {return new type.BigNumber(10).ln()}); - setLazyConstant$2(math, 'LOG2E', function () {return new type.BigNumber(1).div(new type.BigNumber(2).ln());}); - setLazyConstant$2(math, 'LOG10E', function () {return new type.BigNumber(1).div(new type.BigNumber(10).ln())}); - setLazyConstant$2(math, 'PI', function () {return math.pi}); - setLazyConstant$2(math, 'SQRT1_2', function () {return new type.BigNumber('0.5').sqrt()}); - setLazyConstant$2(math, 'SQRT2', function () {return new type.BigNumber(2).sqrt()}); - } - else { - setConstant$1(math, 'Infinity', Infinity); - setConstant$1(math, 'NaN', NaN); - - setConstant$1(math, 'pi', Math.PI); - setConstant$1(math, 'tau', Math.PI * 2); - setConstant$1(math, 'e', Math.E); - setConstant$1(math, 'phi', 1.61803398874989484820458683436563811772030917980576286213545); // golden ratio, (1+sqrt(5))/2 - - // uppercase constants (for compatibility with built-in Math) - setConstant$1(math, 'E', math.e); - setConstant$1(math, 'LN2', Math.LN2); - setConstant$1(math, 'LN10', Math.LN10); - setConstant$1(math, 'LOG2E', Math.LOG2E); - setConstant$1(math, 'LOG10E', Math.LOG10E); - setConstant$1(math, 'PI', math.pi); - setConstant$1(math, 'SQRT1_2', Math.SQRT1_2); - setConstant$1(math, 'SQRT2', Math.SQRT2); - } - - // complex i - setConstant$1(math, 'i', type.Complex.I); - - // meta information - setConstant$1(math, 'version', version$1); - } - - // create a constant in both math and mathWithTransform - function setConstant$1(math, name, value) { - math[name] = value; - math.expression.mathWithTransform[name] = value; - } - - // create a lazy constant in both math and mathWithTransform - function setLazyConstant$2 (math, name, resolver) { - object.lazy(math, name, resolver); - object.lazy(math.expression.mathWithTransform, name, resolver); - } - - var factory_1$282 = factory$283; - var lazy$6 = false; // no lazy loading of constants, the constants themselves are lazy when needed - var math$22 = true; // request access to the math namespace - - var constants$2 = { - factory: factory_1$282, - lazy: lazy$6, - math: math$22 - }; - - var lib$1 = [ - type$1, // data types (Matrix, Complex, Unit, ...) - constants$2, // constants - expression, // expression parsing - _function$3, // functions - json, // serialization utility (math.json.reviver) - error // errors - ]; - - /** - * math.js factory function. Creates a new instance of math.js - * - * @param {Object} [config] Available configuration options: - * {number} epsilon - * Minimum relative difference between two - * compared values, used by all comparison functions. - * {string} matrix - * A string 'matrix' (default) or 'array'. - * {string} number - * A string 'number' (default), 'bignumber', or - * 'fraction' - * {number} precision - * The number of significant digits for BigNumbers. - * Not applicable for Numbers. - * {boolean} predictable - * Predictable output type of functions. When true, - * output type depends only on the input types. When - * false (default), output type can vary depending - * on input values. For example `math.sqrt(-4)` - * returns `complex('2i')` when predictable is false, and - * returns `NaN` when true. - */ - function create$3 (config) { - // create a new math.js instance - var math = core$1.create(config); - math.create = create$3; - - // import data types, functions, constants, expression parser, etc. - math['import'](lib$1); - - return math; - } - - // return a new instance of math.js - var mathjs = create$3(); - - var node$1 = mathjs.expression.node; - - const operators$2 = { - "+": function(operands) { return new node$1.OperatorNode('+', 'add', operands);}, - "*": function(operands) { return new node$1.OperatorNode('*', 'multiply', operands);}, - "/": function(operands) { return new node$1.OperatorNode('/', 'divide', operands);}, - "-": function(operands) { return new node$1.OperatorNode('-', 'unaryMinus', [operands[0]]);}, - "^": function(operands) { return new node$1.OperatorNode('^', 'pow', operands);}, - //"prime": function(operands) { return operands[0] + "'"; }, - //"tuple": function(operands) { return '\\left( ' + operands.join( ', ' ) + ' \\right)';}, - //"array": function(operands) { return '\\left[ ' + operands.join( ', ' ) + ' \\right]';}, - //"set": function(operands) { return '\\left\\{ ' + operands.join( ', ' ) + ' \\right\\}';}, - "vector": function(operands) { return new node$1.ArrayNode(operands);}, - //"interval": function(operands) { return '\\left( ' + operands.join( ', ' ) + ' \\right)';}, - "and": function(operands) { return new node$1.OperatorNode('and', 'and', operands);}, - "or": function(operands) { return new node$1.OperatorNode('or', 'or', operands);}, - "not": function(operands) { return new node$1.OperatorNode('not', 'not', [operands[0]]);}, - "<": function(operands) { return new node$1.OperatorNode('<', 'smaller', operands);}, - ">": function(operands) { return new node$1.OperatorNode('>', 'larger', operands);}, - "le": function(operands) { return new node$1.OperatorNode('<=', 'smallerEq', operands);}, - "ge": function(operands) { return new node$1.OperatorNode('>=', 'largerEq', operands);}, - "ne": function(operands) { return new node$1.OperatorNode('!=', 'unequal', operands);}, - //"union": function (operands) { return operands.join(' \\cup '); }, - //"intersect": function (operands) { return operands.join(' \\cap '); }, - }; - - class astToMathjs { - constructor({ mathjs: mathjs$$1 = null } = {}) { - if(mathjs$$1) - node$1 = mathjs$$1.expression.node; - } - - convert(tree) { - if (typeof tree === 'number' ) { - if(Number.isFinite(tree)) - return new node$1.ConstantNode(tree); - if(Number.isNaN(tree)) - return new node$1.SymbolNode('NaN'); - if(tree < 0) - return operators$2['-']([new node$1.SymbolNode('Infinity')]); - return new node$1.SymbolNode('Infinity'); - } - - if (typeof tree === 'string') { - return new node$1.SymbolNode(tree); - } - - if (typeof tree === 'boolean') - throw Error("no support for boolean"); - - if (!Array.isArray(tree)) - throw Error("Invalid ast"); - - const operator = tree[0]; - const operands = tree.slice(1); - - if(operator === "apply") { - if(typeof operands[0] !== 'string') - throw Error("Non string functions not implemented for conversion to mathjs"); - - if(operands[0] === "factorial") - return new node$1.OperatorNode('!', 'factorial',[this.convert(operands[1])]); - - const f = new node$1.SymbolNode(operands[0]); - const args = operands[1]; - let f_args; - - if (args[0] === 'tuple') - f_args = args.slice(1).map(function(v,i) { return this.convert(v); }.bind(this)); - else - f_args = [this.convert(args)]; - - return new node$1.FunctionNode(f, f_args); - } - - if(operator === 'lts' || operator === 'gts') { - const args = operands[0]; - const strict = operands[1]; - - if(args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); - - const arg_nodes = args.slice(1).map(function(v,i) { return this.convert(v); }.bind(this)); - - let comparisons = []; - for(let i=1; i< args.length-1; i++) { - if(strict[i]) { - if(operator === 'lts') - comparisons.push(new node$1.OperatorNode('<', 'smaller', arg_nodes.slice(i-1, i+1))); - else - comparisons.push(new node$1.OperatorNode('>', 'larger', arg_nodes.slice(i-1, i+1))); - }else{ - if(operator === 'lts') - comparisons.push(new node$1.OperatorNode('<=', 'smallerEq', arg_nodes.slice(i-1, i+1))); - else - comparisons.push(new node$1.OperatorNode('>=', 'largerEq', arg_nodes.slice(i-1, i+1))); - } - } - let result = new node$1.OperatorNode('and', 'and', comparisons.slice(0,2)); - for(let i=2; i=', 'largerEq', [x,a])); - else - comparisons.push(new node$1.OperatorNode('>', 'larger', [x,a])); - if(closed[2]) - comparisons.push(new node$1.OperatorNode('<=', 'smallerEq', [x,b])); - else - comparisons.push(new node$1.OperatorNode('<', 'smaller', [x,b])); - - let result = new node$1.OperatorNode('and', 'and', comparisons); - - if(operator === 'notin' || operator === 'notni') - result = new node$1.OperatorNode('not', 'not', [result]); - - return result; - } - - if(operator === 'subset' || operator === 'notsubset' || - operator === 'superset' || operator === 'notsuperset') { - - let big, small; - if(operator === 'subset' || operator === 'notsubset') { - small = operands[0]; - big = operands[1]; - }else{ - small = operands[1]; - big = operands[0]; - } - if(small[0] !== 'interval' || big[0] !== 'interval') - throw Error("Set containment of non-intervals not implemented for conversion to mathjs"); - - let small_args = small[1]; - let small_closed = small[2]; - let big_args = big[1]; - let big_closed = big[2]; - if(small_args[0] !== 'tuple' || small_closed[0] !== 'tuple' || - big_args[0] !== 'tuple' || big_closed[0] !== 'tuple') - throw Error("Badly formed ast"); - - let small_a = this.convert(small_args[1]); - let small_b = this.convert(small_args[2]); - let big_a = this.convert(big_args[1]); - let big_b = this.convert(big_args[2]); - - let comparisons = []; - if(small_closed[1] && !big_closed[1]) - comparisons.push(new node$1.OperatorNode('>', 'larger',[small_a,big_a])); - else - comparisons.push(new node$1.OperatorNode('>=', 'largerEq',[small_a,big_a])); - - if(small_closed[2] && !big_closed[2]) - comparisons.push(new node$1.OperatorNode('<', 'smaller',[small_b,big_b])); - else - comparisons.push(new node$1.OperatorNode('<=', 'smallerEq',[small_b,big_b])); - - let result = new node$1.OperatorNode('and', 'and', comparisons); - - if(operator === 'notsubset' || operator === 'notsuperset') - result = new node$1.OperatorNode('not', 'not', [result]); - - return result; - } - - if(operator === 'matrix') { - // Convert matrices into nested array nodes - // Will become matrix on eval - - let size = operands[0]; - let nrows = size[1]; - let ncols = size[2]; - - let entries = operands[1]; - - if(!Number.isInteger(nrows) || !Number.isInteger(ncols)) - throw Error('Matrix must have integer dimensions'); - - let result = []; - - for(let i=1; i <= nrows; i++) { - let row = []; - for(let j=1; j <= ncols; j++) { - row.push(this.convert(entries[i][j])); - } - result.push(new node$1.ArrayNode(row)); - } - - return new node$1.ArrayNode(result); - - } - - if (operator in operators$2) { - return operators$2[operator]( - operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); - } - - throw Error("Operator " + operator + " not implemented for conversion to mathjs"); - - } - - - } - - var function_normalizations = { - ln: 'log', - arccos: 'acos', - arccosh: 'acosh', - arcsin: 'asin', - arcsinh: 'asinh', - arctan: 'atan', - arctanh: 'atanh', - arcsec: 'asec', - arcsech: 'asech', - arccsc: 'acsc', - arccsch: 'acsch', - arccot: 'acot', - arccoth: 'acoth', - cosec: 'csc', - }; - - function normalize_function_names(expr_or_tree) { - // replace "ln" with "log" - // "arccos" with "acos", etc. - // e^x with exp(x) - // sqrt(x) with x^0.5 - - var tree = get_tree(expr_or_tree); - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === 'apply') { - if (operands[0] === 'sqrt') { - return ['^', normalize_function_names(operands[1]), 0.5]; - } - - var result = normalize_function_names_sub(operands[0]); - result = ['apply', result]; - - var args = operands.slice(1).map(function (v) { - return normalize_function_names(v); - }); - - if (args.length > 1) - args = ['tuple'].concat(args); - else - args = args[0]; - - result.push(args); - - return result; - } - - if (operator === '^' && operands[0] === 'e' && math$19.define_e) - return ['apply', 'exp', normalize_function_names(operands[1])]; - - return [operator].concat(operands.map(function (v) { - return normalize_function_names(v) - })); - } - - function normalize_function_names_sub(tree) { - - if (typeof tree === 'string') { - if (tree in function_normalizations) - return function_normalizations[tree]; - return tree; - } - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - - var result = [operator].concat(operands.map(function (v) { - return normalize_function_names_sub(v); - })); - - return result; - } - - - - function normalize_applied_functions(expr_or_tree) { - // normalize applied functions - // so that primes and powers occur outside function application - - var tree = get_tree(expr_or_tree); - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === 'apply') { - let result = strip_function_names(operands[0]); - let f_applied = ['apply', result.tree, operands[1]]; - for (let i = 0; i < result.n_primes; i++) - f_applied = ['prime', f_applied]; - - if (result.exponent !== undefined) - f_applied = ['^', f_applied, result.exponent]; - - return f_applied - } - - var result = [operator].concat(operands.map(function (v, i) { return normalize_applied_functions(v); })); - return result; - } - - - function strip_function_names(tree) { - // strip primes and powers off tree - - if (!Array.isArray(tree)) - return { tree: tree, n_primes: 0 }; - - var operator = tree[0]; - var operands = tree.slice(1); - - - if (operator === '^') { - let result = strip_function_names(operands[0]); - let exponent = normalize_applied_functions(operands[1]); - - result.exponent = exponent; - return result; - } - - if (operator === "prime") { - let result = strip_function_names(operands[0]); - result.n_primes += 1; - return result; - } - - return { tree: normalize_applied_functions(tree), n_primes: 0 }; - } - - - function substitute_abs(expr_or_tree) { - - var tree = get_tree(expr_or_tree); - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === "apply" && operands[0] === 'abs') { - return ['^', ['^', substitute_abs(operands[1]), 2], 0.5]; - } - - return [operator].concat(operands.map(function (v) { - return substitute_abs(v); - })); - } - - - function constants_to_floats(expr_or_tree) { - - var tree = get_tree(expr_or_tree); - - if(!(math$19.define_e || math$19.define_pi)) { - return tree; - } - if(typeof tree === "string") { - if(tree === "e") { - if(math$19.define_e) { - return math$19.e; - } - } else if(tree === "pi") { - if(math$19.define_pi) { - return math$19.pi; - } - } - return tree; - } - - if(!Array.isArray(tree)) { - return tree; - } - - let operator = tree[0]; - let operands = tree.slice(1); - - // don't convert exponential function - if(operator === "^" && operands[0] === "e") { - return ["^", "e", constants_to_floats(operands[1])]; - } - - return [operator, ...operands.map(constants_to_floats)] - - } - - var astToMathjs$1 = new astToMathjs({mathjs: math$19 }); - - const f = function(expr_or_tree) { - var tree = get_tree(expr_or_tree); - - var mt = factorial_to_gamma_function( - astToMathjs$1.convert( - normalize_function_names( - normalize_applied_functions( - tree - ) - ) - ) - ); - - return mt.eval.bind(mt); - }; - - const evaluate = function(expr, bindings) { - return f(expr)(bindings); - }; - - // export const finite_field_evaluate = function(expr, bindings, modulus) { - // return parser.ast.to.finiteField( expr.tree, modulus )( bindings ); - // }; - - const evaluate_to_constant = function(expr_or_tree) { - // evaluate to number by converting tree to number - // and calling without arguments - - // return null if couldn't evaluate to constant (e.g., contains a variable) - // otherwise returns constant - // NOTE: constant could be a math.js complex number object - - var tree = get_tree(expr_or_tree); - - if(typeof tree === "number") { - return tree; - }else if(typeof tree === "string") { - if(tree === "pi" && math$19.define_pi) { - return Math.PI; - }else if(tree === "e" && math$19.define_e) { - return Math.E; - }else if(tree === "i" && math$19.define_i) { - return { re: 0, im: 1}; - } - return null; - } - - var num=null; - try { - var the_f = f(expr_or_tree); - num = the_f(); - } - catch (e) {} - return num; - }; - - function factorial_to_gamma_function(math_tree) { - // convert factorial to gamma function - // so that can evaluate at complex numbers - var transformed = math_tree.transform(function (node, path, parent) { - if(node.isOperatorNode && node.op === "!" && node.fn === "factorial") { - var args = [new math$19.expression.node.OperatorNode( - '+', 'add', [node.args[0], - new math$19.expression.node.ConstantNode(1)])]; - return new math$19.expression.node.FunctionNode( - new math$19.expression.node.SymbolNode("gamma"),args); - } - else { - return node; - } - }); - return transformed; - } - - var evaluation = /*#__PURE__*/Object.freeze({ - f: f, - evaluate: evaluate, - evaluate_to_constant: evaluate_to_constant - }); - - // functions that map from one set to another - var functions$1 = { - C: {}, - R: {}, - nonzeroC: {}, - nonneg: {}, - pos: {}, - }; - - functions$1.C.nonneg = ["abs"]; - functions$1.C.nonzero = ["exp"]; - functions$1.C.R = ["abs", "arg"]; - functions$1.C.C = ["abs", "arg", "exp", "sign", "cos", "cosh", "sin", "sinh", - "erf", "sqrt", "log", "ln", "log10"]; - functions$1.R.pos = ["exp"]; - functions$1.R.nonneg = ["abs", "exp", "arg"]; - functions$1.R.R = ["abs", "arg", "exp", "sign", "cos", "cosh", "sin", "sinh", - "erf"]; - functions$1.R.Z = ["sign"]; - functions$1.nonzeroC.pos = ["abs"]; - functions$1.nonneg.nonneg = ["abs", "exp", "arg", "sqrt", "erf"]; - functions$1.nonzeroC.nonzero = ["abs"]; - functions$1.nonneg.R = [...new Set(functions$1.R.R.concat( - functions$1.nonneg.nonneg))]; - functions$1.pos.pos = ["abs", "exp", "sqrt", "erf"]; - functions$1.pos.nonneg = functions$1.pos.pos; - functions$1.pos.nonzero = ["abs", "exp", "sqrt", "erf"]; - functions$1.pos.R = functions$1.nonneg.R.concat(["log", "ln", "log10"]); - - - function negate_adjust(result, negate_assumptions) { - if(result) - return !negate_assumptions; - if(result===false) - return negate_assumptions; - return undefined - } - - function narrow_assumptions(assumptions, original_assumptions) { - // find part of original assumptions after remove assumptions - - if(!Array.isArray(original_assumptions)) - return []; - - var operator = original_assumptions[0]; - var operands = original_assumptions.slice(1); - if(operator !== 'and') - return []; - - var remaining_assumptions = []; - - for(var i=0; i 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_integer_ast(tree, assume_operands[0], - original_assumptions); - let result_right = is_integer_ast(tree, assume_operands[1], - original_assumptions); - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') - return is_integer_ast(operands[0], assume, original_assumptions); - - if(operator === '*') { - - let all_integers = operands.every( - function (v) { - return is_integer_ast(v, assume, original_assumptions); - }); - - if(all_integers) - return true; - else { - return undefined; - - } - } - - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - - if(!base_nonzero) { - // if base is NaN, return false - if(Number.isNaN(operands[0])) - return false; - - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(pow_positive) { - if(base_nonzero === false) - return true; // 0^positive - } - else { - return undefined; // (possibly zero)^(possibly nonpositive) - } - - } - else { // nonzero base - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) { - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) - return false; - - return true; // nonzero^0 - } - - } - - let base_integer = is_integer_ast(operands[0], assume, - original_assumptions); - let pow_integer = is_integer_ast(operands[1], assume, - original_assumptions); - - if(!base_integer) - return base_integer; - - if(!pow_integer) - return undefined; // don't check for cases like 9^(1/2) - - let pow_nonneg= is_positive_ast(operands[1], assume, false, - original_assumptions); - - if(pow_nonneg) - return true; - else - return undefined; - - - } - if(operator === '+') { - - let n_non_integers=0; - - for(let i=0; i < operands.length; i++) { - let result = is_integer_ast(operands[i], assume, - original_assumptions); - - if(result === false) { - if(n_non_integers > 0) - return undefined; - n_non_integers += 1; - } - if(result === undefined) - return undefined; - } - - if(n_non_integers === 0) - return true; - else // only one non-integer - return false; - } - - - // check for functions that map certain sets to integers - if(operator === 'apply') { - if(functions$1.C.Z && functions$1.C.Z.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.Z && functions$1.R.Z.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.Z && functions$1.nonzeroC.Z.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.Z && functions$1.nonneg.Z.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.Z && functions$1.pos.Z.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === '/' || operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } - - return false; - } - - - function is_real_ast(tree, assumptions, original_assumptions) { - // see description of is_real - - if(typeof assumptions !== 'object') - assumptions = []; - - if(original_assumptions===undefined) - original_assumptions = assumptions; - - if(typeof tree === 'number') - return Number.isFinite(tree); - - // if can convert to constant, evaluate directly - var c = evaluate_to_constant(tree); - - if(c !== null) { - if(typeof c === 'number') { - return Number.isFinite(c); - } - return false; - } - - if(typeof tree === 'string') { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions(tree); - - if(!Array.isArray(assume)) - return undefined; - - let assume_with_negations = assume; - - let assume_operator = assume[0]; - let assume_operands = assume.slice(1); - - let negate_assumptions = false; - while(assume_operator === 'not') { - negate_assumptions = !negate_assumptions; - assume = assume_operands[0]; - if(!Array.isArray(assume)) - return undefined; - assume_operator = assume[0]; - assume_operands = assume.slice(1); - } - - if(assume_operator === 'in') - if(assume_operands[0]===tree && assume_operands[1] === 'R') - return negate_adjust(true, negate_assumptions); - if(assume_operator === 'notin') - if(assume_operands[0]===tree && assume_operands[1] === 'R') - return negate_adjust(false, negate_assumptions); - // haven't negated, then determining tree is integer means it is real - if(negate_assumptions===false) { - if(assume_operator === 'in') - if(assume_operands[0]===tree && assume_operands[1] === 'Z') - return true; - } - // if have negated, then determining tree is not integer, - // means it is an integer, hence real - else { - if(assume_operator === 'notin') - if(assume_operands[0]===tree && assume_operands[1] === 'Z') - return true; - } - - // if assumptions is an inequality involving variable - // then return true - if(assume_operator === '<' || assume_operator === 'le') { - - let variables_in_inequality = variables(assume); - let functions_in_inequality = functions(assume); - - if(variables_in_inequality.indexOf(tree) !== -1 - && functions_in_inequality.length === 0) - return true; // don't negate adjust - } - - // assume equality has been expanded so that has two arguments - if((assume_operator === '=' && !negate_assumptions) || - (assume_operator === 'ne' && negate_assumptions)) { - // if assumption is "tree=something" - // check if something is real - // (but without the assumption to avoid infinite loop) - - let new_assumptions = narrow_assumptions(assume_with_negations, - original_assumptions); - if(assume_operands[0]===tree) - return is_real_ast(assume_operands[1], new_assumptions); - if(assume_operands[1]===tree) - return is_real_ast(assume_operands[0], new_assumptions); - } - - - // if isn't a simple And or Or, just give up - if(assume_operator !== 'and' && assume_operator !== 'or') - return undefined; - - // shouldn't have negated assumptions - if(negate_assumptions) - return undefined; - - // if more than two operands, unflatten - // (OK, since not attempting logic where only combined restrictions - // lead to a passing test) - if(assume_operands.length > 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_real_ast(tree, assume_operands[0], - original_assumptions); - let result_right = is_real_ast(tree, assume_operands[1], - original_assumptions); - - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') { - return is_real_ast(operands[0], assume, original_assumptions); - } - if(operator === '*' || operator === '+') { - - // if more than two terms, unflatten - if(operands.length > 2) { - tree = unflattenRight(tree); - operands = tree.slice(1); - } - - if(operator==='*') { - // one confirmed zero factor makes product zero - if((is_nonzero_ast(operands[0], assume, original_assumptions) - === false) || - (is_nonzero_ast(operands[1], assume, original_assumptions) - === false)) - return true; - } - - let left_real = is_real_ast(operands[0], assume, - original_assumptions); - let right_real = is_real_ast(operands[1], assume, - original_assumptions); - - if(left_real && right_real) - return true; - - // can confirm that is not real - // if one term/factor is real and the other is not real - if((left_real && right_real===false) || - (right_real && left_real===false)) - return false - - return undefined; - - } - - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(!base_nonzero) { - // if base is NaN, return false - if(Number.isNaN(operands[0])) - return false; - - if(pow_positive) { - if(base_nonzero === false) - return true; // 0^positive - } - else { - return undefined; // (possibly zero)^(possibly nonpositive) - } - - } - else { // nonzero base - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) { - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) - return false; - - return true; // nonzero^0 - } - - } - - let base_real = is_real_ast(operands[0], assume, - original_assumptions); - let pow_real = is_real_ast(operands[1], assume, - original_assumptions); - - if(!(base_real && pow_real)) - return undefined; - - let base_nonnegative = is_positive_ast(operands[0], assume, false, - original_assumptions); - - if(!base_nonnegative) { - // if base might be negative - // then power must be an integer - // (already excluded 0^0) - - let pow_integer = is_integer_ast(operands[1], assume, - original_assumptions); - if(pow_integer) - return true; - else - return undefined - } - - let base_positive = is_positive_ast(operands[0], assume, true, - original_assumptions); - - if(!base_positive) { - // if base might be zero - // then power must be positive - if(pow_positive) - return true; - else - return undefined; - } - - // base is positive, power is real - return true; - - } - - if(operator === '/') { - // if can't be sure denominator is nonzero - if(!is_nonzero_ast(operands[1], assume, original_assumptions)) - return undefined; - - // zero numerator - if(is_nonzero_ast(operands[0], assume, original_assumptions) === false) - return true; - - if(!(is_real_ast(operands[0], assume, original_assumptions) - && is_real_ast(operands[1], assume, original_assumptions))) - return undefined; - - return true; - - } - - // check for functions that map certain sets to reals - if(operator === 'apply') { - if(functions$1.C.R && functions$1.C.R.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.R && functions$1.R.R.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.R && functions$1.nonzeroC.R.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.R && functions$1.nonneg.R.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.R && functions$1.pos.R.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } - - return false; - } - - - function is_complex_ast(tree, assumptions, original_assumptions) { - // see description of is_complex - - if(typeof assumptions !== 'object') - assumptions = []; - - if(original_assumptions===undefined) - original_assumptions = assumptions; - - if(typeof tree === 'number') - return Number.isFinite(tree); - - // if can convert to constant, evaluate directly - var c = evaluate_to_constant(tree); - if(c !== null) { - if(typeof c === 'number') { - return Number.isFinite(c); - } - if(c.re !== undefined && Number.isFinite(c.re) - && c.im !== undefined && Number.isFinite(c.im) ) - return true; - - return false; - } - - if(typeof tree === 'string') { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions(tree); - - if(!Array.isArray(assume)) - return undefined; - - let assume_with_negations = assume; - - let assume_operator = assume[0]; - let assume_operands = assume.slice(1); - - let negate_assumptions = false; - while(assume_operator === 'not') { - negate_assumptions = !negate_assumptions; - assume = assume_operands[0]; - if(!Array.isArray(assume)) - return undefined; - assume_operator = assume[0]; - assume_operands = assume.slice(1); - } - - if(assume_operator === 'in') - if(assume_operands[0]===tree && assume_operands[1] === 'C') - return negate_adjust(true, negate_assumptions); - if(assume_operator === 'notin') - if(assume_operands[0]===tree && assume_operands[1] === 'C') - return negate_adjust(false, negate_assumptions); - // haven't negated, then determining tree is integer or real - // means it is complex - if(negate_assumptions===false) { - if(assume_operator === 'in') { - if(assume_operands[0]===tree && assume_operands[1] === 'Z') - return true; - if(assume_operands[0]===tree && assume_operands[1] === 'R') - return true; - } - } - // if have negated, then determining tree is not integer or not real, - // means it is an integer/real, hence complex - else { - if(assume_operator === 'notin') { - if(assume_operands[0]===tree && assume_operands[1] === 'Z') - return true; - if(assume_operands[0]===tree && assume_operands[1] === 'R') - return true; - } - } - - // if assumptions is an inequality involving variable - // then must be real, hence complex, so return true - if(assume_operator === '<' || assume_operator === 'le') { - - let variables_in_inequality = variables(assume); - let functions_in_inequality = functions(assume); - - if(variables_in_inequality.indexOf(tree) !== -1 - && functions_in_inequality.length === 0) - return true; // don't negate adjust - } - - // assume equality has been expanded so that has two arguments - if((assume_operator === '=' && !negate_assumptions) || - (assume_operator === 'ne' && negate_assumptions)) { - // if assumption is "tree=something" - // check if something is complex - // (but without the assumption to avoid infinite loop) - - let new_assumptions = narrow_assumptions(assume_with_negations, - original_assumptions); - if(assume_operands[0]===tree) - return is_complex_ast(assume_operands[1], new_assumptions); - if(assume_operands[1]===tree) - return is_complex_ast(assume_operands[0], new_assumptions); - } - - // if isn't a simple And or Or, just give up - if(assume_operator !== 'and' && assume_operator !== 'or') - return undefined; - - // shouldn't have negated assumptions - if(negate_assumptions) - return undefined; - - // if more than two operands, unflatten - // (OK, since not attempting logic where only combined restrictions - // lead to a passing test) - if(assume_operands.length > 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_complex_ast(tree, assume_operands[0], - original_assumptions); - let result_right = is_complex_ast(tree, assume_operands[1], - original_assumptions); - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') - return is_complex_ast(operands[0], assume, original_assumptions); - - if(operator === '*' || operator === '+') { - - if(operator==='*') { - // one confirmed zero factor makes product zero - if(!operands.every(v => is_nonzero_ast(v, assume, original_assumptions) !== false)) - return true; - } - - let all_complex = operands.every(v => is_complex_ast(v, assume, original_assumptions)); - - if(all_complex) - return true; - else { - return undefined; - - } - } - - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(!base_nonzero) { - - // if base is NaN, return false - if(Number.isNaN(operands[0])) - return false; - - if(pow_positive) { - if(base_nonzero === false) - return true; // 0^positive - } - else { - return undefined; // (possibly zero)^(possibly nonpositive) - } - - } - else { // nonzero base - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) { - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) - return false; - - return true; // nonzero^0 - } - - } - - let base_complex = is_complex_ast(operands[0], assume, - original_assumptions); - let pow_complex = is_complex_ast(operands[1], assume, - original_assumptions); - - if(base_complex && pow_complex) - return true; - else - return undefined; - - } - - if(operator === '/') { - // if can't be sure denominator is nonzero - if(!is_nonzero_ast(operands[1], assume, original_assumptions)) - return undefined; - - // zero numerator - if(is_nonzero_ast(operands[0], assume, original_assumptions) === false) - return true; - - if(!(is_complex_ast(operands[0], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions))) - return undefined; - - return true; - - } - - // check for functions that map certain sets to complex numbers - if(operator === 'apply') { - if(functions$1.C.C && functions$1.C.C.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.C && functions$1.R.C.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.C && functions$1.nonzeroC.C.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.C && functions$1.nonneg.C.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.C && functions$1.pos.C.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } - - return false; - } - - - function is_nonzero_ast(tree, assumptions, original_assumptions) { - // see description of is_nonzero - - if(typeof assumptions !== 'object') - assumptions = []; - - if(original_assumptions===undefined) - original_assumptions = assumptions; - - if(typeof tree === 'number') { - if(Number.isFinite(tree)) - return tree !== 0; - if(Number.isNaN(tree)) - return undefined; - return true; // consider infinity to be nonzero - } - - // if can convert to constant, evaluate directly - var c = evaluate_to_constant(tree); - if(c !== null) { - if(typeof c === 'number') { - if(Number.isFinite(c)) - return c !== 0; - if(Number.isNaN(c)) - return undefined; - return true; // consider infinity to be nonzero - } - if(c.re !== undefined && c.im !== undefined && - (c.re !== 0 || c.im !== 0) ) - return true; - return undefined; - } - - if(typeof tree === 'string') { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions(tree); - - if(!Array.isArray(assume)) - return undefined; - - let assume_with_negations = assume; - - let assume_operator = assume[0]; - let assume_operands = assume.slice(1); - - let negate_assumptions = false; - while(assume_operator === 'not') { - negate_assumptions = !negate_assumptions; - assume = assume_operands[0]; - if(!Array.isArray(assume)) - return undefined; - assume_operator = assume[0]; - assume_operands = assume.slice(1); - } - - let new_assumptions = narrow_assumptions(assume_with_negations, - original_assumptions); - - // assume equality has been expanded so that has two arguments - if((assume_operator === '=' && !negate_assumptions) || - (assume_operator === 'ne' && negate_assumptions)) { - // if assumption is "tree=something" - // check if something is nonzero - // (but without the assumption to avoid infinite loop) - - if(assume_operands[0]===tree) - return is_nonzero_ast(assume_operands[1], new_assumptions); - if(assume_operands[1]===tree) - return is_nonzero_ast(assume_operands[0], new_assumptions); - } - - if((assume_operator === 'ne' && !negate_assumptions) || - (assume_operator === '=' && negate_assumptions)) { - // if assumption is "tree!=something" - // check if something is zero - - if(assume_operands[0]===tree) { - if(is_nonzero_ast(assume_operands[1], new_assumptions)===false) - return true - } - if(assume_operands[1]===tree) { - if(is_nonzero_ast(assume_operands[0], new_assumptions)===false) - return true; - } - } - - // assume assumptions are ordered so greater than doesn't appear - if(assume_operator === '<') { - if(!negate_assumptions) { - if(assume_operands[0]===tree) { - if(is_negative_ast( - assume_operands[1], new_assumptions, false)) - return true; - } - if(assume_operands[1]===tree) { - if(is_positive_ast( - assume_operands[0], new_assumptions, false)) - return true; - } - } - else { - // negated, becomes ge - if(assume_operands[0]===tree) { - if(is_positive_ast( - assume_operands[1], new_assumptions, true)) - return true; - } - if(assume_operands[1]===tree) { - if(is_negative_ast( - assume_operands[0], new_assumptions, true)) - return true; - } - - } - } - if(assume_operator === 'le') { - if(!negate_assumptions) { - if(assume_operands[0]===tree) { - if(is_negative_ast( - assume_operands[1], new_assumptions, true)) - return true; - } - if(assume_operands[1]===tree) { - if(is_positive_ast( - assume_operands[0], new_assumptions, true)) - return true; - } - } - else { - // negated, so becomes > - if(assume_operands[0]===tree) { - if(is_positive_ast( - assume_operands[1], new_assumptions, false)) - return true; - } - if(assume_operands[1]===tree) { - if(is_negative_ast( - assume_operands[0], new_assumptions, false)) - return true; - } - - } - } - - // if isn't a simple And or Or, just give up - if(assume_operator !== 'and' && assume_operator !== 'or') - return undefined; - - // shouldn't have negated assumptions - if(negate_assumptions) - return undefined; - - // if more than two operands, unflatten - // (OK, since not attempting logic where only combined restrictions - // lead to a passing test) - if(assume_operands.length > 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_nonzero_ast(tree, assume_operands[0], - original_assumptions); - let result_right = is_nonzero_ast(tree, assume_operands[1], - original_assumptions); - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') - return is_nonzero_ast(operands[0], assume, original_assumptions); - - if(operator === '+') { - - // if more than two terms, unflatten - if(operands.length > 2) { - tree = unflattenRight(tree); - operands = tree.slice(1); - } - - // if operands are opposite - // (trees.equal removes duplicate negatives through default_order) - // TODO: check if operands aren't infinite - if(equal$2(operands[0], - simplify$2(['-', operands[1]], - original_assumptions))) - return false; - - // can definitely determine nonzero if one term is zero - // or if both have the same sign - - let nonzero_left = is_nonzero_ast(operands[0], assume, - original_assumptions); - let nonzero_right = is_nonzero_ast(operands[1], assume, - original_assumptions); - - // if one is known to be zero, return result from other - if(nonzero_left===false) - return nonzero_right; - if(nonzero_right===false) - return nonzero_left; - - - // if one of both aren't real - // decide now - let real_left = is_real_ast(operands[0], assume, - original_assumptions); - let real_right = is_real_ast(operands[1], assume, - original_assumptions); - - if(!real_left || !real_right) { - if(real_left===true) { - if(real_right === false) - return true; - return undefined; - } - if(real_right===true) { - if(real_left===false) - return true; - return undefined; - } - return undefined; - } - - // if reach here, both are real - - let nonneg_left = is_positive_ast(operands[0], assume, false, - original_assumptions); - let nonneg_right = is_positive_ast(operands[1], assume, false, - original_assumptions); - - let positive_left = is_positive_ast(operands[0], assume, true, - original_assumptions); - let positive_right = is_positive_ast(operands[1], assume, true, - original_assumptions); - - // positive + nonnegative is nonzero - if( (nonneg_left && positive_right) - || (positive_left && nonneg_right)) - return true; - - // negative + nonpositive is nonzero - if( (nonneg_left===false && positive_right===false) - || (positive_left===false && nonneg_right===false)) - return true; - - - // have terms of both signs (or undefined sign) - // so can't determine if nonzero by this approach - return undefined; - } - - if(operator === '*') { - let all_nonzero = true; - for(let i=0; i < operands.length; i++) { - - let result = is_nonzero_ast(operands[i], assume, - original_assumptions); - - if(result===false) - return false; // found a zero factor - if(result===undefined) - all_nonzero=false; - } - - if(all_nonzero) - return true; - else - return undefined; - } - - if(operator === '/') { - - let result = is_nonzero_ast(operands[0], assume, - original_assumptions); - - if(is_nonzero_ast(operands[1], assume, original_assumptions)) - return result; - else - return undefined; - } - - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - - if(!base_nonzero) { - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(pow_positive && (base_nonzero === false)) - return false; // 0^positive - - return undefined; - } - else { // nonzero base - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) { - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) - return undefined; - } - - return true; - - // TODO? positive^(-infinity) =? 0 - } - - } - - // check for functions that map certain sets to nonzeros - if(operator === 'apply') { - if(functions$1.C.nonzero && functions$1.C.nonzero.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.nonzero && functions$1.R.nonzero.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.nonzero && functions$1.nonzeroC.nonzero.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.nonzero && functions$1.nonneg.nonzero.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.nonzero && functions$1.pos.nonzero.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } - - return false; - } - - - function is_positive_ast(tree, assumptions, strict, original_assumptions) { - // see description of is_nonnegative - - if(typeof assumptions !== 'object') - assumptions = []; - - if(original_assumptions===undefined) - original_assumptions = assumptions; - - if(strict === undefined) - strict = true; - - if(typeof tree === 'number') { - if(Number.isFinite(tree)) - return (strict ? tree > 0 : tree >= 0); - return false; - } - - var is_real = is_real_ast(tree, assumptions, original_assumptions); - if(!is_real) - return is_real; - - // if can convert to constant, evaluate directly - var c = evaluate_to_constant(tree); - - if(c !== null) { - if(typeof c === 'number') { - if(Number.isFinite(c)) - return (strict ? c > 0 : c >= 0); - return false; - } - return false; - } - - if(typeof tree === 'string') { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions(tree); - - if(!Array.isArray(assume)) - return undefined; - - let assume_with_negations = assume; - - let assume_operator = assume[0]; - let assume_operands = assume.slice(1); - - let negate_assumptions = false; - while(assume_operator === 'not') { - negate_assumptions = !negate_assumptions; - assume = assume_operands[0]; - if(!Array.isArray(assume)) - return undefined; - assume_operator = assume[0]; - assume_operands = assume.slice(1); - } - - let new_assumptions = narrow_assumptions(assume_with_negations, - original_assumptions); - - // assume that equality has been expanded so that - // have only two operands - if((assume_operator === '=' && !negate_assumptions) || - (assume_operator === 'ne' && negate_assumptions)) { - // if assumption is "tree=something" - // check if something is positive - // (but without the assumption to avoid infinite loop) - - if(assume_operands[0]===tree) - return is_positive_ast(assume_operands[1], new_assumptions, - strict); - if(assume_operands[1]===tree) - return is_positive_ast(assume_operands[0], new_assumptions, - strict); - } - - // assume assumptions are ordered so greater than doesn't appear - if(assume_operator === '<') { - if(!negate_assumptions) { - if(assume_operands[0]===tree) { - if(is_negative_ast(assume_operands[1], new_assumptions, - false)) - return false; - } - if(assume_operands[1]===tree) { - if(is_positive_ast(assume_operands[0], new_assumptions, - false)) - return true; - } - } - else { - // negated, so becomes ge - if(assume_operands[0]===tree) { - if(is_positive_ast(assume_operands[1], new_assumptions, - strict)) - return true; - } - if(assume_operands[1]===tree) { - if(is_negative_ast(assume_operands[0], new_assumptions, - !strict)) - return false; - } - - } - } - if(assume_operator === 'le') { - if(!negate_assumptions) { - if(assume_operands[0]===tree) { - if(is_negative_ast(assume_operands[1], new_assumptions, - !strict)) - return false; - } - if(assume_operands[1]===tree) { - if(is_positive_ast(assume_operands[0], new_assumptions, - strict)) - return true; - } - } - else { - // negated, so becomes > - if(assume_operands[0]===tree) { - if(is_positive_ast(assume_operands[1], new_assumptions, - false)) - return true; - } - if(assume_operands[1]===tree) { - if(is_negative_ast(assume_operands[0], new_assumptions, - false)) - return false; - } - - } - } - - - // if isn't a simple And or Or, just give up - if(assume_operator !== 'and' && assume_operator !== 'or') - return undefined; - - // shouldn't have negated assumptions - if(negate_assumptions) - return undefined; - - // if more than two operands, unflatten - // (OK, since not attempting logic where only combined restrictions - // lead to a passing test) - if(assume_operands.length > 2) { - assume = unflattenRight(assume); - assume_operands = assume.slice(1); - } - - let result_left = is_positive_ast(tree, assume_operands[0], strict, - original_assumptions); - let result_right = is_positive_ast(tree, assume_operands[1], strict, - original_assumptions); - return simple_assumption_combination(assume_operator, result_left, - result_right) - } - - if(Array.isArray(tree)) { - - let assume; - if(Array.isArray(assumptions)) - assume = assumptions; - else - assume = assumptions.get_assumptions([variables(tree)]); - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '-') - return is_negative_ast(operands[0], assume, strict, - original_assumptions); - - if(operator === '+') { - - // if more than two terms, unflatten - if(operands.length > 2) { - tree = unflattenRight(tree); - operands = tree.slice(1); - } - - - let nonneg_left = is_positive_ast(operands[0], assume, false, - original_assumptions); - let nonneg_right = is_positive_ast(operands[1], assume, false, - original_assumptions); - - let positive_left = is_positive_ast(operands[0], assume, true, - original_assumptions); - let positive_right = is_positive_ast(operands[1], assume, true, - original_assumptions); - - - if(strict) { - // positive + nonnegative is positive - if( (nonneg_left && positive_right) - || (positive_left && nonneg_right)) - return true; - } - else { - // nonnegative + nonnegative is nonnegative - if(nonneg_left && nonneg_right) - return true; - } - - if(strict) { - // nonpositive + nonpositive is nonpositive - if(positive_left===false && positive_right===false) - return false; - } - else { - // negative + nonpositive is negative - if( (nonneg_left===false && positive_right===false) - || (positive_left===false && nonneg_right===false)) - return false; - } - - // have terms of both signs (or undefined sign) - // so can't determine if positive or negative by this approach - return undefined; - } - - if(operator === '*') { - // one confirmed zero factor makes product zero - if(!operands.every(v => is_nonzero_ast(v, assume, original_assumptions) !== false)) - return !strict; - - // if more than two terms, unflatten - if(operands.length > 2) { - tree = unflattenRight(tree); - operands = tree.slice(1); - } - - let real_left = is_real_ast(operands[0], assume, - original_assumptions); - let real_right = is_real_ast(operands[1], assume, - original_assumptions); - - // if can't determine if real, can't determine positivity - if(real_left===undefined || real_right===undefined) - return undefined; - - // if one nonreal, return false - // if two nonreals, return undefined - if(real_left===false) { - if(real_right===false) - return undefined; - else - return false; - } - else if(real_right===false) - return false; - - // if reach here, both factors are real - - let nonneg_left = is_positive_ast(operands[0], assume, false, - original_assumptions); - let nonneg_right = is_positive_ast(operands[1], assume, false, - original_assumptions); - - let positive_left = is_positive_ast(operands[0], assume, true, - original_assumptions); - let positive_right = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(strict) { - // product of two positives or two negatives is positive - if((positive_left && positive_right) - || (nonneg_left === false && nonneg_right === false)) - return true; - - // product of nonnegative and nonpositive is nonpositive - if((positive_left === false && nonneg_right) - || (nonneg_left && positive_right === false)) - return false; - } - else { - // product of two nonnegatives or two nonpositives - // is nonnegative - if((nonneg_left && nonneg_right) - || (positive_left === false && positive_right === false)) - return true; - - // product of positive and negative is negative - if((positive_left && nonneg_right === false) - || (nonneg_left === false && positive_right)) - return false; - } - - // couldn't figure out sign via above algorithm - return undefined; - - } - - if(operator === '/') { - - // if can't be sure denominator is nonzero - if(!is_nonzero_ast(operands[1], assume, original_assumptions)) - return undefined; - - // zero numerator - if(is_nonzero_ast(operands[0], assume, - original_assumptions) === false) - return !strict; - - let denom_pos = is_positive_ast(operands[1], assume, true, - original_assumptions); - if(denom_pos === undefined) - return undefined; - - // if denominator is negative, sign is swapped - // so need opposite strictness for numerator - let numer_strict = denom_pos ? strict : !strict; - let numer_pos = is_positive_ast(operands[0], assume, - numer_strict, - original_assumptions); - - if(numer_pos === undefined) - return undefined; - - if(numer_pos === true) { - if(denom_pos === true) - return true; - else - return false; - } - else { - if(denom_pos === true) - return false; - else - return true; - } - } - if(operator === '^') { - - let base_nonzero = is_nonzero_ast(operands[0], assume, - original_assumptions); - - if(!base_nonzero) { - let pow_positive = is_positive_ast(operands[1], assume, true, - original_assumptions); - - if(pow_positive) { - if(base_nonzero === false) - return !strict; // 0^positive - if(strict) - return undefined // (possibly 0)^positive - } - else { - return undefined; // (possibly zero)^(possibly nonpositive) - } - - } - else { // nonzero base - let pow_nonzero = is_nonzero_ast(operands[1], assume, - original_assumptions); - if(pow_nonzero === false) { - // infinity^0 is undefined - if(operands[0] === Infinity || operands[0] === -Infinity) - return undefined; - - return true; // nonzero^0 - } - - } - - let base_real = is_real_ast(operands[0], assume, - original_assumptions); - - if(base_real !== true) { - return undefined; - } - - let base_positive = is_positive_ast(operands[0], assume, strict, - original_assumptions); - - if(!base_positive) { - // if base could be negative - // (already excluded zero base if strict) - // then only way to be - // positive (non_negative if not strict) - // is if pow is an even integer - - // since haven't implemented is_even, only check - // if have a constant that is an even integer - let pow_over_two = simplify$2(['/', operands[1], 2], - original_assumptions); - if(is_integer_ast(pow_over_two, assume, original_assumptions)) - return true; - - return undefined; - } - - // base must be nonnegative - let pow_real = is_real_ast(operands[1], assume, - original_assumptions); - - if(pow_real) - return true; // since already excluded 0^0 - else - return undefined; - - } - - // check for functions that map certain sets to nonnegatives - if(operator === 'apply' && !strict) { - if(functions$1.C.nonneg && functions$1.C.nonneg.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.nonneg && functions$1.R.nonneg.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.nonneg && functions$1.nonzeroC.nonneg.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.nonneg && functions$1.nonneg.nonneg.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.nonneg && functions$1.pos.nonneg.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - // check for functions that map certain sets to integers - if(operator === 'apply' && strict) { - if(functions$1.C.pos && functions$1.C.pos.includes(operands[0]) && - is_complex_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.R.pos && functions$1.R.pos.includes(operands[0]) && - is_real_ast(operands[1], assume, original_assumptions)) - return true; - if(functions$1.nonzeroC.pos && functions$1.nonzeroC.pos.includes(operands[0]) - && is_nonzero_ast(operands[1], assume, original_assumptions) - && is_complex_ast(operands[1], assume, original_assumptions) - ) - return true; - if(functions$1.nonneg.pos && functions$1.nonneg.pos.includes(operands[0]) && - is_positive_ast(operands[1], assume, false, original_assumptions)) - return true; - if(functions$1.pos.pos && functions$1.pos.pos.includes(operands[0]) && - is_positive_ast(operands[1], assume, true, original_assumptions)) - return true; - return undefined; - } - - if(operator === 'prime') - return undefined; - - // other operators don't return numbers - return false; - } - - return false; - } - - function is_negative_ast(tree, assumptions, strict, original_assumptions) { - if(strict === undefined) - strict = true; - - var real = is_real_ast(tree, assumptions, original_assumptions); - - if(real === true) { - let nonneg = is_positive_ast(tree, assumptions, !strict, - original_assumptions); - if(nonneg === false) - return true; - if(nonneg === true) - return false; - return undefined; - } - - return real; - } - - function clean(expr_or_tree) { - var tree = get_tree(expr_or_tree); - return flatten(tree); - } - - function evalf(x, n) { - return parseFloat(number_8(x, n)); - } - - function collapse_unary_minus(expr_or_tree) { - var tree = get_tree(expr_or_tree); - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - operands = operands.map(v => collapse_unary_minus(v)); - - if (operator === "-") { - if (typeof operands[0] === 'number') - return -operands[0]; - // check if operand is a multiplication with that begins with - // a constant. If so combine with constant - if (Array.isArray(operands[0]) && operands[0][0] === '*' - && (typeof operands[0][1] === 'number')) { - return ['*', -operands[0][1]].concat(operands[0].slice(2)); - } - // check if operand is a division with that begins with - // either - /// (A) a constant or - // (B) a multiplication that begins with a constant. - // If so. combine with constant - if (Array.isArray(operands[0]) && operands[0][0] === '/') { - if (typeof operands[0][1] === 'number') - return ['/', -operands[0][1], operands[0][2]]; - if (Array.isArray(operands[0][1]) && operands[0][1][0] === '*' - && (typeof operands[0][1][1] === 'number')) { - return ['/', [ - '*', -operands[0][1][1]].concat(operands[0][1].slice(2)), - operands[0][2]]; - } - } - } - - return [operator].concat(operands); - } - - function simplify$2(expr_or_tree, assumptions, max_digits) { - var tree = get_tree(expr_or_tree); - - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); - - tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits, evaluate_functions: true }); - // if already have it down to a number of variable, no need for more simplification - if (!Array.isArray(tree)) { - return tree; - } - tree = simplify_logical(tree, assumptions); - tree = collect_like_terms_factors(tree, assumptions, max_digits); - - return tree; - } - - function simplify_logical(expr_or_tree, assumptions) { - var tree = get_tree(expr_or_tree); - - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); - - tree = evaluate_numbers(tree, { assumptions: assumptions }); - - tree = unflattenRight(tree); - - var transformations = []; - transformations.push([ [ 'not', [ 'not', 'a' ] ], "a"]); - transformations.push([ [ 'not', [ 'and', 'a', 'b' ] ], [ 'or', [ 'not', 'a' ], [ 'not', 'b' ] ] ]); - transformations.push([ [ 'not', [ 'or', 'a', 'b' ] ], [ 'and', [ 'not', 'a' ], [ 'not', 'b' ] ] ]); - transformations.push([ [ 'not', [ '=', 'a', 'b' ] ], [ 'ne', 'a', 'b' ] ]); - transformations.push([ [ 'not', [ 'ne', 'a', 'b' ] ], [ '=', 'a', 'b' ] ]); - transformations.push([ [ 'not', [ '<', 'a', 'b' ] ], [ 'le', 'b', 'a' ] ]); - transformations.push([ [ 'not', [ 'le', 'a', 'b' ] ], [ 'not', [ 'le', 'a', 'b' ] ] ]); - transformations.push([ [ 'not', [ 'in', 'a', 'b' ] ], [ 'notin', 'a', 'b' ] ]); - transformations.push([ [ 'not', [ 'subset', 'a', 'b' ] ], [ 'notsubset', 'a', 'b' ] ]); - - tree = applyAllTransformations(tree, transformations, 20); - - tree = flatten(tree); - - return tree; - } - - function contains_decimal_number(tree) { - if (typeof tree === "string") { - return false; - } - if (typeof tree === "number") { - if (Number.isFinite(tree) && !Number.isInteger(tree)) { - return true; - } else { - return false; - } - } - if (!Array.isArray(tree)) { - return false; - } - return tree.slice(1).some(x => contains_decimal_number(x)); - } - - function contains_only_numbers(tree, { include_number_symbols = false } = {}) { - if (typeof tree === "string") { - if (include_number_symbols) { - if (tree === "e" && math$19.define_e) { - return true; - } - if (tree === "pi" && math$19.define_pi) { - return true; - } - } - return false; - } - if (typeof tree === "number") { - return true; - } - if (!Array.isArray(tree)) { - return false; - } - return tree.slice(1).every(x => contains_only_numbers(x, { include_number_symbols: include_number_symbols })); - } - - function evaluate_numbers_sub(tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero) { - // assume that tree has been sorted to default order (while flattened) - // and then unflattened_right - // returns unflattened tree - - if (tree === undefined) - return tree; - - if (typeof tree === 'number') { - if(set_small_zero > 0 && math$19.abs(tree) < set_small_zero) { - return 0; - } - if(tree === 0) { - return 0; // so that -0 returns 0 - } - return tree; - } - - if (evaluate_functions || contains_only_numbers(tree, { include_number_symbols: true })) { - - var c = evaluate_to_constant(tree); - - if (c !== null) { - if (typeof c === 'number') { - if (Number.isFinite(c)) { - if(set_small_zero > 0 && math$19.abs(c) < set_small_zero) { - return 0; - } - if (max_digits === Infinity) - return c; - if (Number.isInteger(c)) { - if(c === 0) { - return 0; - } - return c; - } - - let c_minround = evalf(c, 14); - let c_round = evalf(c, max_digits); - if (max_digits === 0) { - // interpret 0 max_digits as only accepting integers - // (even though positive max_digits is number of significant digits) - c_round = math$19.round(c); - } - if (c_round === c_minround) { - return c; - } - - // if expression already contained a decimal, - // and contains only numbers (no constants like pi) - // return the number - if (contains_decimal_number(tree) && contains_only_numbers(tree)) { - return c; - } - - let c_frac = math$19.fraction(c); - let c_frac_d_round = evalf(c_frac.d, 3); - - if (c_frac.n < 1E4 || (c_frac_d_round === c_frac.d)) { - let c_reconstruct = evalf(c_frac.s * c_frac.n / c_frac.d, 14); - if (c_reconstruct === c_minround) { - if (c_frac.d === 1) { - return c_frac.s * c_frac.n; - } else { - return ['/', c_frac.s * c_frac.n, c_frac.d]; - } - } - } - } - } - } - } - - if (!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1).map(v => evaluate_numbers_sub( - v, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); - - if (operator === '+') { - let left = operands[0]; - let right = operands[1]; - - if (right === undefined) - return left; - - if (typeof left === 'number') { - if (left === 0) - return right; - if (typeof right === 'number') - return left + right; - // check if right is an addition with that begins with - // a constant. If so combine with left - if (Array.isArray(right) && right[0] === '+' - && (typeof right[1] === 'number')) { - return ['+', left + right[1], right[2]]; - } - // check if right is an addition with that ends with - // a constant. If so combine with left - if (!skip_ordering && Array.isArray(right) && right[0] === '+' - && (typeof right[2] === 'number')) { - return ['+', left + right[2], right[1]]; - } - - } - if (typeof right === 'number') - if (right === 0) - return left; - - return [operator].concat(operands); - } - if (operator === '-') { - if (typeof operands[0] === 'number') - return -operands[0]; - // check if operand is a multiplication with that begins with - // a constant. If so combine with constant - if (Array.isArray(operands[0]) && operands[0][0] === '*' - && (typeof operands[0][1] === 'number')) { - return ['*', -operands[0][1]].concat(operands[0].slice(2)); - } - // check if operand is a division with that begins with - // either - /// (A) a constant or - // (B) a multiplication that begins with a constant. - // If so. combine with constant - if (Array.isArray(operands[0]) && operands[0][0] === '/') { - if (typeof operands[0][1] === 'number') - return ['/', -operands[0][1], operands[0][2]]; - if (Array.isArray(operands[0][1]) && operands[0][1][0] === '*' - && (typeof operands[0][1][1] === 'number')) { - return ['/', [ - '*', -operands[0][1][1]].concat(operands[0][1].slice(2)), - operands[0][2]]; - - } - - } - - return [operator].concat(operands); - } - if (operator === '*') { - let left = operands[0]; - let right = operands[1]; - - if (right === undefined) - return left; - - if (typeof left === 'number') { - if (isNaN(left)) - return NaN; - - if (typeof right === 'number') - return left * right; - - if (!isFinite(left)) { - if ((left === Infinity && is_negative_ast(right)) - || (left === -Infinity && is_positive_ast(right))) - return -Infinity - if (is_nonzero_ast(right) === false) - return NaN; - return Infinity; - } - if (left === 0) { - return 0; - } - if (left === 1) - return right; - - if (left === -1) { - return ['-', right]; - } - // check if right is a multiplication with that begins with - // a constant. If so combine with left - if (Array.isArray(right) && right[0] === '*' - && (typeof right[1] === 'number')) { - left = left * right[1]; - right = right[2]; - if (left === 1) - return right; - if (left === -1) - return ['-', right]; - return ['*', left, right]; - } - - } - if (typeof right === 'number') { - if (isNaN(right)) - return NaN; - if (!isFinite(right)) { - if ((right === Infinity && is_negative_ast(left)) - || (right === -Infinity && is_positive_ast(left))) - return -Infinity - if (is_nonzero_ast(left) === false) - return NaN; - return Infinity; - } - if (right === 0) { - return 0; - } - if (right === 1) - return left; - if (right === -1) { - return ['-', left]; - } - // check if left is a multiplication with that begins with - // a constant. If so combine with right - if (Array.isArray(left) && left[0] === '*' - && (typeof left[1] === 'number')) { - right = right * left[1]; - left = left[2]; - if (right === 1) - return left; - if (right === -1) - return ['-', left]; - return ['*', left, right]; - } - } - - return [operator].concat(operands); - } - - if (operator === '/') { - - let numer = operands[0]; - let denom = operands[1]; - - if (typeof numer === 'number') { - if (numer === 0) { - let denom_nonzero = is_nonzero_ast(denom, assumptions); - if (denom_nonzero) - return 0; - if (denom_nonzero === false) - return NaN; // 0/0 - } - - if (typeof denom === 'number') { - let quotient = numer / denom; - if (max_digits === Infinity - || math$19.round(quotient, max_digits) === quotient) - return quotient; - else if (denom < 0) - return ['/', -numer, -denom]; - } - - // check if denom is a multiplication with that begins with - // a constant. If so combine with numerator - if (Array.isArray(denom) && denom[0] === '*' - && (typeof denom[1] === 'number')) { - let quotient = numer / denom[1]; - - if (max_digits === Infinity - || math$19.round(quotient, max_digits) === quotient) { - return ['/', quotient, denom[2]]; - } - } - } - else if (typeof denom === 'number') { - // check if numer is a multiplication with that begins with - // a constant. If so combine with denominator - if (Array.isArray(numer) && numer[0] === '*' - && (typeof numer[1] === 'number')) { - let quotient = numer[1] / denom; - if (max_digits === Infinity - || math$19.round(quotient, max_digits) === quotient) { - if (quotient === 1) - return numer[2]; - else - return ['*', quotient, numer[2]]; - } - // if denom is negative move negative to number - if (denom < 0) - return ['/', ['*', -numer[1], numer[2]], -denom]; - } - let reciprocal = 1/denom; - if (max_digits === Infinity - || math$19.round(reciprocal, max_digits) === reciprocal) { - return ['*', reciprocal, numer]; - } - // if denominator is negative, negate whole fraction - if (denom < 0) { - if (Array.isArray(numer) && numer[0] === '-') - return ['/', numer[1], -denom]; - else - return ['-', ['/', numer, -denom]]; - - } - } - return [operator].concat(operands); - - } - - if (operator === '^') { - - let base = operands[0]; - let pow = operands[1]; - - if (typeof pow === 'number') { - if (pow === 0) { - if (!math$19.pow_strict) - return 1; - let base_nonzero = is_nonzero_ast(base, assumptions); - if (base_nonzero && (base !== Infinity) && (base !== -Infinity)) - return 1; - if (base_nonzero === false) - return NaN; // 0^0 - } - else if (pow === 1) { - return base; - } - else if (typeof base === 'number') { - let result = math$19.pow(base, pow); - if (max_digits === Infinity - || math$19.round(result, max_digits) === result) - return result; - - } - } else if (base === 1) { - return 1; - } - return [operator].concat(operands); - } - - return [operator].concat(operands); - } - - - function evaluate_numbers(expr_or_tree, { - assumptions, max_digits, skip_ordering = false, - evaluate_functions = false, - set_small_zero = 0, - } = {}) { - - if (max_digits === undefined || - !(Number.isInteger(max_digits) || max_digits === Infinity)) - max_digits = 0; - - if (set_small_zero === true) { - set_small_zero = 1E-14; - } - - var tree = get_tree(expr_or_tree); - - - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); - - var result; - if (skip_ordering) { - tree = unflattenRight(flatten(tree)); - result = evaluate_numbers_sub( - tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero); - } else { - tree = unflattenRight(default_order(flatten(tree))); - result = default_order(evaluate_numbers_sub( - tree, assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); - // TODO: determine how often have to repeat - result = default_order(evaluate_numbers_sub( - unflattenRight(result), assumptions, max_digits, skip_ordering, evaluate_functions, set_small_zero)); - } - - return flatten(result); - } - - function collect_like_terms_factors(expr_or_tree, assumptions, max_digits) { - - function isNumber(s) { - if (typeof s === 'number') - return true; - if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) - return true; - return false; - } - function isNegativeNumber(s) { - if (typeof s === 'number' && s < 0) - return true; - if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) - return true; - return false; - } - function isNumerical(s) { - if (typeof s === 'number') - return true; - if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) - return true; - let c = evaluate_to_constant(s); - if (typeof c === 'number' && Number.isFinite(c)) - return true; - - return false; - - } - - - var tree = get_tree(expr_or_tree); - - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); - - tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits, evaluate_functions: true }); - - var transformations = []; - - // preliminary transformations - transformations.push([ - [ '/', 'x', [ '^', 'y', 'a' ] ], - [ '*', 'x', [ '^', 'y', [ '-', 'a' ] ] ], - { evaluate_numbers: true, max_digits: max_digits }]); - transformations.push([ - [ '/', 'x', 'y' ], - [ '*', 'x', [ '^', 'y', [ '-', 1 ] ] ], - { evaluate_numbers: true, max_digits: max_digits }]); - tree = applyAllTransformations(tree, transformations, 40); - - // collecting like terms and factors - transformations = []; - transformations.push( - [ - [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], - [ '^', 'x', [ '+', 'n', 'm' ] ], - { - variables: { - x: v => is_nonzero_ast(v, assumptions), - n: isNumber, m: isNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_implicit_identities: ['m', 'n'], - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], - [ '^', 'x', [ '+', 'n', 'm' ] ], - { - variables: { - x: true, - n: v => isNumber(v) && is_positive_ast(v, assumptions), - m: v => isNumber(v) && is_positive_ast(v, assumptions) - }, - evaluate_numbers: true, max_digits: max_digits, - allow_implicit_identities: ['m', 'n'], - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '*', [ '^', 'x', 'n' ], [ '^', 'x', 'm' ] ], - [ '^', 'x', [ '+', 'n', 'm' ] ], - { - variables: { - x: true, - n: v => isNumber(v) && is_negative_ast(v, assumptions), - m: v => isNumber(v) && is_negative_ast(v, assumptions) - }, - evaluate_numbers: true, max_digits: max_digits, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '+', [ '*', 'n', 'x' ], [ '*', 'm', 'x' ] ], - [ '*', [ '+', 'n', 'm' ], 'x' ], - { - variables: { - x: true, - n: isNumber, m: isNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_implicit_identities: ['m', 'n'], - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '+', [ '*', 'n', 'x' ], [ '-', [ '*', 'm', 'x' ] ] ], - [ '*', [ '+', 'n', [ '-', 'm' ] ], 'x' ], - { - variables: { - x: true, - n: isNumber, m: isNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_implicit_identities: ['m', 'n'], - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [ - [ '^', [ '*', 'x', 'y' ], 'a' ], - [ '*', [ '^', 'x', 'a' ], [ '^', 'y', 'a' ] ], - { allow_permutations: true, }] - ); - transformations.push( - [ - [ '^', [ '^', 'x', 'n' ], 'm' ], - [ '^', 'x', [ '*', 'n', 'm' ] ], - { - variables: { - x: true, - n: isNumber, m: isNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_permutations: true, - }] - ); - transformations.push([ - [ '-', [ '+', 'a', 'b' ] ], - [ '+', [ '-', 'a' ], [ '-', 'b' ] ] - ]); - - // evaluate any products - // (required since evaluate_numbers needs to be applied separately - // to complicated products to evaluate them as numbers) - transformations.push( - [ - [ '*', 'x', 'y' ], - [ '*', 'x', 'y' ], - { - variables: { x: isNumerical, y: isNumerical }, - evaluate_numbers: true, max_digits: max_digits, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - - tree = applyAllTransformations(tree, transformations, 40); - - transformations = []; - // redo as division - transformations.push( - [ - [ '*', 'x', [ '^', 'y', [ '-', 'a' ] ] ], - [ '/', 'x', [ '^', 'y', 'a' ] ], - { - allow_extended_match: true, - allow_permutations: true, - evaluate_numbers: true, max_digits: max_digits, - max_group: 1, - }]); - transformations.push([ - [ '*', 'x', [ '^', 'y', 'n' ] ], - [ '/', 'x', [ '^', 'y', [ '-', 'n' ] ] ], - { - variables: { - x: true, y: true, - n: isNegativeNumber - }, - evaluate_numbers: true, max_digits: max_digits, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }]); - tree = applyAllTransformations(tree, transformations, 40); - - transformations = []; - // redo as division, try 2 - transformations.push([ - [ '^', 'y', 'n' ], - [ '/', 1, [ '^', 'y', [ '-', 'n' ] ] ], - { - variables: { - y: true, - n: isNegativeNumber - }, - evaluate_numbers: true, max_digits: max_digits, - }]); - tree = applyAllTransformations(tree, transformations, 40); - - transformations = []; - // '*' before '/' and products in denominator - transformations.push([ - [ '*', 'x', [ '/', 'y', 'z' ] ], - [ '/', [ '*', 'x', 'y' ], 'z' ], - { - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }]); - transformations.push([ - [ '/', [ '/', 'x', 'y' ], 'z' ], - [ '/', 'x', [ '*', 'y', 'z' ] ], - { - allow_extended_match: true, - allow_permutations: true, - }]); - transformations.push([ - [ '/', 'x', [ '/', 'y', 'z' ] ], - [ '/', [ '*', 'x', 'z' ], 'y' ], - { - allow_extended_match: true, - allow_permutations: true, - }]); - tree = applyAllTransformations(tree, transformations, 40); - - tree = evaluate_numbers(tree, { assumptions: assumptions, max_digits: max_digits }); - - return tree; - - } - - function simplify_ratios(expr_or_tree, assumptions) { - - // TODO: actually factor numerator and denominator - // for now, assume factored, other than minus sign - - function remove_negative_factors(factors) { - - var sign_change = 1; - - factors = factors.map(function (v) { - if (typeof v === "number") { - if (v < 0) { - sign_change *= -1; - return -v; - } - return v; - } - if (!Array.isArray(v)) - return v; - - if (v[0] === '-') { - sign_change *= -1; - return v[1]; - } - if (v[0] !== '+') - return v; - - var negate = false; - if ((typeof v[1] === "number") && v[1] < 0) - negate = true; - else if (Array.isArray(v[1]) && v[1][0] === '-') - negate = true; - else if (Array.isArray(v[1]) && v[1][0] === '*' && Number(v[1][1]) < 0) { - negate = true; - } - - if (negate) { - sign_change *= -1; - var v_ops = v.slice(1).map(x => ['-', x]); - return evaluate_numbers(['+'].concat(v_ops)); - } - else - return v; - }); - - return { factors: factors, sign_change: sign_change }; - } - - function simplify_ratios_sub(tree, negated) { - - if (!Array.isArray(tree)) { - if (negated) { - return ['-', tree]; - } else { - return tree; - } - } - - var operator = tree[0]; - if (operator === "-") { - return simplify_ratios_sub(tree[1], negated = true); - } - var operands = tree.slice(1).map(v => simplify_ratios_sub(v)); - - if (operator !== '/') { - if (negated) { - return ['-', [operator, ...operands]] - } else { - return [operator, ...operands]; - } - } - - var numer = operands[0]; - var denom = operands[1]; - - // factor a minus sign from each factor in numerator and denominator - // if it is negative or it is a sum with a negative first term - // (when terms are sorted as though they were not negative) - - numer = default_order(numer, { ignore_negatives: true }); - var numer_factors; - if (Array.isArray(numer) && numer[0] === '*') - numer_factors = numer.slice(1); - else - numer_factors = [numer]; - var result_n = remove_negative_factors(numer_factors); - numer_factors = result_n["factors"]; - if (negated) { - result_n["sign_change"] *= -1; - } - - denom = default_order(denom, { ignore_negatives: true }); - var denom_factors; - if (Array.isArray(denom) && denom[0] === '*') - denom_factors = denom.slice(1); - else - denom_factors = [denom]; - var result_d = remove_negative_factors(denom_factors); - denom_factors = result_d["factors"]; - - if (result_n["sign_change"] * result_d["sign_change"] < 0) - numer_factors[0] = ['-', numer_factors[0]]; - - if (numer_factors.length === 1) - numer = numer_factors[0]; - else - numer = ['*'].concat(numer_factors); - if (denom_factors.length === 1) - denom = denom_factors[0]; - else - denom = ['*'].concat(denom_factors); - - return ['/', numer, denom]; - - } - - - var tree = get_tree(expr_or_tree); - - if (assumptions === undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); - - return simplify_ratios_sub(tree); - - } - - var simplify$3 = /*#__PURE__*/Object.freeze({ - clean: clean, - simplify: simplify$2, - simplify_logical: simplify_logical, - evaluate_numbers: evaluate_numbers, - collect_like_terms_factors: collect_like_terms_factors, - collapse_unary_minus: collapse_unary_minus, - simplify_ratios: simplify_ratios, - default_order: default_order - }); - - function tuples_to_vectors(expr_or_tree) { - // convert tuple to vectors - // except if tuple is argument of a function, gts, lts, or interval - - var tree = get_tree(expr_or_tree); - - if (typeof tree === 'number') { - return tree; - } - - if (typeof tree === 'string') { - return tree; - } - - if (typeof tree === 'boolean') { - return tree; - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === 'tuple') { - let result = ['vector'].concat( operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); - return result; - } - - if (operator === 'apply') { - if(operands[1][0] === 'tuple') { - // special case for function applied to tuple. - // preserve tuple - let f = tuples_to_vectors(operands[0]); - let f_operands = operands[1].slice(1); - let f_tuple = ['tuple'].concat( f_operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); - return ['apply', f, f_tuple]; - } - // no special case for function applied to single argument - } - else if(operator === 'gts' || operator === 'lts' || operator === 'interval') { - // don't change tuples of gts, lts, or interval - let args = operands[0]; - let booleans = operands[1]; - - if(args[0] !== 'tuple' || booleans[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); - - let args2= ['tuple'].concat( args.slice(1).map( function(v,i) { return tuples_to_vectors(v); } ) ); - - return [operator, args2, booleans]; - } - - var result = [operator].concat( operands.map( function(v,i) { return tuples_to_vectors(v); } ) ); - return result; - } - - function to_intervals(expr_or_tree) { - // convert tuple and arrays of two arguments to intervals - // except if tuple is argument of a function, gts, lts, or interval - - var tree = get_tree(expr_or_tree); - - if (typeof tree === 'number') { - return tree; - } - - if (typeof tree === 'string') { - return tree; - } - - if (typeof tree === 'boolean') { - return tree; - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === 'tuple' && operands.length === 2) { - // open interval - let result = ['tuple'].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); - result = ['interval', result, ['tuple', false, false]]; - return result; - } - if(operator === 'array' && operands.length === 2) { - // closed interval - let result = ['tuple'].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); - result = ['interval', result, ['tuple', true, true]]; - return result; - } - - if (operator === 'apply') { - if(operands[1][0] === 'tuple') { - // special case for function applied to tuple. - // preserve tuple - let f = to_intervals(operands[0]); - let f_operands = operands[1].slice(1); - let f_tuple = ['tuple'].concat( f_operands.map( function(v,i) { return to_intervals(v); } ) ); - return ['apply', f, f_tuple]; - } - // no special case for function applied to single argument - } - else if(operator === 'gts' || operator === 'lts' || operator === 'interval') { - // don't change tuples of gts, lts, or interval - let args = operands[0]; - let booleans = operands[1]; - - if(args[0] !== 'tuple' || booleans[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); - - let args2= ['tuple'].concat( args.slice(1).map( function(v,i) { return to_intervals(v); } ) ); - - return [operator, args2, booleans]; - } - - var result = [operator].concat( operands.map( function(v,i) { return to_intervals(v); } ) ); - return result; - } - - function ParseError(message, location) { - this.name = 'ParseError'; - this.message = message || 'Error parsing input'; - this.stack = (new Error()).stack; - this.location = location; - } - ParseError.prototype = Object.create(Error.prototype); - ParseError.prototype.constructor = ParseError; - - // lexer class - // - // Processes input string to return tokens - // - // Token rules: - // array of rules to identify tokens - // Rules will be applied in order until a match is found. - // Each rule is an array of two or three elements - // First element: a string to be converted into a regular expression - // Second element: the token type - // Third element (optional): replacement for actual string matched - - - class lexer { - constructor(token_rules, whitespace='\\s') { - - this.input = ''; - this.location = 0; - this.token_rules=[]; - - // regular expression to identify whitespace at beginning - this.initial_whitespace = new RegExp('^(' + whitespace + ')+'); - - // convert first element of each rule to a regular expression that - // starts at the beginning of the string - for(let rule of token_rules) { - this.token_rules.push([new RegExp('^'+rule[0])].concat(rule.slice(1))); - } - } - - set_input(input) { - if(typeof input !== "string") - throw new Error("Input must be a string"); - - this.input = input; - this.location = 0; - } - - return_state() { - return({ input: this.input, location: this.location }); - } - - set_state({ input=null, location=0 } = {}) { - - if(input !== null) { - this.input = input; - this.location = location; - } - } - - - advance({ remove_initial_space=true } = {}) { - // Find next token at beginning of input and delete from input. - // Update location to be the position in original input corresponding - // to end of match. - // Return token, which is an array of token type and matched string - - - let result = this.initial_whitespace.exec(this.input); - if(result) { - //first find any initial whitespace and adjust location - let n_whitespace = result[0].length; - this.input = this.input.slice(n_whitespace); - this.location += n_whitespace; - - // don't remove initial space, return it as next token - if(!remove_initial_space) { - return { - token_type: "SPACE", - token_text: result[0], - original_text: result[0], - } - } - - // otherwise ignore initial space and continue - } - - // check for EOF - if(this.input.length === 0) { - return { - token_type: "EOF", - token_text: "", - original_text: "", - } - } - - // search through each token rule in order, finding first match - result = null; - - for(var rule of this.token_rules) { - result = rule[0].exec(this.input); - - if(result) { - let n_characters = result[0].length; - this.input = this.input.slice(n_characters); - this.location += n_characters; - break; - } - } - - // case that didn't find any matches - if(result === null) { - return { - token_type: "INVALID", - token_text: this.input[0], - original_text: this.input[0], - } - } - - // found a match, set token - if(rule.length > 2) { - // overwrite text by third element of rule - return { token_type: rule[1], - token_text: rule[2], - original_text: result[0], - }; - } - else { - return { token_type: rule[1], - token_text: result[0], - original_text: result[0], - }; - } - } - - - unput(string) { - // add string to beginning of input and adjust location - - if(typeof string !== "string") - throw new Error("Input must be a string"); - - this.location -= string.length; - this.input = string + this.input; - - } - - } - - var is_associative$1 = { '+': true, '*': true, 'and': true, 'or': true, 'union': true, 'intersect': true}; - - function flatten$18(tree) { - - // flatten tree with all associative operators - - if(!Array.isArray(tree)) - return tree; - - var operator = tree[0]; - var operands = tree.slice(1); - - operands = operands.map( function(v,i) { - return flatten$18(v); } ); - - if (is_associative$1[operator]) { - var result = []; - - for( var i=0; i - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - - // UPDATETHIS: Is this grammar still correct? - - /* Grammar: - - statement_list = - statement_list ',' statement | - statement - - statement = - '...' | - statement_a '|' statement_a | - statement_a ':' statement_a | - statement_a - **** statement_a '|' statement_a - used with turning off '|' statement '|' in baseFactor - tried only after parse error encountered - - statement_a = - statement_a 'OR' statement_b | - statement_b - - statement_b = - statement_b 'AND' relation | - relation - - relation = - 'NOT' relation | - '!' relation | - relation '=' expression | - relation 'NE' expression | - relation '<' expression | - relation '>' expression | - relation 'LE' expression | - relation 'GE' expression | - relation 'IN' expression | - relation 'NOTIN' expression | - relation 'NI' expression | - relation 'NOTNI' expression | - relation 'SUBSET' expression | - relation 'NOTSUBSET' expression | - relation 'SUPERSET' expression | - relation 'NOTSUPERSET' expression | - expression - - expression = - expression '+' term | - expression '-' term | - expression 'UNION' term | - expression 'INTERSECT' term | - '+' term | - term - - term = - term '*' factor | - term nonMinusFactor | - term '/' factor | - factor - - baseFactor = - '(' statement_list ')' | - '[' statement_list ']' | - '{' statement_list '}' | - '(' statement ',' statement ']' | - '[' statement ',' statement ')' | - '|' statement '|' | - number | - variable | - modified_function '(' statement_list ')' | - modified_applied_function '(' statement_list ')' | - modified_function | - modified_applied_function factor | - baseFactor '_' baseFactor | - *** modified_applied_function factor - allowed only if allowSimplifiedFunctionApplication==true - *** '|' statement '|' - allowed only at beginning of factor or if not currently in absolute value - - - modified_function = - function | - function '_' baseFactor | - function '_' baseFactor '^' factor | - function '^' factor - function "'" - function '_' baseFactor "'" - function '_' baseFactor "'" '^' factor - function "'" '^' factor - *** where the "'" after the functions can be repeated - - modified_applied_function = - applied_function | - applied_function '_' baseFactor | - applied_function '_' baseFactor '^' factor | - applied_function '^' factor - applied_function "'" - applied_function '_' baseFactor "'" - applied_function '_' baseFactor "'" '^' factor - applied_function "'" '^' factor - *** where the "'" after the applied_functions can be repeated - - nonMinusFactor = - baseFactor | - baseFactor '^' factor | - baseFactor '!' and/or "'" | - baseFactor '!' and/or "'" '^' factor| - *** where '!' and/or "'" indicates arbitrary sequence of "!" and/or "'" - - factor = - '-' factor | - nonMinusFactor - - */ - - // in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, - // it must be at the end or followed a comma, |, ), }, or ] - const sci_notat_exp_regex = '(E[+\\-]?[0-9]+\\s*($|(?=\\,|\\||\\)|\\}|\\])))?'; - - - const text_rules = [ - // in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, - // it must be at the end or followed a |, or a closing ),}, or ] - ['[0-9]+(\\.[0-9]*)?' + sci_notat_exp_regex, 'NUMBER'], - ['\\.[0-9]+' + sci_notat_exp_regex, 'NUMBER'], - ['\\*\\*', '^'], - ['\\*', '*'], // there is some variety in multiplication symbols - ['\\xB7', '*'], // '·' - ['\u00B7', '*'], // '·' - ['\u2022', '*'], // '•' - ['\u22C5', '*'], // '⋅' - ['\u00D7', '*'], // '×' - ['/', '/'], - ['-', '-'], // there is quite some variety with unicode hyphens - ['\u058A', '-'], // '֊' - ['\u05BE', '-'], // '־' - ['\u1806', '-'], // '᠆' - ['\u2010', '-'], // '‐' - ['\u2011', '-'], // '‑' - ['\u2012', '-'], // '‒' - ['\u2013', '-'], // '–' - ['\u2014', '-'], // '—' - ['\u2015', '-'], // '―' - ['\u207B', '-'], // '⁻' - ['\u208B', '-'], // '₋' - ['\u2212', '-'], // '−' - ['\u2E3A', '-'], // '⸺' - ['\u2E3B', '-'], // '⸻' - ['\uFE58', '-'], // '﹘' - ['\uFE63', '-'], // '﹣' - ['\uFF0D', '-'], // '-' - ['\\+', '+'], - ['\\^', '^'], // a few ways to denote exponentiation - ['\u2038', '^'], // '‸' - ['\u028C', '^'], // 'ʌ' - ['\\|', '|'], - ['\\(', '('], - ['\\)', ')'], - ['\\[', '['], - ['\\]', ']'], - ['\\{', '{'], - ['\\}', '}'], - [',', ','], - [':', ':'], - - ['\u03B1', 'VARMULTICHAR', 'alpha'], // 'α' - ['\u03B2', 'VARMULTICHAR', 'beta'], // 'β' - ['\u03D0', 'VARMULTICHAR', 'beta'], // 'ϐ' - ['\u0393', 'VARMULTICHAR', 'Gamma'], // 'Γ' - ['\u03B3', 'VARMULTICHAR', 'gamma'], // 'γ' - ['\u0394', 'VARMULTICHAR', 'Delta'], // 'Δ' - ['\u03B4', 'VARMULTICHAR', 'delta'], // 'δ' - ['\u03B5', 'VARMULTICHAR', 'epsilon'], // 'ε' should this be varepsilon? - ['\u03F5', 'VARMULTICHAR', 'epsilon'], // 'ϵ' - ['\u03B6', 'VARMULTICHAR', 'zeta'], // 'ζ' - ['\u03B7', 'VARMULTICHAR', 'eta'], // 'η' - ['\u0398', 'VARMULTICHAR', 'Theta'], // 'Θ' - ['\u03F4', 'VARMULTICHAR', 'Theta'], // 'ϴ' - ['\u03B8', 'VARMULTICHAR', 'theta'], // 'θ' - ['\u1DBF', 'VARMULTICHAR', 'theta'], // 'ᶿ' - ['\u03D1', 'VARMULTICHAR', 'theta'], // 'ϑ' - ['\u03B9', 'VARMULTICHAR', 'iota'], // 'ι' - ['\u03BA', 'VARMULTICHAR', 'kappa'], // 'κ' - ['\u039B', 'VARMULTICHAR', 'Lambda'], // 'Λ' - ['\u03BB', 'VARMULTICHAR', 'lambda'], // 'λ' - ['\u03BC', 'VARMULTICHAR', 'mu'], // 'μ' - ['\u00B5', 'VARMULTICHAR', 'mu'], // 'µ' should this be micro? - ['\u03BD', 'VARMULTICHAR', 'nu'], // 'ν' - ['\u039E', 'VARMULTICHAR', 'Xi'], // 'Ξ' - ['\u03BE', 'VARMULTICHAR', 'xi'], // 'ξ' - ['\u03A0', 'VARMULTICHAR', 'Pi'], // 'Π' - ['\u03C0', 'VARMULTICHAR', 'pi'], // 'π' - ['\u03D6', 'VARMULTICHAR', 'pi'], // 'ϖ' should this be varpi? - ['\u03C1', 'VARMULTICHAR', 'rho'], // 'ρ' - ['\u03F1', 'VARMULTICHAR', 'rho'], // 'ϱ' should this be varrho? - ['\u03A3', 'VARMULTICHAR', 'Sigma'], // 'Σ' - ['\u03C3', 'VARMULTICHAR', 'sigma'], // 'σ' - ['\u03C2', 'VARMULTICHAR', 'sigma'], // 'ς' should this be varsigma? - ['\u03C4', 'VARMULTICHAR', 'tau'], // 'τ' - ['\u03A5', 'VARMULTICHAR', 'Upsilon'], // 'Υ' - ['\u03C5', 'VARMULTICHAR', 'upsilon'], // 'υ' - ['\u03A6', 'VARMULTICHAR', 'Phi'], // 'Φ' - ['\u03C6', 'VARMULTICHAR', 'phi'], // 'φ' should this be varphi? - ['\u03D5', 'VARMULTICHAR', 'phi'], // 'ϕ' - ['\u03A8', 'VARMULTICHAR', 'Psi'], // 'Ψ' - ['\u03C8', 'VARMULTICHAR', 'psi'], // 'ψ' - ['\u03A9', 'VARMULTICHAR', 'Omega'], // 'Ω' - ['\u03C9', 'VARMULTICHAR', 'omega'], // 'ω' - - - ['oo\\b', 'INFINITY'], - ['OO\\b', 'INFINITY'], - ['infty\\b', 'INFINITY'], - ['infinity\\b', 'INFINITY'], - ['Infinity\\b', 'INFINITY'], - ['\u221E', 'INFINITY'], // '∞' - - ['\u212F', 'VAR', 'e'], // 'ℯ' - - ['\u2660', 'VARMULTICHAR', 'spade'], // '♠' - ['\u2661', 'VARMULTICHAR', 'heart'], // '♡' - ['\u2662', 'VARMULTICHAR', 'diamond'], // '♢' - ['\u2663', 'VARMULTICHAR', 'club'], // '♣' - ['\u2605', 'VARMULTICHAR', 'bigstar'], // '★' - ['\u25EF', 'VARMULTICHAR', 'bigcirc'], // '◯' - ['\u25CA', 'VARMULTICHAR', 'lozenge'], // '◊' - ['\u25B3', 'VARMULTICHAR', 'bigtriangleup'], // '△' - ['\u25BD', 'VARMULTICHAR', 'bigtriangledown'], // '▽' - ['\u29EB', 'VARMULTICHAR', 'blacklozenge'], // '⧫' - ['\u25A0', 'VARMULTICHAR', 'blacksquare'], // '■' - ['\u25B2', 'VARMULTICHAR', 'blacktriangle'], // '▲' - ['\u25BC', 'VARMULTICHAR', 'blacktriangledown'], //'▼' - ['\u25C0', 'VARMULTICHAR', 'blacktriangleleft'], // '◀' - ['\u25B6', 'VARMULTICHAR', 'blacktriangleright'], // '▶' - ['\u25A1', 'VARMULTICHAR', 'Box'], // '□' - ['\u2218', 'VARMULTICHAR', 'circ'], // '∘' - ['\u22C6', 'VARMULTICHAR', 'star'], // '⋆' - - ['and\\b', 'AND'], - ['\\&\\&?', 'AND'], - ['\u2227', 'AND'], // '∧' - - ['or\\b', 'OR'], - ['\u2228', 'OR'], // '∨' - - ['not\\b', 'NOT'], - ['\u00ac', 'NOT'], // '¬' - - ['=', '='], - ['\u1400', '='], // '᐀' - ['\u30A0', '='], // '゠' - ['!=', 'NE'], - ['\u2260', 'NE'], // '≠' - ['<=', 'LE'], - ['\u2264', 'LE'], // '≤' - ['>=', 'GE'], - ['\u2265', 'GE'], // '≥' - ['<', '<'], - ['>', '>'], - - ['elementof\\b', 'IN'], - ['\u2208', 'IN'], // '∈' - - ['notelementof\\b', 'NOTIN'], - ['\u2209', 'NOTIN'], //'∉' - - ['containselement\\b', 'NI'], - ['\u220B', 'NI'], // '∋' - - ['notcontainselement\\b', 'NOTNI'], - ['\u220C', 'NOTNI'], // '∌' - - ['subset\\b', 'SUBSET'], - ['\u2282', 'SUBSET'], // '⊂' - - ['notsubset\\b', 'NOTSUBSET'], - ['\u2284', 'NOTSUBSET'], // '⊄' - - ['superset\\b', 'SUPERSET'], - ['\u2283', 'SUPERSET'], // '⊃' - - ['notsuperset\\b', 'NOTSUPERSET'], - ['\u2285', 'NOTSUPERSET'], //'⊅' - - ['union\\b', 'UNION'], - ['\u222A', 'UNION'], // '∪' - - ['intersect\\b', 'INTERSECT'], - ['\u2229', 'INTERSECT'], //'∩' - - ['!', '!'], - ['\'', '\''], - ['_', '_'], - ['\\.\\.\\.', 'LDOTS'], - ['[a-zA-Z∂][a-zA-Z∂0-9]*', 'VAR'], // include ∂ in VAR - ]; - - - // defaults for parsers if not overridden by context - - // if true, allowed applied functions to omit parentheses around argument - // if false, omitting parentheses will lead to a Parse Error - const allowSimplifiedFunctionApplicationDefault = true; - - // if true, split multicharacter symbols into a product of letters - const splitSymbolsDefault = true; - - // symbols that won't be split into a product of letters if splitSymbols==true - const unsplitSymbolsDefault = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega']; - - // Applied functions must be given an argument so that - // they are applied to the argument - const appliedFunctionSymbolsDefault = ["abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg', 'conj']; - - // Functions could have an argument, in which case they are applied - // or, if they don't have an argument in parentheses, then they are treated - // like a variable, except that trailing ^ and ' have higher precedence - const functionSymbolsDefault = ['f', 'g']; - - // Parse Leibniz notation - const parseLeibnizNotationDefault = true; - - - class textToAst { - constructor({ - allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplicationDefault, - splitSymbols = splitSymbolsDefault, - unsplitSymbols = unsplitSymbolsDefault, - appliedFunctionSymbols = appliedFunctionSymbolsDefault, - functionSymbols = functionSymbolsDefault, - parseLeibnizNotation = parseLeibnizNotationDefault, - } = {}) { - this.allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplication; - this.splitSymbols = splitSymbols; - this.unsplitSymbols = unsplitSymbols; - this.appliedFunctionSymbols = appliedFunctionSymbols; - this.functionSymbols = functionSymbols; - this.parseLeibnizNotation = parseLeibnizNotation; - - this.lexer = new lexer(text_rules); - - } - - advance(params) { - this.token = this.lexer.advance(params); - if (this.token.token_type === 'INVALID') { - throw new ParseError("Invalid symbol '" + this.token.original_text + "'", - this.lexer.location); - } - } - - return_state() { - return ({ - lexer_state: this.lexer.return_state(), - token: Object.assign({}, this.token) - }); - } - - set_state(state) { - this.lexer.set_state(state.lexer_state); - this.token = Object.assign({}, state.token); - } - - - convert(input) { - - this.lexer.set_input(input); - this.advance(); - - var result = this.statement_list(); - - if (this.token.token_type !== 'EOF') { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } - - return flatten$18(result); - - } - - - statement_list() { - - var list = [this.statement()]; - - while (this.token.token_type === ",") { - this.advance(); - list.push(this.statement()); - } - - if (list.length > 1) - list = ['list'].concat(list); - else - list = list[0]; - - return list; - } - - statement({ inside_absolute_value = 0 } = {}) { - - // three periods ... can be a statement by itself - if (this.token.token_type === 'LDOTS') { - this.advance(); - return ['ldots']; - } - - var original_state; - - try { - - original_state = this.return_state(); - - let lhs = this.statement_a({ inside_absolute_value: inside_absolute_value }); - - if (this.token.token_type !== ':') - return lhs; - - this.advance(); - - let rhs = this.statement_a(); - - return [':', lhs, rhs]; - - } - catch (e) { - try { - - // if ran into problem parsing statement - // then try again with ignoring absolute value - // and then interpreting bar as a binary operator - - // return state to what it was before attempting to parse statement - this.set_state(original_state); - - let lhs = this.statement_a({ parse_absolute_value: false }); - - if (this.token.token_type !== '|') { - throw (e); - } - - this.advance(); - - let rhs = this.statement_a({ parse_absolute_value: false }); - - return ['|', lhs, rhs]; - - } - catch (e2) { - throw (e); // throw original error - } - } - } - - statement_a({ inside_absolute_value = 0, parse_absolute_value = true } = {}) { - - var lhs = this.statement_b({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value - }); - - while (this.token.token_type === 'OR') { - - let operation = this.token.token_type.toLowerCase(); - - this.advance(); - - let rhs = this.statement_b({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value - }); - - lhs = [operation, lhs, rhs]; - } - - return lhs; - } - - statement_b(params) { - // split AND into second statement to give higher precedence than OR - - var lhs = this.relation(params); - - while (this.token.token_type === 'AND') { - - let operation = this.token.token_type.toLowerCase(); - - this.advance(); - - let rhs = this.relation(params); - - lhs = [operation, lhs, rhs]; - } - - return lhs; - } - - - relation(params) { - - if (this.token.token_type === 'NOT' || this.token.token_type === '!') { - this.advance(); - return ['not', this.relation(params)]; - } - - var lhs = this.expression(params); - - while ((this.token.token_type === '=') || (this.token.token_type === 'NE') || - (this.token.token_type === '<') || (this.token.token_type === '>') || - (this.token.token_type === 'LE') || (this.token.token_type === 'GE') || - (this.token.token_type === 'IN') || (this.token.token_type === 'NOTIN') || - (this.token.token_type === 'NI') || (this.token.token_type === 'NOTNI') || - (this.token.token_type === 'SUBSET') || (this.token.token_type === 'NOTSUBSET') || - (this.token.token_type === 'SUPERSET') || (this.token.token_type === 'NOTSUPERSET')) { - - let operation = this.token.token_type.toLowerCase(); - - let inequality_sequence = 0; - - if ((this.token.token_type === '<') || (this.token.token_type === 'LE')) { - inequality_sequence = -1; - } else if ((this.token.token_type === '>') || (this.token.token_type === 'GE')) { - inequality_sequence = 1; - } - - this.advance(); - let rhs = this.expression(params); - - if (inequality_sequence === -1) { - if ((this.token.token_type === '<') || this.token.token_type === 'LE') { - // sequence of multiple < or <= - let strict = ['tuple']; - if (operation === '<') - strict.push(true); - else - strict.push(false); - - let args = ['tuple', lhs, rhs]; - while ((this.token.token_type === '<') || this.token.token_type === 'LE') { - if (this.token.token_type === '<') - strict.push(true); - else - strict.push(false); - - this.advance(); - args.push(this.expression(params)); - } - lhs = ['lts', args, strict]; - } else { - lhs = [operation, lhs, rhs]; - } - - } else if (inequality_sequence === 1) { - if ((this.token.token_type === '>') || this.token.token_type === 'GE') { - // sequence of multiple > or >= - let strict = ['tuple']; - if (operation === '>') - strict.push(true); - else - strict.push(false); - - let args = ['tuple', lhs, rhs]; - while ((this.token.token_type === '>') || this.token.token_type === 'GE') { - if (this.token.token_type === '>') - strict.push(true); - else - strict.push(false); - - this.advance(); - args.push(this.expression(params)); - } - lhs = ['gts', args, strict]; - } else { - lhs = [operation, lhs, rhs]; - } - - } else if (operation === '=') { - lhs = ['=', lhs, rhs]; - - // check for sequence of multiple = - while (this.token.token_type === '=') { - this.advance(); - lhs.push(this.expression(params)); - } - } else { - - lhs = [operation, lhs, rhs]; - } - - } - - return lhs; - } - - - expression(params) { - if (this.token.token_type === '+') - this.advance(); - - let negative_begin = false; - if (this.token.token_type === '-') { - negative_begin = true; - this.advance(); - } - - var lhs = this.term(params); - - if (negative_begin) { - lhs = ['-', lhs]; - } - - while ((this.token.token_type === '+') || (this.token.token_type === '-') - || (this.token.token_type === 'UNION') || - (this.token.token_type === 'INTERSECT')) { - - let operation = this.token.token_type.toLowerCase(); - let negative = false; - - if (this.token.token_type === '-') { - operation = '+'; - negative = true; - this.advance(); - } else { - this.advance(); - if (operation === '+' && this.token.token_type === '-') { - negative = true; - this.advance(); - } - } - let rhs = this.term(params); - if (negative) { - rhs = ['-', rhs]; - } - - lhs = [operation, lhs, rhs]; - } - - return lhs; - } - - - term(params) { - var lhs = this.factor(params); - - var keepGoing = false; - - do { - keepGoing = false; - - if (this.token.token_type === '*') { - this.advance(); - lhs = ['*', lhs, this.factor(params)]; - keepGoing = true; - } else if (this.token.token_type === '/') { - this.advance(); - lhs = ['/', lhs, this.factor(params)]; - keepGoing = true; - } else { - // this is the one case where a | could indicate a closing absolute value - let params2 = Object.assign({}, params); - params2.allow_absolute_value_closing = true; - let rhs = this.nonMinusFactor(params2); - if (rhs !== false) { - lhs = ['*', lhs, rhs]; - keepGoing = true; - } - } - } while (keepGoing); - - return lhs; - } - - - factor(params) { - - if (this.token.token_type === '-') { - this.advance(); - return ['-', this.factor(params)]; - } - - var result = this.nonMinusFactor(params); - - if (result === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", this.lexer.location); - } else { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } - } else { - return result; - } - - } - - nonMinusFactor(params) { - - var result = this.baseFactor(params); - - // allow arbitrary sequence of factorials - if (this.token.token_type === '!' || this.token.token_type === "'") { - if (result === false) - throw new ParseError("Invalid location of " + this.token.token_type, - this.lexer.location); - while (this.token.token_type === '!' || this.token.token_type === "'") { - if (this.token.token_type === '!') - result = ['apply', 'factorial', result]; - else - result = ['prime', result]; - this.advance(); - } - } - - if (this.token.token_type === '^') { - if (result === false) { - throw new ParseError("Invalid location of ^", this.lexer.location); - } - this.advance(); - - // do not allow absolute value closing here - let params2 = Object.assign({}, params); - delete params2.allow_absolute_value_closing; - delete params2.inside_absolute_value; - - return ['^', result, this.factor(params2)]; - } - - return result; - } - - - baseFactor({ inside_absolute_value = 0, - parse_absolute_value = true, - allow_absolute_value_closing = false - } = {}) { - - var result = false; - - if (this.token.token_type === 'NUMBER') { - result = parseFloat(this.token.token_text); - this.advance(); - } else if (this.token.token_type === 'INFINITY') { - result = Infinity; - this.advance(); - } else if (this.token.token_type === 'VAR' || this.token.token_type === 'VARMULTICHAR') { - result = this.token.token_text; - - if (this.appliedFunctionSymbols.includes(result) || - this.functionSymbols.includes(result)) { - let must_apply = false; - if (this.appliedFunctionSymbols.includes(result)) - must_apply = true; - - this.advance(); - - if (this.token.token_type === '_') { - this.advance(); - let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); - - // since baseFactor could return false, must check - if (subresult === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", - this.lexer.location); - } else { - throw new ParseError("Invalid location of '" + this.token.original_text + - "'", this.lexer.location); - } - } - result = ['_', result, subresult]; - } - - while (this.token.token_type === "'") { - result = ['prime', result]; - this.advance(); - } - - if (this.token.token_type === '^') { - this.advance(); - result = ['^', result, this.factor({ parse_absolute_value: parse_absolute_value })]; - } - - if (this.token.token_type === '(') { - this.advance(); - let parameters = this.statement_list(); - - if (this.token.token_type !== ')') { - throw new ParseError('Expecting )', this.lexer.location); - } - this.advance(); - - if (parameters[0] === 'list') { - // rename from list to tuple - parameters[0] = 'tuple'; - } - - result = ['apply', result, parameters]; - } else { - // if was an applied function symbol, - // cannot omit argument - if (must_apply) { - if (!this.allowSimplifiedFunctionApplication) - throw new ParseError("Expecting ( after function", - this.lexer.location); - - // if allow simplied function application - // let the argument be the next factor - result = ['apply', result, this.factor({ parse_absolute_value: parse_absolute_value })]; - } - } - } else { - - // determine if may be a derivative in Leibniz notation - if (this.parseLeibnizNotation) { - - let original_state = this.return_state(); - - let r = this.leibniz_notation(); - - if (r) { - // successfully parsed derivative in Leibniz notation, so return - return r; - } - else { - // didn't find a properly format Leibniz notation - // so reset state and continue - this.set_state(original_state); - } - } - - // determine if should split text into single letter factors - let split = this.splitSymbols; - - if (split) { - if (this.token.token_type === 'VARMULTICHAR' || - this.unsplitSymbols.includes(result) || - result.length === 1) { - split = false; - } else if (result.match(/[\d]/g)) { - // don't split if has a number in it - split = false; - } - } - - if (split) { - // so that each character gets processed separately - // put all characters back on the input - // but with spaces - // then process again - - for (let i = result.length - 1; i >= 0; i--) { - this.lexer.unput(" "); - this.lexer.unput(result[i]); - } - this.advance(); - - return this.baseFactor({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value, - allow_absolute_value_closing: allow_absolute_value_closing - }); - } else { - this.advance(); - } - } - } else if (this.token.token_type === '(' || this.token.token_type === '[' || - this.token.token_type === '{') { - let token_left = this.token.token_type; - let expected_right, other_right; - if (this.token.token_type === '(') { - expected_right = ')'; - other_right = ']'; - } else if (this.token.token_type === '[') { - expected_right = ']'; - other_right = ')'; - } else { - expected_right = '}'; - other_right = null; - } - - this.advance(); - result = this.statement_list(); - - let n_elements = 1; - if (result[0] === "list") { - n_elements = result.length - 1; - } - - if (this.token.token_type !== expected_right) { - if (n_elements !== 2 || other_right === null) { - throw new ParseError('Expecting ' + expected_right, - this.lexer.location); - } else if (this.token.token_type !== other_right) { - throw new ParseError('Expecting ) or ]', this.lexer.location); - } - - // half-open interval - result[0] = 'tuple'; - result = ['interval', result]; - let closed; - if (token_left === '(') - closed = ['tuple', false, true]; - else - closed = ['tuple', true, false]; - result.push(closed); - - } else if (n_elements >= 2) { - if (token_left === '(') { - result[0] = 'tuple'; - } else if (token_left === '[') { - result[0] = 'array'; - } else { - result[0] = 'set'; - } - } else if (token_left === '{') { - if (result[0] === '|' || result[0] === ':') { - result = ['set', result]; // set builder notation - } - else { - result = ['set', result]; // singleton set - } - } - - this.advance(); - - } else if (this.token.token_type === '|' && parse_absolute_value && - (inside_absolute_value === 0 || !allow_absolute_value_closing)) { - - // allow the opening of an absolute value here if either - // - we aren't already inside an absolute value (inside_absolute_value==0), or - // - we don't allows an absolute value closing - // otherwise, skip this token so that will drop out the factor (and entire statement) - // to where the absolute value will close - - inside_absolute_value += 1; - - this.advance(); - - result = this.statement({ inside_absolute_value: inside_absolute_value }); - result = ['apply', 'abs', result]; - - if (this.token.token_type !== '|') { - throw new ParseError('Expecting |', this.lexer.location); - } - - this.advance(); - } - - if (this.token.token_type === '_') { - if (result === false) { - throw new ParseError("Invalid location of _", this.lexer.location); - } - this.advance(); - let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); - - if (subresult === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", this.lexer.location); - } else { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } - } - return ['_', result, subresult]; - } - - return result; - } - - - leibniz_notation() { - // attempt to find and return a derivative in Leibniz notation - // if unsuccessful, return false - - var result = this.token.token_text; - - if (!(this.token.token_type === 'VAR' && (result[0] === "d" || result[0] === "∂") - && (result.length === 1 || (result.length === 2 && /[a-zA-Z]/.exec(result[1]))))) { - return false; - } - - // found one of these two possibilities for start of derivative are - // - dx or ∂x (no space, x is a single letter) - // - d or ∂ - - let deriv_symbol = result[0]; - - let n_deriv = 1; - - let var1 = ""; - let var2s = []; - let var2_exponents = []; - - if (result.length === 2) - var1 = result[1]; - else { // result is length 1 - - // since have just a d or ∂ - // must be followed by a ^ or a VARMULTICHAR/VAR with no ∂ - this.advance(); - if (this.token.token_type === 'VARMULTICHAR' || - (this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) - ) { - var1 = this.token.token_text; - } - - else { - // since not VARMULTICHAR, must be a ^ next - if (this.token.token_type !== '^') { - return false; - } - - // so far have d or ∂ followed by ^ - // must be followed by an integer - this.advance(); - - if (this.token.token_type !== 'NUMBER') { - return false; - } - - n_deriv = parseFloat(this.token.token_text); - if (!Number.isInteger(n_deriv)) { - return false; - } - - // see if next character is single character - this.advance(); - - // either a VAR with no ∂ - // or a VARMULTICHAR - if ((this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) - || this.token.token_type === 'VARMULTICHAR') { - var1 = this.token.token_text; - } - else { - return false; - } - } - } - - // next character must be a / - - this.advance(); // allow a space this time - - if (this.token.token_type !== '/') - return false; - - // find sequence of - // derivative symbol followed by a single character or VARMULTICHAR (with no space) - // optionally followed by a ^ and an integer (with no spaces) - // (with spaces allowed between elements of sequence) - // End when sum of exponents meets or exceeds n_deriv - - let exponent_sum = 0; - - this.advance(); // allow space just after the / - - while (true) { - - // next must either be - // - a VAR whose first character matches derivative symbol - // and whose second character is a letter, or - // - a single character VAR that matches derivative symbol - // which must be followed by a VARMULTICHAR/VAR with no ∂ - - if (this.token.token_type !== 'VAR' || this.token.token_text[0] !== deriv_symbol) { - return false; - } - - if (this.token.token_text.length > 2) { - // Put extra characters back on lexer - this.lexer.unput(this.token.token_text.slice(2)); - - // keep just two character token - this.token.token_text = this.token.token_text.slice(0, 2); - - } - - let token_text = this.token.token_text; - - // derivative symbol and variable together - if (token_text.length === 2) { - if (/[a-zA-Z]/.exec(token_text[1])) - var2s.push(token_text[1]); - else { - return false; - } - } - else { // token text was just the derivative symbol - this.advance(); - - if (!((this.token.token_type === 'VAR' && !this.token.token_text.includes('∂')) - || this.token.token_type === 'VARMULTICHAR')) { - return false; - } - var2s.push(this.token.token_text); - } - - // have derivative and variable, now check for optional ^ followed by number - - let this_exponent = 1; - - let lastWasSpace = false; - - this.advance({ remove_initial_space: false }); - // if last token was a space advance to next non-space token - if (this.token.token_type === "SPACE") { - lastWasSpace = true; - this.advance(); - } - - if (this.token.token_type === '^') { - - this.advance(); - - if (this.token.token_type !== 'NUMBER') { - return false; - } - - this_exponent = parseFloat(this.token.token_text); - if (!Number.isInteger(this_exponent)) { - return false; - } - - lastWasSpace = false; - - this.advance({ remove_initial_space: false }); - // if last token was a space advance to next non-space token - if (this.token.token_type === "SPACE") { - lastWasSpace = true; - this.advance(); - } - - } - var2_exponents.push(this_exponent); - exponent_sum += this_exponent; - - if (exponent_sum > n_deriv) { - return false; - } - - // possibly found derivative - if (exponent_sum === n_deriv) { - - // check to make sure next token isn't another VAR or VARMULTICHAR - // in this case, the derivative isn't separated from what follows - if (!lastWasSpace && (this.token.token_type === "VAR" || this.token.token_type === "VARMULTICHAR")) { - return false; - } - - // found derivative! - - // if last token was a space advance to next non-space token - if (this.token.token_type === "SPACE") - this.advance(); - - let result_name = "derivative_leibniz"; - if (deriv_symbol === "∂") - result_name = "partial_" + result_name; - - result = [result_name]; - - if (n_deriv === 1) - result.push(var1); - else - result.push(["tuple", var1, n_deriv]); - - let r2 = []; - for (let i = 0; i < var2s.length; i += 1) { - if (var2_exponents[i] === 1) - r2.push(var2s[i]); - else - r2.push(["tuple", var2s[i], var2_exponents[i]]); - } - r2 = ["tuple"].concat(r2); - - result.push(r2); - - return result; - } - } - } - } - - var textToAst$1 = new textToAst(); - - - function expand(expr_or_tree, no_division) { - // Initial implementation of expand - // Expands polynomials only up to degree 4 - - var tree = get_tree(expr_or_tree); - - var transformations = []; - transformations.push([textToAst$1.convert("a*(b+c)"), textToAst$1.convert("a*b+a*c")]); - transformations.push([textToAst$1.convert("(a+b)*c"), textToAst$1.convert("a*c+b*c")]); - if(!no_division) - transformations.push([textToAst$1.convert("(a+b)/c"), textToAst$1.convert("a/c+b/c")]); - transformations.push([textToAst$1.convert("-(a+b)"), textToAst$1.convert("-a-b")]); - transformations.push([textToAst$1.convert("a(-b)"), textToAst$1.convert("-ab")]); - transformations.push([textToAst$1.convert("(a+b)^2"), textToAst$1.convert("a^2+2ab+b^2")]); - transformations.push([textToAst$1.convert("(a+b)^3"), textToAst$1.convert("a^3+3a^2b+3ab^2+b^3")]); - transformations.push([textToAst$1.convert("(a+b)^4"), textToAst$1.convert("a^4+4a^3b+6a^2b^2+4ab^3+b^4")]); - transformations.push([textToAst$1.convert("(-a)^2"), textToAst$1.convert("a^2")]); - transformations.push([textToAst$1.convert("(-a)^3"), textToAst$1.convert("-a^3")]); - transformations.push([textToAst$1.convert("(-a)^4"), textToAst$1.convert("a^4")]); - - tree = applyAllTransformations(tree, transformations, 20); - - tree = flatten(tree); - - tree = evaluate_numbers(tree); - - tree = collect_like_terms_factors(tree); - - tree = normalize_negatives(tree); - - return tree; - } - - function expand_relations(expr_or_tree) { - var tree = get_tree(expr_or_tree); - return transform$2(tree, expand_relations_transform); - } - - function expand_relations_transform (ast) { - if(!Array.isArray(ast)) { - return ast; - } - - var operator = ast[0]; - var operands = ast.slice(1); - // since transforms in bottom up fashion, - // operands have already been expanded - - if(operator === '=') { - if(operands.length <= 2) - return ast; - let result = ['and']; - for(let i=0; i < operands.length-1; i++) { - result.push(['=', operands[i], operands[i+1]]); - } - return result; - } - if(operator === 'gts' || operator === 'lts') { - let args = operands[0]; - let strict = operands[1]; - - if(args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); - - - let comparisons = []; - for(let i=1; i< args.length-1; i++) { - let new_operator; - if(strict[i]) { - if(operator === 'lts') - new_operator = '<'; - else - new_operator = '>'; - } - else { - if(operator === 'lts') - new_operator = 'le'; - else - new_operator = 'ge'; - } - comparisons.push([new_operator, args[i], args[i+1]]); - } - - let result = ['and', comparisons[0], comparisons[1]]; - for(let i=2; i', x, a]); - } - if(closed[2]) { - if(negate) - comparisons.push(['>', x, b]); - else - comparisons.push(['le', x, b]); - } - else { - if(negate) - comparisons.push(['ge', x, b]); - else - comparisons.push(['<', x, b]); - } - - let result; - if(negate) - result = ['or'].concat(comparisons); - else - result = ['and'].concat(comparisons); - - return result; - } - - // convert interval containment to inequalities - if(operator === 'subset' || operator === 'notsubset' || - operator === 'superset' || operator === 'notsuperset') { - - let negate=false; - if(operator === 'notsubset' || operator === 'notsuperset') - negate=true; - - let small, big; - if(operator === 'subset' || operator === 'notsubset') { - small = operands[0]; - big = operands[1]; - } - else { - small = operands[1]; - big = operands[0]; - } - - // convert any tuples/arrays of length two to intervals - small = to_intervals(small); - big = to_intervals(big); - - // if not interval, don't transform - if(small[0] !== 'interval' || big[0] !== 'interval') - return ast; - - let small_args = small[1]; - let small_closed = small[2]; - let big_args = big[1]; - let big_closed = big[2]; - if(small_args[0] !== 'tuple' || small_closed[0] !== 'tuple' || - big_args[0] !== 'tuple' || big_closed[0] !== 'tuple') - throw new Error("Badly formed ast"); - - let small_a = small_args[1]; - let small_b = small_args[2]; - let big_a = big_args[1]; - let big_b = big_args[2]; - - let comparisons = []; - if(small_closed[1] && !big_closed[1]) { - if(negate) - comparisons.push(['le', small_a,big_a]); - else - comparisons.push(['>', small_a,big_a]); - } - else { - if(negate) - comparisons.push(['<', small_a,big_a]); - else - comparisons.push(['ge', small_a,big_a]); - } - if(small_closed[2] && !big_closed[2]) { - if(negate) - comparisons.push(['ge', small_b,big_b]); - else - comparisons.push(['<', small_b,big_b]); - } - else { - if(negate) - comparisons.push(['>',small_b,big_b]); - else - comparisons.push(['le',small_b,big_b]); - } - let result; - if(negate) - result = ['or'].concat(comparisons); - else - result = ['and'].concat(comparisons); - - return result; - - } - - return ast; - } - - function substitute$1(pattern, bindings) { - var pattern_tree = get_tree(pattern); - - var bindings_tree = {}; - for(let b in bindings) { - bindings_tree[b] = get_tree(bindings[b]); - } - - return substitute(pattern_tree, bindings_tree); - - } - - function substitute_component(pattern, component, value) { - let pattern_tree = get_tree(pattern); - let value_tree = get_tree(value); - - if(typeof component === "number") { - component = [component]; - } - else if(!Array.isArray(component)) { - throw Error("Invalid substitute_component: " + component); - } - - - let container_operators = ["list", "tuple", "vector", "array"]; - - return substitute_component_sub(pattern_tree, component, value_tree); - - - function substitute_component_sub(tree, component, value_tree) { - - if(component.length === 0) { - return value; - } - if(!Array.isArray(tree)) { - throw Error("Invalid substitute_component: expected list, tuple, vector, or array"); - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if(!container_operators.includes(operator)) { - throw Error("Invalid substitute_component: expected list, tuple, vector, or array"); - } - - let ind = component[0]; - if(ind < 0 || ind > operands.length-1) { - throw Error("Invalid substitute_component: component out of range"); - } - let new_components = component.slice(1); - let result = substitute_component_sub(operands[ind], new_components, value_tree); - - return [operator, ...operands.slice(0,ind), result, ...operands.slice(ind+1)]; - } - - } - - function get_component(pattern, component) { - let pattern_tree = get_tree(pattern); - - if(typeof component === "number") { - component = [component]; - } - else if(!Array.isArray(component)) { - throw Error("Invalid get_component: " + component); - } - - let container_operators = ["list", "tuple", "vector", "array"]; - - return get_component_sub(pattern_tree, component); - - - function get_component_sub(tree, component) { - - if(component.length === 0) { - return tree; - } - - if(!Array.isArray(tree)) { - throw Error("Invalid get_component: expected list, tuple, vector, or array"); - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if(!container_operators.includes(operator)) { - throw Error("Invalid get_component: expected list, tuple, vector, or array"); - } - - let ind = component[0]; - if(ind < 0 || ind > operands.length-1) { - throw Error("Invalid get_component: component out of range"); - } - let new_components = component.slice(1); - return get_component_sub(operands[ind], new_components); - - } - - } - - var transformation = /*#__PURE__*/Object.freeze({ - expand: expand, - expand_relations: expand_relations, - substitute: substitute$1, - substitute_component: substitute_component, - get_component: get_component - }); - - function solve_linear(expr_or_tree, variable, assumptions) { - // assume expr is linear in variable - - - if(!(typeof variable === 'string')) - return undefined; - - if(assumptions===undefined && expr_or_tree.context !== undefined - && expr_or_tree.context.get_assumptions !== undefined) - assumptions = expr_or_tree.context.get_assumptions( - [expr_or_tree.variables()]); - - var tree = simplify$2(get_tree(expr_or_tree), assumptions); - //var tree = get_tree(expr_or_tree); - - if(!Array.isArray(tree)) - return undefined; - - var operator = tree[0]; - var operands = tree.slice(1); - - if(!(operator === '=' || operator === 'ne' - || operator === '<' || operator === 'le' - || operator === '>' || operator === 'ge')) - return undefined; - - - // set equal to zero, as lhs = 0 - var lhs = simplify$2(['+', operands[0], ['-', operands[1]]], - assumptions); - - var no_var = tree => !variables(tree).includes(variable); - - // factor out variable - var transformation = [ - ['+', ['*', '_a', variable], ['*', '_b', variable]], - ['*', ['+', '_a', '_b'], variable], - {variables: {_a: no_var, _b: no_var}, - allow_permutations: true, - allow_extended_match: true, - allow_implicit_identities: ['_a', '_b'], - evaluate_numbers: true, - - }]; - - lhs = simplify$2( - applyAllTransformations(lhs, [transformation], 20)); - - if(!variables(lhs).includes(variable)) - return undefined; - - var pattern = ['+', ['*', '_a', variable], '_b']; - - var params = { - variables: { _a: no_var, _b: no_var}, - allow_permutations: true, - allow_implicit_identities: ['_a', '_b'], - }; - - var match$$1 = match(lhs, pattern, params); - - if(!match$$1) - return undefined; // not linear in variable - - var a = simplify$2(match$$1['_a']); - var b = simplify$2(match$$1['_b']); - - if(!is_nonzero_ast(a, assumptions)) - return undefined; // can't confirm that there is a variable - - // equality or inequality with positive coefficient - if(operator === '=' || operator === 'ne' || is_positive_ast(a, assumptions)) { - let result = simplify$2(['/', ['-', b], a]); - return [operator, variable, result]; - } - - if(!is_negative_ast(a, assumptions)) - return undefined; // couldn't determined sign and have inequality - - // have inequality with negative coefficient - var result = simplify$2(['/', ['-', b], a]); - if(operator === '<') - operator = '>'; - else if(operator === 'le') - operator = 'ge'; - else if(operator === '>') - operator = '<'; - else - operator = 'le'; - - return [operator, variable, result]; - } - - var solve = /*#__PURE__*/Object.freeze({ - solve_linear: solve_linear - }); - - function clean_assumptions(tree, known) { - // normalize order and operators of assumptions in tree, - // remove any duplicates or those in known - // return ast or undefined if no assumptions found - - if(!Array.isArray(tree) || tree.length === 0) - return tree; - - tree= flatten( - default_order( - simplify_logical( - expand_relations(tree) - ) - ) - ); - - // check for duplicates (within tree or already in known) - var operator=tree[0]; - var operands=tree.slice(1); - - if(operator === 'and' || operator === 'or') { - // remove duplicates, using trees.equal - operands = operands.reduce(function (a,b) { - if(a.every(function(v) { return !equal$2(v,b)})) - a.push(b); - return a; - },[]); - - // if known exists, filter out those - if(operator === 'and' && known && Array.isArray(known)) { - let known_operands; - if(known[0] === 'and') - known_operands = known.slice(1); - else - known_operands = [known]; - - operands = operands.filter( - v => known_operands.every(u => !equal$2(u, v)) - ); - - } - - if(operands.length === 1) - tree = operands[0]; - else - tree = [operator].concat(operands); - } - - // check if whole thing is known - if(operator !== 'and' && known && Array.isArray(known)) { - let known_operands; - if(known[0] === 'and') - known_operands = known.slice(1); - else - known_operands = [known]; - - if(!known_operands.every(u => !equal$2(u, tree))) - return undefined; - } - - return tree; - } - - - function calculate_derived_assumptions(assumptions, tree) { - // Calculate all assumptions on variables within tree that - // can be derived from the assumptions within tree, - // eliminating any assumptions that are already recorded - // in byvar or generic of assumptions - // - // if tree is undefined, calculate assumptions that can be - // derived from all given assumptions - - - if(tree === undefined) { - tree = []; - for(let v in assumptions.byvar) { - let a = assumptions.byvar[v]; - if(a.length > 0) - tree.push(a); - } - if(tree.length === 0) - return {}; - - if(tree.length === 1) - tree = tree[0]; - else - tree = ['and'].concat(tree); - - tree = clean_assumptions(tree); - } - - if(!Array.isArray(tree) || tree.length === 0) - return {}; - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === 'and' || operator === 'or') { - let results = operands.map(function (v) { - return calculate_derived_assumptions(assumptions, v); - }); - - // array of all vars found in at least one result - let allvars = [...new Set(results.reduce( - (a,b) => [...a, ...Object.keys(b)], []))]; - - let derived = {}; - - for(let v of allvars) { - let res = results.reduce(function (a,b) { - if(b[v] !== undefined) - a.push(b[v]); - return a; - },[]); - - - // for OR, add only if obtain result for each operand - if(operator === 'and' || res.length === results.length) { - let new_derived = derived[v]; - if(new_derived === undefined) { - if(res.length > 1) - new_derived = [operator].concat(res); - else - new_derived = res[0]; - } - else { - if(res.length > 1) - new_derived = ['and', new_derived, - [operator].concat(res)]; - else - new_derived = ['and', new_derived, res[0]]; - } - - derived[v] = clean_assumptions( - new_derived, - get_assumptions(assumptions, v, {omit_derived: true})); - } - } - - return derived; - } - // Shouldn't get a NOT of (in)equality after simplifying logical - // if(operator === 'not') { - // let results = calculate_derived_assumptions(assumptions, operands[0]); - // for(let v of Object.keys(results)) { - // derived[v] = ['not', results[v]]; - // } - // return derived; - // } - - let derived = {}; - - if(operator === '=' || operator === 'ne' || - operator === '<' || operator === 'le' || - operator === 'in' || operator === 'subset' || - operator === 'notin' || operator === 'notsubset' - ) { - - var addressed_assumption = false; - - // calculate derived if one side is equal to a variable - for(let ind = 0; ind < 2; ind++) { - let v = operands[ind]; - let other = operands[1-ind]; - let other_var = variables(other); - if((typeof v !== 'string') || other_var.length === 0 - || other_var.includes(v)) - continue; - - addressed_assumption = true; - - // look for any assumptions that from other that - // do not contain a v - var adjusted_op = operator; - if(ind === 1) { - if(operator === '<') - adjusted_op = '>'; - else if(operator === 'le') - adjusted_op = 'ge'; - else if(operator === 'in') - adjusted_op = 'ni'; - else if(operator === 'subset') - adjusted_op = 'superset'; - else if(operator === 'notin') - adjusted_op = 'notni'; - else if(operator === 'notsubset') - adjusted_op = 'notsuperset'; - } - let result = get_assumptions_for_expr( - assumptions, other, [v]); - - // combine with results for expr, if compatible - result = combine_assumptions(v, adjusted_op, other, result); - - if(result !== undefined) { - let new_derived = derived[v]; - - if(new_derived === undefined) { - new_derived = result; - } - else { - new_derived = ['and', new_derived, result]; - } - - derived[v] = clean_assumptions( - new_derived, get_assumptions( - assumptions, v, {omit_derived: true})); - - } - - } - if(addressed_assumption) - return derived; - } - - // if wasn't able to combine expressions, just add any assumptions - // on the operands - let results = []; - - for(let op of operands) { - let res = get_assumptions_for_expr(assumptions, op, []); - if(res !== undefined) - results.push(res); - } - - if(results.length === 0) - return {}; - - if(results.length === 1) - results = results[0]; - else - results = ['and'].concat(results); - - for(let v of variables(tree)) { - derived[v] = clean_assumptions( - results, get_assumptions( - assumptions, v, {omit_derived: true})); - } - - return derived; - - } - - function get_assumptions_for_expr(assumptions, expr, exclude_variables) { - // return any assumptions that can be calculated for expression expr - // that don't include exclude_variables - // - // The assumptions will be given directly in terms of expr when possible. - - - let variables$$1 = variables(expr); - - // filter out any of the excluded variables - variables$$1 = variables$$1.filter(v => !exclude_variables.includes(v)); - - if(variables$$1.length === 0) - return undefined; - - function isNumber(s) { - if (typeof s === 'number') - return true; - if (Array.isArray(s) && s[0] === '-' && (typeof s[1] === 'number')) - return true; - return false; - } - - // will proccess assumptions in case where variables are linear in expr - var pattern = ['_b']; - var implicit_identities = ['_b']; - var match_vars = {_b: isNumber}; - var coeff_mapping = {}; - for(let i=0; i < variables$$1.length; i++) { - let a = '_a' + i; - coeff_mapping[variables$$1[i]] = a; - pattern.push(['*', a, variables$$1[i]]); - implicit_identities.push(a); - match_vars[a] = isNumber; - } - - pattern = ['+'].concat(pattern); - - var m = match(expr, pattern, - {variables: match_vars, - allow_permutations: true, - allow_extended_match: false, - allow_implicit_identities: implicit_identities, - max_group: 1}); - - if(!m) { - // if not linear, get assumptions for each variable of expr - let results = []; - for(let v of variables(expr)) { - let res = get_assumptions_for_expr( - assumptions, v, exclude_variables); - if(res !== undefined) - results.push(res); - } - if(results.length === 0) - return undefined; - if(results.length === 1) - return results[0]; - return ['and'].concat(results); - } - - for(let v of variables$$1) - coeff_mapping[v] = m[coeff_mapping[v]]; - - let identity = false; - if(m["_b"] === 0 && m["_a0"] === 1 && variables$$1.length === 1) - identity = true; - - // find all assumptions involving variables but excluding exclude_variables - var new_assumptions; - new_assumptions = get_assumptions( - assumptions, [variables$$1], {exclude_variables: exclude_variables}); - - if(new_assumptions === undefined) - return undefined; - - return clean_assumptions(process_additional_assumptions(new_assumptions)); - - - function process_additional_assumptions(new_as) { - - if(!Array.isArray(new_as)) - return undefined; - - var operator = new_as[0]; - var operands = new_as.slice(1); - - if(operator === 'and' || operator === 'or') { - let results = operands - .map(process_additional_assumptions) - .filter(v => v !== undefined); - - if(results.length === 0) - return undefined; - if(operator === 'or') { - if(results.length === operands.length) - return ['or'].concat(results); - else - return undefined; - } - if(results.length === 1) - return results[0]; - else - return ['and'].concat(results); - } - - // can ignore NOTs, as simplify_logical should remove - // any before (in)equalities or containments - - if(!(['=', 'ne', '<', 'le'].includes(operator) || - (['in', 'notin', 'subset', 'notsubset'].includes(operator) - && identity))) { - - let new_exclude = exclude_variables.concat(variables(expr)); - let results = []; - for(let v of variables(new_as)) { - if(new_exclude.includes(v)) - continue; - let res = get_assumptions_for_expr(assumptions, v, new_exclude); - if(res !== undefined) - results.push(res); - } - if(results.length === 0) - return new_as; - if(results.length === 1) - return ['and', new_as, results[0]]; - return ['and', new_as].concat(results); - } - - let results = []; - - for(let ind=0; ind <= 1; ind++) { - let next_var = operands[ind]; - let next_rhs = operands[1-ind]; - - if((typeof next_var === 'string') && variables$$1.includes(next_var)) { - - var bindings = {}; - bindings[next_var] = next_rhs; - var new_expr = simplify$2(substitute(expr, bindings)); - - // may need to flip operator if it is an inequality - // Two factors could induce flipping - // - coefficient from expr is negative - // - switched sides in next inequality (ind === 1) - // The factors could cancel each other out - var flip = false; - var operator_eff = operator; - if((ind === 1 && coeff_mapping[next_var] > 0) || - (ind === 0 && coeff_mapping[next_var] < 0)) { - if(operator === '<') { - flip = true; - operator_eff = '>'; - } - else if(operator === 'le') { - flip = true; - operator_eff = 'ge'; - } - else if(operator === 'in') { - flip = true; - operator_eff = 'ni'; - } - else if(operator === 'subset') { - flip = true; - operator_eff = 'superset'; - } - else if(operator === 'notin') { - flip = true; - operator_eff = 'notni'; - } - else if(operator === 'notsubset') { - flip = true; - operator_eff = 'notsuperset'; - } - } - - if(flip) - results.push([operator, new_expr, expr]); - else - results.push([operator, expr, new_expr]); - - // look for more assumptions - let new_exclude = exclude_variables.concat([next_var]); - let res = get_assumptions_for_expr( - assumptions, new_expr, new_exclude); - // combine with results for expr, if compatible - res = combine_assumptions(expr, operator_eff, new_expr, res); - - if(res !== undefined) - results.push(res); - - } - } - - if(results.length === 1) - return results[0]; - else if(results.length > 1) - return ['and'].concat(results); - - // didn't address assumption - let new_exclude = exclude_variables.concat(variables(expr)); - results = []; - for(let v of variables(new_as)) { - if(new_exclude.includes(v)) - continue; - let res = get_assumptions_for_expr(assumptions, v, new_exclude); - if(res !== undefined) - results.push(res); - } - if(results.length === 0) - return new_as; - if(results.length === 1) - return ['and', new_as, results[0]]; - return ['and', new_as].concat(results); - } - } - - - function combine_assumptions(expr1, op1, expr2, new_as) { - // given the assumption "expr1 op1 expr2" and assumptions from new_as - // - return new assumptions involving expr1, if possible - // - return undefined if new_as appears to not affect expr1 - // - return new_as if new_as appear to affect expr1 but cannot - // be distilled to assumptions on expr1 - - if(!['=', 'ne', '<', 'le', '>', 'ge', 'in', 'notin', 'ni', 'notni', - 'subset', 'notsubset', 'superset', 'notsuperset'].includes(op1)) - return new_as; - - if(!Array.isArray(new_as)) - return undefined; - - var op2 = new_as[0]; - var operands2 = new_as.slice(1); - - if(op2 === 'and' || op2 === 'or') { - let results = operands2.map( - v => combine_assumptions(expr1, op1, expr2, v)) - .filter(v => v !== undefined); - - if(results.length === 0) - return undefined; - if(op2 === 'or') { - if(results.length === operands2.length) - return [['or'].concat(results)]; - else - return undefined; - } - if(results.length === 1) - return results[0]; - else - return ['and'].concat(results); - } - - if(!['=', 'ne', '<', 'le', 'in', 'notin', 'subset', 'notsubset'] - .includes(op2)) - return new_as; - - var op2_eff = op2; - var rhs; - if(equal$2(operands2[0], expr2)) { - rhs = operands2[1]; - } - else if(equal$2(operands2[1], expr2)) { - rhs = operands2[0]; - if(op2 === '<') - op2_eff = '>'; - else if(op2 === 'le') - op2_eff = 'ge'; - else if(op2 === 'in') - op2_eff = 'ni'; - else if(op2 === 'notin') - op2_eff = 'notni'; - else if(op2 === 'subset') - op2_eff = 'superset'; - else if(op2 === 'notsubset') - op2_eff = 'notsuperset'; - } - else { - return new_as; - } - - - // determined operator of combined expression - var combined_op; - if(op1 === '=') - combined_op = op2_eff; - else if(op2_eff === '=') - combined_op = op1; - else if(op1 === '<') { - if(op2_eff === '<' || op2_eff === 'le') - combined_op = '<'; - else if(op2_eff === 'in' || op2_eff === 'notin') - return new_as; - else - return undefined; // incompatible operators - } - else if(op1 === 'le') { - if(op2_eff === '<') - combined_op = '<'; - else if(op2_eff === 'le') - combined_op = 'le'; - else if(op2_eff === 'in' || op2_eff === 'notin') - return new_as; - else - return undefined; // incompatible operators - } - else if(op1 === '>') { - if(op2_eff === '>' || op2_eff === 'ge') - combined_op = '>'; - else if(op2_eff === 'in' || op2_eff === 'notin') - return new_as; - else - return undefined; // incompatible operators - } - else if(op1 === 'ge') { - if(op2_eff === '>') - combined_op = '>'; - else if(op2_eff === 'ge') - combined_op = 'ge'; - else if(op2_eff === 'in' || op2_eff === 'notin') - return new_as; - else - return undefined; // incompatible operators - } - else if(op1 === 'in') { - if(op2_eff === 'subset') - combined_op = 'in'; - else - return undefined; // incompatible operators - } - else if(op1 === 'notin') { - if(op2_eff === 'superset') - combined_op = 'notin'; - else - return undefined; // incompatible operators - } - else if(op1 === 'ni') { - if(op2_eff === 'notin') - combined_op = 'notsubset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'notni') { - if(op2_eff === 'in') - combined_op = 'notsuperset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'subset') { - if(op2_eff === 'subset') - combined_op = 'subset'; - else if(op2_eff === 'notni') - combined_op = 'notni'; - else if(op2_eff === 'notsuperset') - combined_op = 'notsuperset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'notsubset') { - if(op2_eff === 'superset') - combined_op = 'notsubset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'superset') { - if(op2_eff === 'superset') - combined_op = 'superset'; - else if(op2_eff === 'ni') - combined_op = 'ni'; - else if(op2_eff === 'notsubset') - combined_op = 'notsubset'; - else - return undefined; // incompatible operators - } - else if(op1 === 'notsuperset') { - if(op2_eff === 'subset') - combined_op = 'notsuperset'; - else - return undefined; // incompatible operators - } - else - return undefined; - - - if(combined_op === '>') - return ['<', rhs, expr1]; - else if(combined_op === 'ge') - return ['le', rhs, expr1]; - else if(combined_op === 'ni') - return ['in', rhs, expr1]; - else if(combined_op === 'notni') - return ['notin', rhs, expr1]; - else if(combined_op === 'superset') - return ['subset', rhs, expr1]; - else if(combined_op === 'notsuperset') - return ['notsubset', rhs, expr1]; - else - return [combined_op, expr1, rhs]; - - } - - - function filter_assumptions_from_tree(tree, exclude_variables) { - // return an ast if found in tree assumptions without exclude_variables - // otherwise return undefined - - if(!Array.isArray(tree) || tree.length === 0) { - return undefined; - } - - if(!Array.isArray(exclude_variables)) - exclude_variables = [exclude_variables]; - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === 'and') { - - var a= operands.map(function (v) { - return filter_assumptions_from_tree(v, exclude_variables); - }); - - a=a.filter(v => v !== undefined); - - if(a.length === 0) - return undefined; - else if(a.length === 1) - return a[0]; - else - return ['and'].concat(a); - } - - // if no intersection between exclude variables and variables in tree - // return tree - var tree_variables = variables(tree); - var contains_excluded = exclude_variables.filter( - (v) => tree_variables.includes(v)).length > 0; - - if(!contains_excluded) - return tree; - else - return undefined; - } - - - function get_assumptions_sub(assumptions, variables$$1, exclude_variables, - omit_derived) { - // return an ast if found assumptions involving variables - // otherwise return undefined - - if(!Array.isArray(variables$$1)) - variables$$1 = [variables$$1]; - - var a = []; - - // add assumptions specified by each variable - variables$$1.forEach(function (v) { - // get assumption from byvar and derived, if exist - if(assumptions.byvar[v] || assumptions.derived[v]) { - if(assumptions.byvar[v] && assumptions.byvar[v].length > 0) { - // only get assumptions that don't contain - // exclude variables - var byvar = filter_assumptions_from_tree( - assumptions.byvar[v], exclude_variables); - if(byvar !== undefined) - a.push(byvar); - } - if(assumptions.derived[v] && assumptions.derived[v].length > 0 - && !omit_derived) { - // only get derived assumptions that don't contain - // exclude variables - var da = filter_assumptions_from_tree( - assumptions.derived[v], exclude_variables); - if(da !== undefined) - a.push(da); - } - } - // if byvar and derived are undefined, - // then get assumptions from generic - else if(assumptions['generic'].length > 0) { - // if generic contains any variables other than x - // don't substitute those back into generic - if(v === 'x' || - !variables(assumptions['generic']).includes(v)) - a.push(substitute(assumptions['generic'], {x: v})); - } - }); - - if(a.length === 1) - a=a[0]; - else if(a.length > 1) - a=['and'].concat(a); - - if(a.length > 0) - return clean_assumptions(a); - else - return undefined - - } - - function get_assumptions(assumptions, variables_or_expr, params) { - // return an ast if found assumptions - // otherwise return undefined - // - // variables_or_expr - // - if a string or an array of an array, find assumptions on - // each of the variables represented by those strings - // directly from byvar and derived or from generic - // - if an ast, then - // - calculate assumptions of the expression itself, if possible, or - // - calculate assumptions on the variables of the expression. - - // include any additional assumptions - // involving new variables found in assumptions - - if(params === undefined) - params = {}; - - var exclude_variables = params.exclude_variables; - if(exclude_variables === undefined) - exclude_variables = []; - else if(!Array.isArray(exclude_variables)) - exclude_variables = [exclude_variables]; - - var variables$$1; - var tree = get_tree(variables_or_expr); - - // if string, have a variable - if(typeof tree === "string") - variables$$1 = [tree]; - else if(!Array.isArray(tree)) - return undefined; - else if(Array.isArray(tree[0])) - // if array containing array, is list of variables - variables$$1 = tree[0]; - - - if(variables$$1) - return get_assumptions_sub(assumptions, variables$$1, - exclude_variables, params.omit_derived); - else - return get_assumptions_for_expr(assumptions, tree, exclude_variables) - - } - - - function add_assumption(assumptions, expr_or_tree, exclude_generic) { - // add assumption in tree to assumptions - // if !exclude_generic, then add any generic assumptions to - // variables if they don't have previous assumptions - // return 1 if added assumption or 0 otherwise - - var tree = get_tree(expr_or_tree); - - if(!Array.isArray(tree)) - return 0; - - tree = clean_assumptions(simplify$2(tree,assumptions)); - - var added = add_assumption_sub(assumptions, tree, exclude_generic); - - if(added) - assumptions.derived = calculate_derived_assumptions(assumptions); - - return added; - } - - - function add_assumption_sub(assumptions, tree, exclude_generic) { - // add assumption in tree to assumptions - // if !exclude_generic, then add any generic assumptions to - // variables if they don't have previous assumptions - // return number of assumptions added - - // if tree is an 'and', call once for each operand - // so that assumptions can be separated by variable - if(tree[0] === 'and') { - var results = tree.slice(1).map( - v => add_assumption_sub(assumptions, v, exclude_generic)); - return results.reduce(function (a,b) { return a + b;}); - } - - var variables$$1 = variables(tree); - - if(variables$$1.length === 0) - return 0; - - let n_added = 0; - - if(!exclude_generic && assumptions['generic'].length > 0) { - // check to see if any assumptions already for each variable - // if not, start by assigning generic assumptions - variables$$1.forEach(function (v) { - if(assumptions.byvar[v] === undefined) { - - // no previous assumptions, so - // include add assumption for v corresponding to generic - // unless non-x v is explicitly in generic - if(v === 'x' || - !variables(assumptions['generic']).includes(v)) { - add_assumption_sub( - assumptions, - substitute(assumptions['generic'], {x: v}), - true); - n_added += 1; - } - - } - }); - - } - - - // attempt to solve for each variable - for(let variable of variables$$1) { - - // solve using current state of assumptions - let solved = solve_linear(tree, variable, assumptions); - - let new_a = tree; - if(solved) - new_a = solved; - - let current_a = assumptions['byvar'][variable]; - - if(current_a !== undefined && current_a.length !== 0) - new_a = ['and', current_a, new_a]; - - new_a = clean_assumptions(new_a); - - if(!equal$2(new_a, current_a)) { - assumptions['byvar'][variable] = new_a; - n_added +=1; - } - } - - return n_added; - - } - - - function add_generic_assumption(assumptions, expr_or_tree) { - // add assumption in expr_or_tree to generic assumptions - - // tree must contain the variable x - // the variable x represents any variable for which - // assumptions aren't specifically assigned - - // return 1 if added assumption or 0 otherwise - - var tree = get_tree(expr_or_tree); - - if(!Array.isArray(tree)) - return 0; - - tree = clean_assumptions(simplify$2(tree,assumptions)); - - var added = add_generic_assumption_sub(assumptions, tree); - - if(added) - assumptions.derived = calculate_derived_assumptions(assumptions); - - return added; - } - - function add_generic_assumption_sub(assumptions, tree) { - - // if tree is an 'and', call once for each operand - // so that assumptions involving one variable can be separated - if(tree[0] === 'and') { - var results = tree.slice(1).map( - v => add_generic_assumption_sub(assumptions, v)); - return results.reduce(function (a,b) { return a + b;}); - } - - var variables$$1 = variables(tree); - - if(!variables$$1.includes('x')) - return 0; - - // attempt to solve for x - // solve using current state of assumptions - let solved = solve_linear(tree, 'x', assumptions); - - let new_a = tree; - if(solved) - new_a = solved; - - let current_a = assumptions['generic']; - - if(current_a.length !== 0) - new_a = ['and', current_a, new_a]; - - new_a = clean_assumptions(new_a); - - if(equal$2(new_a, current_a)) { - return 0; - } - - assumptions['generic'] = new_a; - - return 1; - } - - - function remove_assumption(assumptions, expr_or_tree) { - - var tree=get_tree(expr_or_tree); - - if(!Array.isArray(tree)) - return 0; - - tree = clean_assumptions(simplify$2(tree,assumptions)); - - var removed = remove_assumption_sub(assumptions, tree); - - if(removed) - assumptions.derived = calculate_derived_assumptions(assumptions); - - return removed; - - } - - - function remove_assumption_sub(assumptions, tree) { - - - // if tree is an 'and', call once for each operand - // so that assumptions can be separated by variable - if(tree[0] === 'and') { - var results = tree.slice(1).map(v => remove_assumption_sub( - assumptions, v)); - return results.reduce(function (a,b) { return a+b;}); - } - - var variables$$1 = variables(tree); - - if(variables$$1.length === 0) - return 0; - - var n_removed = 0; - - // attempt to solve for each variable - for(let variable of variables$$1) { - - // solve using current state of assumptions - let solved = solve_linear(tree, variable, assumptions); - - let current = assumptions['byvar'][variable]; - - // didn't find any assumptions to remove - if(!current || current.length === 0) { - continue; - } - - // remove any occurence of tree from current - let operator=current[0]; - let operands=current.slice(1); - - let n_op = operands.length; - - let result; - - if(operator === 'and') { - // remove any match, using trees.equal - operands = operands.filter( - v => !(equal$2(v, tree) || equal$2(v,solved))); - - if(operands.length === 0) { - result = []; - } - else if(operands.length === 1) { - result = operands[0]; - } - else if(operands.length < n_op) { - result = [operator].concat(operands); - } - else { - // didn't find anything to remove - continue - } - } - else { - if(equal$2(current, tree) || equal$2(current, solved)) { - result = []; - } - else { - // didn't find anything to remove - continue; - } - } - - n_removed += 1; - assumptions['byvar'][variable] = result; - - } - - return n_removed; - - } - - function remove_generic_assumption(assumptions, expr_or_tree) { - // remove assumption in expr_or_tree from generic assumptions - - // return 1 if removed assumption or 0 otherwise - - var tree=get_tree(expr_or_tree); - - if(!Array.isArray(tree)) - return 0; - - tree = clean_assumptions(simplify$2(tree,assumptions)); - - var removed = remove_generic_assumption_sub(assumptions, tree); - - if(removed) - assumptions.derived = calculate_derived_assumptions(assumptions); - - return removed; - } - - - function remove_generic_assumption_sub(assumptions, tree) { - - // if tree is an 'and', call once for each operand - // so that assumptions involving one variable can be separated - if(tree[0] === 'and') { - var results = tree.slice(1).map(v => remove_generic_assumption_sub( - assumptions, v)); - return results.reduce(function (a,b) { return a+b;}); - } - - var variables$$1 = variables(tree); - - if(!variables$$1.includes('x')) - return 0; - - var current = assumptions['generic']; - - if(current.length === 0) - return 0; - - // solve using current state of assumptions - let solved = solve_linear(tree, 'x', assumptions); - - // remove any occurence of tree from current - var operator=current[0]; - var operands=current.slice(1); - - var n_op = operands.length; - - var result; - - if(operator === 'and') { - // remove any match, using trees.equal - operands = operands.filter( - v => !(equal$2(v, tree) || equal$2(v,solved))); - - if(operands.length === 0) { - result = []; - } - else if(operands.length === 1) { - result = operands[0]; - } - else if(operands.length < n_op) { - result = [operator].concat(operands); - } - else { - // didn't find anything to remove - return 0; - } - } - else { - if(equal$2(current, tree) || equal$2(current, solved)) { - result = []; - } - else { - // didn't find anything to remove - return 0; - } - } - - assumptions['generic'] = result; - - return 1; - } - - - function initialize_assumptions() { - var assumptions = {}; - assumptions['byvar'] = {}; - assumptions['derived'] = {}; - assumptions['generic'] = []; - assumptions['not_commutative'] = []; - assumptions['get_assumptions'] = function(v, params) { - return get_assumptions(assumptions, v, params); - }; - assumptions['add_assumption'] = function(v, exclude_generic) { - return add_assumption(assumptions, v, exclude_generic); - }; - assumptions['add_generic_assumption'] = function(v) { - return add_generic_assumption(assumptions, v); - }; - assumptions['remove_assumption'] = function(v) { - return remove_assumption(assumptions, v); - }; - assumptions['remove_generic_assumption'] = function(v) { - return remove_generic_assumption(assumptions, v); - }; - - return assumptions; - } - - /* - * convert syntax trees back to LaTeX code - * - * Copyright 2014-2017 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - - const operators$3 = { - "+": function(operands) { - return operands.join(' '); - }, - "-": function(operands) { - return "- " + operands[0]; - }, - "*": function(operands) { - return operands.join(" "); - }, - "/": function(operands) { - return "\\frac{" + operands[0] + "}{" + operands[1] + "}"; - }, - "_": function(operands) { - return operands[0] + "_{" + operands[1] + "}"; - }, - "^": function(operands) { - return operands[0] + "^{" + operands[1] + "}"; - }, - "prime": function(operands) { - return operands[0] + "'"; - }, - "tuple": function(operands) { - return '\\left( ' + operands.join(', ') + ' \\right)'; - }, - "array": function(operands) { - return '\\left[ ' + operands.join(', ') + ' \\right]'; - }, - "list": function(operands) { - return operands.join(', '); - }, - "set": function(operands) { - return '\\left\\{ ' + operands.join(', ') + ' \\right\\}'; - }, - "vector": function(operands) { - return '\\left( ' + operands.join(', ') + ' \\right)'; - }, - "interval": function(operands) { - return '\\left( ' + operands.join(', ') + ' \\right)'; - }, - "matrix": function(operands) { - return '\\left( ' + operands.join(', ') + ' \\right)'; - }, - "and": function(operands) { - return operands.join(' \\land '); - }, - "or": function(operands) { - return operands.join(' \\lor '); - }, - "not": function(operands) { - return '\\lnot ' + operands[0]; - }, - "=": function(operands) { - return operands.join(' = '); - }, - "<": function(operands) { - return operands.join(' < '); - }, - ">": function(operands) { - return operands.join(' > '); - }, - "lts": function(operands) { - return operands.join(' < '); - }, - "gts": function(operands) { - return operands.join(' > '); - }, - "le": function(operands) { - return operands.join(' \\le '); - }, - "ge": function(operands) { - return operands.join(' \\ge '); - }, - "ne": function(operands) { - return operands.join(' \\ne '); - }, - "in": function(operands) { - return operands[0] + " \\in " + operands[1]; - }, - "notin": function(operands) { - return operands[0] + " \\notin " + operands[1]; - }, - "ni": function(operands) { - return operands[0] + " \\ni " + operands[1]; - }, - "notni": function(operands) { - return operands[0] + " \\not\\ni " + operands[1]; - }, - "subset": function(operands) { - return operands[0] + " \\subset " + operands[1]; - }, - "notsubset": function(operands) { - return operands[0] + " \\not\\subset " + operands[1]; - }, - "superset": function(operands) { - return operands[0] + " \\supset " + operands[1]; - }, - "notsuperset": function(operands) { - return operands[0] + " \\not\\supset " + operands[1]; - }, - "union": function(operands) { - return operands.join(' \\cup '); - }, - "intersect": function(operands) { - return operands.join(' \\cap '); - }, - "derivative_leibniz": function (operands) { - return "\\frac{d" + operands[0] + "}{d" + operands[1] + "}"; - }, - "partial_derivative_leibniz": function (operands) { - return "\\frac{d" + operands[0] + "}{d" + operands[1] + "}"; - }, - "|": function (operands) { - return operands[0] + " \\mid " + operands[1]; - }, - ":": function (operands) { - return operands[0] + " : " + operands[1]; - }, - }; - - // defaults for parsers if not overridden by context - - - // allowed multicharacter latex symbols - // in addition to the below applied function symbols - const allowedLatexSymbolsDefault = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'partial', "abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg']; - - const matrixEnvironmentDefault = 'bmatrix'; - - class astToLatex { - - constructor({ - allowedLatexSymbols=allowedLatexSymbolsDefault, - matrixEnvironment=matrixEnvironmentDefault, - } = {}){ - this.allowedLatexSymbols = allowedLatexSymbols; - this.matrixEnvironment = matrixEnvironment; - } - - convert(tree) { - return this.statement(tree); - } - - statement(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.single_statement(tree); - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === 'ldots') - return '\\ldots'; - - if ((!(operator in operators$3)) && operator !== "apply") - throw new Error("Badly formed ast: operator " + operator + " not recognized."); - - if (operator === 'and' || operator === 'or') { - return operators$3[operator](operands.map(function(v, i) { - let result = this.single_statement(v); - // for clarity, add parenthesis unless result is - // single quantity (with no spaces) or already has parens - if (result.toString().match(/ /) && - (!(result.toString().match(/^\\left\(.*\\right\)$/)))) - return '\\left(' + result + '\\right)'; - else - return result; - }.bind(this))); - } - return this.single_statement(tree); - } - - single_statement(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.expression(tree); - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === 'not') { - return operators$3[operator](operands.map(function(v, i) { - let result = this.single_statement(v); - // for clarity, add parenthesis unless result is - // single quantity (with no spaces) or already has parens - if (result.toString().match(/ /) && - (!(result.toString().match(/^\\left\(.*\\right\)$/)))) - return '\\left(' + result + '\\right)'; - else - return result; - }.bind(this))); - } - - if ((operator === '=') || (operator === 'ne') || - (operator === '<') || (operator === '>') || - (operator === 'le') || (operator === 'ge') || - (operator === 'in') || (operator === 'notin') || - (operator === 'ni') || (operator === 'notni') || - (operator === 'subset') || (operator === 'notsubset') || - (operator === 'superset') || (operator === 'notsuperset')) { - return operators$3[operator](operands.map(function(v, i) { - return this.expression(v); - }.bind(this))); - } - - if (operator === 'lts' || operator === 'gts') { - let args = operands[0]; - let strict = operands[1]; - - if (args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); - - let result = this.expression(args[1]); - for (let i = 1; i < args.length - 1; i++) { - if (strict[i]) { - if (operator === 'lts') - result += " < "; - else - result += " > "; - } - else { - if (operator === 'lts') { - result += " \\le "; - } - else { - result += " \\ge "; - } - } - result += this.expression(args[i + 1]); - } - return result; - } - - return this.expression(tree); - } - - expression(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.term(tree); - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === '+') { - return operators$3[operator](operands.map(function(v, i) { - if (i > 0) - return this.termWithPlusIfNotNegated(v); - else - return this.term(v); - }.bind(this))); - } - - if ((operator === 'union') || (operator === 'intersect')) { - return operators$3[operator](operands.map(function(v, i) { - return this.term(v); - }.bind(this))); - } - - return this.term(tree); - } - - term(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.factor(tree); - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === '-') { - return operators$3[operator](operands.map(function(v, i) { - return this.term(v); - }.bind(this))); - } - if (operator === '*') { - return operators$3[operator](operands.map(function(v, i) { - let result; - if (i > 0) { - result = this.factorWithParenthesesIfNegated(v); - if (result.toString().match(/^[0-9]/)) - return '\\cdot ' + result; - else - return '\\, ' + result - } - else - return this.factor(v); - }.bind(this))); - } - - if (operator === '/') { - return operators$3[operator](operands.map(function(v, i) { - return this.expression(v); - }.bind(this))); - } - - return this.factor(tree); - } - - simple_factor_or_function_or_parens(tree) { - // return true if - // factor(tree) is a single character - // or tree is a non-negative number not in scientific notation - // or tree is a string - // or tree is a function call other than sqrt - // or factor(tree) is in parens - - var result = this.factor(tree); - - if (result.toString().length === 1 || - (typeof tree === 'string') || - (tree[0] === 'apply' && tree[1] !== "sqrt") || - result.toString().match(/^\\left\(.*\\right\)$/) - ) { - return true; - } else if (typeof tree === "number") { - if(tree >= 0 && !tree.toString().includes('e')) { - return true; - } else { - return false; - } - } else { - return false - } - } - - stringConvert(string) { - if (string.length > 1) { - if(this.allowedLatexSymbols.includes(string)) - return "\\" + string; - else - return "\\var{" + string + '}'; - } - return string; - } - - factor(tree) { - if (typeof tree === 'string') { - return this.stringConvert(tree); - } - - if (typeof tree === 'number') { - if(tree === Infinity) - return "\\infty"; - else if(tree === -Infinity) - return "-\\infty"; - else { - let numberString = tree.toString(); - let eIndex = numberString.indexOf('e'); - if(eIndex === -1) { - return numberString; - } - let num = numberString.substring(0,eIndex); - let exponent = numberString.substring(eIndex+1); - - return num + " \\cdot 10^{" + exponent + "}"; - } - } - - var operator = tree[0]; - var operands = tree.slice(1); - - - if (operator === "^") { - let operand0 = this.factor(operands[0]); - - // so that f_(st)'^2(x) doesn't get extra parentheses - // (and no longer recognized as function call) - // check for simple factor after removing primes - let remove_primes = operands[0]; - while (remove_primes[0] === 'prime') { - remove_primes = remove_primes[1]; - } - - if (!(this.simple_factor_or_function_or_parens(remove_primes) || - (remove_primes[0] === '_' && (typeof remove_primes[1] === 'string')) - )) - operand0 = '\\left(' + operand0.toString() + '\\right)'; - - return operand0 + '^{' + this.statement(operands[1]) + '}'; - } - else if (operator === "_") { - let operand0 = this.factor(operands[0]); - if (!(this.simple_factor_or_function_or_parens(operands[0]))) - operand0 = '\\left(' + operand0.toString() + '\\right)'; - - return operand0 + '_{' + this.statement(operands[1]) + '}'; - } - else if (operator === "prime") { - let op = operands[0]; - - let n_primes = 1; - while (op[0] === "prime") { - n_primes += 1; - op = op[1]; - } - - let result = this.factor(op); - - if (!(this.simple_factor_or_function_or_parens(op) || - (op[0] === '_' && (typeof op[1] === 'string')) - )) - result = '\\left(' + result.toString() + '\\right)'; - for (let i = 0; i < n_primes; i++) { - result += "'"; - } - return result; - } - else if (operator === "-") { - return operators$3[operator](operands.map(function(v, i) { - return this.factor(v); - }.bind(this))); - } - else if (operator === 'tuple' || operator === 'array' || - operator === 'list' || - operator === 'set' || operator === 'vector' || - operator === '|' || operator === ':') { - return operators$3[operator](operands.map(function(v, i) { - return this.statement(v); - }.bind(this))); - - } - else if (operator === 'interval') { - - let args = operands[0]; - let closed = operands[1]; - if (args[0] !== 'tuple' || closed[0] !== 'tuple') - throw new Error("Badly formed ast"); - - let result = this.statement(args[1]) + ", " + - this.statement(args[2]); - - if (closed[1]) - result = '\\left[ ' + result; - else - result = '\\left( ' + result; - - if (closed[2]) - result = result + ' \\right]'; - else - result = result + ' \\right)'; - - return result; - - } - else if (operator === 'matrix') { - let size = operands[0]; - let args = operands[1]; - - let result = '\\begin{' + this.matrixEnvironment + '} '; - - for(let row = 0; row < size[1]; row += 1) { - for(let col = 0; col < size[2]; col += 1) { - result = result + this.statement(args[row+1][col+1]); - if(col < size[2]-1) - result = result + ' & '; - } - if(row < size[1]-1) - result = result + ' \\\\ '; - } - result = result + ' \\end{' + this.matrixEnvironment + '}'; - - return result; - - } - else if(operator === 'derivative_leibniz' || operator === 'partial_derivative_leibniz') { - let deriv_symbol = "d"; - if(operator === 'partial_derivative_leibniz') - deriv_symbol = "\\partial "; - - let num = operands[0]; - let denom = operands[1]; - - let n_deriv = 1; - let var1 = ""; - if(Array.isArray(num)) { - var1 = num[1]; - n_deriv = num[2]; - } - else - var1 = num; - - let result = deriv_symbol; - if(n_deriv > 1) - result = result.trimRight() + "^{" + n_deriv + "}" + this.stringConvert(var1); - else { - result = result + this.stringConvert(var1); - } - - result = "\\frac{ " + result + " }{ "; - - let n_denom = 1; - if(Array.isArray(denom)) { - n_denom = denom.length-1; - } - - for(let i=1; i <= n_denom; i++) { - let denom_part = denom[i]; - - let exponent = 1; - let var2 = ""; - if(Array.isArray(denom_part)) { - var2 = denom_part[1]; - exponent = denom_part[2]; - } - else - var2 = denom_part; - - result = result + deriv_symbol + this.stringConvert(var2); - - if(exponent > 1) - result = result + "^{" + exponent + "}"; - - result = result + " "; - - } - result = result + "}"; - return result; - - } - else if (operator === 'apply') { - - if (operands[0] === 'abs') { - return '\\left|' + this.statement(operands[1]) + '\\right|'; - } - - if (operands[0] === "factorial") { - let result = this.factor(operands[1]); - if (this.simple_factor_or_function_or_parens(operands[1]) || - (operands[1][0] === '_' && (typeof operands[1][1] === 'string')) - ) - return result + "!"; - else - return '\\left(' + result.toString() + '\\right)!'; - } - - if (operands[0] === 'sqrt') { - return '\\sqrt{' + this.statement(operands[1]) + '}'; - } - - let f = this.factor(operands[0]); - let f_args = this.statement(operands[1]); - - if (operands[1][0] !== 'tuple') - f_args = "\\left(" + f_args + "\\right)"; - - return f + f_args; - } - else { - return '\\left(' + this.statement(tree) + '\\right)'; - } - } - - factorWithParenthesesIfNegated(tree) { - var result = this.factor(tree); - - if (result.toString().match(/^-/)) - return '\\left(' + result.toString() + '\\right)'; - - // else - return result; - } - - termWithPlusIfNotNegated(tree) { - var result = this.term(tree); - - if (!result.toString().match(/^-/)) - return '+ ' + result.toString(); - - // else - return result; - } - - } - - const textToAst$2 = new textToAst(); - const astToLatex$1 = new astToLatex(); - - var derivatives = { - "sin": textToAst$2.convert('cos x'), - "cos": textToAst$2.convert('-(sin x)'), - "tan": textToAst$2.convert('(sec x)^2'), - "cot": textToAst$2.convert('-((csc x)^2)'), - "sec": textToAst$2.convert('(sec x)*(tan x)'), - "csc": textToAst$2.convert('-(csc x)*(cot x)'), - "sqrt": textToAst$2.convert('1/(2*sqrt(x))'), - "log": textToAst$2.convert('1/x'), - "ln": textToAst$2.convert('1/x'), - "exp": textToAst$2.convert('exp(x)'), - "arcsin": textToAst$2.convert('1/sqrt(1 - x^2)'), - "arccos": textToAst$2.convert('-1/sqrt(1 - x^2)'), - "arctan": textToAst$2.convert('1/(1 + x^2)'), - "arccsc": textToAst$2.convert('-1/(sqrt(-1/x^2 + 1)*x^2)'), - "arcsec": textToAst$2.convert('1/(sqrt(-1/x^2 + 1)*x^2)'), - "arccot": textToAst$2.convert('-1/(1 + x^2)'), - "abs": textToAst$2.convert('abs(x)/x'), - }; - - - function derivative$2(expr_or_tree,x,story = []) { - var tree = get_tree(expr_or_tree); - - var ddx = '\\frac{d}{d' + x + '} '; - - // Derivative of a constant - if (typeof tree === 'number') { - story.push( 'The derivative of a constant is zero, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); - return 0; - } - - // Derivative of a more complicated constant - if ((variables(tree)).indexOf(x) < 0) { - story.push( 'The derivative of a constant is zero, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); - return 0; - } - - // Derivative of a variable - if (typeof tree === 'string') { - if (x === tree) { - story.push( 'We know the derivative of the identity function is one, that is, \\(' + ddx + astToLatex$1.convert(tree) + ' = 1\\).' ); - return 1; - } - - // should never get to this line - // as would have been considered a constant - story.push( 'As far as \\(' + astToLatex$1.convert(x) + '\\) is concerned, \\(' + astToLatex$1.convert(tree) + '\\) is constant, so ' + ddx + astToLatex$1.convert(tree) + ' = 0\\).' ); - return 0; - } - - var operator = tree[0]; - var operands = tree.slice(1); - - // derivative of sum is sum of derivatives - if ((operator === '+') || (operator === '-') || (operator === '~')) { - story.push( 'Using the sum rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (operands.map( function(v,i) { return ddx + astToLatex$1.convert(v); } )).join( ' + ' ) + '\\).' ); - let result = [operator].concat( operands.map( function(v,i) { return derivative$2(v,x,story); } ) ); - result = simplify$2(result); - story.push( 'So using the sum rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - // product rule - if (operator === '*') { - let non_numeric_operands = []; - let numeric_operands = []; - - for( let i=0; i 0) { - if (non_numeric_operands.length === 0) { - story.push( 'Since the derivative of a constant is zero, \\(' + ddx + astToLatex$1.convert( tree ) + ' = 0.\\)' ); - let result = 0; - return result; - } - - let remaining = ['*'].concat( non_numeric_operands ); - if (non_numeric_operands.length === 1) - remaining = non_numeric_operands[0]; - - - - if (remaining === x) { - story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (numeric_operands.map( function(v,i) { return astToLatex$1.convert(v); } )).join( ' \\cdot ' ) + '\\).' ); - let result = ['*'].concat( numeric_operands ); - result = simplify$2(result); - return result; - } - - story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + (numeric_operands.map( function(v,i) { return astToLatex$1.convert(v); } )).join( ' \\cdot ' ) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(remaining) + '\\right)\\).' ); - - let d = derivative$2(remaining,x,story); - let result = ['*'].concat( numeric_operands.concat( [d] ) ); - result = simplify$2(result); - story.push( 'And so \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - story.push( 'Using the product rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + - (operands.map( function(v,i) { - return (operands.map( function(w,j) { - if (i === j) - return ddx + '\\left(' + astToLatex$1.convert(v) + '\\right)'; - else - return astToLatex$1.convert(w); - })).join( ' \\cdot ' ) })).join( ' + ' ) + '\\).' ); - - let inner_operands = operands.slice(); - - let result = ['+'].concat( operands.map( function(v,i) { - return ['*'].concat( inner_operands.map( function(w,j) { - if (i === j) { - let d = derivative$2(w,x,story); - // remove terms that have derivative 1 - if (d === 1) - return null; - - return d; - } else { - return w; - } - } ).filter( function(t) { return t != null; } ) ); - } ) ); - result = simplify$2(result); - story.push( 'So using the product rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - - return result; - } - - // quotient rule - if (operator === '/') { - let f = operands[0]; - let g = operands[1]; - - if ((variables(g)).indexOf(x) < 0) { - story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(['/', 1, g]) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(f) + '\\right)\\).' ); - - let df = derivative$2(f,x,story); - let quotient_rule = textToAst$2.convert('(1/g)*d'); - let result = substitute( quotient_rule, { "d": df, "g": g } ); - result = simplify$2(result); - story.push( 'So \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - - return result; - } - - if ((variables(f)).indexOf(x) < 0) { - if (f !== 1) { - story.push( 'By the constant multiple rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(f) + ' \\cdot ' + ddx + '\\left(' + astToLatex$1.convert(['/',1,g]) + '\\right)\\).' ); - } - - story.push( 'Since \\(\\frac{d}{du} \\frac{1}{u}\\) is \\(\\frac{-1}{u^2}\\), the chain rule gives \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(f) + '\\cdot \\frac{-1}{ ' + astToLatex$1.convert(g) + '^2} \\cdot ' + ddx + astToLatex$1.convert( g ) + "\\)." ); - - let a = derivative$2(g,x,story); - - let quotient_rule = textToAst$2.convert('f * (-a/(g^2))'); - let result = substitute( quotient_rule, { "f": f, "a": a, "g": g } ); - result = simplify$2(result); - story.push( 'So since \\(\\frac{d}{du} \\frac{1}{u}\\) is \\(\\frac{-1}{u^2}\\), the chain rule gives \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - - return result; - } - - story.push( 'Using the quotient rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = \\frac{' + ddx + '\\left(' + astToLatex$1.convert(f) + '\\right) \\cdot ' + astToLatex$1.convert(g) + ' - ' + astToLatex$1.convert(f) + '\\cdot ' + ddx + '\\left(' + astToLatex$1.convert(g) + '\\right)}{ \\left( ' + astToLatex$1.convert(g) + ' \\right)^2} \\).' ); - - let a = derivative$2(f,x,story); - let b = derivative$2(g,x,story); - - let quotient_rule = textToAst$2.convert('(a * g - f * b)/(g^2)'); - - let result = substitute( quotient_rule, { "a": a, "b": b, "f": f, "g": g } ); - result = simplify$2(result); - story.push( 'So using the quotient rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - - return result; - } - - // power rule - if (operator === '^') { - let base = operands[0]; - let exponent = operands[1]; - - if ((variables(exponent)).indexOf(x) < 0) { - if ((typeof base === 'string') && (base === 'x')) { - if (typeof exponent === 'number') { - let power_rule = textToAst$2.convert('n * (f^m)'); - let result = substitute( power_rule, { "n": exponent, "m": exponent - 1, "f": base } ); - result = simplify$2(result); - story.push( 'By the power rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '}\\).' ); - return result; - } - - let power_rule = textToAst$2.convert('n * (f^(n-1))'); - let result = substitute( power_rule, { "n": exponent, "f": base } ); - result = simplify$2(result); - story.push( 'By the power rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '}\\).' ); - - return result; - } - - if (exponent !== 1) { - story.push( 'By the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( exponent ) + ' \\cdot \\left(' + astToLatex$1.convert( base ) + '\\right)^{' + astToLatex$1.convert( ['-', exponent, 1] ) + '} \\cdot ' + ddx + astToLatex$1.convert( base ) + '\\).' ); - } - - let a = derivative$2(base,x,story); - - if (exponent === 1) - return a; - - if (typeof exponent === 'number') { - let power_rule = textToAst$2.convert('n * (f^m) * a'); - let result = substitute( power_rule, { "n": exponent, "m": exponent - 1, "f": base, "a" : a } ); - result = simplify$2(result); - story.push( 'So by the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - let power_rule = textToAst$2.convert('n * (f^(n-1)) * a'); - let result = substitute( power_rule, { "n": exponent, "f": base, "a" : a } ); - result = simplify$2(result); - story.push( 'So by the power rule and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - if (base === 'e' && math$19.define_e) { - if ((typeof exponent === 'string') && (exponent === x)) { - let power_rule = textToAst$2.convert('e^(f)'); - let result = substitute( power_rule, { "f": exponent } ); - result = simplify$2(result); - story.push( 'The derivative of \\(e^' + astToLatex$1.convert( x ) + '\\) is itself, that is, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( tree ) + '\\).' ); - - return result; - } - - story.push( 'Using the rule for \\(e^x\\) and the chain rule, we know \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( tree ) + ' \\cdot ' + ddx + astToLatex$1.convert( exponent ) + '\\).' ); - - let power_rule = textToAst$2.convert('e^(f)*d'); - - let d = derivative$2(exponent,x,story); - let result = substitute( power_rule, { "f": exponent, "d": d } ); - result = simplify$2(result); - story.push( 'So using the rule for \\(e^x\\) and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - if (typeof base === 'number') { - if ((typeof exponent === 'string') && (exponent === x)) { - let power_rule = textToAst$2.convert('a^(f) * log(a)'); - let result = substitute( power_rule, { "a": base, "f": exponent } ); - result = simplify$2(result); - story.push( 'The derivative of \\(a^' + astToLatex$1.convert( x ) + '\\) is \\(a^{' + astToLatex$1.convert( x ) + '} \\, \\log a\\), that is, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( result ) + '\\).' ); - - return result; - } - - let exp_rule = textToAst$2.convert('a^(f) * log(a)'); - let partial_result = substitute( exp_rule, { "a": base, "f": exponent } ); - - story.push( 'Using the rule for \\(a^x\\) and the chain rule, we know \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert( partial_result ) + ' \\cdot ' + ddx + astToLatex$1.convert( exponent ) + '\\).' ); - - let power_rule = textToAst$2.convert('a^(b)*log(a)*d'); - let d = derivative$2(exponent,x,story); - let result = substitute( power_rule, { "a": base, "b": exponent, "d": d } ); - result = simplify$2(result); - story.push( 'So using the rule for \\(a^x\\) and the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - // general case of a function raised to a function - let f = base; - let g = exponent; - - story.push( "Recall the general rule for exponents, namely that \\(\\frac{d}{dx} u(x)^{v(x)} = u(x)^{v(x)} \\cdot \\left( v'(x) \\cdot \\log u(x) + \\frac{v(x) \\cdot u'(x)}{u(x)} \\right)\\). In this case, \\(u(x) = " + astToLatex$1.convert( f ) + "\\) and \\(v(x) = " + astToLatex$1.convert( g ) + "\\)." ); - - let a = derivative$2(f,x,story); - let b = derivative$2(g,x,story); - - let power_rule = textToAst$2.convert('(f^g)*(b * log(f) + (g * a)/f)'); - let result = substitute( power_rule, { "a": a, "b": b, "f": f, "g": g } ); - result = simplify$2(result); - story.push( 'So by the general rule for exponents, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - if (operator === "apply" && !(operands[0] in derivatives)) { - // derivative of function whose derivative is not given - - let input = operands[1]; - - story.push( 'By the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(substitute( ["apply",operands[0] + "'","x"], { "x": input } )) + " \\cdot " + ddx + astToLatex$1.convert(input) + '\\).' ); - - let result = ['*', - substitute( ["apply",operands[0] + "'","x"], { "x": input } ), - derivative$2( input, x, story )]; - result = simplify$2(result); - story.push( 'So by the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - - // chain rule - if ((operator === "apply" && operands[0] in derivatives) || - operator in derivatives) { - - let used_apply = false; - if(operator === "apply") { - operator = operands[0]; - operands = operands.slice(1); - used_apply = true; - } - - let input = operands[0]; - - if (typeof input === "number") { - let result = 0; - story.push( 'The derivative of a constant is zero so \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } else if ((typeof input === "string") && (input === x)) { - let result = ['*', - substitute( derivatives[operator], { "x": input } )]; - result = simplify$2(result); - story.push( 'It is the case that \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } else if ((typeof input === "string") && (input !== x)) { - let result = 0; - story.push( 'Since the derivative of a constant is zero, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } else { - let example_ast = [operator,'u']; - if(used_apply) - example_ast = ["apply"].concat(example_ast); - story.push( 'Recall \\(\\frac{d}{du}' + astToLatex$1.convert( example_ast ) + ' = ' + - astToLatex$1.convert( derivative$2( example_ast, 'u', [] ) ) + '\\).' ); - - story.push( 'By the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(substitute( derivatives[operator], { "x": input } )) + " \\cdot " + ddx + astToLatex$1.convert(input) + '\\).' ); - - let result = ['*', - substitute( derivatives[operator], { "x": input } ), - derivative$2( input, x, story )]; - result = simplify$2(result); - story.push( 'So by the chain rule, \\(' + ddx + astToLatex$1.convert( tree ) + ' = ' + astToLatex$1.convert(result) + '\\).' ); - return result; - } - } - - return 0; - } - - /****************************************************************/ - // - // The "story" that the differentiation code produces can be somewhat repetitive - // - // Here we fix this - // - - function lowercaseFirstLetter(string) - { - return string.charAt(0).toLowerCase() + string.slice(1); - } - - function simplify_story( story ) { - // remove neighboring duplicates - for (let i = story.length - 1; i >= 1; i--) { - if (story[i] === story[i-1]) - story.splice( i, 1 ); - } - - // Make it seem obvious that I know I am repeating myself - for (let i = 0; i < story.length; i++ ) { - for( let j = i + 1; j < story.length; j++ ) { - if (story[i] === story[j]) { - story[j] = 'Again, ' + lowercaseFirstLetter( story[j] ); - } - } - } - - return story; - } - - - function derivative_story(expr, x) { - var story = []; - derivative$2( expr, x, story ); - story = simplify_story( story ); - return story; - } - const derivativeStory = derivative_story; - - var differentiation = /*#__PURE__*/Object.freeze({ - derivative: derivative$2, - derivative_story: derivative_story, - derivativeStory: derivativeStory - }); - - /* - * convert syntax trees back to string representations - * - * Copyright 2014-2017 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - - const unicode_operators = { - "+": function(operands) { return operands.join( ' ' ); }, - "-": function(operands) { return "- " + operands[0]; }, - "*": function(operands) { return operands.join( " " ); }, - "/": function(operands) { return operands[0] + "/" + operands[1]; }, - "_": function(operands) { return operands[0] + "_" + operands[1]; }, - "^": function(operands) { return operands[0] + "^" + operands[1]; }, - "prime": function(operands) { return operands[0] + "'"; }, - "tuple": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "array": function(operands) { return '[ ' + operands.join( ', ' ) + ' ]';}, - "list": function(operands) { return operands.join( ', ' );}, - "set": function(operands) { return '{ ' + operands.join( ', ' ) + ' }';}, - "vector": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "interval": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "matrix": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "and": function(operands) { return operands.join( ' and ' );}, - "or": function(operands) { return operands.join( ' or ' );}, - "not": function(operands) { return 'not ' + operands[0]; }, - "=": function(operands) { return operands.join( ' = ' );}, - "<": function(operands) { return operands.join( ' < ' );}, - ">": function(operands) { return operands.join( ' > ' );}, - "lts": function(operands) { return operands.join( ' < ' );}, - "gts": function(operands) { return operands.join( ' > ' );}, - - "le": function(operands) { return operands.join( ' ≤ ' );}, - "ge": function(operands) { return operands.join( ' ≥ ' );}, - "ne": function(operands) { return operands.join( ' ≠ ' );}, - "in": function(operands) { return operands[0] + " ∈ " + operands[1]; }, - "notin": function(operands) { return operands[0] + " ∉ " + operands[1]; }, - "ni": function(operands) { return operands[0] + " ∋ " + operands[1]; }, - "notni": function(operands) { return operands[0] + " ∌ " + operands[1]; }, - "subset": function(operands) { return operands[0] + " ⊂ " + operands[1]; }, - "notsubset": function(operands) { return operands[0] + " ⊄ " + operands[1]; }, - "superset": function(operands) { return operands[0] + " ⊃ " + operands[1]; }, - "notsuperset": function(operands) { return operands[0] + " ⊅ " + operands[1]; }, - "union": function (operands) { return operands.join(' ∪ '); }, - "intersect": function (operands) { return operands.join(' ∩ '); }, - "derivative_leibniz": function (operands) { return "d" + operands[0] + "/d" + operands[1]; }, - "partial_derivative_leibniz": function (operands) { return "∂" + operands[0] + "/∂" + operands[1]; }, - "|": function (operands) { return operands[0] + " | " + operands[1]; }, - ":": function (operands) { return operands[0] + " : " + operands[1]; }, - - }; - - const nonunicode_operators = { - "+": function(operands) { return operands.join( ' ' ); }, - "-": function(operands) { return "- " + operands[0]; }, - "*": function(operands) { return operands.join( " " ); }, - "/": function(operands) { return operands[0] + "/" + operands[1]; }, - "_": function(operands) { return operands[0] + "_" + operands[1]; }, - "^": function(operands) { return operands[0] + "^" + operands[1]; }, - "prime": function(operands) { return operands[0] + "'"; }, - "tuple": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "array": function(operands) { return '[ ' + operands.join( ', ' ) + ' ]';}, - "list": function(operands) { return operands.join( ', ' );}, - "set": function(operands) { return '{ ' + operands.join( ', ' ) + ' }';}, - "vector": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "interval": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "matrix": function(operands) { return '( ' + operands.join( ', ' ) + ' )';}, - "and": function(operands) { return operands.join( ' and ' );}, - "or": function(operands) { return operands.join( ' or ' );}, - "not": function(operands) { return 'not ' + operands[0]; }, - "=": function(operands) { return operands.join( ' = ' );}, - "<": function(operands) { return operands.join( ' < ' );}, - ">": function(operands) { return operands.join( ' > ' );}, - "lts": function(operands) { return operands.join( ' < ' );}, - "gts": function(operands) { return operands.join( ' > ' );}, - - "le": function(operands) { return operands.join( ' <= ' );}, - "ge": function(operands) { return operands.join( ' >= ' );}, - "ne": function(operands) { return operands.join( ' ne ' );}, - "in": function(operands) { return operands[0] + " elementof " + operands[1]; }, - "notin": function(operands) { return operands[0] + " notelementof " + operands[1]; }, - "ni": function(operands) { return operands[0] + " containselement " + operands[1]; }, - "notni": function(operands) { return operands[0] + " notcontainselement " + operands[1]; }, - "subset": function(operands) { return operands[0] + " subset " + operands[1]; }, - "notsubset": function(operands) { return operands[0] + " notsubset " + operands[1]; }, - "superset": function(operands) { return operands[0] + " superset " + operands[1]; }, - "notsuperset": function(operands) { return operands[0] + " notsuperset " + operands[1]; }, - "union": function (operands) { return operands.join(' union '); }, - "intersect": function (operands) { return operands.join(' intersect '); }, - "derivative_leibniz": function (operands) { return "d" + operands[0] + "/d" + operands[1]; }, - "partial_derivative_leibniz": function (operands) { return "∂" + operands[0] + "/∂" + operands[1]; }, - "|": function (operands) { return operands[0] + " | " + operands[1]; }, - ":": function (operands) { return operands[0] + " : " + operands[1]; }, - }; - - - const output_unicodeDefault = true; - - - class astToText { - constructor({ - output_unicode = output_unicodeDefault - } = {}) { - this.output_unicode = output_unicode; - this.operators = unicode_operators; - if(!output_unicode){ this.operators = nonunicode_operators;} - } - - convert(tree) { - return this.statement(tree); - } - - statement(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.single_statement(tree); - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === 'ldots') - return '...'; - - if((!(operator in this.operators)) && operator!=="apply") - throw new Error("Badly formed ast: operator " + operator + " not recognized."); - - if (operator === 'and' || operator === 'or') { - return this.operators[operator]( operands.map( function(v,i) { - let result = this.single_statement(v); - // for clarity, add parenthesis unless result is - // single quantity (with no spaces) or already has parens - if (result.toString().match(/ /) - && (!(result.toString().match(/^\(.*\)$/)))) - return '(' + result + ')'; - else - return result; - }.bind(this))); - } - return this.single_statement(tree); - } - - single_statement(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.expression(tree); - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if (operator === 'not') { - return this.operators[operator]( operands.map( function(v,i) { - let result = this.single_statement(v); - // for clarity, add parenthesis unless result is - // single quantity (with no spaces) or already has parens - if (result.toString().match(/ /) - && (!(result.toString().match(/^\(.*\)$/)))) - return '(' + result + ')'; - else - return result; - }.bind(this))); - } - - if((operator === '=') || (operator === 'ne') - || (operator === '<') || (operator === '>') - || (operator === 'le') || (operator === 'ge') - || (operator === 'in') || (operator === 'notin') - || (operator === 'ni') || (operator === 'notni') - || (operator === 'subset') || (operator === 'notsubset') - || (operator === 'superset') || (operator === 'notsuperset')) { - return this.operators[operator]( operands.map( function(v,i) { - return this.expression(v); - }.bind(this))); - } - - if(operator === 'lts' || operator === 'gts') { - let args = operands[0]; - let strict = operands[1]; - - if(args[0] !== 'tuple' || strict[0] !== 'tuple') - // something wrong if args or strict are not tuples - throw new Error("Badly formed ast"); - - let result = this.expression(args[1]); - for(let i=1; i< args.length-1; i++) { - if(strict[i]) { - if(operator === 'lts') - result += " < "; - else - result += " > "; - } - else { - if(operator === 'lts') { - if(this.output_unicode) - result += " ≤ "; - else - result += " <= "; - } - else { - if(this.output_unicode) - result += " ≥ "; - else - result += " >= "; - } - } - result += this.expression(args[i+1]); - } - return result; - } - - return this.expression(tree); - } - - expression(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.term(tree); - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if (operator === '+') { - return this.operators[operator]( operands.map( function(v,i) { - if(i>0) - return this.termWithPlusIfNotNegated(v); - else - return this.term(v); - }.bind(this) )); - } - - if ((operator === 'union') || (operator === 'intersect')) { - return this.operators[operator]( operands.map( function(v,i) { - return this.term(v); - }.bind(this))); - } - - return this.term(tree); - } - - term(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.factor(tree); - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if (operator === '-') { - return this.operators[operator]( operands.map( function(v,i) { - return this.term(v); - }.bind(this))); - } - if (operator === '*') { - return this.operators[operator]( operands.map( function(v,i) { - let result; - if(i > 0) { - result = this.factorWithParenthesesIfNegated(v); - if (result.toString().match( /^[0-9]/ )) - return '* ' + result; - else - return result - } - else - return this.factor(v); - }.bind(this))); - } - - if (operator === '/') { - return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); - } - - return this.factor(tree); - } - - symbolConvert(symbol) { - let symbolConversions= { - 'alpha': 'α', - 'beta': 'β', - 'Gamma': 'Γ', - 'gamma': 'γ', - 'Delta': 'Δ', - 'delta': 'δ', - 'epsilon': 'ε', - 'zeta': 'ζ', - 'eta': 'η', - 'Theta': 'ϴ', - 'theta': 'θ', - 'iota': 'ι', - 'kappa': 'κ', - 'Lambda': 'Λ', - 'lambda': 'λ', - 'mu': 'μ', - 'nu': 'ν', - 'Xi': 'Ξ', - 'xi': 'ξ', - 'Pi': 'Π', - 'pi': 'π', - 'rho': 'ρ', - 'Sigma': 'Σ', - 'sigma': 'σ', - 'tau': 'τ', - 'Upsilon': 'Υ', - 'upsilon': 'υ', - 'Phi': 'Φ', - 'phi': 'ϕ', - 'Psi': 'Ψ', - 'psi': 'ψ', - 'Omega': 'Ω', - 'omega': 'ω', - }; - if (this.output_unicode && (symbol in symbolConversions)) - return symbolConversions[symbol]; - else - return symbol - } - - simple_factor_or_function_or_parens(tree) { - // return true if - // factor(tree) is a single character - // or tree is a non-negative number not in scientific notation - // or tree is a string - // or tree is a function call - // or factor(tree) is in parens - - let result = this.factor(tree); - - if (result.toString().length === 1 - || (typeof tree === 'string') - || (tree[0] === 'apply') - || result.toString().match(/^\(.*\)$/) - ) { - return true; - } else if (typeof tree === 'number') { - if (tree >= 0 && !tree.toString().includes('e')) { - return true; - } else { - return false; - } - } else { - return false - } - } - - factor(tree) { - if (typeof tree === 'string') { - return this.symbolConvert(tree); - } - - if (typeof tree === 'number') { - if(tree === Infinity) { - if(this.output_unicode) { - return '∞'; - } - else { - return 'infinity'; - } - } - else if(tree === -Infinity) { - if(this.output_unicode) { - return '-∞'; - } - else { - return '-infinity'; - } - } - else { - let numberString = tree.toString(); - let eIndex = numberString.indexOf('e'); - if(eIndex === -1) { - return numberString; - } - let num = numberString.substring(0,eIndex); - let exponent = numberString.substring(eIndex+1); - if(exponent[0] === "+") { - return num + " * 10^" + exponent.substring(1); - } else { - return num + " * 10^(" + exponent + ")"; - } - } - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if (operator === "^") { - let operand0 = this.factor(operands[0]); - - // so that f_(st)'^2(x) doesn't get extra parentheses - // (and no longer recognized as function call) - // check for simple factor after removing primes - let remove_primes = operands[0]; - while(remove_primes[0] === 'prime') { - remove_primes=remove_primes[1]; - } - - if(!(this.simple_factor_or_function_or_parens(remove_primes) || - (remove_primes[0] === '_' && (typeof remove_primes[1] === 'string')) - )) - operand0 = '(' + operand0.toString() + ')'; - - let operand1 = this.factor(operands[1]); - if(!(this.simple_factor_or_function_or_parens(operands[1]))) - operand1 = '(' + operand1.toString() + ')'; - - return operand0 + '^' + operand1; - } - else if (operator === "_") { - return this.operators[operator]( operands.map( function(v,i) { - let result = this.factor(v); - if(this.simple_factor_or_function_or_parens(v)) - return result; - else - return '(' + result.toString() + ')'; - }.bind(this))); - } - else if(operator === "prime") { - let op = operands[0]; - - let n_primes=1; - while(op[0] === "prime") { - n_primes+=1; - op=op[1]; - } - - let result = this.factor(op); - - if (!(this.simple_factor_or_function_or_parens(op) || - (op[0] === '_' && (typeof op[1] === 'string')) - )) - result = '(' + result.toString() + ')'; - for(let i=0; i 1) - result = result + "^" + n_deriv; - result = result + this.symbolConvert(var1) + "/"; - - let n_denom = 1; - if(Array.isArray(denom)) { - n_denom = denom.length-1; - } - - for(let i=1; i <= n_denom; i++) { - let denom_part = denom[i]; - - let exponent = 1; - let var2 = ""; - if(Array.isArray(denom_part)) { - var2 = denom_part[1]; - exponent = denom_part[2]; - } - else - var2 = denom_part; - - result = result + deriv_symbol + this.symbolConvert(var2); - - if(exponent > 1) - result = result + "^" + exponent; - - } - return result; - - } - else if(operator === 'apply'){ - - if(operands[0] === 'abs') { - return '|' + this.statement(operands[1]) + '|'; - } - - if (operands[0] === "factorial") { - let result = this.factor(operands[1]); - if(this.simple_factor_or_function_or_parens(operands[1]) || - (operands[1][0] === '_' && (typeof operands[1][1] === 'string')) - ) - return result + "!"; - else - return '(' + result.toString() + ')!'; - - } - - let f = this.factor(operands[0]); - let f_args = this.statement(operands[1]); - - if(operands[1][0] !== 'tuple') - f_args = "(" + f_args + ")"; - - return f+f_args; - } - else { - return '(' + this.statement(tree) + ')'; - } - } - - factorWithParenthesesIfNegated(tree){ - let result = this.factor(tree); - - if (result.toString().match( /^-/ )) - return '(' + result.toString() + ')'; - - // else - return result; - } - - termWithPlusIfNotNegated(tree){ - let result = this.term(tree); - - if (!result.toString().match( /^-/ )) - return '+ ' + result.toString(); - - // else - return result; - } - - } - - var astToText$1 = new astToText(); - - function subscripts_to_strings(expr_or_tree, force=false) { - // convert ['_', a,b] to string - // if force is set, perform conversions for any values of a or b - // otherwise (the default), perform conversion only - // when both a and b are strings or numbers - - var tree = get_tree(expr_or_tree); - - if(!Array.isArray(tree)) { - return tree; - } - - let operator = tree[0]; - let operands = tree.slice(1); - - if(operator === '_') { - if(force || operands.every(x => ['number', 'string'].includes(typeof x))) { - return astToText$1.convert(tree); - } - } - - return [operator].concat(operands.map(x => subscripts_to_strings(x,force))); - } - - - - function strings_to_subscripts(expr_or_tree) { - // convert string 'a_b' to ['_', 'a','b'] and string 'a_1' to ['_', 'a', 1] - - var tree = get_tree(expr_or_tree); - - if(typeof tree === "string") { - let res = tree.match(/^([0-9a-zA-Z]+)_([a-zA-Z]+|[0-9]+)$/); - if(res) { - let base = Number(res[1]); - if(isNaN(base)) { - base = res[1]; - } - let sub = Number(res[2]); - if(isNaN(sub)) { - sub = res[2]; - } - return ['_', base, sub] - }else { - return tree; - } - } - - if(!Array.isArray(tree)) { - return tree; - } - - let operator = tree[0]; - let operands = tree.slice(1); - - return [operator].concat(operands.map(strings_to_subscripts)); - } - - - - var normalization = /*#__PURE__*/Object.freeze({ - normalize_function_names: normalize_function_names, - normalize_applied_functions: normalize_applied_functions, - substitute_abs: substitute_abs, - default_order: default_order, - constants_to_floats: constants_to_floats, - tuples_to_vectors: tuples_to_vectors, - to_intervals: to_intervals, - subscripts_to_strings: subscripts_to_strings, - strings_to_subscripts: strings_to_subscripts - }); - - // check for equality by randomly sampling - - function generate_random_integer(minvalue, maxvalue, rng) { - minvalue = math$19.ceil(minvalue); - maxvalue = math$19.floor(maxvalue); - return math$19.floor(rng() * (maxvalue - minvalue + 1)) + minvalue; - } - - - - const equals = function ({ expr, other, randomBindings, - expr_context, other_context, - relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - rng, - }) { - - if (Array.isArray(expr.tree) && Array.isArray(other.tree)) { - - let expr_operator = expr.tree[0]; - let expr_operands = expr.tree.slice(1); - let other_operator = other.tree[0]; - let other_operands = other.tree.slice(1); - - if (expr_operator === 'tuple' || expr_operator === 'vector' - || expr_operator === 'list' || expr_operator === 'array' - || expr_operator === 'matrix' || expr_operator === 'interval' - ) { - - if (other_operator !== expr_operator) - return false; - - if (other_operands.length !== expr_operands.length) - return false; - - for (let i = 0; i < expr_operands.length; i++) { - if (!equals({ - expr: expr_context.fromAst(expr_operands[i]), - other: other_context.fromAst(other_operands[i]), - randomBindings: randomBindings, - expr_context: expr_context, - other_context: other_context, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - rng, - })) - return false; - } - - return true; // each component is equal - } - - // check if a relation with two operands - if (expr_operands.length === 2 && ["=", '>', '<', 'ge', 'le'].includes(expr_operator)) { - if (other_operands.length !== 2) { - return false; - } - //normalize operator - if (expr_operator === ">") { - expr_operator = "<"; - expr_operands = [expr_operands[1], expr_operands[0]]; - } else if (expr_operator === "ge") { - expr_operator = "le"; - expr_operands = [expr_operands[1], expr_operands[0]]; - } - if (other_operator === ">") { - other_operator = "<"; - other_operands = [other_operands[1], other_operands[0]]; - } else if (other_operator === "ge") { - other_operator = "le"; - other_operands = [other_operands[1], other_operands[0]]; - } - - if (expr_operator !== other_operator) { - return false; - } - - // put in standard form - let expr_rhs = ['+', expr_operands[0], ['-', expr_operands[1]]]; - let other_rhs = ['+', other_operands[0], ['-', other_operands[1]]]; - let require_positive_proportion = (expr_operator !== "="); - - return component_equals({ - expr: expr_context.fromAst(expr_rhs), - other: other_context.fromAst(other_rhs), - randomBindings: randomBindings, - expr_context: expr_context, - other_context: other_context, - allow_proportional: true, - require_positive_proportion: require_positive_proportion, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - rng, - }); - - } - - } - - // if not special case, use standard numerical equality - return component_equals({ - expr: expr, - other: other, - randomBindings: randomBindings, - expr_context: expr_context, - other_context: other_context, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - rng, - }); - - }; - - - const component_equals = function ({ expr, other, randomBindings, - expr_context, other_context, - allow_proportional = false, require_positive_proportion = false, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers, include_error_in_number_exponents, - allowed_error_is_absolute, - rng - }) { - - var max_value = Number.MAX_VALUE * 1E-20; - var min_nonzero_value = 0;//1E-100; //Number.MIN_VALUE & 1E20; - - var minimum_matches = 10; - var number_tries = 100; - // if (allowed_error_in_numbers > 0) { - // minimum_matches = 400; - // number_tries = 4000; - // } - - // normalize function names, so in particular, e^x becomes exp(x) - expr = expr.normalize_function_names(); - other = other.normalize_function_names(); - - // convert subscripts to strings so that variables like x_t are considered single variable - expr = expr.subscripts_to_strings(); - other = other.subscripts_to_strings(); - - // Get set of variables mentioned in at least one of the two expressions - var variables = [expr.variables(), other.variables()]; - variables = variables.reduce(function (a, b) { return a.concat(b); }); - variables = variables.reduce(function (p, c) { - if (p.indexOf(c) < 0) p.push(c); - return p; - }, []); - - // pi, e, and i shouldn't be treated as a variable - // for the purposes of equality if they are defined as having values - if (math$19.define_pi) { - variables = variables.filter(function (a) { - return (a !== "pi"); - }); - } - if (math$19.define_i) { - variables = variables.filter(function (a) { - return (a !== "i"); - }); - } - if (math$19.define_e) { - variables = variables.filter(function (a) { - return (a !== "e"); - }); - } - - // determine if any of the variables are integers - // consider integer if is integer in either expressions' assumptions - var integer_variables = []; - for (let i = 0; i < variables.length; i++) - if (is_integer_ast(variables[i], expr_context.assumptions) - || is_integer_ast(variables[i], other_context.assumptions)) - integer_variables.push(variables[i]); - - // determine if any of the variables are functions - var functions = [expr.functions(), other.functions()]; - functions = functions.reduce(function (a, b) { return a.concat(b); }); - functions = functions.reduce(function (p, c) { - if (p.indexOf(c) < 0) p.push(c); - return p; - }, []); - functions = functions.filter(function (a) { - return a.length == 1; - }); - - try { - var expr_f = expr.f(); - var other_f = other.f(); - } - catch (e) { - // Can't convert to mathjs to create function - // just check if equal via syntax - return expr.equalsViaSyntax(other) - } - - let expr_with_params, parameters_for_numbers; - let tolerance_function; - - if (allowed_error_in_numbers > 0) { - let result = replace_numbers_with_parameters({ - expr: expr, - variables: variables, - include_exponents: include_error_in_number_exponents, - }); - expr_with_params = expr_context.fromAst(result.expr_with_params); - parameters_for_numbers = result.parameters; - - let parameter_list = Object.keys(parameters_for_numbers); - if (parameter_list.length > 0) { - let derivative_sum = expr_with_params.derivative(parameter_list[0]); - if (!allowed_error_is_absolute) { - derivative_sum = derivative_sum - .multiply(parameters_for_numbers[parameter_list[0]]); - } - if (parameter_list.length > 1) { - for (let par of parameter_list.slice(1)) { - let term = expr_with_params.derivative(par); - if (!allowed_error_is_absolute) { - term = term.multiply(parameters_for_numbers[par]); - } - derivative_sum = derivative_sum.add(term); - } - } - - let tolerance_expression = derivative_sum.multiply(allowed_error_in_numbers); - - try { - tolerance_function = tolerance_expression.f(); - } catch (e) { - // can't create function out of derivative - // so can't compute tolerance that would correspond - // to the allowed error in numbers - - // Leave tolerance_function undefined - - } - - } - - } - - - - var noninteger_binding_scale = 1; - - var binding_scales = [10, 1, 100, 0.1, 1000, 0.01]; - var scale_num = 0; - - // Numerical test of equality - // If can find a region of the complex plane where the functions are equal - // at minimum_matches points, consider the functions equal - // unless the functions were always zero, in which case - // test at multiple scales to check for underflow - - // In order to account for possible branch cuts, - // finding points where the functions are not equal does not lead to the - // conclusion that expression are unequal. Instead, to be consider unequal - // the functions must be unequal around many different points. - - let num_at_this_scale = 0; - - let always_zero = true; - - let num_finite_unequal = 0; - - for (let i = 0; i < 10 * number_tries; i++) { - - // Look for a location where the magnitudes of both expressions - // are below max_value; - try { - var result = find_equality_region(binding_scales[scale_num], rng); - } - catch (e) { - continue; - } - - if (result.always_zero === false) { - always_zero = false; - } - - - if (!result.equal && !result.out_of_bounds && !result.always_zero && - result.sufficient_finite_values !== false - ) { - num_finite_unequal++; - if (num_finite_unequal > number_tries) { - return false; - } - } - - if (result.equal) { - if (result.always_zero) { - if (!always_zero) { - // if found always zero this time, but wasn't zero at a different point - // don't count as equal - continue; - } - // functions equal but zero - // repeat to make sure (changing if continuing to be zero) - num_at_this_scale += 1; - if (num_at_this_scale > 5) { - scale_num += 1; - num_at_this_scale = 0; - } - if (scale_num >= binding_scales.length) { - return true; // were equal and zero at all scales - } else - continue - } - else { - return true; - } - } - } - return false; - - - - function find_equality_region(noninteger_scale, rng) { - - // Check if expr and other are equal in a region as follows - // 1. Randomly select bindings (use noninteger scale for non-integer variables) - // and evaluate expr and other at that point - // 2. If either value is too large, return { out_of_bounds: true } - // 3. If values are not equal (within tolerance), return { equal_at_start: false } - // 4. If functions are equal, then - // randomly select binding in neighborhood of that point - // (use non_integer scale/100 for non-integer variables) - // 5. If find a point where the functions are not equal, - // then return { equal_in_middle: false } - // 6. If find that functions are equal at minimum_matches points - // then return { equality: true, always_zero: always_zero } - // where always_zero is true if both functions were always zero - // and is false otherwise - // 7. If were unable to find sufficent points where both functions are finite - // return { sufficient_finite_values: false } - // If allow_proportional is true, then instead of return non-equal - // in step 3, use the ratio of value of these first evaluations to set - // the proportion, and base equality on remaining values having the - // same proportion - - - - var bindings = randomBindings(rng, variables, noninteger_scale); - - // replace any integer variables with integer - for (let i = 0; i < integer_variables.length; i++) { - bindings[integer_variables[i]] = generate_random_integer(-10, 10, rng); - } - - // replace any function variables with a function - for (let i = 0; i < functions.length; i++) { - var a = generate_random_integer(-10, 10, rng); - var b = generate_random_integer(-10, 10, rng); - var c = generate_random_integer(-10, 10, rng); - bindings[functions[i]] = function (x) { - return math$19.add(math$19.multiply(math$19.add(math$19.multiply(a, x), b), x), c); - }; - } - - - var bindingsIncludingParameters; - if (tolerance_function) { - bindingsIncludingParameters = Object.assign({}, bindings, parameters_for_numbers); - } - - var expr_evaluated = expr_f(bindings); - var other_evaluated = other_f(bindings); - - var expr_abs = math$19.abs(expr_evaluated); - var other_abs = math$19.abs(other_evaluated); - - if (!(expr_abs < max_value && other_abs < max_value)) - return { out_of_bounds: true, always_zero: false }; - - if (!((expr_abs === 0 || expr_abs > min_nonzero_value) && - (other_abs === 0 || other_abs > min_nonzero_value))) - return { out_of_bounds: true, always_zero: false }; - - // now that found a finite point, - // check to see if expressions are nearly equal. - - var min_mag = Math.min(expr_abs, other_abs); - var max_mag = Math.max(expr_abs, other_abs); - var proportion = 1; - - let tol = 0; - if (tolerance_function) { - try { - tol = math$19.abs(tolerance_function(bindingsIncludingParameters)); - } catch (e) { - return { equal_at_start: false, always_zero: false }; - } - if (!Number.isFinite(tol)) { - return { equal_at_start: false, always_zero: false }; - } - } - - tol += min_mag * relative_tolerance; - - // never allow tol to get over 10% the min_mag - tol = Math.min(tol, 0.1 * min_mag); - - - // don't use min_mag to check for zero as mag will be zero - // for very small complex numbers - if (tol === 0 && (expr_evaluated === 0 || other_evaluated === 0)) { - tol += tolerance_for_zero; - } else { - tol += absolute_tolerance; - } - - if (!( - max_mag === 0 || - math$19.abs(math$19.subtract(expr_evaluated, other_evaluated)) < tol - )) { - if (!allow_proportional) { - return { equal_at_start: false, always_zero: false }; - } - // at this point, know both are not zero - if (expr_abs === 0 || other_abs === 0) { - return { equal_at_start: false, always_zero: false }; - } - - proportion = math$19.divide(expr_evaluated, other_evaluated); - if (require_positive_proportion && !(proportion > 0)) { - return { equal_at_start: false, always_zero: false }; - } - } - - - var always_zero = (max_mag === 0); - - // Look for a region around point - var finite_tries = 0; - for (let j = 0; j < 100; j++) { - var bindings2 = randomBindings( - rng, variables, noninteger_binding_scale / 100, bindings); - - // replace any integer variables with integer - for (let k = 0; k < integer_variables.length; k++) { - bindings2[integer_variables[k]] - = generate_random_integer(-10, 10, rng); - } - - // replace any function variables with a function - for (let i = 0; i < functions.length; i++) { - var a = generate_random_integer(-10, 10, rng); - var b = generate_random_integer(-10, 10, rng); - var c = generate_random_integer(-10, 10, rng); - bindings2[functions[i]] = function (x) { - return math$19.add(math$19.multiply(math$19.add(math$19.multiply(a, x), b), x), c); - }; - } - - var bindings2IncludingParameters; - if (tolerance_function) { - bindings2IncludingParameters = Object.assign({}, bindings2, parameters_for_numbers); - } - - try { - expr_evaluated = expr_f(bindings2); - other_evaluated = math$19.multiply(other_f(bindings2), proportion); - } - catch (e) { - continue; - } - expr_abs = math$19.abs(expr_evaluated); - other_abs = math$19.abs(other_evaluated); - - if (expr_abs < max_value && other_abs < max_value) { - min_mag = Math.min(expr_abs, other_abs); - max_mag = Math.max(expr_abs, other_abs); - - finite_tries++; - - let tol = 0; - if (tolerance_function) { - try { - tol = math$19.abs(tolerance_function(bindings2IncludingParameters)); - } catch (e) { - continue; - } - if (!Number.isFinite(tol)) { - continue; - } - } - tol += min_mag * relative_tolerance; - - // never allow tol to get over 10% the min_mag - tol = Math.min(tol, 0.1 * min_mag); - - // don't use min_mag to check for zero as mag will be zero - // for very small complex numbers - if (tol === 0 && (expr_evaluated === 0 || other_evaluated === 0)) { - tol += tolerance_for_zero; - } else { - tol += absolute_tolerance; - } - - if (!( - max_mag === 0 || - math$19.abs(math$19.subtract(expr_evaluated, other_evaluated)) < tol - )) { - return { equality_in_middle: false, always_zero: false }; - } - - always_zero = always_zero && (max_mag === 0); - - if (finite_tries >= minimum_matches) { - return { equal: true, always_zero: always_zero } - } - } - } - return { sufficient_finite_values: false, always_zero: always_zero }; - } - - }; - - function replace_numbers_with_parameters({ expr, variables, include_exponents = false }) { - - // find all numbers, including pi and e, if defined as numerical - let parameters = {}; - let lastParNum = 0; - - function get_new_parameter_name() { - lastParNum++; - let parName = "par" + lastParNum; - while (variables.includes(parName)) { - lastParNum++; - parName = "par" + lastParNum; - } - - // found a new parameter name that isn't a variable - return parName; - - } - - function replace_number_sub(tree) { - if (typeof tree === 'number') { - if (tree === 0) { - // since will compute bounds for relative error in numbers - // can't include zero - return tree; - } else { - let par = get_new_parameter_name(); - parameters[par] = tree; - return par; - } - } - - if (typeof tree === "string") { - if (tree === "pi") { - if (math$19.define_pi) { - let par = get_new_parameter_name(); - parameters[par] = math$19.PI; - return par; - } - } else if (tree === "e") { - if (math$19.define_e) { - let par = get_new_parameter_name(); - parameters[par] = math$19.e; - return par; - } - } - return tree; - } - - if (!Array.isArray(tree)) { - return tree; - } - - let operator = tree[0]; - let operands = tree.slice(1); - if (operator === "^" && !include_exponents) { - return [operator, replace_number_sub(operands[0]), operands[1]] - } else { - return [operator, ...operands.map(replace_number_sub)]; - } - - } - - // first evaluate numbers to combine then - // and turn any numerical constants to floating points - expr = expr.evaluate_numbers({ max_digits: Infinity }); - return { - expr_with_params: replace_number_sub(expr.tree), - parameters: parameters - } - - } - - var alea = createCommonjsModule(function (module) { - // A port of an algorithm by Johannes Baagøe , 2010 - // http://baagoe.com/en/RandomMusings/javascript/ - // https://github.com/nquinlan/better-random-numbers-for-javascript-mirror - // Original work is under MIT license - - - // Copyright (C) 2010 by Johannes Baagøe - // - // Permission is hereby granted, free of charge, to any person obtaining a copy - // of this software and associated documentation files (the "Software"), to deal - // in the Software without restriction, including without limitation the rights - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - // copies of the Software, and to permit persons to whom the Software is - // furnished to do so, subject to the following conditions: - // - // The above copyright notice and this permission notice shall be included in - // all copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - // THE SOFTWARE. - - - - (function(global, module, define) { - - function Alea(seed) { - var me = this, mash = Mash(); - - me.next = function() { - var t = 2091639 * me.s0 + me.c * 2.3283064365386963e-10; // 2^-32 - me.s0 = me.s1; - me.s1 = me.s2; - return me.s2 = t - (me.c = t | 0); - }; - - // Apply the seeding algorithm from Baagoe. - me.c = 1; - me.s0 = mash(' '); - me.s1 = mash(' '); - me.s2 = mash(' '); - me.s0 -= mash(seed); - if (me.s0 < 0) { me.s0 += 1; } - me.s1 -= mash(seed); - if (me.s1 < 0) { me.s1 += 1; } - me.s2 -= mash(seed); - if (me.s2 < 0) { me.s2 += 1; } - mash = null; - } - - function copy(f, t) { - t.c = f.c; - t.s0 = f.s0; - t.s1 = f.s1; - t.s2 = f.s2; - return t; - } - - function impl(seed, opts) { - var xg = new Alea(seed), - state = opts && opts.state, - prng = xg.next; - prng.int32 = function() { return (xg.next() * 0x100000000) | 0; }; - prng.double = function() { - return prng() + (prng() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53 - }; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - function Mash() { - var n = 0xefc8249d; - - var mash = function(data) { - data = String(data); - for (var i = 0; i < data.length; i++) { - n += data.charCodeAt(i); - var h = 0.02519603282416938 * n; - n = h >>> 0; - h -= n; - h *= n; - n = h >>> 0; - h -= n; - n += h * 0x100000000; // 2^32 - } - return (n >>> 0) * 2.3283064365386963e-10; // 2^-32 - }; - - return mash; - } - - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.alea = impl; - } - - })( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader - ); - }); - - var xor128 = createCommonjsModule(function (module) { - // A Javascript implementaion of the "xor128" prng algorithm by - // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper - - (function(global, module, define) { - - function XorGen(seed) { - var me = this, strseed = ''; - - me.x = 0; - me.y = 0; - me.z = 0; - me.w = 0; - - // Set up generator function. - me.next = function() { - var t = me.x ^ (me.x << 11); - me.x = me.y; - me.y = me.z; - me.z = me.w; - return me.w ^= (me.w >>> 19) ^ t ^ (t >>> 8); - }; - - if (seed === (seed | 0)) { - // Integer seed. - me.x = seed; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 64; k++) { - me.x ^= strseed.charCodeAt(k) | 0; - me.next(); - } - } - - function copy(f, t) { - t.x = f.x; - t.y = f.y; - t.z = f.z; - t.w = f.w; - return t; - } - - function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.xor128 = impl; - } - - })( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader - ); - }); - - var xorwow = createCommonjsModule(function (module) { - // A Javascript implementaion of the "xorwow" prng algorithm by - // George Marsaglia. See http://www.jstatsoft.org/v08/i14/paper - - (function(global, module, define) { - - function XorGen(seed) { - var me = this, strseed = ''; - - // Set up generator function. - me.next = function() { - var t = (me.x ^ (me.x >>> 2)); - me.x = me.y; me.y = me.z; me.z = me.w; me.w = me.v; - return (me.d = (me.d + 362437 | 0)) + - (me.v = (me.v ^ (me.v << 4)) ^ (t ^ (t << 1))) | 0; - }; - - me.x = 0; - me.y = 0; - me.z = 0; - me.w = 0; - me.v = 0; - - if (seed === (seed | 0)) { - // Integer seed. - me.x = seed; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 64; k++) { - me.x ^= strseed.charCodeAt(k) | 0; - if (k == strseed.length) { - me.d = me.x << 10 ^ me.x >>> 4; - } - me.next(); - } - } - - function copy(f, t) { - t.x = f.x; - t.y = f.y; - t.z = f.z; - t.w = f.w; - t.v = f.v; - t.d = f.d; - return t; - } - - function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.xorwow = impl; - } - - })( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader - ); - }); - - var xorshift7 = createCommonjsModule(function (module) { - // A Javascript implementaion of the "xorshift7" algorithm by - // François Panneton and Pierre L'ecuyer: - // "On the Xorgshift Random Number Generators" - // http://saluc.engr.uconn.edu/refs/crypto/rng/panneton05onthexorshift.pdf - - (function(global, module, define) { - - function XorGen(seed) { - var me = this; - - // Set up generator function. - me.next = function() { - // Update xor generator. - var X = me.x, i = me.i, t, v; - t = X[i]; t ^= (t >>> 7); v = t ^ (t << 24); - t = X[(i + 1) & 7]; v ^= t ^ (t >>> 10); - t = X[(i + 3) & 7]; v ^= t ^ (t >>> 3); - t = X[(i + 4) & 7]; v ^= t ^ (t << 7); - t = X[(i + 7) & 7]; t = t ^ (t << 13); v ^= t ^ (t << 9); - X[i] = v; - me.i = (i + 1) & 7; - return v; - }; - - function init(me, seed) { - var j, w, X = []; - - if (seed === (seed | 0)) { - // Seed state array using a 32-bit integer. - w = X[0] = seed; - } else { - // Seed state using a string. - seed = '' + seed; - for (j = 0; j < seed.length; ++j) { - X[j & 7] = (X[j & 7] << 15) ^ - (seed.charCodeAt(j) + X[(j + 1) & 7] << 13); - } - } - // Enforce an array length of 8, not all zeroes. - while (X.length < 8) X.push(0); - for (j = 0; j < 8 && X[j] === 0; ++j); - if (j == 8) w = X[7] = -1; else w = X[j]; - - me.x = X; - me.i = 0; - - // Discard an initial 256 values. - for (j = 256; j > 0; --j) { - me.next(); - } - } - - init(me, seed); - } - - function copy(f, t) { - t.x = f.x.slice(); - t.i = f.i; - return t; - } - - function impl(seed, opts) { - if (seed == null) seed = +(new Date); - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (state.x) copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.xorshift7 = impl; - } - - })( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader - ); - }); - - var xor4096 = createCommonjsModule(function (module) { - // A Javascript implementaion of Richard Brent's Xorgens xor4096 algorithm. - // - // This fast non-cryptographic random number generator is designed for - // use in Monte-Carlo algorithms. It combines a long-period xorshift - // generator with a Weyl generator, and it passes all common batteries - // of stasticial tests for randomness while consuming only a few nanoseconds - // for each prng generated. For background on the generator, see Brent's - // paper: "Some long-period random number generators using shifts and xors." - // http://arxiv.org/pdf/1004.3115v1.pdf - // - // Usage: - // - // var xor4096 = require('xor4096'); - // random = xor4096(1); // Seed with int32 or string. - // assert.equal(random(), 0.1520436450538547); // (0, 1) range, 53 bits. - // assert.equal(random.int32(), 1806534897); // signed int32, 32 bits. - // - // For nonzero numeric keys, this impelementation provides a sequence - // identical to that by Brent's xorgens 3 implementaion in C. This - // implementation also provides for initalizing the generator with - // string seeds, or for saving and restoring the state of the generator. - // - // On Chrome, this prng benchmarks about 2.1 times slower than - // Javascript's built-in Math.random(). - - (function(global, module, define) { - - function XorGen(seed) { - var me = this; - - // Set up generator function. - me.next = function() { - var w = me.w, - X = me.X, i = me.i, t, v; - // Update Weyl generator. - me.w = w = (w + 0x61c88647) | 0; - // Update xor generator. - v = X[(i + 34) & 127]; - t = X[i = ((i + 1) & 127)]; - v ^= v << 13; - t ^= t << 17; - v ^= v >>> 15; - t ^= t >>> 12; - // Update Xor generator array state. - v = X[i] = v ^ t; - me.i = i; - // Result is the combination. - return (v + (w ^ (w >>> 16))) | 0; - }; - - function init(me, seed) { - var t, v, i, j, w, X = [], limit = 128; - if (seed === (seed | 0)) { - // Numeric seeds initialize v, which is used to generates X. - v = seed; - seed = null; - } else { - // String seeds are mixed into v and X one character at a time. - seed = seed + '\0'; - v = 0; - limit = Math.max(limit, seed.length); - } - // Initialize circular array and weyl value. - for (i = 0, j = -32; j < limit; ++j) { - // Put the unicode characters into the array, and shuffle them. - if (seed) v ^= seed.charCodeAt((j + 32) % seed.length); - // After 32 shuffles, take v as the starting w value. - if (j === 0) w = v; - v ^= v << 10; - v ^= v >>> 15; - v ^= v << 4; - v ^= v >>> 13; - if (j >= 0) { - w = (w + 0x61c88647) | 0; // Weyl. - t = (X[j & 127] ^= (v + w)); // Combine xor and weyl to init array. - i = (0 == t) ? i + 1 : 0; // Count zeroes. - } - } - // We have detected all zeroes; make the key nonzero. - if (i >= 128) { - X[(seed && seed.length || 0) & 127] = -1; - } - // Run the generator 512 times to further mix the state before using it. - // Factoring this as a function slows the main generator, so it is just - // unrolled here. The weyl generator is not advanced while warming up. - i = 127; - for (j = 4 * 128; j > 0; --j) { - v = X[(i + 34) & 127]; - t = X[i = ((i + 1) & 127)]; - v ^= v << 13; - t ^= t << 17; - v ^= v >>> 15; - t ^= t >>> 12; - X[i] = v ^ t; - } - // Storing state as object members is faster than using closure variables. - me.w = w; - me.X = X; - me.i = i; - } - - init(me, seed); - } - - function copy(f, t) { - t.i = f.i; - t.w = f.w; - t.X = f.X.slice(); - return t; - } - function impl(seed, opts) { - if (seed == null) seed = +(new Date); - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (state.X) copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.xor4096 = impl; - } - - })( - commonjsGlobal, // window object or global - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader - ); - }); - - var tychei = createCommonjsModule(function (module) { - // A Javascript implementaion of the "Tyche-i" prng algorithm by - // Samuel Neves and Filipe Araujo. - // See https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf - - (function(global, module, define) { - - function XorGen(seed) { - var me = this, strseed = ''; - - // Set up generator function. - me.next = function() { - var b = me.b, c = me.c, d = me.d, a = me.a; - b = (b << 25) ^ (b >>> 7) ^ c; - c = (c - d) | 0; - d = (d << 24) ^ (d >>> 8) ^ a; - a = (a - b) | 0; - me.b = b = (b << 20) ^ (b >>> 12) ^ c; - me.c = c = (c - d) | 0; - me.d = (d << 16) ^ (c >>> 16) ^ a; - return me.a = (a - b) | 0; - }; - - /* The following is non-inverted tyche, which has better internal - * bit diffusion, but which is about 25% slower than tyche-i in JS. - me.next = function() { - var a = me.a, b = me.b, c = me.c, d = me.d; - a = (me.a + me.b | 0) >>> 0; - d = me.d ^ a; d = d << 16 ^ d >>> 16; - c = me.c + d | 0; - b = me.b ^ c; b = b << 12 ^ d >>> 20; - me.a = a = a + b | 0; - d = d ^ a; me.d = d = d << 8 ^ d >>> 24; - me.c = c = c + d | 0; - b = b ^ c; - return me.b = (b << 7 ^ b >>> 25); - } - */ - - me.a = 0; - me.b = 0; - me.c = 2654435769 | 0; - me.d = 1367130551; - - if (seed === Math.floor(seed)) { - // Integer seed. - me.a = (seed / 0x100000000) | 0; - me.b = seed | 0; - } else { - // String seed. - strseed += seed; - } - - // Mix in string seed, then discard an initial batch of 64 values. - for (var k = 0; k < strseed.length + 20; k++) { - me.b ^= strseed.charCodeAt(k) | 0; - me.next(); - } - } - - function copy(f, t) { - t.a = f.a; - t.b = f.b; - t.c = f.c; - t.d = f.d; - return t; - } - function impl(seed, opts) { - var xg = new XorGen(seed), - state = opts && opts.state, - prng = function() { return (xg.next() >>> 0) / 0x100000000; }; - prng.double = function() { - do { - var top = xg.next() >>> 11, - bot = (xg.next() >>> 0) / 0x100000000, - result = (top + bot) / (1 << 21); - } while (result === 0); - return result; - }; - prng.int32 = xg.next; - prng.quick = prng; - if (state) { - if (typeof(state) == 'object') copy(state, xg); - prng.state = function() { return copy(xg, {}); }; - } - return prng; - } - - if (module && module.exports) { - module.exports = impl; - } else if (define && define.amd) { - define(function() { return impl; }); - } else { - this.tychei = impl; - } - - })( - commonjsGlobal, - ('object') == 'object' && module, // present in node.js - (typeof undefined) == 'function' && undefined // present with an AMD loader - ); - }); - - var require$$2 = {}; - - var seedrandom$1 = createCommonjsModule(function (module) { - /* - Copyright 2019 David Bau. - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - */ - - (function (global, pool, math) { - // - // The following constants are related to IEEE 754 limits. - // - - var width = 256, // each RC4 output is 0 <= x < 256 - chunks = 6, // at least six RC4 outputs for each double - digits = 52, // there are 52 significant digits in a double - rngname = 'random', // rngname: name for Math.random and Math.seedrandom - startdenom = math.pow(width, chunks), - significance = math.pow(2, digits), - overflow = significance * 2, - mask = width - 1, - nodecrypto; // node.js crypto module, initialized at the bottom. - - // - // seedrandom() - // This is the seedrandom function described above. - // - function seedrandom(seed, options, callback) { - var key = []; - options = (options == true) ? { entropy: true } : (options || {}); - - // Flatten the seed string or build one from local entropy if needed. - var shortseed = mixkey(flatten( - options.entropy ? [seed, tostring(pool)] : - (seed == null) ? autoseed() : seed, 3), key); - - // Use the seed to initialize an ARC4 generator. - var arc4 = new ARC4(key); - - // This function returns a random double in [0, 1) that contains - // randomness in every bit of the mantissa of the IEEE 754 value. - var prng = function() { - var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48 - d = startdenom, // and denominator d = 2 ^ 48. - x = 0; // and no 'extra last byte'. - while (n < significance) { // Fill up all significant digits by - n = (n + x) * width; // shifting numerator and - d *= width; // denominator and generating a - x = arc4.g(1); // new least-significant-byte. - } - while (n >= overflow) { // To avoid rounding up, before adding - n /= 2; // last byte, shift everything - d /= 2; // right using integer math until - x >>>= 1; // we have exactly the desired bits. - } - return (n + x) / d; // Form the number within [0, 1). - }; - - prng.int32 = function() { return arc4.g(4) | 0; }; - prng.quick = function() { return arc4.g(4) / 0x100000000; }; - prng.double = prng; - - // Mix the randomness into accumulated entropy. - mixkey(tostring(arc4.S), pool); - - // Calling convention: what to return as a function of prng, seed, is_math. - return (options.pass || callback || - function(prng, seed, is_math_call, state) { - if (state) { - // Load the arc4 state from the given state if it has an S array. - if (state.S) { copy(state, arc4); } - // Only provide the .state method if requested via options.state. - prng.state = function() { return copy(arc4, {}); }; - } - - // If called as a method of Math (Math.seedrandom()), mutate - // Math.random because that is how seedrandom.js has worked since v1.0. - if (is_math_call) { math[rngname] = prng; return seed; } - - // Otherwise, it is a newer calling convention, so return the - // prng directly. - else return prng; - })( - prng, - shortseed, - 'global' in options ? options.global : (this == math), - options.state); - } - - // - // ARC4 - // - // An ARC4 implementation. The constructor takes a key in the form of - // an array of at most (width) integers that should be 0 <= x < (width). - // - // The g(count) method returns a pseudorandom integer that concatenates - // the next (count) outputs from ARC4. Its return value is a number x - // that is in the range 0 <= x < (width ^ count). - // - function ARC4(key) { - var t, keylen = key.length, - me = this, i = 0, j = me.i = me.j = 0, s = me.S = []; - - // The empty key [] is treated as [0]. - if (!keylen) { key = [keylen++]; } - - // Set up S using the standard key scheduling algorithm. - while (i < width) { - s[i] = i++; - } - for (i = 0; i < width; i++) { - s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))]; - s[j] = t; - } - - // The "g" method returns the next (count) outputs as one number. - (me.g = function(count) { - // Using instance members instead of closure state nearly doubles speed. - var t, r = 0, - i = me.i, j = me.j, s = me.S; - while (count--) { - t = s[i = mask & (i + 1)]; - r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))]; - } - me.i = i; me.j = j; - return r; - // For robust unpredictability, the function call below automatically - // discards an initial batch of values. This is called RC4-drop[256]. - // See http://google.com/search?q=rsa+fluhrer+response&btnI - })(width); - } - - // - // copy() - // Copies internal state of ARC4 to or from a plain object. - // - function copy(f, t) { - t.i = f.i; - t.j = f.j; - t.S = f.S.slice(); - return t; - } - // - // flatten() - // Converts an object tree to nested arrays of strings. - // - function flatten(obj, depth) { - var result = [], typ = (typeof obj), prop; - if (depth && typ == 'object') { - for (prop in obj) { - try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {} - } - } - return (result.length ? result : typ == 'string' ? obj : obj + '\0'); - } - - // - // mixkey() - // Mixes a string seed into a key that is an array of integers, and - // returns a shortened string seed that is equivalent to the result key. - // - function mixkey(seed, key) { - var stringseed = seed + '', smear, j = 0; - while (j < stringseed.length) { - key[mask & j] = - mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++)); - } - return tostring(key); - } - - // - // autoseed() - // Returns an object for autoseeding, using window.crypto and Node crypto - // module if available. - // - function autoseed() { - try { - var out; - if (nodecrypto && (out = nodecrypto.randomBytes)) { - // The use of 'out' to remember randomBytes makes tight minified code. - out = out(width); - } else { - out = new Uint8Array(width); - (global.crypto || global.msCrypto).getRandomValues(out); - } - return tostring(out); - } catch (e) { - var browser = global.navigator, - plugins = browser && browser.plugins; - return [+new Date, global, plugins, global.screen, tostring(pool)]; - } - } - - // - // tostring() - // Converts an array of charcodes to a string - // - function tostring(a) { - return String.fromCharCode.apply(0, a); - } - - // - // When seedrandom.js is loaded, we immediately mix a few bits - // from the built-in RNG into the entropy pool. Because we do - // not want to interfere with deterministic PRNG state later, - // seedrandom will not call math.random on its own again after - // initialization. - // - mixkey(math.random(), pool); - - // - // Nodejs and AMD support: export the implementation as a module using - // either convention. - // - if (('object') == 'object' && module.exports) { - module.exports = seedrandom; - // When in node.js, try using crypto package for autoseeding. - try { - nodecrypto = require$$2; - } catch (ex) {} - } else if ((typeof undefined) == 'function' && undefined.amd) { - undefined(function() { return seedrandom; }); - } else { - // When included as a plain script, set up Math.seedrandom global. - math['seed' + rngname] = seedrandom; - } - - - // End anonymous scope, and pass initial values. - })( - // global: `self` in browsers (including strict mode and web workers), - // otherwise `this` in Node and other environments - (typeof self !== 'undefined') ? self : commonjsGlobal, - [], // pool: entropy pool starts empty - Math // math: package containing random, pow, and seedrandom - ); - }); - - // A library of seedable RNGs implemented in Javascript. - // - // Usage: - // - // var seedrandom = require('seedrandom'); - // var random = seedrandom(1); // or any seed. - // var x = random(); // 0 <= x < 1. Every bit is random. - // var x = random.quick(); // 0 <= x < 1. 32 bits of randomness. - - // alea, a 53-bit multiply-with-carry generator by Johannes Baagøe. - // Period: ~2^116 - // Reported to pass all BigCrush tests. - - - // xor128, a pure xor-shift generator by George Marsaglia. - // Period: 2^128-1. - // Reported to fail: MatrixRank and LinearComp. - - - // xorwow, George Marsaglia's 160-bit xor-shift combined plus weyl. - // Period: 2^192-2^32 - // Reported to fail: CollisionOver, SimpPoker, and LinearComp. - - - // xorshift7, by François Panneton and Pierre L'ecuyer, takes - // a different approach: it adds robustness by allowing more shifts - // than Marsaglia's original three. It is a 7-shift generator - // with 256 bits, that passes BigCrush with no systmatic failures. - // Period 2^256-1. - // No systematic BigCrush failures reported. - - - // xor4096, by Richard Brent, is a 4096-bit xor-shift with a - // very long period that also adds a Weyl generator. It also passes - // BigCrush with no systematic failures. Its long period may - // be useful if you have many generators and need to avoid - // collisions. - // Period: 2^4128-2^32. - // No systematic BigCrush failures reported. - - - // Tyche-i, by Samuel Neves and Filipe Araujo, is a bit-shifting random - // number generator derived from ChaCha, a modern stream cipher. - // https://eden.dei.uc.pt/~sneves/pubs/2011-snfa2.pdf - // Period: ~2^127 - // No systematic BigCrush failures reported. - - - // The original ARC4-based prng included in this library. - // Period: ~2^1600 - - - seedrandom$1.alea = alea; - seedrandom$1.xor128 = xor128; - seedrandom$1.xorwow = xorwow; - seedrandom$1.xorshift7 = xorshift7; - seedrandom$1.xor4096 = xor4096; - seedrandom$1.tychei = tychei; - - var seedrandom$2 = seedrandom$1; - - //import { substitute_abs } from '../normalization/standard_form'; - - function randomComplexBindings(rng, variables, radius, centers) { - var result = {}; - - if (centers === undefined) { - variables.forEach(function (v) { - result[v] = math$19.complex(rng() * 2 * radius - radius, - rng() * 2 * radius - radius); - }); - } - else { - variables.forEach(function (v) { - result[v] = math$19.complex( - centers[v].re + rng() * 2 * radius - radius, - centers[v].im + rng() * 2 * radius - radius); - }); - } - - return result; - } - - const equals$1 = function (expr, other, - { relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - } = {}) { - - let rng = seedrandom$2('complex_seed'); - - //expr = expr.substitute_abs(); - //other = other.substitute_abs(); - - // don't use complex equality if not analytic expression - // except abs is OK - if ((!expr.isAnalytic({ allow_abs: true, allow_relation: true })) || - (!other.isAnalytic({ allow_abs: true, allow_relation: true }))) - return false; - - return equals({ - expr: expr, - other: other, - randomBindings: randomComplexBindings, - expr_context: expr.context, - other_context: other.context, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers, - include_error_in_number_exponents, - allowed_error_is_absolute, - rng - }); - }; - - function randomRealBindings(rng, variables, radius, centers) { - var result = {}; - - if (centers === undefined) { - variables.forEach(function (v) { - result[v] = rng() * 2 * radius - radius; - }); - } - else { - variables.forEach(function (v) { - result[v] = centers[v] + rng() * 2 * radius - radius; - }); - } - - return result; - } - - const equals$2 = function (expr, other, - { relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - } = {}) { - - // don't use real equality if not analytic expression - if ((!expr.isAnalytic()) || (!other.isAnalytic())) - return false; - - let rng = seedrandom('real_seed'); - - return equals({ - expr: expr, - other: other, - randomBindings: randomRealBindings, - expr_context: expr.context, - other_content: other.context, - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers, - include_error_in_number_exponents, - allowed_error_is_absolute, - rng - }); - }; - - const equals$3 = function (expr, other, { - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - } = {}) { - return equal$2(expr.tree, other.tree, { - allowed_error_in_numbers: allowed_error_in_numbers, - include_error_in_number_exponents: include_error_in_number_exponents, - allowed_error_is_absolute: allowed_error_is_absolute, - }); - }; - - const equals$$1 = function(expr, other, { min_elements_match=3, match_partial = false } = {} ) { - - // expr must be a discrete infinite set - if(!is_discrete_infinite_set(expr)) - return false; - - // other must be a discrete infinite set or a list - if(is_discrete_infinite_set(other)) { - var assumptions = []; - let a = expr.context.get_assumptions(expr); - if(a !== undefined) - assumptions.push(a); - a = other.context.get_assumptions(other); - if(a !== undefined) - assumptions.push(a); - if(assumptions.length === 0) - assumptions = undefined; - else if(assumptions.length === 1) - assumptions=assumptions[0]; - else - assumptions = clean_assumptions(['and'].concat(assumptions)); - - if(match_partial) { - let match1 = contained_in(expr.tree, other.tree, assumptions, match_partial); - if(match1 === false) { - return 0; - } - let match2 = contained_in(other.tree, expr.tree, assumptions, match_partial); - if(match2 === false) { - return 0; - } - - if(match1 === true) { - if(match2 === true) { - return 1; - } else { - return match2; - } - } else if(match2 === true) { - return match1; - } else { - return Math.min(match1, match2); - } - - } else { - return contained_in(expr.tree, other.tree, assumptions, match_partial) && - contained_in(other.tree, expr.tree, assumptions, match_partial); - } - } - else { - // check if other is a list than ends in 'ldots' - let other_tree = other.tree; - - if(other_tree[0] !== 'list') - return false; - - let n_in_list = other_tree.length-2; - - if(other_tree[n_in_list+1][0] !== 'ldots') - return false; - - if(n_in_list < min_elements_match) - return false; - - let the_list = other_tree.slice(0,n_in_list+1); - - // get list of same size from - let generated_list = sequence_from_discrete_infinite(expr, n_in_list); - - if(!generated_list) - return false; - - generated_list = ['list'].concat(generated_list); - - return equals$5(expr.context.from(generated_list), other.context.from(the_list)); - - } - - }; - - - function is_discrete_infinite_set(expr) { - - var tree = expr.tree; - if(!Array.isArray(tree)) - return false; - if(tree[0] !== 'discrete_infinite_set') - return false; - var operands = tree.slice(1); - - for(var v of operands) { - if(!Array.isArray(v)) - return false; - if(v[0] !== 'tuple') - return false; - if(v.length !== 5) - return false; - } - - return true; - } - - - function contained_in(tree, i_set, assumptions, match_partial) { - // true if tree is contained in the discrete infinite set i_set - // tree is either a discrete infinite set - // or a tuple of form [offset, period, min_index, max_index] - - if(tree[0] === 'discrete_infinite_set') { - if(match_partial) { - let num_matches = 0; - for(let piece of tree.slice(1)){ - let match = contained_in(piece, i_set, assumptions, match_partial); - if(match === true) { - num_matches++; - } else if(match !== false) { - num_matches += match; - } - } - - let num_pieces = tree.length - 1; - - if(num_matches === num_pieces) { - return true; - }else if(num_matches === 0) { - return false; - }else { - return num_matches/num_pieces; - } - } else { - return tree.slice(1).every(v => contained_in(v, i_set, assumptions)); - } - } - - // tree is a tuple of the form [offset, period, min_index, max_index] - - var offset0 = tree[1]; - var period0 = tree[2]; - var min_index = tree[3]; - var max_index = tree[4]; - - // implemented only if min_index === -infinity and max_index === infinity - if(!Array.isArray(min_index) || min_index[0] !== '-' || min_index[1] !== Infinity - || max_index !== Infinity) - return false; - - // normalize to period 1 - offset0 = simplify$2( - ['/', offset0, period0], assumptions, Infinity); - - // if(!(typeof offset0 === 'number')) - // return false; - - var tuples = i_set.slice(1); - - // data will be array of form [p, q, offset, period] - // where offset and period are normalized by period0 - // and p/q is fraction form of period - - var data = []; - for(let i=0; i v[0]))]; - - let max_fraction_covered = 0; - - for(let base_p of all_ps) { - // find all ps where base_p is a multiple - let options = data.map(function (v,i) { - let m = base_p/v[0]; - if(Number.isInteger(m)) - return [v[0], m, i]; - else - return undefined; - }).filter(v=>v); - - let covered = []; - - for(let opt of options) { - let p = opt[0]; - let m = opt[1]; - let i = opt[2]; - let offset = data[i][2]; - let period = data[i][3]; - - - for(let j=0; j < p; j++) { - - let offset_diff = simplify$2( - expand( - ['+', offset, ['-', ['+', offset0, j]]]), - assumptions, Infinity); - - // use math.mod rather than % so it always non-negative - if(Number.isFinite(offset_diff) && Number.isFinite(period)) { - offset_diff = math$19.mod(offset_diff, period); - - if(math$19.min(offset_diff, period-offset_diff) < 1E-10*period) { - - for(let k=0; k max_fraction_covered) { - max_fraction_covered = fraction_covered; - } - } - } - - if(match_partial && max_fraction_covered > 0) { - return max_fraction_covered; - } - - return false; - - } - - - function sequence_from_discrete_infinite(expr, n_elements) { - - // assuming without checking that expr is discrete infinite set - - var tree = expr.tree; - var operands = tree.slice(1); - - // implemented only if have just one tuple defining set - if(operands.length > 1) - return; - - let offset = operands[0][1]; - let period = operands[0][2]; - let min_index = evaluate_numbers(operands[0][3]); - let max_index = operands[0][4]; - - // implemented only if min_index is defined and an integer and max_index is infinity - if(!Number.isInteger(min_index) || max_index !== Infinity) - return; - - let result = []; - - for(let i=0; i < n_elements; i++) { - result.push(evaluate_numbers(['+', ['*', period, min_index+i], offset])); - } - - return result; - } - - //exports.equalsViaFiniteField = equalsViaFiniteField; - - const equals$5 = function (expr, other, { - relative_tolerance = 1E-12, absolute_tolerance = 0, tolerance_for_zero = 1E-15, - allowed_error_in_numbers = 0, - include_error_in_number_exponents = false, - allowed_error_is_absolute = false, - } = {}) { - if (expr.variables().includes('\uFF3F') || other.variables().includes('\uFF3F')) { - return false; - } - - // first check with symbolic equality - // converting all numbers and numerical quantities to floating point - // and normalizing form of each expression - let exprNormalized = expr.evaluate_numbers({ max_digits: Infinity }) - .normalize_function_names() - .normalize_applied_functions() - .simplify(); - let otherNormalized = other.evaluate_numbers({ max_digits: Infinity }) - .normalize_function_names() - .normalize_applied_functions() - .simplify(); - - if (exprNormalized.equalsViaSyntax(otherNormalized, { - allowed_error_in_numbers, - include_error_in_number_exponents, - allowed_error_is_absolute, - }) - ) { - return true; - } else if (expr.equalsViaComplex(other, { - relative_tolerance, absolute_tolerance, tolerance_for_zero, - allowed_error_in_numbers, - include_error_in_number_exponents, - allowed_error_is_absolute, - })) { - return true; - // } else if (expr.equalsViaReal(other)) { - // return true; - } else if (equals$$1(expr, other)) { - return true; - } else { - return false; - } - }; - - var equality = /*#__PURE__*/Object.freeze({ - equals: equals$5, - equalsViaComplex: equals$1, - equalsViaReal: equals$2, - equalsViaSyntax: equals$3, - equalsDiscreteInfinite: equals$$1 - }); - - const equalWithSignErrors = function (expr, other, - { equalityFunction = equals$5, max_sign_errors = 1 } = {} - ) { - - if (equalityFunction(expr, other)) { - return { matched: true, n_sign_errors: 0 }; - } - - for (let i = 1; i <= max_sign_errors; i++) { - if (equalSpecifiedSignErrors(expr, other, { equalityFunction, n_sign_errors: i })) { - return { matched: true, n_sign_errors: i }; - } - } - - return { matched: false }; - }; - - const equalSpecifiedSignErrors = function (expr, other, - { equalityFunction = equals$5, n_sign_errors = 1 } = {} - ) { - - if (n_sign_errors === 0) { - return equalityFunction(expr, other); - } else if (!(Number.isInteger(n_sign_errors) && n_sign_errors > 0)) { - throw Error(`Have not implemented equality check with ${n_sign_errors} sign errors.`) - } - - if (n_sign_errors > 1) { - let oldEqualityFunction = equalityFunction; - equalityFunction = function (expr, other) { - return equalSpecifiedSignErrors(expr, other, { equalityFunction: oldEqualityFunction, n_sign_errors: n_sign_errors - 1}); - }; - } - - var root = expr.tree; - var stack = [[root]]; - var pointer = 0; - var tree; - var i; - - /* Unfortunately the root is handled separately */ - expr.tree = ['-', root]; - var equals$$2 = equalityFunction(expr, other); - expr.tree = root; - - if (equals$$2) return true; - - while (tree = stack[pointer++]) { - tree = tree[0]; - - if (!Array.isArray(tree)) { - continue; - } - - for (i = 1; i < tree.length; i++) { - stack.push([tree[i]]); - tree[i] = ['-', tree[i]]; - equals$$2 = equalityFunction(expr, other); - tree[i] = tree[i][1]; - - if (equals$$2) return true; - } - } - - return false; - }; - - var sign_error = /*#__PURE__*/Object.freeze({ - equalSpecifiedSignErrors: equalSpecifiedSignErrors, - equalWithSignErrors: equalWithSignErrors - }); - - function add$2(expr_or_tree1, expr_or_tree2) { - var result = ['+', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; - return clean(result); - } - - function subtract$2(expr_or_tree1, expr_or_tree2) { - var result = ['+', get_tree(expr_or_tree1), ['-', get_tree(expr_or_tree2)]]; - return clean(result); - } - - function multiply$2(expr_or_tree1, expr_or_tree2) { - var result = ['*', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; - return clean(result); - } - - function divide$2(expr_or_tree1, expr_or_tree2) { - var result = ['/', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; - return clean(result); - } - - function pow$2(expr_or_tree1, expr_or_tree2) { - var result = ['^', get_tree(expr_or_tree1), get_tree(expr_or_tree2)]; - return clean(result); - } - - function mod$2(expr_or_tree1, expr_or_tree2) { - var result = ['apply', 'mod', ['tuple', get_tree(expr_or_tree1), - get_tree(expr_or_tree2)]]; - return clean(result); - } - - function copy(expr_or_tree) { - return get_tree(expr_or_tree); - } - - var arithmetic$1 = /*#__PURE__*/Object.freeze({ - add: add$2, - subtract: subtract$2, - multiply: multiply$2, - divide: divide$2, - pow: pow$2, - mod: mod$2, - copy: copy - }); - - var analytic_operators = ['+', '-', '*', '/', '^', 'tuple', 'vector', 'list', 'array', 'matrix', 'interval']; - var analytic_functions = ["exp", "log", "log10", "sqrt", "factorial", "gamma", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec']; - var relation_operators = ['=', 'le', 'ge', '<', '>']; - - function isAnalytic(expr_or_tree, { allow_abs = false, allow_relation = false } = {}) { - - var tree = normalize_applied_functions( - normalize_function_names(expr_or_tree)); - - tree = subscripts_to_strings(tree); - - var operators_found = operators$1(tree); - for (let i = 0; i < operators_found.length; i++) { - let oper = operators_found[i]; - if (analytic_operators.indexOf(oper) === -1) { - if (allow_relation) { - if (relation_operators.indexOf(oper) === -1) { - return false; - } - } else { - return false; - } - } - } - - var functions_found = functions(tree); - for (let i = 0; i < functions_found.length; i++) { - let fun = functions_found[i]; - if (analytic_functions.indexOf(fun) === -1) { - if ((!allow_abs) || fun !== "abs") - return false; - } - } - - return true; - } - - var analytic = /*#__PURE__*/Object.freeze({ - isAnalytic: isAnalytic - }); - - function create_discrete_infinite_set({ - offsets, - periods, - min_index = ['-', Infinity], - max_index = Infinity, - } = {}) { - - offsets = get_tree(offsets); - periods = get_tree(periods); - min_index = get_tree(min_index); - max_index = get_tree(max_index); - - - - if(offsets === undefined || periods === undefined) - return undefined; - - let results = []; - if(offsets[0] === 'list') { - if(periods[0] === 'list') { - if(offsets.length !== periods.length || offsets.length === 1) - return undefined; - for(let i=1; i - * - * This file is part of a math-this.expressions library - * - * math-this.expressions is free software: you can redistribute - * it and/or modify it under the this.terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-this.expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - - - - class astToGuppy{ - constructor(){ - this.operators = { - "+": function(operands) { return operands.join( '+' ); }, - "-": function(operands) { return "-" + operands.join( '-' ) + ""; }, - "*": function(operands) { return operands.join( '\\cdot*' ); }, - "/": function(operands) { return astToGuppy.dfrac(operands[0], operands[1]); }, - "^": function(operands) { return astToGuppy.power(operands[0],operands[1]); }, - "sin": function(operands) { return astToGuppy.trig("sin",operands[0]); }, - "cos": function(operands) { return astToGuppy.trig("cos",operands[0]); }, - "tan": function(operands) { return astToGuppy.trig("tan",operands[0]); }, - "arcsin": function(operands) { return astToGuppy.trig("arcsin",operands[0]); }, - "arccos": function(operands) { return astToGuppy.trig("arccos",operands[0]); }, - "arctan": function(operands) { return astToGuppy.trig("arctan",operands[0]); }, - "arccsc": function(operands) { return astToGuppy.trig("arccsc",operands[0]); }, - "arcsec": function(operands) { return astToGuppy.trig("arcsec",operands[0]); }, - "arccot": function(operands) { return astToGuppy.trig("arccot",operands[0]); }, - "csc": function(operands) { return astToGuppy.trig("csc",operands[0]); }, - "sec": function(operands) { return astToGuppy.trig("sec",operands[0]); }, - "cot": function(operands) { return astToGuppy.trig("cot",operands[0]); }, - "log": function(operands) { return astToGuppy.trig("log",operands[0]); }, - "exp": function(operands) { return astToGuppy.trig("exp",operands[0]); }, - "ln": function(operands) { return astToGuppy.trig("ln",operands[0]); }, - "sqrt": function(operands) { return astToGuppy.sqrt(operands[0]); }, - "abs": function(operands) { return astToGuppy.abs(operands[0]); }, - //"factorial": function(operands) { return operands[0] + "!"; }, - }; - - } - - static dfrac(a,b) { - return '\\dfrac{}{}\\frac{}{}()/()' + a + '' + b + ''; - } - - static trig(name, parameter ) { - return '\\' + name + '\\left(\\right) ' + name + '()' + parameter + ''; - } - - static sqrt(x) { - return '\\sqrt{}sqrt()' + x + ''; - } - - static power(x,y) { - return '{}^{}()^()' + x + '' + y + ''; - } - - static abs(x) { - return '\\left|\\right|abs()' + x + ''; - } - - static paren(x) { - return '\\left(\\right)()' + x + ''; - } - - static isFunctionSymbol( symbol ){ - var functionSymbols = ['sin', 'cos', 'tan', 'csc', 'sec', 'cot', 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'log', 'ln', 'exp', 'sqrt', 'abs', 'this.factorial']; - return (functionSymbols.indexOf(symbol) !== -1); - } - - static isGreekLetterSymbol( symbol ){ - var greekSymbols = ['pi', 'theta', 'theta', 'Theta', 'alpha', 'nu', 'beta', 'xi', 'Xi', 'gamma', 'Gamma', 'delta', 'Delta', 'pi', 'Pi', 'epsilon', 'epsilon', 'rho', 'rho', 'zeta', 'sigma', 'Sigma', 'eta', 'tau', 'upsilon', 'Upsilon', 'iota', 'phi', 'phi', 'Phi', 'kappa', 'chi', 'lambda', 'Lambda', 'psi', 'Psi', 'omega', 'Omega']; - return (greekSymbols.indexOf(symbol) !== -1); - } - - factorWithParenthesesIfNegated(tree){ - var result = this.factor(tree); - - if (result.toString().match( /^-/ )) - return astToGuppy.paren( result.toString() ); - - // else - return result; - } - - - - - - /* - this.factor = - '(' this.expression ')' | - number | - variable | - function this.factor | - this.factor '^' this.factor - '-' this.factor | - nonMinusthis.factor - */ - - factor(tree) { - if (typeof tree === 'string') { - if (astToGuppy.isGreekLetterSymbol(tree)) { - return '\\' + tree + ' $' + tree + ''; - } - - return '' + tree + ''; - } - - if (typeof tree === 'number') { - return '' + tree + ''; - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === "apply") { - operator = tree[1]; - operands = tree.slice(2); - } - - // Absolute value doesn't need any special parentheses handling, but its operand is really an this.expression - if (operator === "abs") { - return this.operators[operator]( operands.map( function(v,i) { return this.expression(v); }.bind(this) )); - } else if (astToGuppy.isFunctionSymbol(operator)) { - if ((operator === 'this.factorial') && ((operands[0].toString().length === 1) || (operands[0].toString().match( /^[0-9]*$/ )))) - return this.operators[operator]( operands ); - - return this.operators[operator]( operands.map( function(v,i) { - var result = this.factor(v); - return result; - }.bind(this))); - } - - if (operator === "^") { - return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); - } - - if (operator === '~') { - return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); - } - - return astToGuppy.paren( this.expression(tree) ); - } - - - /* - this.term = - this.term '*' this.factor | - this.term nonMinusthis.factor | - this.term '/' this.factor | - this.factor - */ - - term(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.factor(tree); - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if (operator === '*') { - return this.operators[operator]( operands.map( function(v,i) { - var result = this.factorWithParenthesesIfNegated(v); - - if (result.toString().match( /^[0-9]/ ) && (i > 0)) - return ' * ' + result; - else - return result; - }.bind(this))); - } - - if (operator === '/') { - return this.operators[operator]( operands.map( function(v,i) { return this.factor(v); }.bind(this) ) ); - } - - return this.factor(tree); - } - - /* - this.expression = - this.expression '+' this.term | - this.expression '-' this.term | - this.term - */ - - expression(tree) { - if ((typeof tree === 'string') || (typeof tree === 'number')) { - return this.term(tree); - } - - var operator = tree[0]; - var operands = tree.slice(1); - - if ((operator === '+') || (operator === '-')) { - return this.operators[operator]( operands.map( function(v,i) { return this.factorWithParenthesesIfNegated(v); }.bind(this) )); - } - - return this.term(tree); - } - - - convert(tree){ - return ('' + this.expression(tree) + '').replace(/<\/e>/g,''); - } - - } - - /* - * convert syntax trees to GLSL representations - * - * Copyright 2014-2018 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - - const glslOperators = { - "+": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = result + "+" + rhs; }); return result; }, - "-": function(operands) { var result = "-" + operands[0]; operands.slice(1).forEach(function(rhs) { result = result + "-" + rhs; }); return result; }, - "~": function(operands) { var result = "vec2(0.0,0.0)"; operands.forEach(function(rhs) { result = result + "-" + rhs; }); return result; }, - "*": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = "cmul(" + result + "," + rhs + ")"; }); return result; }, - "/": function(operands) { var result = operands[0]; operands.slice(1).forEach(function(rhs) { result = "cdiv(" + result + "," + rhs + ")"; }); return result; }, - - "sin": function(operands) { return "csin(" + operands[0] + ")"; }, - "cos": function(operands) { return "ccos(" + operands[0] + ")"; }, - "tan": function(operands) { return "ctan(" + operands[0] + ")"; }, - - "sinh": function(operands) { return "csinh(" + operands[0] + ")"; }, - "cosh": function(operands) { return "ccosh(" + operands[0] + ")"; }, - - "arcsin": function(operands) { return "carcsin(" + operands[0] + ")"; }, - "arccos": function(operands) { return "carccos(" + operands[0] + ")"; }, - "arctan": function(operands) { return "carctan(" + operands[0] + ")"; }, - - "arccsc": function(operands) { return "carcsin(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, - "arcsec": function(operands) { return "carccos(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, - "arccot": function(operands) { return "carctan(cdiv(vec2(1.0,0)," + operands[0] + "))"; }, - - "csc": function(operands) { return "ccsc(" + operands[0] + ")"; }, - "sec": function(operands) { return "csec(" + operands[0] + ")"; }, - "cot": function(operands) { return "ccot(" + operands[0] + ")"; }, - - "exp": function(operands) { return "cexp(" + operands[0] + ")"; }, - - "conj": function(operands) { return "conjugate(" + operands[0] + ")"; }, - - "sqrt": function(operands) { return "cpower(" + operands[0] + ",vec2(0.5,0.0))"; }, - "log": function(operands) { return "clog(" + operands[0] + ")"; }, - "ln": function(operands) { return "clog(" + operands[0] + ")"; }, - "^": function(operands) { return "cpower(" + operands[0] + "," + operands[1] + ")"; }, - - "abs": function(operands) { return "cabs(" + operands[0] + ")"; }, - "apply": function(operands) { return "vec2(NaN,NaN)"; }, - }; - - class astToGLSL { - constructor() { - } - - convert(tree) { - if (typeof tree === 'boolean') - throw Error("no support for boolean"); - - - if (typeof tree === 'string') { - if (tree === "e") - return "vec2(2.71828182845905,0.0)"; - - if (tree === "pi") - return "vec2(3.14159265358979,0.0)"; - - if (tree === "i") - return "vec2(0.0,1.0)"; - - return String(tree); - } - - if (typeof tree === 'number') { - return "vec2(" + String(tree) + ",0.0)"; - } - - if (("real" in tree) && ("imaginary" in tree)) - return tree; - - if (!Array.isArray(tree)) { - throw Error("Invalid ast"); - } - - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === "apply") { - if(typeof operands[0] !== 'string') - throw Error("Non string functions not implemented for conversion to GLSL"); - - var operator = operands[0]; - var operands = operands.slice(1); - - return glslOperators[operator]( operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); - } - - if (operator in glslOperators) { - return glslOperators[operator]( operands.map( function(v,i) { return this.convert(v); }.bind(this) ) ); - } - - throw Error("Operator " + operator + " not implemented for conversion to mathjs"); - } - } - - var astToLatex$2 = new astToLatex(); - var astToText$2 = new astToText(); - var astToGuppy$1 = new astToGuppy(); - var astToGLSL$1 = new astToGLSL(); - - const tex = function(expr) { - return astToLatex$2.convert( expr.tree ); - }; - - const toLatex = tex; - - const toString = function(expr) { - return astToText$2.convert( expr.tree ); - }; - - const toGLSL = function(expr) { - return astToGLSL$1.convert( expr.tree ); - }; - - const toXML = function(expr) { - return astToGuppy$1.convert( expr.tree ); - }; - - var printing = /*#__PURE__*/Object.freeze({ - tex: tex, - toLatex: toLatex, - toString: toString, - toXML: toXML, - toGLSL: toGLSL - }); - - const integrateNumerically = function(expr, x,a,b) { - var intervals = 100; - var total = 0.0; - var bindings = {}; - - for( var i=0; i < intervals; i++ ) { - var sample_point = a + ((b - a) * (i + 0.5) / intervals); - bindings[x] = sample_point; - total = total + expr.evaluate( bindings ); - } - - return total * (b - a) / intervals; - }; - - var integration = /*#__PURE__*/Object.freeze({ - integrateNumerically: integrateNumerically - }); - - function expression_to_polynomial(expr_or_tree) { - - var tree = get_tree(expr_or_tree); - - if(typeof tree === 'string') { - if((tree === 'pi' && math$19.define_pi) - || (tree === 'i' && math$19.define_i) - || (tree === 'e' && math$19.define_e)) - return tree; // treat as number - else - return ['polynomial', tree, [[1, 1]]]; // treat a polynomial variable - } - - if(typeof tree === 'number') - return tree; - - let c = evaluate_to_constant(tree); - if(c !== null && Number.isFinite(c)) { - return simplify$2(tree); - } - - if(!Array.isArray(tree)) - return false; - - // if contains invalid operators, it's not a polynomial - if(!operators$1(tree).every( - v => ['+', '-', '*', '^', '/', '_', 'prime'].includes(v))) - return false; - - var operator = tree[0]; - var operands = tree.slice(1); - - if(operator === '+') { - let result = operands.map(expression_to_polynomial); - - // return false if any operand returned false - if(!result.every(v => v !== false)) - return false; - - return result.reduce((u,v) => polynomial_add(u,v)); - } - else if(operator === '-') { - let result = expression_to_polynomial(operands[0]); - - if(!result) - return false; - - return polynomial_neg(result); - } - else if(operator === '*') { - let result = operands.map(expression_to_polynomial); - - // return false if any operand returned false - if(!result.every(v => v !== false )) - return false; - - return result.reduce((u,v) => polynomial_mul(u,v)); - } - else if(operator === '^') { - - let base = operands[0]; - let subresult = expression_to_polynomial(base); - - // if subresult itself is false, then don't have a polynomial - if(subresult === false) - return false; - - let pow = simplify$2(operands[1]); - - // if pow isn't a literal nonnegative integer - if((typeof pow !== 'number') || pow < 0 || !Number.isInteger(pow)) { - - let pow_num = evaluate_to_constant(pow); - - // check if pow is a rational number with a small base - if(pow_num !== null || Number.isFinite(pow_num)) { - let pow_fraction = math$19.fraction(pow_num); - if(pow_fraction.d <= 100) { - if(pow_fraction.s < 0) - base = ['^', base, ['/', -1, pow_fraction.d]]; - else - base = ['^', base, ['/', 1, pow_fraction.d]]; - - var results = ['polynomial', simplify$2(base), []]; - - results[2].push([pow_fraction.n, 1]); - - return results; - - } - } - - // just return entire tree as a polynomial variable - return ["polynomial", tree, [[1,1]]]; - } - - if(pow===0) { - return 1; - } - if(pow===1) { - return subresult; - } - - return polynomial_pow(subresult, pow); - - } - else if(operator === '/') { - var denom = operands[1]; - - var denom_num = evaluate_to_constant(denom); - - if(denom_num === null || !Number.isFinite(denom_num)) { - // return entire tree as polynomial variable - return ['polynomial', tree, [[1, 1]]]; - } - - var numer_result = expression_to_polynomial(operands[0]); - - return polynomial_mul(numer_result, ['/', 1, denom_num]); - } - - - else { - // return entire tree as polynomial variable - return ['polynomial', tree, [[1, 1]]]; - } - - - } - - - function polynomials_in_same_leading_variable(p,q) { - // If both polynomials have same leading variable, return unchanged. - // Else, rewrite the polymomial whose leading variable comes later - // as a polynomial that is constant in leading variable of other - - if(p[1] !== q[1]) { - if(compare_function(p[1], q[1]) < 0) { - // variable p[1] is earlier in default order - // so write q as a polynomial constant in p[1] - q = ["polynomial", p[1], [[0, q]]]; - } - else { - // variable q[1] is earlier in default order - // so write p as a polynomial constant in q[1] - p = ["polynomial", q[1], [[0, p]]]; - } - } - - return [p, q]; - } - - - function polynomial_add(p,q) { //being called on empty polynomials - - if(p[0] !== "polynomial") { - if(q[0] !== "polynomial") - return simplify$2(['+', p, q]); - else { - // write p as a constant polynomial in q's first variable - p = ["polynomial", q[1], [[0, p]]]; - } - } - else { - if (q[0] !== "polynomial") { - // write q as a constant polynomial in p's first variable - q = ["polynomial", p[1], [[0, q]]]; - } - else { - // if needed, rewrite polynomials so have same first variable - let tmp = polynomials_in_same_leading_variable(p,q); - p = tmp[0]; - q = tmp[1]; - } - } - - // at this point, both q and p are polynomials with same first variable - - let sum = ["polynomial", p[1], []]; - - let p_terms = p[2]; - let q_terms = q[2]; - let sum_terms = sum[2]; - - let len_p = p_terms.length; - let len_q = q_terms.length; - let i = 0; - let j = 0; - - while (i < len_p || j < len_q){ - if (i === len_p){ - if (q_terms[j][1]) - sum_terms.push(q_terms[j]); - j = j+1; - } - else if (j === len_q){ - if (p_terms[i][1]) - sum_terms.push(p_terms[i]); - i = i+1; - } - else if (p_terms[i][0] === q_terms[j][0]){ - let temp = polynomial_add(p_terms[i][1], q_terms[j][1]); - if(temp) - sum_terms.push([p_terms[i][0], temp]); - i = i+1; - j = j+1; - } - else if (p_terms[i][0] < q_terms[j][0]){ - if (p_terms[i][1]) - sum_terms.push(p_terms[i]); - i = i+1; - } - else{ - if (q_terms[j][1]) - sum_terms.push(q_terms[j]); - j = j+1; - } - } - - // all terms canceled - if(sum_terms.length === 0) - return 0; - - // only a term that is constant in leading variable is left - if(sum_terms.length === 1 && (sum_terms[0][0] === 0)) - return sum_terms[0][1]; - - return sum; - - } - - - function polynomial_neg(p) { - - if(p[0] !== "polynomial") { - return simplify$2(['-', p ]); - } - - let result = ["polynomial", p[1], []]; - let p_terms = p[2]; - let result_terms = result[2]; - - let len = p_terms.length; - - for (var i = 0; i < len; i = i + 1){ - result_terms.push([p_terms[i][0], polynomial_neg(p_terms[i][1])]); - } - - return result; - } - - - function polynomial_sub(p,q) { - - return polynomial_add(p, polynomial_neg(q)); - - } - - - function polynomial_mul(p,q) { - - if(p[0] !== "polynomial") { - if(q[0] !== "polynomial") { - return simplify$2(['*', p, q]); - } - else if(p) { - let prod = ["polynomial", q[1], []]; - let q_terms = q[2]; - let prod_terms = prod[2]; - for(let term of q_terms) { - if(term[1]) - prod_terms.push([term[0], polynomial_mul(p, term[1])]); - } - return prod; - } - } - else { - if (q && q[0] !== "polynomial") { - let prod = ["polynomial", p[1], []]; - let p_terms = p[2]; - let prod_terms = prod[2]; - for(let term of p_terms) { - if(term[1]) - prod_terms.push([term[0], polynomial_mul(term[1], q)]); - } - return prod; - } - } - - // two non-constant polynomials - // if needed, rewrite polynomials so have same first variable - let tmp = polynomials_in_same_leading_variable(p,q); - p = tmp[0]; - q = tmp[1]; - - let p_terms = p[2]; - let q_terms = q[2]; - - let prod = ["polynomial", p[1], []]; - let prod_terms = prod[2]; - let p_len = p_terms.length; - let q_len = q_terms.length; - - //find the degrees that will occur in the product - let degrees = []; - for (let term_p of p_terms){ - for (let term_q of q_terms){ - let found = false; - let current_deg = term_p[0] + term_q[0]; - for (let deg of degrees){ - if (current_deg === deg){ - found = true; - break; - } - } - if (!found) - degrees.push(current_deg); - } - } - - degrees.sort(function(a, b){return a - b}); - - //this is where the product is computed - for(let deg of degrees){ - let sum = 0; - let i = 0; - while (i < p_len && p_terms[i][0] <= deg){ - let j = 0; - while (j < q_len && q_terms[j][0] <= deg){ - if ((p_terms[i][0] + q_terms[j][0]) === deg){ - sum = polynomial_add(sum, polynomial_mul(p_terms[i][1], q_terms[j][1])); - break; - } - j = j+1; - } - i = i+1; - } - if(sum) - prod_terms.push([deg, sum]); - } - - return prod; - } - - - function polynomial_pow(p, e) { - - if(isNaN(e) || e < 0 || !Number.isInteger(e)) - return undefined; - - let res = 1; - - while(e > 0) { - - if(e & 1) { - // odd exponent - res = polynomial_mul(res, p); - } - - p = polynomial_mul(p, p); - - e >>= 1; // divide by 2 and truncate - - } - - return res; - } - - - function polynomial_to_expression(p) { - - if(!Array.isArray(p) || p[0] !== "polynomial") - return p; - - let x = p[1]; - let terms = p[2]; - - let result = []; - - let len_terms = terms.length; - for(var i = 0; i < len_terms; i = i+1) { - if(terms[i][1]) { - if(terms[i][0]===0) - result.push(polynomial_to_expression(terms[i][1])); - else if(terms[i][0]===1) - result.push(['*', polynomial_to_expression(terms[i][1]), x]); - else - result.push(['*', polynomial_to_expression(terms[i][1]), - ['^', x, terms[i][0]]]); - - } - } - - if(result.length === 0) - return 0; - else if(result.length === 1) - result = result[0]; - else - result.unshift('+'); - - return simplify$2(result); - } - - - function initial_term(p) { - //takes a polynomial ["polynomial", "var"...] and returns the initial term according to lexicographic order, in form ["monomial", coefficient, [[variable1, power1], ...]] - - if (!Array.isArray(p) || p[0] !== "polynomial") - return p; - - let var_powers = []; - - while( Array.isArray(p) && p[0] === "polynomial"){ - let x = p[1]; - let terms = p[2]; - let exp = (terms[terms.length-1])[0]; - p = (terms[terms.length-1])[1]; - var_powers.push([x,exp]); - } - - return ["monomial", p, var_powers]; - } - - function mono_less_than(left,right) { - //takes two monomials ["monomial", coeff, terms array] and returns true if left is less than right in lexicographic order. - //stringify vars before calling this - - if (!Array.isArray(right) || right[0] !== "monomial") - return false; //if right is constant, always false - - if (!Array.isArray(left) || left[0] !== "monomial") - return true; //if left is constant and right is not, always true - - let left_vars = left[2]; - let right_vars = right[2]; - let left_length = left_vars.length; - let right_length = right_vars.length; - var shorter; - if (left_length < right_length) - shorter = left_length; - else - shorter = right_length; - - for ( var i = 0; i < shorter; i++ ){ - if(left_vars[i][0] !== right_vars[i][0]) { - if(compare_function(left_vars[i][0], right_vars[i][0]) < 0) { - // left variable is earlier in default order - return false; - } - else { - // right variable is earlier in default order - return true; - } - } - if(left_vars[i][1] < right_vars[i][1]) { - // left power is lower - return true; - } - if(left_vars[i][1] > right_vars[i][1]) { - // right power is lower - return false; - } - } - if ( left_length === right_length || shorter === right_length ){ - // same monomial, except possibly coefficient, or same until left is longer - return false; - } - else { - // same until right is longer - return true; - } - } - - - function mono_gcd(left, right) { - //takes two monomials ["monomial", coeff, terms array] and returns their greatest common divisor as a monomial - //stringify vars before calling this - - if (!Array.isArray(left) || !Array.isArray(right) || left[0] !== "monomial" || right[0] !== "monomial") - return 1; //if either is constant, gcd is 1 - - let left_vars = left[2]; - let right_vars = right[2]; - let gcd_vars = []; - let left_length = left_vars.length; - let right_length = right_vars.length; - - let i = 0; - let j = 0; - while (i < left_length && j < right_length){ - if (left_vars[i][0] === right_vars[j][0]){ - if (left_vars[i][1] < right_vars[j][1]){ - gcd_vars.push(left_vars[i]); - } - else{ - gcd_vars.push(right_vars[j]); - } - i = i + 1; - j = j + 1; - } - else if (compare_function(left_vars[i][0], right_vars[j][0]) < 0){ - i = i + 1; - } - else if (compare_function(right_vars[j][0], left_vars[i][0]) < 0){ - j = j + 1; - } - } - - if (gcd_vars.length === 0) - return 1; //if they have no common variables, gcd is 1 - - return ["monomial", 1, gcd_vars]; - } - - function mono_div(top, bottom) { - //!!This function should only be called if bottom has coefficient 1 and divides the top (e.g., bottom was computed using mono_gcd)!! - //takes two monomials ["monomial", coeff, terms array] and returns their quotient as a monomial - //stringify vars before calling this - - if ( !Array.isArray(bottom) || bottom[0] !== "monomial"){ - //if bottom is constant - if (bottom === 1) - return top; - if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant - return evaluate_numbers(['/', top, bottom]); - else - return [top[0], evaluate_numbers(['/', top[1], bottom]), top[2]]; //shouldn't be passing constants other than 1 - } - - if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant and bottom is not - return undefined; - - let top_vars = top[2]; - let bottom_vars = bottom[2]; - let div_vars = []; - let top_length = top_vars.length; - let bottom_length = bottom_vars.length; - - let i = 0; - let j = 0; - while (i < top_length && j < bottom_length){ - if (top_vars[i][0] === bottom_vars[j][0]){ - if (top_vars[i][1] < bottom_vars[j][1]){ - return undefined; //does not divide - } - else{ - let diff = top_vars[i][1] - bottom_vars[j][1]; - if (diff !== 0) - div_vars.push( [ top_vars[i][0] , diff ] ); - } - i = i + 1; - j = j + 1; - } - else if (compare_function(top_vars[i][0], bottom_vars[j][0]) < 0){ - div_vars.push( top_vars[i] ); - i = i + 1; - } - else if (compare_function(bottom_vars[j][0], top_vars[i][0]) < 0){ - return undefined; //does not divide - } - } - - if (j < bottom_length) - return undefined; - - while (i < top_length){ - div_vars.push( top_vars[i]); - i=i+1; - } - - if (div_vars.length === 0){ - if (bottom[1] === 1) - return top[1]; //everything canceled, return coefficient of the top - else - return evaluate_numbers(['/', top[1], bottom[1]]); - } - - if (bottom[1] === 1) - return ["monomial", top[1], div_vars]; - else - return ["monomial", evaluate_numbers(['/', top[1], bottom[1]]), div_vars]; - } - - function mono_is_div(top, bottom) { - //takes two monomials ["monomial", coeff, terms array] and returns true if bottom divides top, otherwise returns false - //stringify vars before calling this - - if (bottom === 0) - return false; - - if ( !Array.isArray(bottom) || bottom[0] !== "monomial"){ //if bottom is nonzero constant - return true; - } - - if ( !Array.isArray(top) || top[0] !== "monomial") //if top is constant and bottom is not - return false; - - let top_vars = top[2]; - let bottom_vars = bottom[2]; - let div_vars = []; - let top_length = top_vars.length; - let bottom_length = bottom_vars.length; - - let i = 0; - let j = 0; - while (i < top_length && j < bottom_length){ - if (top_vars[i][0] === bottom_vars[j][0]){ - if (top_vars[i][1] < bottom_vars[j][1]){ - return false; //does not divide - } - else{ - let diff = top_vars[i][1] - bottom_vars[j][1]; - if (diff !== 0) - div_vars.push( [ top_vars[i][0] , diff ] ); - } - i = i + 1; - j = j + 1; - } - else if (compare_function(top_vars[i][0], bottom_vars[j][0]) < 0){ - div_vars.push( top_vars[i] ); - i = i + 1; - } - else if (compare_function(bottom_vars[j][0], top_vars[i][0]) < 0){ - return false; //does not divide - } - } - - if (j < bottom_length) - return false; - - return true; - } - - function mono_to_poly(mono){ - //takes a monomial ["monomial", coeff, terms array] and returns the corresponding polynomial ["polynomial", var1, ...] - - if ( !Array.isArray(mono) || mono[0] !== "monomial") - return mono; //if constant, just return itself - - let num_vars = mono[2].length; - let i = num_vars-1; - let result = mono[1]; - - while ( i >= 0){ - var coeffs = []; - coeffs.push([mono[2][i][1],result]); - result = ["polynomial", mono[2][i][0], coeffs]; - i=i-1; - } - - return result; - } - - function max_div_init(f$$1, monos){ - //f is a polynomial ["polynomial", ...], monos is array of monomials ["monomial", ...]. returns the largest term (a monomial) of f divisible by something - //in monos, and the index of the divisor. - //stringify vars before calling this - - if ( f$$1 === 0){ - return 0; - } - let focus = f$$1; - let var_powers = []; - - while( Array.isArray(focus) && focus[0] === "polynomial"){ - let x = focus[1]; - let terms = focus[2]; - let exp = terms[terms.length-1][0]; - focus = terms[terms.length-1][1]; - var_powers.push([x,exp]); - } - - let current_term = ["monomial", focus, var_powers]; - - let monos_size = monos.length; - for ( var i = 0; i < monos_size; i = i+1 ){ - if (mono_is_div(current_term, monos[i])){ - return [current_term, i]; - } - } - - return max_div_init(polynomial_sub( f$$1, mono_to_poly(current_term)), monos); - } - - function poly_div(f$$1, divs){ - //takes a polynomial f and an array of polynomials div = [g1,g2,...], and returns a standard expression (according to mult. division) of the form [[[s1,m1],[s2,m2],....], f'] where f=m1g_{s1}+m2g_{s2}+...+f' - //stringify vars before calling this - - let inits = []; - let su_mu = []; - let sp = []; - let mp = []; - let f_prime = f$$1; - - for (var g of divs){ - inits.push(initial_term(g)); - } - - let m = max_div_init(f_prime, inits); - - while (m !== 0){ - sp = m[1]; - mp = mono_div(m[0], inits[sp]); - su_mu.push([sp, mp]); - f_prime = polynomial_sub(f_prime, polynomial_mul(mono_to_poly(mp), divs[sp])); - m = max_div_init(f_prime, inits); - } - - return [su_mu, f_prime]; - } - - function prereduce(polys){ - //takes an array of polys, and does some simply reductions: gets rid of 0 polynomials, if there's a constant: just return [1], if there are no nonzero polys: return [0]. - - let len = polys.length; - let new_polys = []; - - //check for 0's, constants - for (var j = 0; j < len; j++ ){ - if (polys[j] !== 0 && (!Array.isArray(polys[j]) || polys[j][0] !== "polynomial")){ - return [1]; //if there's a nonzero constant, return [1] - } - if (polys[j] !== 0){ - new_polys.push(polys[j]); - } - } - - if (new_polys.length === 0) - return [0]; - - return new_polys; - } - - function reduce_ith(i, polys){ - //takes an index i and an array polys of polynomials, and reduces the ith polynomial wrt the rest (i.e., finds a std expression and replaces with f'). Returns the reduced polynomial. - //stringify vars before calling this - - let inits = []; - let sp = []; - let mp = []; - let f_prime = polys[i]; - let len = polys.length; - - for (var j = 0; j < len; j = j+1){ - if (j === i) //don't want to cancel out with itself, so put 0 for this initial term instead to avoid it being used - inits.push(0); - else - inits.push(initial_term(polys[j])); - } - - let m = max_div_init(f_prime, inits); - - while (m !== 0){ - sp = m[1]; - mp = mono_div(m[0], inits[sp]); - f_prime = polynomial_sub(f_prime, polynomial_mul(mono_to_poly(mp), polys[sp])); - m = max_div_init(f_prime, inits); - } - - return f_prime; - - /* OLD CODE: - - if (!Array.isArray(polys) || i >= polys.length){ - return undefined; - } - - let len = polys.length; - let new_polys = []; - - //check for 0's, constants - for (var j = 0; j < len; j++ ){ - if (polys[j] !== 0 && (!Array.isArray(polys[j]) || polys[j][0] !== "polynomial")){ - return 1; //if there's a nonzero constant, return [1] - } - if (polys[j] !== 0){ - new_polys.push(polys[j]); - } - } - - len = new_polys.length; - - if (len === 0) - return 0; //if there were no nonzero polys, return [0] - - if (len === 1) - return new_polys[0]; //if there's only one poly, don't need to reduce - - let others = []; - for ( var j = 0; j < len; j++ ){ - if (j !== i) - others.push(new_polys[j]); - } - - return poly_div(new_polys[i], others)[1];*/ - } - - function reduce$1(polys){ - //takes an array of polynomials, and reduces them with respect to each other until they can't be reduced anymore. Returns array of reduced polynomials. - //this could be made more efficient with better bookkeeping if necessary - currently copying sub-arrays a lot, whenever call reduce_ith. Would need to track changes in sub-arrays. - //stringify vars before calling this - - let i = 0; - let h=[]; - let new_polys = prereduce(polys); - let len = new_polys.length; - - if (len === 1) - return new_polys; //if there's only one poly, don't need to reduce - /*prereduce more frequently: - while (i < len){ - h = reduce_ith(i, new_polys); - if ( _.isEqual( h, new_polys[i] )){ //from underscore lib to compare arrays with objects - i=i+1; - } - else{ - new_polys[i] = h; - i = 0; - new_polys = prereduce(new_polys); - len = new_polys.length; - } - }*/ - - /* This code prereduces less frequently, maybe slightly faster?*/ - let trigger = true; - while (trigger){ - trigger = false; - new_polys = prereduce(new_polys); - len = new_polys.length; - i = 0; - while (i < len){ - h = reduce_ith(i, new_polys); - if ( !underscore.isEqual( h, new_polys[i] )){ //from underscore lib to compare arrays with objects - new_polys[i]=h; - trigger = true; - } - i = i+1; - } - } - - i = 0; - let init = []; - let coeff = 0; - while (i < len){ //leading coeffs should be 1 - init = initial_term(new_polys[i]); - if (!Array.isArray(init) || init[0] !== "monomial") - new_polys[i] = 1; - else{ - coeff = init[1]; - if (coeff !== 1) - new_polys[i] = polynomial_mul(new_polys[i], ['/', 1, coeff]); - } - i = i + 1; - } - - return new_polys; - } - - function hij(i, j, polys){ - //takes indices i,j and an array of polynomials. Returns the polynomial hij computed from the ith and jth polys in polynomials, for Buchberger's criterion. - //stringify vars before calling this - - let init_gi = initial_term(polys[i]); - let init_gj = initial_term(polys[j]); - let gcd = mono_gcd(init_gi, init_gj); - let mij = mono_to_poly(mono_div(init_gi, gcd)); - let mji = mono_to_poly(mono_div(init_gj, gcd)); - let std_exp = poly_div(polynomial_sub(polynomial_mul(mji, polys[i]), polynomial_mul(mij, polys[j])), polys); - return std_exp[1]; - } - - function build_hij_table(table, polys){ - //takes an empty table and an array of polynomials, and fills in table where table[[i,j]]=h_ij for i < j < polys.length. (Look up h_ij based on the index in polys) returns first choice for h - //stringify vars before calling this - - let len = polys.length; - let i = 0; - let j = 1; - - let candidates = []; - - while (j < len){ - while (i < j){ - table[[i,j]] = hij(i,j,polys); - if (table[[i,j]] !== 0) - candidates.push(table[[i,j]]); - i = i + 1; - } - i = 0; - j = j + 1; - } - - if (candidates.length > 0) - return choice_lowest_degree(candidates); //call different choice functions here. Could avoid iterating through again if check as go. - - return 0; - } - - function update_hij_table(table, polys, h){ - //takes an hij table, array of polynomials that the table was built for, and a poynomial h. Updates the hij values for the addition of the polynomial h, h is added with the highest index. return next choice of h. - - let len = polys.length; - polys.push(h); - let i = 0; - let j = 1; - - let candidates = []; - while (j < len){ //this loop updates old hij values. - while (i < j){ - if (table[[i,j]] !== 0){ - table[[i,j]] = hij(i,j,polys); - if (table[[i,j]] !== 0) - candidates.push(table[[i,j]]); - } - i = i + 1; - } - i = 0; - j = j+1; - } - - while (i < len){ //this loop adds values with h - table [[i,len]] = hij(i,len,polys); - if (table[[i,len]] !== 0) - candidates.push(table[[i,len]]); - i = i + 1; - } - - if (candidates.length > 0) - return choice_lowest_degree(candidates); //call different choice functions here. Could avoid iterating through again if check as go. - - return 0; - } - - function choice_lowest_degree(polys){ - //takes an array of polynomials, returns the polynomial of lowest degree. - - let inits = []; - let len = polys.length; - - for (i = 0; i < len; i = i+1){ - inits.push(initial_term(polys[i])); - } - - let min_index = 0; - for (var i = 1; i < len; i = i+1){ - if (inits[i] === 1) - return 1; - if (mono_less_than(inits[i], inits[min_index])) - min_index = i; - } - - return polys[min_index]; - } - - function reduced_grobner(polys){ - //takes an array of polynomials, returns reduced grobner basis of the ideal they generate. - //stringify vars before calling this - - let new_polys = reduce$1(polys); - - let table = {}; - let h = build_hij_table(table, new_polys); - while (h !== 0){ - h = update_hij_table(table, new_polys, h); - } - - new_polys = reduce$1(new_polys); - - return new_polys; - } - - function poly_lcm(f$$1,g){ - //takes two polynomials f and g, and returns their least common multiple. - //stringify vars before calling this - - let t = ["polynomial", "_t", [[1,1]]]; - let one_minus_t = ["polynomial", "_t", [[0,1], [1,-1]]]; - let grob = reduced_grobner([polynomial_mul(t, f$$1), polynomial_mul(one_minus_t, g)]); - - //find term without _t - let len = grob.length; - for (var i = 0; i < len; i = i + 1){ - if (!Array.isArray(grob[i]) || grob[i][0] !== "polynomial"){ - return 1; //if there is a constant in the grobner basis, return 1 (shouldn't have constants other than 1, so could probably just check for 1) - } - if (grob[i][1] !== "_t") - return grob[i]; - } - - return undefined; //this should never be reached, unless something bad happens? - } - - function poly_gcd(f$$1,g){ - //takes two polynomials f and g, and returns their greatest common divisor. - //stringify vars before calling this - - let lcm = poly_lcm(f$$1,g); - let fg = polynomial_mul(f$$1,g); - let std_exp = poly_div(fg, [lcm]); - - let sum = 0; - let len = std_exp[0].length; - for (var i = 0; i < len; i = i+1){ - sum = polynomial_add(sum, mono_to_poly(std_exp[0][i][1])); - } - - //divide by leading coeff, so leading coeff of gcd is 1 - let init = initial_term(sum); - if (!Array.isArray(init) || init[0] !== "monomial") - sum = 1; - else{ - let coeff = init[1]; - if (coeff !== 1) - sum = polynomial_mul(sum, ['/', 1, coeff]); - } - - return sum; - } - - function poly_by_divisor(f$$1, d){ - //takes two polynomials f and d (where d is a divisor of f), and returns f divided by d. - //!!Only call if d evenly divides f!! - //stringify vars before calling this - - let std_exp = poly_div(f$$1, [d]); - let sum = 0; - let len = std_exp[0].length; - for (var i = 0; i < len; i = i+1){ - sum = polynomial_add(sum, mono_to_poly(std_exp[0][i][1])); - } - return sum; - } - - function reduce_rational_expression(top, bottom){ - //input: top and bottom of a rational expression. top and bottom should be polynomials, ["polynomial", ...]. returns an array with two entries: new_top and new_bottom, which are reduced (gcd of new_top and new_bottom is 1). new_bottom will always have leading coefficient 1 (according to lexicographic order) - - let stringy_top = stringify_vars(top); - let stringy_bottom = stringify_vars(bottom); - top = stringy_top[0]; - bottom = stringy_bottom[0]; - - let gcd = poly_gcd(top, bottom); - let denom_coeff = (initial_term(bottom))[1]; - let div = polynomial_mul(gcd,denom_coeff); - let new_top = poly_by_divisor(top, div); - let new_bottom = poly_by_divisor(bottom, div); - return [destringify_vars(destringify_vars(new_top, stringy_top[1]), stringy_bottom[1]), destringify_vars(destringify_vars(new_bottom, stringy_top[1]), stringy_bottom[1])]; - } - - function stringify_vars(f$$1){ - //takes a polynomial f and converts all variables to strings. Returns the new, stringy polynomial, and a dictionary to convert back to the original degrees. - - if (!Array.isArray(f$$1) || f$$1[0] !== "polynomial") - return [f$$1, {}]; //if it's not a polynomial, don't need to change anything. - - let table = {}; - let var_string = "z" + JSON.stringify(f$$1[1]); - table[var_string] = f$$1[1]; - f$$1[1] = var_string; - - let terms = f$$1[2]; - let current = []; - for (let f_term of terms){ - current = stringify_vars(f_term[1]); - f_term[1] = current[0]; - for (let key in current[1]){ - table[key] = current[1][key]; - } - } - - return [f$$1, table]; - } - - function destringify_vars(f$$1, table){ - //takes a stringy polynomial and a dictionary {string:actual_variable,...} and returns the polynomial with strings replaced with the actual variable they represent. - - if (!Array.isArray(f$$1) || f$$1[0] !== "polynomial") - return f$$1; //it it's not a polynomial, don't need to change anything. - - if (table[f$$1[1]]) - f$$1[1] = table[f$$1[1]]; - - let terms = f$$1[2]; - for (let f_term of terms){ - f_term[1] = destringify_vars(f_term[1], table); - } - - return f$$1; - } - - var textToAst$3 = new textToAst(); - - function common_denominator(tree, assumptions) { - - tree = simplify$2(tree, assumptions); - - var transformations = []; - transformations.push( - [textToAst$3.convert("a/c+b/c"), textToAst$3.convert("(a+b)/c"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a/c-b/c"), textToAst$3.convert("(a-b)/c"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a+b/c"), textToAst$3.convert("(ac+b)/c"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a-b/c"), textToAst$3.convert("(ac-b)/c"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a/d+b/c"), textToAst$3.convert("(ac+bd)/(cd)"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push( - [textToAst$3.convert("a/d-b/c"), textToAst$3.convert("(ac-bd)/(cd)"), - {evaluate_numbers: true, - allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }] - ); - transformations.push([textToAst$3.convert("x*(y/z)"), textToAst$3.convert("(x*y)/z"), - {allow_extended_match: true, - allow_permutations: true, - max_group: 1, - }]); - transformations.push([textToAst$3.convert("(x/y)/z"), textToAst$3.convert("x/(y*z)"), - {allow_extended_match: true, - allow_permutations: true, - }]); - transformations.push([textToAst$3.convert("x/(y/z)"), textToAst$3.convert("xz/y"), - {allow_extended_match: true, - allow_permutations: true, - }]); - - tree = applyAllTransformations(tree, transformations, 40); - - tree = expand(tree, true); - - return tree; - } - - - function as_num_denom(expr_or_tree) { - // Return tuple containing numerator and denominator - // after attempting to place over common denominator - - var tree = get_tree(expr_or_tree); - - tree = common_denominator(tree); - - if(tree[0] === '/') - return [tree[1], tree[2]]; - else - return [tree, 1]; - } - - function reduce_rational(expr_or_tree) { - var tree = get_tree(expr_or_tree); - - var num_denom = as_num_denom(tree); - - if(num_denom[1] === 1) - return tree; - - var poly_num = expression_to_polynomial(num_denom[0]); - var poly_denom = expression_to_polynomial(num_denom[1]); - - var reduced_polys = reduce_rational_expression(poly_num, poly_denom); - - var num_new = polynomial_to_expression(reduced_polys[0]); - var denom_new = polynomial_to_expression(reduced_polys[1]); - - if(denom_new === 1) - return num_new; - else - return ['/', num_new, denom_new]; - - } - - const common_demoninator = common_denominator; - - var rational = /*#__PURE__*/Object.freeze({ - reduce_rational: reduce_rational, - common_demoninator: common_demoninator - }); - - function round_numbers_to_precision(expr_or_tree, digits=14) { - // round any decimals to specified number of significant digits - - var tree = get_tree(expr_or_tree); - - if(digits < 1) { - throw Error("For round_numbers_to_precision, digits must be positive"); - } - - if(!Number.isFinite(digits)) { - throw Error("For round_numbers_to_precision, digits must be a number"); - } - - if(digits > 15) { - return tree; - } - - digits = Math.round(digits); - - return round_numbers_to_precision_sub(tree,digits); - } - - const round_numbers_to_precision_sub = function(tree, digits=14) { - - if(typeof tree === "number") { - - if(Number.isFinite(tree) && tree !== 0) { - const scaleFactor = math$19.floor(math$19.log10(math$19.abs(tree))); - const n = digits - scaleFactor - 1; - if(n < 0) { - // mathjs toFixed truncates zeros when n is negative - // so add back on when creating float - return parseFloat(number_7(tree, n)+'0'.repeat(math$19.abs(n))); - } else { - return parseFloat(number_7(tree, n)) - } - } - } - if(!Array.isArray(tree)) { - return tree; - } - let operator = tree[0]; - let operands = tree.slice(1); - return [operator, ...operands.map(x => round_numbers_to_precision_sub(x,digits))] - }; - - - function round_numbers_to_decimals(expr_or_tree, ndecimals=14) { - // round any numbers to specified number of decimals - - var tree = get_tree(expr_or_tree); - - - if(!Number.isFinite(ndecimals)) { - throw Error("For round_numbers_to_decimals, ndecimals must be a number"); - } - - ndecimals = Math.round(ndecimals); - - // no need to go much beyond limits of double precision - ndecimals = Math.max(-330, Math.min(330, ndecimals)); - - return round_numbers_to_decimals_sub(tree,ndecimals); - } - - const round_numbers_to_decimals_sub = function(tree, ndecimals=0) { - - if(typeof tree === "number") { - if(ndecimals < 0) { - // mathjs toFixed truncates zeros when n is negative - // so add back on when creating float - return parseFloat(number_7(tree, ndecimals)+'0'.repeat(math$19.abs(ndecimals))); - } else { - return parseFloat(number_7(tree, ndecimals)) - } - } - if(!Array.isArray(tree)) { - return tree; - } - let operator = tree[0]; - let operands = tree.slice(1); - return [operator, ...operands.map(x => round_numbers_to_decimals_sub(x,ndecimals))] - }; - - var round$2 = /*#__PURE__*/Object.freeze({ - round_numbers_to_precision: round_numbers_to_precision, - round_numbers_to_decimals: round_numbers_to_decimals - }); - - const expression_to_tree = [ - simplify$3, - differentiation, - normalization, - arithmetic$1, - transformation, - solve, - sets, - matrix$5, - rational, - round$2, - ]; - - const expression_to_other = [ - variables$1, - printing, - equality, - integration, - evaluation, - analytic, - sign_error, - ]; - - // standard functions - - //"intersect", "cross", "det", "diag", "dot", "eye", " inv", " sort", " trace", " transpose", "max", "mean", "median", "min", "mode", "nthRoot" - // "ceil", "fix", "floor", "round" - - function abs$2(expr_or_tree) {return ['apply', 'abs', get_tree(expr_or_tree)];} - function exp$2(expr_or_tree) {return ['apply', 'exp', get_tree(expr_or_tree)];} - function log$2(expr_or_tree) {return ['apply', 'log', get_tree(expr_or_tree)];} - function log10$2(expr_or_tree) {return ['apply', 'log10', get_tree(expr_or_tree)];} - function sign$4(expr_or_tree) {return ['apply', 'sign', get_tree(expr_or_tree)];} - function sqrt$2(expr_or_tree) {return ['apply', 'sqrt', get_tree(expr_or_tree)];} - function conj$2(expr_or_tree) {return ['apply', 'conj', get_tree(expr_or_tree)];} - function im$2(expr_or_tree) {return ['apply', 'im', get_tree(expr_or_tree)];} - function re$2(expr_or_tree) {return ['apply', 're', get_tree(expr_or_tree)];} - function factorial$2(expr_or_tree) {return ['apply', 'factorial', get_tree(expr_or_tree)];} - function gamma$2(expr_or_tree) {return ['apply', 'gamma', get_tree(expr_or_tree)];} - function erf$2(expr_or_tree) {return ['apply', 'erf', get_tree(expr_or_tree)];} - function acos$2(expr_or_tree) {return ['apply', 'acos', get_tree(expr_or_tree)];} - function acosh$2(expr_or_tree) {return ['apply', 'acosh', get_tree(expr_or_tree)];} - function acot$2(expr_or_tree) {return ['apply', 'acot', get_tree(expr_or_tree)];} - function acoth$2(expr_or_tree) {return ['apply', 'acoth', get_tree(expr_or_tree)];} - function acsc$2(expr_or_tree) {return ['apply', 'acsc', get_tree(expr_or_tree)];} - function acsch$2(expr_or_tree) {return ['apply', 'acsch', get_tree(expr_or_tree)];} - function asec$2(expr_or_tree) {return ['apply', 'asec', get_tree(expr_or_tree)];} - function asech$2(expr_or_tree) {return ['apply', 'asech', get_tree(expr_or_tree)];} - function asin$2(expr_or_tree) {return ['apply', 'asin', get_tree(expr_or_tree)];} - function asinh$2(expr_or_tree) {return ['apply', 'asinh', get_tree(expr_or_tree)];} - function atan$2(expr_or_tree) {return ['apply', 'atan', get_tree(expr_or_tree)];} - function atanh$2(expr_or_tree) {return ['apply', 'atanh', get_tree(expr_or_tree)];} - function cos$2(expr_or_tree) {return ['apply', 'cos', get_tree(expr_or_tree)];} - function cosh$2(expr_or_tree) {return ['apply', 'cosh', get_tree(expr_or_tree)];} - function cot$2(expr_or_tree) {return ['apply', 'cot', get_tree(expr_or_tree)];} - function coth$2(expr_or_tree) {return ['apply', 'coth', get_tree(expr_or_tree)];} - function csc$2(expr_or_tree) {return ['apply', 'csc', get_tree(expr_or_tree)];} - function csch$2(expr_or_tree) {return ['apply', 'csch', get_tree(expr_or_tree)];} - function sec$2(expr_or_tree) {return ['apply', 'sec', get_tree(expr_or_tree)];} - function sech$2(expr_or_tree) {return ['apply', 'sech', get_tree(expr_or_tree)];} - function sin$2(expr_or_tree) {return ['apply', 'sin', get_tree(expr_or_tree)];} - function sinh$2(expr_or_tree) {return ['apply', 'sinh', get_tree(expr_or_tree)];} - function tan$2(expr_or_tree) {return ['apply', 'tan', get_tree(expr_or_tree)];} - function tanh$2(expr_or_tree) {return ['apply', 'tanh', get_tree(expr_or_tree)];} - - // function of two variables - function atan2$2(expr_or_tree1, expr_or_tree2) { - return ['apply', 'atan2', ['tuple', get_tree(expr_or_tree1), - get_tree(expr_or_tree2)]]; - } - - var standard = /*#__PURE__*/Object.freeze({ - abs: abs$2, - exp: exp$2, - log: log$2, - log10: log10$2, - sign: sign$4, - sqrt: sqrt$2, - conj: conj$2, - im: im$2, - re: re$2, - factorial: factorial$2, - gamma: gamma$2, - erf: erf$2, - acos: acos$2, - acosh: acosh$2, - acot: acot$2, - acoth: acoth$2, - acsc: acsc$2, - acsch: acsch$2, - asec: asec$2, - asech: asech$2, - asin: asin$2, - asinh: asinh$2, - atan: atan$2, - atanh: atanh$2, - cos: cos$2, - cosh: cosh$2, - cot: cot$2, - coth: coth$2, - csc: csc$2, - csch: csch$2, - sec: sec$2, - sech: sech$2, - sin: sin$2, - sinh: sinh$2, - tan: tan$2, - tanh: tanh$2, - atan2: atan2$2 - }); - - const expression_to_tree$1 = [ - standard, - ]; - - // UPDATETHIS: Delete or change to new license & package name - - /* - * recursive descent parser for math expressions - * - * Copyright 2014-2017 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - // UPDATETHIS: Is this grammar still correct? - - /* Grammar: - - statement_list = - statement_list ',' statement | - statement - - statement = - '\\dots' | - statement_a '|' statement_a | - statement_a 'MID' statement_a | - statement_a ':' statement_a - **** statement_a '|' statement_a - used with turning off '|' statement '|' in baseFactor - tried only after parse error encountered - - statement_a = - statement_a 'OR' statement_b | - statement_b - - statement_b = - statement_b 'AND' relation | - relation - - relation = - 'NOT' relation | - relation '=' expression | - relation 'NE' expression | - relation '<' expression | - relation '>' expression | - relation 'LE' expression | - relation 'GE' expression | - relation 'IN' expression | - relation 'NOTIN' expression | - relation 'NI' expression | - relation 'NOTNI' expression | - relation 'SUBSET' expression | - relation 'NOTSUBSET' expression | - relation 'SUPERSET' expression | - relation 'NOTSUPERSET' expression | - expression - - expression = - expression '+' term | - expression '-' term | - expression 'UNION' term | - expression 'INTERSECT' term | - '+' term | - term - - term = - term '*' factor | - term nonMinusFactor | - term '/' factor | - factor - - baseFactor = - '(' statement_list ')' | - '[' statement_list ']' | - '{' statement_list '}' | - 'LBRACE' statement_list 'RBRACE' | - '(' statement ',' statement ']' | - '[' statement ',' statement ')' | - '|' statement '|' | - \frac{statement}{statement} | - number | - variable | - modified_function '(' statement_list ')' | - modified_applied_function '(' statement_list ')' | - modified_function '{' statement_list '}' | - modified_applied_function '{' statement_list '}' | - modified_function | - modified_applied_function factor | - sqrt '[' statement ']' '{' statement '}' | - baseFactor '_' baseFactor | - *** modified_applied_function factor - allowed only if allowSimplifiedFunctionApplication==true - *** '|' statement '|' - allowed only at beginning of factor or if not currently in absolute value - - modified_function = - function | - function '_' baseFactor | - function '_' baseFactor '^' factor | - function '^' factor - function "'" - function '_' baseFactor "'" - function '_' baseFactor "'" '^' factor - function "'" '^' factor - *** where the "'" after the functions can be repeated - - modified_applied_function = - applied_function | - applied_function '_' baseFactor | - applied_function '_' baseFactor '^' factor | - applied_function '^' factor - applied_function "'" - applied_function '_' baseFactor "'" - applied_function '_' baseFactor "'" '^' factor - applied_function "'" '^' factor - *** where the "'" after the applied_functions can be repeated - - nonMinusFactor = - baseFactor | - baseFactor '^' factor | - baseFactor '!' and/or "'" | - baseFactor '!' and/or "'" '^' factor| - *** where '!' and/or "'" indicates arbitrary sequence of "!" and/or "'" - - factor = - '-' factor | - nonMinusFactor - - */ - - - // Some of the latex commands that lead to spacing - const whitespace_rule = '\\s|\\\\,|\\\\!|\\\\ |\\\\>|\\\\;|\\\\:|\\\\quad\\b|\\\\qquad\\b'; - - // in order to parse as scientific notation, e.g., 3.2E-12 or .7E+3, - // it must be at the end or followed a comma, &, |, \|, ), }, \}, ], \\, or \end - const sci_notat_exp_regex$1 = '(E[+\\-]?[0-9]+\\s*($|(?=\\,|&|\\||\\\\\\||\\)|\\}|\\\\}|\\]|\\\\\\\\|\\\\end)))?'; - - const latex_rules = [ - ['[0-9]+(\\.[0-9]*)?'+sci_notat_exp_regex$1 , 'NUMBER'], - ['\\.[0-9]+'+sci_notat_exp_regex$1, 'NUMBER'], - ['\\*', '*'], - ['\\/', '/'], - ['-', '-'], - ['\\+', '+'], - ['\\^', '^'], - ['\\(', '('], - ['\\\\left\\s*\\(', '('], - ['\\\\bigl\\s*\\(', '('], - ['\\\\Bigl\\s*\\(', '('], - ['\\\\biggl\\s*\\(', '('], - ['\\\\Biggl\\s*\\(', '('], - ['\\)', ')'], - ['\\\\right\\s*\\)', ')'], - ['\\\\bigr\\s*\\)', ')'], - ['\\\\Bigr\\s*\\)', ')'], - ['\\\\biggr\\s*\\)', ')'], - ['\\\\Biggr\\s*\\)', ')'], - ['\\[', '['], - ['\\\\left\\s*\\[', '['], - ['\\\\bigl\\s*\\[', '['], - ['\\\\Bigl\\s*\\[', '['], - ['\\\\biggl\\s*\\[', '['], - ['\\\\Biggl\\s*\\[', '['], - ['\\]', ']'], - ['\\\\right\\s*\\]', ']'], - ['\\\\bigr\\s*\\]', ']'], - ['\\\\Bigr\\s*\\]', ']'], - ['\\\\biggr\\s*\\]', ']'], - ['\\\\Biggr\\s*\\]', ']'], - ['\\|', '|'], - ['\\\\left\\s*\\|', '|L'], - ['\\\\bigl\\s*\\|', '|L'], - ['\\\\Bigl\\s*\\|', '|L'], - ['\\\\biggl\\s*\\|', '|L'], - ['\\\\Biggl\\s*\\|', '|L'], - ['\\\\right\\s*\\|', '|'], - ['\\\\bigr\\s*\\|', '|'], - ['\\\\Bigr\\s*\\|', '|'], - ['\\\\biggr\\s*\\|', '|'], - ['\\\\Biggr\\s*\\|', '|'], - ['\\\\big\\s*\\|', '|'], - ['\\\\Big\\s*\\|', '|'], - ['\\\\bigg\\s*\\|', '|'], - ['\\\\Bigg\\s*\\|', '|'], - ['{', '{'], - ['}', '}'], - ['\\\\{', 'LBRACE'], - ['\\\\left\\s*\\\\{', 'LBRACE'], - ['\\\\bigl\\s*\\\\{', 'LBRACE'], - ['\\\\Bigl\\s*\\\\{', 'LBRACE'], - ['\\\\biggl\\s*\\\\{', 'LBRACE'], - ['\\\\Biggl\\s*\\\\{', 'LBRACE'], - ['\\\\}', 'RBRACE'], - ['\\\\right\\s*\\\\}', 'RBRACE'], - ['\\\\bigr\\s*\\\\}', 'RBRACE'], - ['\\\\Bigr\\s*\\\\}', 'RBRACE'], - ['\\\\biggr\\s*\\\\}', 'RBRACE'], - ['\\\\Biggr\\s*\\\\}', 'RBRACE'], - ['\\\\cdot(?![a-zA-Z])', '*'], - ['\\\\div(?![a-zA-Z])', '/'], - ['\\\\times(?![a-zA-Z])', '*'], - ['\\\\frac(?![a-zA-Z])', 'FRAC'], - [',', ','], - [':', ':'], - ['\\\\mid', 'MID'], - - ['\\\\vartheta(?![a-zA-Z])', 'LATEXCOMMAND', '\\theta'], - ['\\\\varepsilon(?![a-zA-Z])', 'LATEXCOMMAND', '\\epsilon'], - ['\\\\varrho(?![a-zA-Z])', 'LATEXCOMMAND', '\\rho'], - ['\\\\varphi(?![a-zA-Z])', 'LATEXCOMMAND', '\\phi'], - - ['\\\\infty(?![a-zA-Z])', 'INFINITY'], - - ['\\\\asin(?![a-zA-Z])', 'LATEXCOMMAND', '\\arcsin'], - ['\\\\acos(?![a-zA-Z])', 'LATEXCOMMAND', '\\arccos'], - ['\\\\atan(?![a-zA-Z])', 'LATEXCOMMAND', '\\arctan'], - ['\\\\sqrt(?![a-zA-Z])', 'SQRT'], - - ['\\\\land(?![a-zA-Z])', 'AND'], - ['\\\\wedge(?![a-zA-Z])', 'AND'], - - ['\\\\lor(?![a-zA-Z])', 'OR'], - ['\\\\vee(?![a-zA-Z])', 'OR'], - - ['\\\\lnot(?![a-zA-Z])', 'NOT'], - - ['=', '='], - ['\\\\neq(?![a-zA-Z])', 'NE'], - ['\\\\ne(?![a-zA-Z])', 'NE'], - ['\\\\not\\s*=', 'NE'], - ['\\\\leq(?![a-zA-Z])', 'LE'], - ['\\\\le(?![a-zA-Z])', 'LE'], - ['\\\\geq(?![a-zA-Z])', 'GE'], - ['\\\\ge(?![a-zA-Z])', 'GE'], - ['<', '<'], - ['\\\\lt(?![a-zA-Z])', '<'], - ['>', '>'], - ['\\\\gt(?![a-zA-Z])', '>'], - - ['\\\\in(?![a-zA-Z])', 'IN'], - - ['\\\\notin(?![a-zA-Z])', 'NOTIN'], - ['\\\\not\\s*\\\\in(?![a-zA-Z])', 'NOTIN'], - - ['\\\\ni(?![a-zA-Z])', 'NI'], - - ['\\\\not\\s*\\\\ni(?![a-zA-Z])', 'NOTNI'], - - ['\\\\subset(?![a-zA-Z])', 'SUBSET'], - - ['\\\\not\\s*\\\\subset(?![a-zA-Z])', 'NOTSUBSET'], - - ['\\\\supset(?![a-zA-Z])', 'SUPERSET'], - - ['\\\\not\\s*\\\\supset(?![a-zA-Z])', 'NOTSUPERSET'], - - ['\\\\cup(?![a-zA-Z])', 'UNION'], - - ['\\\\cap(?![a-zA-Z])', 'INTERSECT'], - - ['!', '!'], - ['\'', '\''], - ['_', '_'], - ['&', '&'], - ['\\\\ldots', 'LDOTS'], - - ['\\\\\\\\', 'LINEBREAK'], - - ['\\\\begin\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'BEGINENVIRONMENT'], - - ['\\\\end\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'ENDENVIRONMENT'], - - ['\\\\var\\s*{\\s*[a-zA-Z0-9]+\\s*}', 'VARMULTICHAR'], - - ['\\\\[a-zA-Z]+(?![a-zA-Z])', 'LATEXCOMMAND'], - ['[a-zA-Z]', 'VAR'] - ]; - - - // defaults for parsers if not overridden by context - - // if true, allowed applied functions to omit parentheses around argument - // if false, omitting parentheses will lead to a Parse Error - const allowSimplifiedFunctionApplicationDefault$1 = true; - - - // allowed multicharacter latex symbols - // in addition to the below applied function symbols - const allowedLatexSymbolsDefault$1 = ['alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'Tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'partial']; - - // Applied functions must be given an argument so that - // they are applied to the argument - const appliedFunctionSymbolsDefault$1 = ["abs", "exp", "log", "ln", "log10", "sign", "sqrt", "erf", "acos", "acosh", "acot", "acoth", "acsc", "acsch", "asec", "asech", "asin", "asinh", "atan", "atanh", "cos", "cosh", "cot", "coth", "csc", "csch", "sec", "sech", "sin", "sinh", "tan", "tanh", 'arcsin', 'arccos', 'arctan', 'arccsc', 'arcsec', 'arccot', 'cosec', 'arg']; - - // Functions could have an argument, in which case they are applied - // or, if they don't have an argument in parentheses, then they are treated - // like a variable, except that trailing ^ and ' have higher precedence - const functionSymbolsDefault$1 = ['f', 'g']; - - // Parse Leibniz notation - const parseLeibnizNotationDefault$1 = true; - - - class latexToAst { - constructor({ - allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplicationDefault$1, - allowedLatexSymbols = allowedLatexSymbolsDefault$1, - appliedFunctionSymbols = appliedFunctionSymbolsDefault$1, - functionSymbols = functionSymbolsDefault$1, - parseLeibnizNotation = parseLeibnizNotationDefault$1, - } = {}) { - this.allowSimplifiedFunctionApplication = allowSimplifiedFunctionApplication; - this.allowedLatexSymbols = allowedLatexSymbols; - this.appliedFunctionSymbols = appliedFunctionSymbols; - this.functionSymbols = functionSymbols; - this.parseLeibnizNotation = parseLeibnizNotation; - - this.lexer = new lexer(latex_rules, whitespace_rule); - - } - - advance(params) { - this.token = this.lexer.advance(params); - if (this.token.token_type === 'INVALID') { - throw new ParseError("Invalid symbol '" + this.token.original_text + "'", - this.lexer.location); - } - } - - return_state() { - return ({ - lexer_state: this.lexer.return_state(), - token: Object.assign({}, this.token) - }); - } - - set_state(state) { - this.lexer.set_state(state.lexer_state); - this.token = Object.assign({}, state.token); - } - - - convert(input) { - - this.lexer.set_input(input); - this.advance(); - - var result = this.statement_list(); - - if (this.token.token_type !== 'EOF') { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } - - return flatten$18(result); - - } - - statement_list() { - - var list = [this.statement()]; - - while (this.token.token_type === ",") { - this.advance(); - list.push(this.statement()); - } - - if (list.length > 1) - list = ['list'].concat(list); - else - list = list[0]; - - return list; - } - - statement({ inside_absolute_value = 0 } = {}) { - - // \ldots can be a statement by itself - if (this.token.token_type === 'LDOTS') { - this.advance(); - return ['ldots']; - } - - var original_state; - - try { - - original_state = this.return_state(); - - let lhs = this.statement_a({ inside_absolute_value: inside_absolute_value }); - - if (this.token.token_type !== ':' && this.token.token_type !== 'MID') - return lhs; - - let operator = this.token.token_type === ':' ? ':' : '|'; - - this.advance(); - - let rhs = this.statement_a(); - - return [operator, lhs, rhs]; - - } - catch (e) { - try { - - // if ran into problem parsing statement - // then try again with ignoring absolute value - // and then interpreting bar as a binary operator - - // return state to what it was before attempting to parse statement - this.set_state(original_state); - - let lhs = this.statement_a({ parse_absolute_value: false }); - - if (this.token.token_type[0] !== '|') { - throw (e); - } - - this.advance(); - - let rhs = this.statement_a({ parse_absolute_value: false }); - - return ['|', lhs, rhs]; - - } - catch (e2) { - throw (e); // throw original error - } - } - } - - statement_a({ inside_absolute_value = 0, parse_absolute_value = true } = {}) { - - var lhs = this.statement_b({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value - }); - - while (this.token.token_type === 'OR') { - - let operation = this.token.token_type.toLowerCase(); - - this.advance(); - - let rhs = this.statement_b({ - inside_absolute_value: inside_absolute_value, - parse_absolute_value: parse_absolute_value - }); - - lhs = [operation, lhs, rhs]; - } - - return lhs; - } - - - statement_b(params) { - // split AND into second statement to give higher precedence than OR - - var lhs = this.relation(params); - - while (this.token.token_type === 'AND') { - - let operation = this.token.token_type.toLowerCase(); - - this.advance(); - - let rhs = this.relation(params); - - lhs = [operation, lhs, rhs]; - } - - return lhs; - } - - - relation(params) { - - if (this.token.token_type === 'NOT' || this.token.token_type === '!') { - this.advance(); - return ['not', this.relation(params)]; - } - - var lhs = this.expression(params); - - while ((this.token.token_type === '=') || (this.token.token_type === 'NE') - || (this.token.token_type === '<') || (this.token.token_type === '>') - || (this.token.token_type === 'LE') || (this.token.token_type === 'GE') - || (this.token.token_type === 'IN') || (this.token.token_type === 'NOTIN') - || (this.token.token_type === 'NI') || (this.token.token_type === 'NOTNI') - || (this.token.token_type === 'SUBSET') || (this.token.token_type === 'NOTSUBSET') - || (this.token.token_type === 'SUPERSET') || (this.token.token_type === 'NOTSUPERSET')) { - - let operation = this.token.token_type.toLowerCase(); - - let inequality_sequence = 0; - - if ((this.token.token_type === '<') || (this.token.token_type === 'LE')) { - inequality_sequence = -1; - } - else if ((this.token.token_type === '>') || (this.token.token_type === 'GE')) { - inequality_sequence = 1; - } - - this.advance(); - let rhs = this.expression(params); - - if (inequality_sequence === -1) { - if ((this.token.token_type === '<') || this.token.token_type === 'LE') { - // sequence of multiple < or <= - let strict = ['tuple']; - if (operation === '<') - strict.push(true); - else - strict.push(false); - - let args = ['tuple', lhs, rhs]; - while ((this.token.token_type === '<') || this.token.token_type === 'LE') { - if (this.token.token_type === '<') - strict.push(true); - else - strict.push(false); - - this.advance(); - args.push(this.expression(params)); - } - lhs = ['lts', args, strict]; - } - else { - lhs = [operation, lhs, rhs]; - } - - } - else if (inequality_sequence === 1) { - if ((this.token.token_type === '>') || this.token.token_type === 'GE') { - // sequence of multiple > or >= - let strict = ['tuple']; - if (operation === '>') - strict.push(true); - else - strict.push(false); - - let args = ['tuple', lhs, rhs]; - while ((this.token.token_type === '>') || this.token.token_type === 'GE') { - if (this.token.token_type === '>') - strict.push(true); - else - strict.push(false); - - this.advance(); - args.push(this.expression(params)); - } - lhs = ['gts', args, strict]; - } - else { - lhs = [operation, lhs, rhs]; - } - - } - else if (operation === '=') { - lhs = ['=', lhs, rhs]; - - // check for sequence of multiple = - while (this.token.token_type === '=') { - this.advance(); - lhs.push(this.expression(params)); - } - } - else { - - lhs = [operation, lhs, rhs]; - } - - } - - return lhs; - } - - - expression(params) { - if (this.token.token_type === '+') - this.advance(); - - let negative_begin = false; - if (this.token.token_type === '-') { - negative_begin = true; - this.advance(); - } - - var lhs = this.term(params); - - if (negative_begin) { - lhs = ['-', lhs]; - } - - while ((this.token.token_type === '+') || (this.token.token_type === '-') - || (this.token.token_type === 'UNION') - || (this.token.token_type === 'INTERSECT')) { - - let operation = this.token.token_type.toLowerCase(); - let negative = false; - - if (this.token.token_type === '-') { - operation = '+'; - negative = true; - this.advance(); - } - else { - this.advance(); - if (operation === '+' && this.token.token_type === '-') { - negative = true; - this.advance(); - } - } - let rhs = this.term(params); - if (negative) { - rhs = ['-', rhs]; - } - - lhs = [operation, lhs, rhs]; - } - - return lhs; - } - - - term(params) { - var lhs = this.factor(params); - - var keepGoing = false; - - do { - keepGoing = false; - - if (this.token.token_type === '*') { - this.advance(); - lhs = ['*', lhs, this.factor(params)]; - keepGoing = true; - } else if (this.token.token_type === '/') { - this.advance(); - lhs = ['/', lhs, this.factor(params)]; - keepGoing = true; - } else { - // this is the one case where a | could indicate a closing absolute value - let params2 = Object.assign({}, params); - params2.allow_absolute_value_closing = true; - let rhs = this.nonMinusFactor(params2); - if (rhs !== false) { - lhs = ['*', lhs, rhs]; - keepGoing = true; - } - } - } while (keepGoing); - - return lhs; - } - - - factor(params) { - if (this.token.token_type === '-') { - this.advance(); - return ['-', this.factor(params)]; - } - - var result = this.nonMinusFactor(params); - - if (result === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", this.lexer.location); - } - else { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } - } - else { - return result; - } - - } - - nonMinusFactor(params) { - - var result = this.baseFactor(params); - - // allow arbitrary sequence of factorials - if (this.token.token_type === '!' || this.token.token_type === "'") { - if (result === false) - throw new ParseError("Invalid location of " + this.token.token_type, - this.lexer.location); - while (this.token.token_type === '!' || this.token.token_type === "'") { - if (this.token.token_type === '!') - result = ['apply', 'factorial', result]; - else - result = ['prime', result]; - this.advance(); - } - } - - if (this.token.token_type === '^') { - if (result === false) { - throw new ParseError("Invalid location of ^", this.lexer.location); - } - this.advance(); - - // do not allow absolute value closing here - let params2 = Object.assign({}, params); - delete params2.allow_absolute_value_closing; - delete params2.inside_absolute_value; - - return ['^', result, this.factor(params2)]; - } - - return result; - } - - - baseFactor({ inside_absolute_value = 0, - parse_absolute_value = true, - allow_absolute_value_closing = false - } = {}) { - - var result = false; - - if (this.token.token_type === 'FRAC') { - this.advance(); - - if (this.token.token_type !== '{') { - throw new ParseError("Expecting {", this.lexer.location); - } - this.advance(); - - // determine if may be a derivative in Leibniz notation - if (this.parseLeibnizNotation) { - - let original_state = this.return_state(); - - let r = this.leibniz_notation(); - - if (r) { - // successfully parsed derivative in Leibniz notation, so return - return r; - } - else { - // didn't find a properly format Leibniz notation - // so reset state and continue - this.set_state(original_state); - } - } - - let numerator = this.statement({ parse_absolute_value: parse_absolute_value }); - - if (this.token.token_type !== '}') { - throw new ParseError("Expecting }", this.lexer.location); - } - this.advance(); - - if (this.token.token_type !== '{') { - throw new ParseError("Expecting {", this.lexer.location); - } - this.advance(); - - let denominator = this.statement({ parse_absolute_value: parse_absolute_value }); - - if (this.token.token_type !== '}') { - throw new ParseError("Expecting }", this.lexer.location); - } - this.advance(); - - return ['/', numerator, denominator]; - } - - if (this.token.token_type === 'BEGINENVIRONMENT') { - let environment = /\\begin\s*{\s*([a-zA-Z0-9]+)\s*}/.exec(this.token.token_text)[1]; - - if (['matrix', 'pmatrix', 'bmatrix'].includes(environment)) { - - let n_rows = 0; - let n_cols = 0; - - let all_rows = []; - let row = []; - let n_this_row = 0; - let last_token = this.token.token_type; - - this.advance(); - - - while (this.token.token_type !== 'ENDENVIRONMENT') { - if (this.token.token_type === '&') { - if (last_token === '&' || last_token === 'LINEBREAK') { - // blank entry, let entry be zero - row.push(0); - n_this_row += 1; - } - last_token = this.token.token_type; - this.advance(); - } - else if (this.token.token_type === 'LINEBREAK') { - if (last_token === '&' || last_token === 'LINEBREAK') { - // blank entry, let entry be zero - row.push(0); - n_this_row += 1; - } - all_rows.push(row); - if (n_this_row > n_cols) - n_cols = n_this_row; - - n_rows += 1; - n_this_row = 0; - row = []; - last_token = this.token.token_type; - this.advance(); - } - else { - if (last_token === '&' || last_token === 'LINEBREAK' || 'BEGINENVIRONMENT') { - row.push(this.statement({ parse_absolute_value: parse_absolute_value })); - n_this_row += 1; - last_token = ' '; - - } - else { - throw new ParseError("Invalid location of " + this.token.original_text, this.lexer.location); - } - } - } - - // token is ENDENVIRONMENT - let environment2 = /\\end\s*{\s*([a-zA-Z0-9]+)\s*}/.exec(this.token.token_text)[1]; - if (environment2 !== environment) { - throw new ParseError("Expecting \\end{" + environment + "}", this.lexer.location); - } - - // add last row - if (last_token === '&') { - // blank entry, let entry be zero - row.push(0); - n_this_row += 1; - } - all_rows.push(row); - if (n_this_row > n_cols) - n_cols = n_this_row; - n_rows += 1; - - - this.advance(); - - // create matrix - result = ["matrix", ["tuple", n_rows, n_cols]]; - let body = ["tuple"]; - for (let r of all_rows) { - let new_row = ["tuple"].concat(r); - for (let i = r.length; i < n_cols; i += 1) - new_row.push(0); - - body.push(new_row); - - } - result.push(body); - - return result; - } - else { - throw new ParseError("Unrecognized environment " + environment, this.lexer.location); - } - - } - - if (this.token.token_type === 'NUMBER') { - result = parseFloat(this.token.token_text); - this.advance(); - } else if (this.token.token_type === 'INFINITY') { - result = Infinity; - this.advance(); - } else if (this.token.token_type === 'SQRT') { - this.advance(); - - let root = 2; - if (this.token.token_type === '[') { - this.advance(); - let parameter = this.statement({ parse_absolute_value: parse_absolute_value }); - if (this.token.token_type !== ']') { - throw new ParseError("Expecting ]", this.lexer.location); - } - this.advance(); - - root = parameter; - } - - if (this.token.token_type !== '{') { - throw new ParseError("Expecting {", this.lexer.location); - } - - this.advance(); - let parameter = this.statement({ parse_absolute_value: parse_absolute_value }); - if (this.token.token_type !== '}') { - throw new ParseError("Expecting }", this.lexer.location); - } - this.advance(); - - if (root === 2) - result = ['apply', 'sqrt', parameter]; - else - result = ['^', parameter, ['/', 1, root]]; - } else if (this.token.token_type === 'VAR' || this.token.token_type === 'LATEXCOMMAND' - || this.token.token_type === 'VARMULTICHAR') { - result = this.token.token_text; - - if (this.token.token_type === 'LATEXCOMMAND') { - result = result.slice(1); - if (!(this.appliedFunctionSymbols.includes(result) - || this.functionSymbols.includes(result) - || this.allowedLatexSymbols.includes(result) - )) { - throw new ParseError("Unrecognized latex command " + this.token.original_text, - this.lexer.location); - } - } - else if (this.token.token_type === 'VARMULTICHAR') { - // strip out name of variable from \var command - result = /\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(result)[1]; - } - - if (this.appliedFunctionSymbols.includes(result) - || this.functionSymbols.includes(result)) { - let must_apply = false; - if (this.appliedFunctionSymbols.includes(result)) - must_apply = true; - - this.advance(); - - if (this.token.token_type === '_') { - this.advance(); - let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); - - // since baseFactor could return false, must check - if (subresult === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", - this.lexer.location); - } - else { - throw new ParseError("Invalid location of '" + this.token.original_text - + "'", this.lexer.location); - } - } - result = ['_', result, subresult]; - } - - while (this.token.token_type === "'") { - result = ['prime', result]; - this.advance(); - } - - if (this.token.token_type === '^') { - this.advance(); - result = ['^', result, this.factor({ parse_absolute_value: parse_absolute_value })]; - } - - if (this.token.token_type === '{' || this.token.token_type === '(') { - let expected_right; - if (this.token.token_type === '{') - expected_right = '}'; - else - expected_right = ')'; - - this.advance(); - let parameters = this.statement_list(); - - if (this.token.token_type !== expected_right) { - throw new ParseError('Expecting ' + expected_right, - this.lexer.location); - } - this.advance(); - - if (parameters[0] === 'list') { - // rename from list to tuple - parameters[0] = 'tuple'; - } - - result = ['apply', result, parameters]; - - } - else { - // if was an applied function symbol, - // cannot omit argument - if (must_apply) { - if (!this.allowSimplifiedFunctionApplication) - throw new ParseError("Expecting ( after function", - this.lexer.location); - - // if allow simplied function application - // let the argument be the next factor - result = ['apply', result, this.factor({ parse_absolute_value: parse_absolute_value })]; - } - } - } - else { - this.advance(); - } - } else if (this.token.token_type === '(' || this.token.token_type === '[' - || this.token.token_type === '{' - || this.token.token_type === 'LBRACE') { - let token_left = this.token.token_type; - let expected_right, other_right; - if (this.token.token_type === '(') { - expected_right = ')'; - other_right = ']'; - } - else if (this.token.token_type === '[') { - expected_right = ']'; - other_right = ')'; - } - else if (this.token.token_type === '{') { - expected_right = '}'; - other_right = null; - } - else { - expected_right = 'RBRACE'; - other_right = null; - } - - this.advance(); - result = this.statement_list(); - - let n_elements = 1; - if (result[0] === "list") { - n_elements = result.length - 1; - } - - if (this.token.token_type !== expected_right) { - if (n_elements !== 2 || other_right === null) { - throw new ParseError('Expecting ' + expected_right, - this.lexer.location); - } - else if (this.token.token_type !== other_right) { - throw new ParseError('Expecting ) or ]', this.lexer.location); - } - - // half-open interval - result[0] = 'tuple'; - result = ['interval', result]; - let closed; - if (token_left === '(') - closed = ['tuple', false, true]; - else - closed = ['tuple', true, false]; - result.push(closed); - - } - else if (n_elements >= 2) { - if (token_left === '(' || token_left === '{') { - result[0] = 'tuple'; - } - else if (token_left === '[') { - result[0] = 'array'; - } - else { - result[0] = 'set'; - } - } - else if (token_left === 'LBRACE') { - if (result[0] === '|' || result[0] === ':') { - result = ['set', result]; // set builder notation - } - else { - result = ['set', result]; // singleton set - } - } - - this.advance(); - - } else if (this.token.token_type[0] === '|' && parse_absolute_value && - (inside_absolute_value === 0 || !allow_absolute_value_closing || - this.token.token_type[1] === 'L')) { - - // allow the opening of an absolute value here if either - // - we aren't already inside an absolute value (inside_absolute_value==0), - // - we don't allows an absolute value closing, or - // - the | was marked as a left - // otherwise, skip this token so that will drop out the factor (and entire statement) - // to where the absolute value will close - - inside_absolute_value += 1; - - this.advance(); - - result = this.statement({ inside_absolute_value: inside_absolute_value }); - result = ['apply', 'abs', result]; - - if (this.token.token_type !== '|') { - throw new ParseError('Expecting |', this.lexer.location); - } - - this.advance(); - } - - if (this.token.token_type === '_') { - if (result === false) { - throw new ParseError("Invalid location of _", this.lexer.location); - } - this.advance(); - let subresult = this.baseFactor({ parse_absolute_value: parse_absolute_value }); - - if (subresult === false) { - if (this.token.token_type === "EOF") { - throw new ParseError("Unexpected end of input", this.lexer.location); - } - else { - throw new ParseError("Invalid location of '" + this.token.original_text + "'", - this.lexer.location); - } - } - return ['_', result, subresult]; - } - - return result; - } - - - leibniz_notation() { - // attempt to find and return a derivative in Leibniz notation - // if unsuccessful, return false - - var result = this.token.token_text; - - let deriv_symbol = ""; - - let n_deriv = 1; - - let var1 = ""; - let var2s = []; - let var2_exponents = []; - - if (this.token.token_type === "LATEXCOMMAND" && result.slice(1) === "partial") - deriv_symbol = "∂"; - else if (this.token.token_type === "VAR" && result === "d") - deriv_symbol = "d"; - else - return false; - - // since have just a d or ∂ - // one option is that have a ^ followed by an integer next possibly in {} - - this.advance(); - - if (this.token.token_type === '^') { - // so far have d or ∂ followed by ^ - // must be followed by an integer - this.advance(); - - let in_braces = false; - if (this.token.token_type === '{') { - in_braces = true; - - this.advance(); - } - - if (this.token.token_type !== 'NUMBER') { - return false; - } - - n_deriv = parseFloat(this.token.token_text); - if (!Number.isInteger(n_deriv)) { - return false; - } - - // found integer, - - // if in braces, require } - if (in_braces) { - this.advance(); - - if (this.token.token_type !== '}') { - return false; - } - } - - this.advance(); - } - - - // since have a d or ∂, optionally followed by ^ and integer - // next we must have: - // a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols - - if (this.token.token_type === 'VAR') - var1 = this.token.token_text; - else if (this.token.token_type === 'VARMULTICHAR') { - // strip out name of variable from \var command - var1 = /\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(this.token.token_text)[1]; - } - else if (this.token.token_type === 'LATEXCOMMAND') { - result = this.token.token_text.slice(1); - if (this.allowedLatexSymbols.includes(result)) - var1 = result; - else - return false; - } - - // Finished numerator. - // Next need a } and { - - this.advance(); - - if (this.token.token_type !== '}') { - return false; - } - - this.advance(); - - if (this.token.token_type !== '{') { - return false; - } - else { - this.advance(); - - } - - // In denominator now - // find sequence of - // derivative symbol followed by - // - a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols - // optionally followed by a ^ and an integer - // End when sum of exponents meets or exceeds n_deriv - - let exponent_sum = 0; - - while (true) { - - // next must be - // - a VAR equal to deriv_symbol="d" or \partial when deriv_symbol = "∂" - - - if (!((deriv_symbol === "d" && this.token.token_type === "VAR" && this.token.token_text === "d") - || (deriv_symbol === "∂" && this.token.token_type === "LATEXCOMMAND" - && this.token.token_text.slice(1) === "partial"))) { - return false; - } - - // followed by - // - a VAR, a VARMULTICHAR, or a LATEXCOMMAND that is in allowedLatexSymbols - - this.advance(); - - if (this.token.token_type === 'VAR') - var2s.push(this.token.token_text); - else if (this.token.token_type === 'VARMULTICHAR') { - // strip out name of variable from \var command - var2s.push(/\\var\s*\{\s*([a-zA-Z0-9]+)\s*\}/.exec(this.token.token_text)[1]); - } - else if (this.token.token_type === 'LATEXCOMMAND') { - let r = this.token.token_text.slice(1); - if (this.allowedLatexSymbols.includes(r)) - var2s.push(r); - else { - return false; - } - } - else { - return false; - } - // have derivative and variable, now check for optional ^ followed by number - - let this_exponent = 1; - - this.advance(); - - if (this.token.token_type === '^') { - - this.advance(); - - let in_braces = false; - if (this.token.token_type === '{') { - in_braces = true; - - this.advance(); - } - - if (this.token.token_type !== 'NUMBER') { - return false; - } - - this_exponent = parseFloat(this.token.token_text); - if (!Number.isInteger(this_exponent)) { - return false; - } - - // if in braces, require } - if (in_braces) { - this.advance(); - - if (this.token.token_type !== '}') { - return false; - } - } - - this.advance(); - - } - - var2_exponents.push(this_exponent); - exponent_sum += this_exponent; - - if (exponent_sum > n_deriv) { - return false; - } - - // possibly found derivative - if (exponent_sum === n_deriv) { - - // next token must be a } - if (this.token.token_type !== '}') { - return false; - - } - - // found derivative! - - this.advance(); - - let result_name = "derivative_leibniz"; - if (deriv_symbol === "∂") - result_name = "partial_" + result_name; - - result = [result_name]; - - if (n_deriv === 1) - result.push(var1); - else - result.push(["tuple", var1, n_deriv]); - - let r2 = []; - for (let i = 0; i < var2s.length; i += 1) { - if (var2_exponents[i] === 1) - r2.push(var2s[i]); - else - r2.push(["tuple", var2s[i], var2_exponents[i]]); - } - r2 = ["tuple"].concat(r2); - - result.push(r2); - - return result; - - } - } - } - } - - class latexToGuppy{ - constructor(){ - this.latexToAst = new latexToAst(); - this.astToGuppy = new astToGuppy(); - } - - convert(latex){ - return this.astToGuppy.convert(this.latexToAst.convert(latex)); - } - } - - class latexToMathjs{ - constructor(){ - this.latexToAst = new latexToAst(); - this.astToMathjs = new astToMathjs(); - } - - convert(latex){ - return this.astToMathjs.convert(this.latexToAst.convert(latex)); - } - } - - class latexToText{ - constructor(){ - this.latexToAst = new latexToAst(); - this.astToText = new astToText(); - } - - convert(latex){ - return this.astToText.convert(this.latexToAst.convert(latex)); - } - } - - /* - * convert math.s tree to AST - * - * Copyright 2014-2017 by - * Jim Fowler - * Duane Nykamp - * - * This file is part of a math-expressions library - * - * math-expressions is free software: you can redistribute - * it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation, either - * version 3 of the License, or at your option any later version. - * - * math-expressions is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ - - - - const operators$4 = { - "+,add": function(operands) { return ['+'].concat(operands); }, - "*,multiply": function(operands) { return ['*'].concat(operands); }, - "/,divide": function(operands) { return ['/', operands[0], operands[1]]; }, - "-,unaryMinus": function(operands) { return ['-', operands[0]]; }, - "-,subtract": function(operands) { return ['+', operands[0], ['-', operands[1]]]; }, - "^,pow": function(operands) { return ['^', operands[0], operands[1]]; }, - "and,and": function(operands) { return ['and'].concat(operands); }, - "or,or": function(operands) { return ['or'].concat(operands); }, - "not,not": function(operands) { return ['not', operands[0]]; }, - "==,equal": function(operands) { return ['='].concat(operands); }, - "<,smaller": function(operands) { return ['<', operands[0], operands[1]]; }, - ">,larger": function(operands) { return ['>', operands[0], operands[1]]; }, - "<=,smallerEq": function(operands) { return ['le', operands[0], operands[1]]; }, - ">=,largerEq": function(operands) { return ['ge', operands[0], operands[1]]; }, - "!=,unequal": function(operands) { return ['ne', operands[0], operands[1]]; }, - "!,factorial": function(operands) { return ['apply', 'factorial', operands[0]];}, - }; - - class mathjsToAst { - - convert(mathnode){ - if(mathnode.isConstantNode) - return mathnode.value; - if(mathnode.isSymbolNode) - return mathnode.name; - - if(mathnode.isOperatorNode) { - var key = [mathnode.op, mathnode.fn].join(','); - if(key in operators$4) - return operators$4[key]( - mathnode.args.map( function(v,i) { return this.convert(v); }.bind(this) ) ); - else - throw Error("Unsupported operator: " + mathnode.op - + ", " + mathnode.fn); - } - - if(mathnode.isFunctionNode) { - var args = mathnode.args.map( - function(v,i) { return this.convert(v); }.bind(this) ); - - if( args.length > 1) - args = ["tuple"].concat(args); - else - args = args[0]; - - var result = ["apply", mathnode.name]; - result.push(args); - return result; - - } - - if(mathnode.isArrayNode) { - return ["vector"].concat(mathnode.args.map( - function(v,i) { return this.convert(v); }.bind(this) ) ); - } - - if(mathnode.isParenthesisNode) - return this.convert(mathnode.content); - - throw Error("Unsupported node type: " + mathnode.type); - - } - - } - - class mathjsToGuppy{ - constructor(){ - this.mathjsToAst = new mathjsToAst(); - this.astToGuppy = new astToGuppy(); - } - - convert(mathjs){ - return this.astToGuppy.convert(this.mathjsToAst.convert(mathjs)); - } - } - - class mathjsToLatex{ - constructor(){ - this.mathjsToAst = new mathjsToAst(); - this.astToLatex = new astToLatex(); - } - - convert(mathjs){ - return this.astToLatex.convert(this.mathjsToAst.convert(mathjs)); - } - } - - class mathjsToText{ - constructor(){ - this.mathjsToAst = new mathjsToAst(); - this.astToText = new astToText(); - } - - convert(mathjs){ - return this.astToText.convert(this.mathjsToAst.convert(mathjs)); - } - } - - /** - * Helpers. - */ - - var s = 1000; - var m = s * 60; - var h = m * 60; - var d = h * 24; - var y = d * 365.25; - - /** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public - */ - - var ms = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse$2(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); - }; - - /** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - - function parse$2(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; - } - } - - /** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - - function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; - } - - /** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - - function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; - } - - /** - * Pluralization helper. - */ - - function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; - } - - var debug = createCommonjsModule(function (module, exports) { - /** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. - */ - - exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; - exports.coerce = coerce; - exports.disable = disable; - exports.enable = enable; - exports.enabled = enabled; - exports.humanize = ms; - - /** - * The currently active debug mode names, and names to skip. - */ - - exports.names = []; - exports.skips = []; - - /** - * Map of special "%n" handling functions, for the debug "format" argument. - * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". - */ - - exports.formatters = {}; - - /** - * Previous log timestamp. - */ - - var prevTime; - - /** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ - - function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer - } - - return exports.colors[Math.abs(hash) % exports.colors.length]; - } - - /** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public - */ - - function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; - - // set `diff` timestamp - var curr = +new Date(); - var ms$$1 = curr - (prevTime || curr); - self.diff = ms$$1; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; - - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } - - args[0] = exports.coerce(args[0]); - - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } - - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); - - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); - - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } - - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); - - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); - } - - return debug; - } - - /** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ - - function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } - } - - /** - * Disable debug output. - * - * @api public - */ - - function disable() { - exports.enable(''); - } - - /** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ - - function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; - } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; - } - } - return false; - } - - /** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private - */ - - function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; - } - }); - var debug_1 = debug.coerce; - var debug_2 = debug.disable; - var debug_3 = debug.enable; - var debug_4 = debug.enabled; - var debug_5 = debug.humanize; - var debug_6 = debug.names; - var debug_7 = debug.skips; - var debug_8 = debug.formatters; - - var browser = createCommonjsModule(function (module, exports) { - /** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - - exports = module.exports = debug; - exports.log = log; - exports.formatArgs = formatArgs; - exports.save = save; - exports.load = load; - exports.useColors = useColors; - exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); - - /** - * Colors. - */ - - exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' - ]; - - /** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors - */ - - function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; - } - - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); - } - - /** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. - */ - - exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; - } - }; - - - /** - * Colorize log arguments if enabled. - * - * @api public - */ - - function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); - - if (!useColors) return; - - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit'); - - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); - - args.splice(lastC, 0, c); - } - - /** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - - function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); - } - - /** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - - function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} - } - - /** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - - function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} - - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } - - return r; - } - - /** - * Enable namespaces listed in `localStorage.debug` initially. - */ - - exports.enable(load()); - - /** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. - * - * @return {LocalStorage} - * @api private - */ - - function localstorage() { - try { - return window.localStorage; - } catch (e) {} - } - }); - var browser_1 = browser.log; - var browser_2 = browser.formatArgs; - var browser_3 = browser.save; - var browser_4 = browser.load; - var browser_5 = browser.useColors; - var browser_6 = browser.storage; - var browser_7 = browser.colors; - - // MIT lisence - // from https://github.com/substack/tty-browserify/blob/1ba769a6429d242f36226538835b4034bf6b7886/index.js - - function isatty() { - return false; - } - - function ReadStream() { - throw new Error('tty.ReadStream is not implemented'); - } - - function WriteStream() { - throw new Error('tty.ReadStream is not implemented'); - } - - var tty = { - isatty: isatty, - ReadStream: ReadStream, - WriteStream: WriteStream - } - - // shim for using process in browser - // based off https://github.com/defunctzombie/node-process/blob/master/browser.js - - function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); - } - function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); - } - var cachedSetTimeout = defaultSetTimout; - var cachedClearTimeout = defaultClearTimeout; - if (typeof global.setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } - if (typeof global.clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } - - function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - - } - function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - - } - var queue = []; - var draining = false; - var currentQueue; - var queueIndex = -1; - - function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } - } - - function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); - } - function nextTick(fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } - } - // v8 likes predictible objects - function Item(fun, array) { - this.fun = fun; - this.array = array; - } - Item.prototype.run = function () { - this.fun.apply(null, this.array); - }; - var title = 'browser'; - var platform = 'browser'; - var browser$1 = true; - var env = {}; - var argv = []; - var version$2 = ''; // empty string to avoid regexp issues - var versions = {}; - var release = {}; - var config$2 = {}; - - function noop() {} - - var on = noop; - var addListener = noop; - var once = noop; - var off = noop; - var removeListener = noop; - var removeAllListeners = noop; - var emit = noop; - - function binding(name) { - throw new Error('process.binding is not supported'); - } - - function cwd () { return '/' } - function chdir (dir) { - throw new Error('process.chdir is not supported'); - }function umask() { return 0; } - - // from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js - var performance = global.performance || {}; - var performanceNow = - performance.now || - performance.mozNow || - performance.msNow || - performance.oNow || - performance.webkitNow || - function(){ return (new Date()).getTime() }; - - // generate timestamp or delta - // see http://nodejs.org/api/process.html#process_process_hrtime - function hrtime(previousTimestamp){ - var clocktime = performanceNow.call(performance)*1e-3; - var seconds = Math.floor(clocktime); - var nanoseconds = Math.floor((clocktime%1)*1e9); - if (previousTimestamp) { - seconds = seconds - previousTimestamp[0]; - nanoseconds = nanoseconds - previousTimestamp[1]; - if (nanoseconds<0) { - seconds--; - nanoseconds += 1e9; - } - } - return [seconds,nanoseconds] - } - - var startTime = new Date(); - function uptime() { - var currentTime = new Date(); - var dif = currentTime - startTime; - return dif / 1000; - } - - var process$1 = { - nextTick: nextTick, - title: title, - browser: browser$1, - env: env, - argv: argv, - version: version$2, - versions: versions, - on: on, - addListener: addListener, - once: once, - off: off, - removeListener: removeListener, - removeAllListeners: removeAllListeners, - emit: emit, - binding: binding, - cwd: cwd, - chdir: chdir, - umask: umask, - hrtime: hrtime, - platform: platform, - release: release, - config: config$2, - uptime: uptime - }; - - var inherits; - if (typeof Object.create === 'function'){ - inherits = function inherits(ctor, superCtor) { - // implementation from standard node.js 'util' module - ctor.super_ = superCtor; - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; - } else { - inherits = function inherits(ctor, superCtor) { - ctor.super_ = superCtor; - var TempCtor = function () {}; - TempCtor.prototype = superCtor.prototype; - ctor.prototype = new TempCtor(); - ctor.prototype.constructor = ctor; - }; - } - var inherits$1 = inherits; - - // Copyright Joyent, Inc. and other Node contributors. - var formatRegExp = /%[sdj%]/g; - function format$10(f) { - if (!isString$6(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; - } - - // Mark that a method should not be used. - // Returns a modified function which warns once by default. - // If --no-deprecation is set, then it is a no-op. - function deprecate(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return deprecate(fn, msg).apply(this, arguments); - }; - } - - if (process$1.noDeprecation === true) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (process$1.throwDeprecation) { - throw new Error(msg); - } else if (process$1.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; - } - - var debugs = {}; - var debugEnviron; - function debuglog(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process$1.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = 0; - debugs[set] = function() { - var msg = format$10.apply(null, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; - } - - /** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - * @param {Object} obj The object to print out. - * @param {Object} opts Optional options object that alters the output. - */ - /* legacy: obj, showHidden, depth, colors*/ - function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean$1(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - _extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); - } - - // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics - inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] - }; - - // Don't use 'blue' not visible on cmd.exe - inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' - }; - - - function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } - } - - - function stylizeNoColor(str, styleType) { - return str; - } - - - function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - - return hash; - } - - - function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString$6(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray$5(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); - } - - - function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString$6(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber$5(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean$1(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); - } - - - function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; - } - - - function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty$5(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; - } - - - function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty$5(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; - } - - - function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; - } - - - // NOTE: These type checking functions intentionally don't use `instanceof` - // because it is fragile and can be easily faked with `Object.create()`. - function isArray$5(ar) { - return Array.isArray(ar); - } - - function isBoolean$1(arg) { - return typeof arg === 'boolean'; - } - - function isNull(arg) { - return arg === null; - } - - function isNullOrUndefined(arg) { - return arg == null; - } - - function isNumber$5(arg) { - return typeof arg === 'number'; - } - - function isString$6(arg) { - return typeof arg === 'string'; - } - - function isSymbol(arg) { - return typeof arg === 'symbol'; - } - - function isUndefined(arg) { - return arg === void 0; - } - - function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; - } - - function isObject(arg) { - return typeof arg === 'object' && arg !== null; - } - - function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; - } - - function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); - } - - function isFunction(arg) { - return typeof arg === 'function'; - } - - function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; - } - - function isBuffer(maybeBuf) { - return Buffer.isBuffer(maybeBuf); - } - - function objectToString(o) { - return Object.prototype.toString.call(o); - } - - - function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); - } - - - var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - - // 26 Feb 16:19:34 - function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); - } - - - // log is just a thin wrapper to console.log that prepends a timestamp - function log$3() { - console.log('%s - %s', timestamp(), format$10.apply(null, arguments)); - } - - function _extend(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; - } - function hasOwnProperty$5(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); - } - - var util$1 = { - inherits: inherits$1, - _extend: _extend, - log: log$3, - isBuffer: isBuffer, - isPrimitive: isPrimitive, - isFunction: isFunction, - isError: isError, - isDate: isDate, - isObject: isObject, - isRegExp: isRegExp, - isUndefined: isUndefined, - isSymbol: isSymbol, - isString: isString$6, - isNumber: isNumber$5, - isNullOrUndefined: isNullOrUndefined, - isNull: isNull, - isBoolean: isBoolean$1, - isArray: isArray$5, - inspect: inspect, - deprecate: deprecate, - format: format$10, - debuglog: debuglog - } - - var node$2 = createCommonjsModule(function (module, exports) { - /** - * Module dependencies. - */ - - - - - /** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. - */ - - exports = module.exports = debug; - exports.init = init; - exports.log = log; - exports.formatArgs = formatArgs; - exports.save = save; - exports.load = load; - exports.useColors = useColors; - - /** - * Colors. - */ - - exports.colors = [6, 2, 3, 4, 5, 1]; - - /** - * Build up the default `inspectOpts` object from the environment variables. - * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js - */ - - exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); - }).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); - - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); - - obj[prop] = val; - return obj; - }, {}); - - /** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ - - var fd = parseInt(process.env.DEBUG_FD, 10) || 2; - - if (1 !== fd && 2 !== fd) { - util$1.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')(); - } - - var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); - - /** - * Is stdout a TTY? Colored output is enabled when `true`. - */ - - function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); - } - - /** - * Map %o to `util.inspect()`, all on a single line. - */ - - exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util$1.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); - }; - - /** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ - - exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util$1.inspect(v, this.inspectOpts); - }; - - /** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ - - function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; - - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; - - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } - } - - /** - * Invokes `util.format()` with the specified arguments and writes to `stream`. - */ - - function log() { - return stream.write(util$1.format.apply(util$1, arguments) + '\n'); - } - - /** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ - - function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } - } - - /** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ - - function load() { - return process.env.DEBUG; - } - - /** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ - - function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); - - // Note stream._type is used for test-module-load-list.js - - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; - - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - case 'FILE': - var fs = require$$2; - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = require$$2; - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); - - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; - - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; - } - - /** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ - - function init (debug$$1) { - debug$$1.inspectOpts = {}; - - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug$$1.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } - } - - /** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - - exports.enable(load()); - }); - var node_1 = node$2.init; - var node_2 = node$2.log; - var node_3 = node$2.formatArgs; - var node_4 = node$2.save; - var node_5 = node$2.load; - var node_6 = node$2.useColors; - var node_7 = node$2.colors; - var node_8 = node$2.inspectOpts; - - var src = createCommonjsModule(function (module) { - /** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. - */ - - if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = browser; - } else { - module.exports = node$2; - } - }); - - /** - * Module dependencies. - */ - - var debug$1 = src('xml-parser'); - - /** - * Expose `parse`. - */ - - var xmlParser = parse$3; - - /** - * Parse the given string of `xml`. - * - * @param {String} xml - * @return {Object} - * @api public - */ - - function parse$3(xml) { - xml = xml.trim(); - - // strip comments - xml = xml.replace(//g, ''); - - return document(); - - /** - * XML document. - */ - - function document() { - return { - declaration: declaration(), - root: tag() - } - } - - /** - * Declaration. - */ - - function declaration() { - var m = match(/^<\?xml\s*/); - if (!m) return; - - // tag - var node = { - attributes: {} - }; - - // attributes - while (!(eos() || is('?>'))) { - var attr = attribute(); - if (!attr) return node; - node.attributes[attr.name] = attr.value; - } - - match(/\?>\s*/); - - return node; - } - - /** - * Tag. - */ - - function tag() { - debug$1('tag %j', xml); - var m = match(/^<([\w-:.]+)\s*/); - if (!m) return; - - // name - var node = { - name: m[1], - attributes: {}, - children: [] - }; - - // attributes - while (!(eos() || is('>') || is('?>') || is('/>'))) { - var attr = attribute(); - if (!attr) return node; - node.attributes[attr.name] = attr.value; - } - - // self closing tag - if (match(/^\s*\/>\s*/)) { - return node; - } - - match(/\??>\s*/); - - // content - node.content = content(); - - // children - var child; - while (child = tag()) { - node.children.push(child); - } - - // closing - match(/^<\/[\w-:.]+>\s*/); - - return node; - } - - /** - * Text content. - */ - - function content() { - debug$1('content %j', xml); - var m = match(/^([^<]*)/); - if (m) return m[1]; - return ''; - } - - /** - * Attribute. - */ - - function attribute() { - debug$1('attribute %j', xml); - var m = match(/([\w:-]+)\s*=\s*("[^"]*"|'[^']*'|\w+)\s*/); - if (!m) return; - return { name: m[1], value: strip(m[2]) } - } - - /** - * Strip quotes from `val`. - */ - - function strip(val) { - return val.replace(/^['"]|['"]$/g, ''); - } - - /** - * Match `re` and advance the string. - */ - - function match(re) { - var m = xml.match(re); - if (!m) return; - xml = xml.slice(m[0].length); - return m; - } - - /** - * End-of-source. - */ - - function eos() { - return 0 == xml.length; - } - - /** - * Check for `prefix`. - */ - - function is(prefix) { - return 0 == xml.indexOf(prefix); - } - } - - // I would need var parseString = require('../node_modules/xml-parser/index.js'); for urequire? - - // fix missing semicolons - const entities = { - "Α": "\\Alpha", - "Α": "\\Alpha", - "Α": "\\Alpha", - "\\u0391;": "\\Alpha", - "Β": "\\Beta", - "Β": "\\Beta", - "Β": "\\Beta", - "\\u0392;": "\\Beta", - "Γ": "\\Gamma", - "Γ": "\\Gamma", - "Γ": "\\Gamma", - "\\u0393;": "\\Gamma", - "Δ": "\\Delta", - "Δ": "\\Delta", - "Δ": "\\Delta", - "\\u0394;": "\\Delta", - "Ε": "\\Epsilon", - "Ε": "\\Epsilon", - "Ε": "\\Epsilon", - "\\u0395;": "\\Epsilon", - "Ζ": "\\Zeta", - "Ζ": "\\Zeta", - "Ζ": "\\Zeta", - "\\u0396;": "\\Zeta", - "Η": "\\Eta", - "Η": "\\Eta", - "Η": "\\Eta", - "\\u0397;": "\\Eta", - "Θ": "\\Theta", - "Θ": "\\Theta", - "Θ": "\\Theta", - "\\u0398;": "\\Theta", - "Ι": "\\Iota", - "Ι": "\\Iota", - "Ι": "\\Iota", - "\\u0399;": "\\Iota", - "Κ": "\\Kappa", - "Κ": "\\Kappa", - "Κ": "\\Kappa", - "\\u039A;": "\\Kappa", - "Λ": "\\Lambda", - "Λ": "\\Lambda", - "Λ": "\\Lambda", - "\\u039B;": "\\Lambda", - "Μ": "\\Mu", - "Μ": "\\Mu", - "Μ": "\\Mu", - "\\u039C;": "\\Mu", - "Ν": "\\Nu", - "Ν": "\\Nu", - "Ν": "\\Nu", - "\\u039D;": "\\Nu", - "Ξ": "\\Xi", - "Ξ": "\\Xi", - "Ξ": "\\Xi", - "\\u039E;": "\\Xi", - "Ο": "\\Omicron", - "Ο": "\\Omicron", - "Ο": "\\Omicron", - "\\u039F;": "\\Omicron", - "Π": "\\Pi", - "Π": "\\Pi", - "Π": "\\Pi", - "\\u03A0;": "\\Pi", - "Ρ": "\\Rho", - "Ρ": "\\Rho", - "Ρ": "\\Rho", - "\\u03A1;": "\\Rho", - "Σ": "\\Sigma", - "Σ": "\\Sigma", - "Σ": "\\Sigma", - "\\u03A3;": "\\Sigma", - "Τ": "\\Tau", - "Τ": "\\Tau", - "Τ": "\\Tau", - "\\u03A4;": "\\Tau", - "Υ": "\\Upsilon", - "Υ": "\\Upsilon", - "Υ": "\\Upsilon", - "\\u03A5;": "\\Upsilon", - "Φ": "\\Phi", - "Φ": "\\Phi", - "Φ": "\\Phi", - "\\u03A6;": "\\Phi", - "Χ": "\\Chi", - "Χ": "\\Chi", - "Χ": "\\Chi", - "\\u03A7;": "\\Chi", - "Ψ": "\\Psi", - "Ψ": "\\Psi", - "Ψ": "\\Psi", - "\\u03A8;": "\\Psi", - "Ω": "\\Omega", - "Ω": "\\Omega", - "Ω": "\\Omega", - "\\u03A9;": "\\Omega", - "α": "\\alpha", - "α": "\\alpha", - "α": "\\alpha", - "\\u03B1;": "\\alpha", - "β": "\\beta", - "β": "\\beta", - "β": "\\beta", - "\\u03B2;": "\\beta", - "γ": "\\gamma", - "γ": "\\gamma", - "γ": "\\gamma", - "\\u03B3;": "\\gamma", - "δ": "\\delta", - "δ": "\\delta", - "δ": "\\delta", - "\\u03B4;": "\\delta", - "ε": "\\epsilon", - "ε": "\\epsilon", - "ε": "\\epsilon", - "\\u03B5;": "\\epsilon", - "ζ": "\\zeta", - "ζ": "\\zeta", - "ζ": "\\zeta", - "\\u03B6;": "\\zeta", - "η": "\\eta", - "η": "\\eta", - "η": "\\eta", - "\\u03B7;": "\\eta", - "θ": "\\theta", - "θ": "\\theta", - "θ": "\\theta", - "\\u03B8;": "\\theta", - "ι": "\\iota", - "ι": "\\iota", - "ι": "\\iota", - "\\u03B9;": "\\iota", - "κ": "\\kappa", - "κ": "\\kappa", - "κ": "\\kappa", - "\\u03BA;": "\\kappa", - "λ": "\\lambda", - "λ": "\\lambda", - "λ": "\\lambda", - "\\u03BB;": "\\lambda", - "μ": "\\mu", - "μ": "\\mu", - "μ": "\\mu", - "\\u03BC;": "\\mu", - "ν": "\\nu", - "ν": "\\nu", - "ν": "\\nu", - "\\u03BD;": "\\nu", - "ξ": "\\xi", - "ξ": "\\xi", - "ξ": "\\xi", - "\\u03BE;": "\\xi", - "ο": "\\omicron", - "ο": "\\omicron", - "ο": "\\omicron", - "\\u03BF;": "\\omicron", - "π": "\\pi", - "π": "\\pi", - "π": "\\pi", - "\\u03C0;": "\\pi", - "ρ": "\\rho", - "ρ": "\\rho", - "ρ": "\\rho", - "\\u03C1;": "\\rho", - "ς": "\\sigma", - ";": "\\sigma", - "ς": "\\sigma", - "\\u03C2;": "\\sigma", - "σ": "\\sigma", - "σ": "\\sigma", - "σ": "\\sigma", - "\\u03C3;": "\\sigma", - "τ": "\\tau", - "τ": "\\tau", - "τ": "\\tau", - "\\u03C4;": "\\tau", - "υ": "\\upsilon", - "υ": "\\upsilon", - "υ": "\\upsilon", - "\\u03C5;": "\\upsilon", - "φ": "\\phi", - "φ": "\\phi", - "φ": "\\phi", - "\\u03C6;": "\\phi", - "χ": "\\chi", - "χ": "\\chi", - "χ": "\\chi", - "\\u03C7;": "\\chi", - "ψ": "\\psi", - "ψ": "\\psi", - "ψ": "\\psi", - "\\u03C8;": "\\psi", - "ω": "\\omega", - "ω": "\\omega", - "ω": "\\omega", - "\\u03C9;": "\\omega", - "−": "-", - "−": "-", - "∞": "\\infty", - "∞": "\\infty", - "∞": "\\infty", - "⋅": "\\cdot", - "⋅": "\\cdot", - "⋅": "\\cdot", - "×": "\\times", - "×": "\\times", - "×": "\\times" - }; - - class mmlToLatex{ - - // This is an awfully weak MathML parser, but it's good enough for what MathJax generates - parse(mml) { - // math identifier - if (mml.name === 'mi') { - if (entities[mml.content]) { - return entities[mml.content]; - } - - if (mml.content.length > 1) { - return "\\" + mml.content; - } else { - return mml.content; - } - }else if (mml.name === 'mn') { // math number - return mml.content; - }else if (mml.name === 'msup') { // superscript - return this.parse( mml.children[0] ) + '^{' + this.parse( mml.children[1] ) + "}"; - }else if (mml.name === 'mroot') {// root - return "\\sqrt[" + this.parse( mml.children[1] ) + ']{' + this.parse( mml.children[1] ) + "}"; - }else if (mml.name === 'mfrac') { - return "\\frac{" + this.parse( mml.children[0] ) + '}{' + this.parse( mml.children[1] ) + "}"; - }else if (mml.name === 'msqrt') { // superscript - return "\\sqrt{" + mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' ') + "}"; - }else if (mml.name === 'mo') { // math operator - if (entities[mml.content]) { - return entities[mml.content]; - } else if (mml.content === '⁡') { - return ' '; - } else { - return mml.content; - } - }else if ((mml.name === "mrow") && (mml.attributes.class === "MJX-TeXAtom-ORD")) { - return mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' '); - } else if ((mml.name === 'math') || (mml.name === 'mrow')) { - return '(' + mml.children.map( function(v,i) { return this.parse(v); }.bind(this) ).join(' ') + ')'; - } - } - - convert(xml) { - var result = this.parse( xmlParser(xml).root ); - // console.log( "parsed =", JSON.stringify(result) ); - return result; - }; - - } - - class mmlToAst{ - constructor(){ - this.mmlToLatex = new mmlToLatex(); - this.latexToAst = new latexToAst(); - } - - convert(mml){ - return this.latexToAst.convert(this.mmlToLatex.convert(mml)); - } - } - - class mmlToGuppy{ - constructor(){ - this.mmlToLatex = new mmlToLatex(); - this.latexToAst = new latexToAst(); - this.astToGuppy = new astToGuppy(); - } - - convert(mml){ - return this.astToGuppy.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); - } - } - - class mmlToMathjs{ - constructor(){ - this.mmlToLatex = new mmlToLatex(); - this.latexToAst = new latexToAst(); - this.astToMathjs = new astToMathjs(); - } - - convert(mml){ - return this.astToMathjs.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); - } - } - - class mmlToText{ - constructor(){ - this.mmlToLatex = new mmlToLatex(); - this.latexToAst = new latexToAst(); - this.astToText = new astToText(); - } - - convert(mml){ - return this.astToText.convert(this.latexToAst.convert(this.mmlToLatex.convert(mml))); - } - } - - class textToGuppy{ - constructor(){ - this.textToAst = new textToAst(); - this.astToGuppy = new astToGuppy(); - } - - convert(text){ - return this.astToGuppy.convert(this.textToAst.convert(text)); - } - } - - class textToLatex{ - constructor(){ - this.textToAst = new textToAst(); - this.astToLatex = new astToLatex(); - } - - convert(text){ - return this.astToLatex.convert(this.textToAst.convert(text)); - } - } - - class textToMathjs{ - constructor(){ - this.textToAst = new textToAst(); - this.astToMathjs = new astToMathjs(); - } - - convert(text){ - return this.astToMathjs.convert(this.textToAst.convert(text)); - } - } - - - - var converters = /*#__PURE__*/Object.freeze({ - astToLatexObj: astToLatex, - astToTextObj: astToText, - astToGuppyObj: astToGuppy, - astToMathjsObj: astToMathjs, - latexToAstObj: latexToAst, - latexToGuppyObj: latexToGuppy, - latexToMathjsObj: latexToMathjs, - latexToTextObj: latexToText, - mathjsToAstObj: mathjsToAst, - mathjsToGuppyObj: mathjsToGuppy, - mathjsToLatexObj: mathjsToLatex, - mathjsToTextObj: mathjsToText, - mmlToAstObj: mmlToAst, - mmlToGuppyObj: mmlToGuppy, - mmlToLatexObj: mmlToLatex, - mmlToMathjsObj: mmlToMathjs, - mmlToTextObj: mmlToText, - textToAstObj: textToAst, - textToGuppyObj: textToGuppy, - textToLatexObj: textToLatex, - textToMathjsObj: textToMathjs, - astToGLSL: astToGLSL - }); - - var textToAst$4 = new textToAst(); - var latexToAst$1 = new latexToAst(); - var mmlToAst$1 = new mmlToAst(); - - var utils$2 = { match, flatten, unflattenLeft, unflattenRight }; - - function Expression(ast, context) { - this.tree = flatten(ast); - this.context = context; - - this.toJSON = function () { - let serializedExpression = { - objectType: "math-expression", - tree: this.tree, - }; - let assumptions = {}; - for(let item in this.context.assumptions) { - if(Object.keys(this.context.assumptions[item]).length > 0) { - assumptions[item] = this.context.assumptions[item]; - } - } - if(Object.keys(assumptions).length > 0) { - serializedExpression.assumptions = assumptions; - } - - return serializedExpression; - }; - } - - function extend$4(object, tree_to_expression) { - // if tree_to_expression, convert ast to expression - - // arguments object is NOT an array - var args = flatten_array(Array.prototype.slice.call(arguments, 2)); - - args.forEach( - function (rhs) { - if (rhs) { - for (var property in rhs) { - if (tree_to_expression) { - (function () { - var prop = property; - object[prop] = function () { - return this.fromAst( - rhs[prop].apply(null, arguments)); - }; - })(); - } - else - object[property] = rhs[property]; - } - } - } - ); - - return object; - } - - function extend_prototype(object, tree_to_expression) { - // append a properties to object prepending this as first argument - // if tree_to_expression, convert ast to expression - - // arguments object is NOT an array - var args = flatten_array(Array.prototype.slice.call(arguments, 2)); - - args.forEach( - function (rhs) { - if (rhs) { - for (var property in rhs) { - // prepend this as first argument - (function () { - var prop = property; - object[prop] = function () { - var arg2 = [this].concat( - Array.prototype.slice.call(arguments)); - // convert to expression if output_expression - if (tree_to_expression) - return this.context.fromAst( - rhs[prop].apply(null, arg2)); - else - return rhs[prop].apply(null, arg2); - }; - })(); - } - } - } - ); - - return object; - } - - - - /****************************************************************/ - /* Factory methods */ - - function create_from_multiple(expr, pars) { - if (Array.isArray(expr) || (typeof expr === 'number')) { - return new Expression(expr, Context); - } - else if (typeof expr === 'string') { - try { - return new Expression(textToAst$4.convert(expr), Context); - } - catch (e_text) { - try { - return new Expression(latexToAst$1.convert(expr), Context); - } - catch (e_latex) { - try { - return new Expression(mmlToAst$1.convert(expr), Context); - } - catch (e_mml) { - if (expr.indexOf("\\") !== -1) - throw (e_latex) - if (expr.indexOf("demo of math-expressions - +

demo of math-expressions

@@ -13,13 +13,13 @@

demo of math-expressions

Left hand TeX:

- +
Right hand side:

Right hand TeX:

- +

LHS = RHS?

diff --git a/package-lock.json b/package-lock.json index 2e1285b..5ec0fcd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -938,9 +938,9 @@ } }, "browserify-cipher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", - "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", "dev": true, "requires": { "browserify-aes": "^1.0.4", @@ -949,14 +949,23 @@ } }, "browserify-des": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", - "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } } }, "browserify-fs": { @@ -1290,9 +1299,9 @@ "dev": true }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -1346,9 +1355,9 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-ecdh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", - "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", "dev": true, "requires": { "bn.js": "^4.1.0", @@ -1356,21 +1365,22 @@ } }, "create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", - "ripemd160": "^2.0.0", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", "sha.js": "^2.4.0" } }, "create-hmac": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", - "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "dev": true, "requires": { "cipher-base": "^1.0.3", @@ -1592,9 +1602,9 @@ "dev": true }, "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -1622,9 +1632,9 @@ "dev": true }, "diffie-hellman": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", - "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", "dev": true, "requires": { "bn.js": "^4.1.0", @@ -1695,9 +1705,9 @@ } }, "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -2797,22 +2807,23 @@ } }, "hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", "dev": true, "requires": { - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "^1.0.1" } }, "hmac-drbg": { @@ -4556,24 +4567,21 @@ } }, "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" }, "dependencies": { - "hash-base": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", - "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true } } }, @@ -4685,9 +4693,9 @@ "dev": true }, "minimalistic-assert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", - "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", "dev": true }, "minimalistic-crypto-utils": { @@ -5074,16 +5082,17 @@ "dev": true }, "parse-asn1": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", - "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", "dev": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" } }, "parse-glob": { @@ -5167,9 +5176,9 @@ } }, "pbkdf2": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz", - "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "dev": true, "requires": { "create-hash": "^1.1.2", @@ -5319,16 +5328,25 @@ "dev": true }, "public-encrypt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", - "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1" + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "dev": true + } } }, "punycode": { @@ -5366,9 +5384,9 @@ } }, "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { "safe-buffer": "^5.1.0" @@ -5686,12 +5704,12 @@ } }, "ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dev": true, "requires": { - "hash-base": "^2.0.0", + "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, @@ -5749,6 +5767,43 @@ "process-es6": "^0.11.2" } }, + "rollup-plugin-node-globals": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-globals/-/rollup-plugin-node-globals-1.4.0.tgz", + "integrity": "sha512-xRkB+W/m1KLIzPUmG0ofvR+CPNcvuCuNdjVBVS7ALKSxr3EDhnzNceGkGi1m8MToSli13AzKFYH4ie9w3I5L3g==", + "dev": true, + "requires": { + "acorn": "^5.7.3", + "buffer-es6": "^4.9.3", + "estree-walker": "^0.5.2", + "magic-string": "^0.22.5", + "process-es6": "^0.11.6", + "rollup-pluginutils": "^2.3.1" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "estree-walker": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz", + "integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==", + "dev": true + }, + "magic-string": { + "version": "0.22.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz", + "integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==", + "dev": true, + "requires": { + "vlq": "^0.2.2" + } + } + } + }, "rollup-plugin-node-resolve": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-3.4.0.tgz", @@ -7463,6 +7518,12 @@ "extsprintf": "^1.2.0" } }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==", + "dev": true + }, "w3c-hr-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", diff --git a/package.json b/package.json index f0f4b66..ac4091d 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "rollup": "^0.57.1", "rollup-plugin-commonjs": "^9.3.4", "rollup-plugin-node-builtins": "^2.1.2", + "rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-node-resolve": "^3.4.0" }, "jest": { diff --git a/rollup.config.js b/rollup.config.js index b5d6169..1d5db8f 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,21 +1,20 @@ // rollup.config.js import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; +import globals from 'rollup-plugin-node-globals'; import builtins from 'rollup-plugin-node-builtins'; export default { input: 'lib/math-expressions.js', - output: [{ - file: 'build/math-expressions_umd.js', + output: { + file: 'build/math-expressions.js', format: 'umd', name: 'MathExpression' - },{ - file: 'build/math-expressions.js', - format: 'es' - }], + }, plugins: [ resolve(), commonjs(), + globals(), builtins() ] };