mirror of
https://github.com/josdejong/mathjs.git
synced 2025-12-08 19:46:04 +00:00
14185 lines
375 KiB
JavaScript
14185 lines
375 KiB
JavaScript
/**
|
|
* math.js
|
|
* https://github.com/josdejong/mathjs
|
|
*
|
|
* Math.js is an extensive math library for JavaScript and Node.js,
|
|
* It features real and complex numbers, units, matrices, a large set of
|
|
* mathematical functions, and a flexible expression parser.
|
|
*
|
|
* @version 0.13.0
|
|
* @date 2013-09-03
|
|
*
|
|
* @license
|
|
* Copyright (C) 2013 Jos de Jong <wjosdejong@gmail.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License. You may obtain a copy
|
|
* of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
(function(e){if("function"==typeof bootstrap)bootstrap("math",e);else if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else if("undefined"!=typeof ses){if(!ses.ok())return;ses.makeMath=e}else"undefined"!=typeof window?window.math=e():global.math=e()})(function(){var define,ses,bootstrap,module,exports;
|
|
return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
|
|
// options (global configuration settings)
|
|
exports.options = require('./lib/options');
|
|
|
|
// expression (Parser, Scope, nodes, docs)
|
|
exports.expression = {};
|
|
exports.expression.node = require('./lib/expression/node/index.js');
|
|
exports.expression.Scope = require('./lib/expression/Scope.js');
|
|
exports.expression.Parser = require('./lib/expression/Parser.js');
|
|
exports.expression.docs = require('./lib/expression/docs/index.js');
|
|
|
|
// TODO: deprecated since version 0.13.0. cleanup deprecated stuff some day
|
|
exports.expr = {};
|
|
exports.expr.Scope = function () {
|
|
throw new Error('Moved to math.expression.Scope');
|
|
};
|
|
exports.expr.Parser = function () {
|
|
throw new Error('Moved to math.expression.Parser');
|
|
};
|
|
|
|
|
|
// types (Matrix, Complex, Unit, ...)
|
|
exports.type = {};
|
|
exports.type.Complex = require('./lib/type/Complex.js');
|
|
exports.type.Range = require('./lib/type/Range.js');
|
|
exports.type.Index = require('./lib/type/Index.js');
|
|
exports.type.Matrix = require('./lib/type/Matrix.js');
|
|
exports.type.Unit = require('./lib/type/Unit.js');
|
|
exports.type.Help = require('./lib/type/Help.js');
|
|
|
|
exports.collection = require('./lib/type/collection.js');
|
|
|
|
// expression parser
|
|
require('./lib/function/expression/eval.js')(exports);
|
|
require('./lib/function/expression/help.js')(exports);
|
|
require('./lib/function/expression/parse.js')(exports);
|
|
|
|
// functions - arithmetic
|
|
require('./lib/function/arithmetic/abs.js')(exports);
|
|
require('./lib/function/arithmetic/add.js')(exports);
|
|
require('./lib/function/arithmetic/add.js')(exports);
|
|
require('./lib/function/arithmetic/ceil.js')(exports);
|
|
require('./lib/function/arithmetic/cube.js')(exports);
|
|
require('./lib/function/arithmetic/divide.js')(exports);
|
|
require('./lib/function/arithmetic/edivide.js')(exports);
|
|
require('./lib/function/arithmetic/emultiply.js')(exports);
|
|
require('./lib/function/arithmetic/epow.js')(exports);
|
|
require('./lib/function/arithmetic/equal.js')(exports);
|
|
require('./lib/function/arithmetic/exp.js')(exports);
|
|
require('./lib/function/arithmetic/fix.js')(exports);
|
|
require('./lib/function/arithmetic/floor.js')(exports);
|
|
require('./lib/function/arithmetic/gcd.js')(exports);
|
|
require('./lib/function/arithmetic/larger.js')(exports);
|
|
require('./lib/function/arithmetic/largereq.js')(exports);
|
|
require('./lib/function/arithmetic/lcm.js')(exports);
|
|
require('./lib/function/arithmetic/log.js')(exports);
|
|
require('./lib/function/arithmetic/log10.js')(exports);
|
|
require('./lib/function/arithmetic/mod.js')(exports);
|
|
require('./lib/function/arithmetic/multiply.js')(exports);
|
|
require('./lib/function/arithmetic/pow.js')(exports);
|
|
require('./lib/function/arithmetic/round.js')(exports);
|
|
require('./lib/function/arithmetic/sign.js')(exports);
|
|
require('./lib/function/arithmetic/smaller.js')(exports);
|
|
require('./lib/function/arithmetic/smallereq.js')(exports);
|
|
require('./lib/function/arithmetic/sqrt.js')(exports);
|
|
require('./lib/function/arithmetic/square.js')(exports);
|
|
require('./lib/function/arithmetic/subtract.js')(exports);
|
|
require('./lib/function/arithmetic/unary.js')(exports);
|
|
require('./lib/function/arithmetic/unequal.js')(exports);
|
|
require('./lib/function/arithmetic/xgcd.js')(exports);
|
|
|
|
// functions - complex
|
|
require('./lib/function/complex/arg.js')(exports);
|
|
require('./lib/function/complex/conj.js')(exports);
|
|
require('./lib/function/complex/re.js')(exports);
|
|
require('./lib/function/complex/im.js')(exports);
|
|
|
|
// functions - construction
|
|
require('./lib/function/construction/boolean.js')(exports);
|
|
require('./lib/function/construction/complex.js')(exports);
|
|
require('./lib/function/construction/index.js')(exports);
|
|
require('./lib/function/construction/matrix.js')(exports);
|
|
require('./lib/function/construction/number.js')(exports);
|
|
require('./lib/function/construction/parser.js')(exports);
|
|
require('./lib/function/construction/string.js')(exports);
|
|
require('./lib/function/construction/unit.js')(exports);
|
|
|
|
// functions - matrix
|
|
require('./lib/function/matrix/concat.js')(exports);
|
|
require('./lib/function/matrix/det.js')(exports);
|
|
require('./lib/function/matrix/diag.js')(exports);
|
|
require('./lib/function/matrix/eye.js')(exports);
|
|
require('./lib/function/matrix/inv.js')(exports);
|
|
require('./lib/function/matrix/ones.js')(exports);
|
|
require('./lib/function/matrix/range.js')(exports);
|
|
require('./lib/function/matrix/size.js')(exports);
|
|
require('./lib/function/matrix/squeeze.js')(exports);
|
|
require('./lib/function/matrix/subset.js')(exports);
|
|
require('./lib/function/matrix/transpose.js')(exports);
|
|
require('./lib/function/matrix/zeros.js')(exports);
|
|
|
|
// functions - probability
|
|
require('./lib/function/probability/factorial.js')(exports);
|
|
require('./lib/function/probability/random.js')(exports);
|
|
|
|
// functions - statistics
|
|
require('./lib/function/statistics/min.js')(exports);
|
|
require('./lib/function/statistics/max.js')(exports);
|
|
|
|
// functions - trigonometry
|
|
require('./lib/function/trigonometry/acos.js')(exports);
|
|
require('./lib/function/trigonometry/asin.js')(exports);
|
|
require('./lib/function/trigonometry/atan.js')(exports);
|
|
require('./lib/function/trigonometry/atan2.js')(exports);
|
|
require('./lib/function/trigonometry/cos.js')(exports);
|
|
require('./lib/function/trigonometry/cot.js')(exports);
|
|
require('./lib/function/trigonometry/csc.js')(exports);
|
|
require('./lib/function/trigonometry/sec.js')(exports);
|
|
require('./lib/function/trigonometry/sin.js')(exports);
|
|
require('./lib/function/trigonometry/tan.js')(exports);
|
|
|
|
// functions - units
|
|
require('./lib/function/units/in.js')(exports);
|
|
|
|
// functions - utils
|
|
require('./lib/function/utils/clone.js')(exports);
|
|
require('./lib/function/utils/format.js')(exports);
|
|
require('./lib/function/utils/import.js')(exports);
|
|
require('./lib/function/utils/select.js')(exports);
|
|
require('./lib/function/utils/typeof.js')(exports);
|
|
require('./lib/function/utils/map.js')(exports);
|
|
require('./lib/function/utils/forEach.js')(exports);
|
|
|
|
// constants
|
|
require('./lib/constants.js')(exports);
|
|
|
|
// selector (we initialize after all functions are loaded)
|
|
exports.chaining = {};
|
|
exports.chaining.Selector = require('./lib/chaining/Selector.js')(exports);
|
|
|
|
// TODO: deprecated since version 0.13.0. Cleanup some day
|
|
exports.expr.Selector = function () {
|
|
throw new Error('Moved to math.expression.Selector');
|
|
};
|
|
|
|
},{"./lib/chaining/Selector.js":2,"./lib/constants.js":3,"./lib/expression/Parser.js":4,"./lib/expression/Scope.js":5,"./lib/expression/docs/index.js":100,"./lib/expression/node/index.js":113,"./lib/function/arithmetic/abs.js":114,"./lib/function/arithmetic/add.js":115,"./lib/function/arithmetic/ceil.js":116,"./lib/function/arithmetic/cube.js":117,"./lib/function/arithmetic/divide.js":118,"./lib/function/arithmetic/edivide.js":119,"./lib/function/arithmetic/emultiply.js":120,"./lib/function/arithmetic/epow.js":121,"./lib/function/arithmetic/equal.js":122,"./lib/function/arithmetic/exp.js":123,"./lib/function/arithmetic/fix.js":124,"./lib/function/arithmetic/floor.js":125,"./lib/function/arithmetic/gcd.js":126,"./lib/function/arithmetic/larger.js":127,"./lib/function/arithmetic/largereq.js":128,"./lib/function/arithmetic/lcm.js":129,"./lib/function/arithmetic/log.js":130,"./lib/function/arithmetic/log10.js":131,"./lib/function/arithmetic/mod.js":132,"./lib/function/arithmetic/multiply.js":133,"./lib/function/arithmetic/pow.js":134,"./lib/function/arithmetic/round.js":135,"./lib/function/arithmetic/sign.js":136,"./lib/function/arithmetic/smaller.js":137,"./lib/function/arithmetic/smallereq.js":138,"./lib/function/arithmetic/sqrt.js":139,"./lib/function/arithmetic/square.js":140,"./lib/function/arithmetic/subtract.js":141,"./lib/function/arithmetic/unary.js":142,"./lib/function/arithmetic/unequal.js":143,"./lib/function/arithmetic/xgcd.js":144,"./lib/function/complex/arg.js":145,"./lib/function/complex/conj.js":146,"./lib/function/complex/im.js":147,"./lib/function/complex/re.js":148,"./lib/function/construction/boolean.js":149,"./lib/function/construction/complex.js":150,"./lib/function/construction/index.js":151,"./lib/function/construction/matrix.js":152,"./lib/function/construction/number.js":153,"./lib/function/construction/parser.js":154,"./lib/function/construction/string.js":155,"./lib/function/construction/unit.js":156,"./lib/function/expression/eval.js":157,"./lib/function/expression/help.js":158,"./lib/function/expression/parse.js":159,"./lib/function/matrix/concat.js":160,"./lib/function/matrix/det.js":161,"./lib/function/matrix/diag.js":162,"./lib/function/matrix/eye.js":163,"./lib/function/matrix/inv.js":164,"./lib/function/matrix/ones.js":165,"./lib/function/matrix/range.js":166,"./lib/function/matrix/size.js":167,"./lib/function/matrix/squeeze.js":168,"./lib/function/matrix/subset.js":169,"./lib/function/matrix/transpose.js":170,"./lib/function/matrix/zeros.js":171,"./lib/function/probability/factorial.js":172,"./lib/function/probability/random.js":173,"./lib/function/statistics/max.js":174,"./lib/function/statistics/min.js":175,"./lib/function/trigonometry/acos.js":176,"./lib/function/trigonometry/asin.js":177,"./lib/function/trigonometry/atan.js":178,"./lib/function/trigonometry/atan2.js":179,"./lib/function/trigonometry/cos.js":180,"./lib/function/trigonometry/cot.js":181,"./lib/function/trigonometry/csc.js":182,"./lib/function/trigonometry/sec.js":183,"./lib/function/trigonometry/sin.js":184,"./lib/function/trigonometry/tan.js":185,"./lib/function/units/in.js":186,"./lib/function/utils/clone.js":187,"./lib/function/utils/forEach.js":188,"./lib/function/utils/format.js":189,"./lib/function/utils/import.js":190,"./lib/function/utils/map.js":191,"./lib/function/utils/select.js":192,"./lib/function/utils/typeof.js":193,"./lib/options":194,"./lib/type/Complex.js":195,"./lib/type/Help.js":196,"./lib/type/Index.js":197,"./lib/type/Matrix.js":198,"./lib/type/Range.js":199,"./lib/type/Unit.js":200,"./lib/type/collection.js":201}],2:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../util/index.js'),
|
|
string = util.string;
|
|
|
|
/**
|
|
* @constructor Selector
|
|
* Wrap any value in a Selector, allowing to perform chained operations on
|
|
* the value.
|
|
*
|
|
* All methods available in the math.js library can be called upon the selector,
|
|
* and then will be evaluated with the value itself as first argument.
|
|
* The selector can be closed by executing selector.done(), which will return
|
|
* the final value.
|
|
*
|
|
* The Selector has a number of special functions:
|
|
* - done() Finalize the chained operation and return the selectors value.
|
|
* - valueOf() The same as done()
|
|
* - toString() Executes math.format() onto the selectors value, returning
|
|
* a string representation of the value.
|
|
*
|
|
* @param {*} [value]
|
|
*/
|
|
function Selector (value) {
|
|
if (!(this instanceof Selector)) {
|
|
throw new SyntaxError(
|
|
'Selector constructor must be called with the new operator');
|
|
}
|
|
|
|
if (value instanceof Selector) {
|
|
this.value = value.value;
|
|
}
|
|
else {
|
|
this.value = value;
|
|
}
|
|
}
|
|
|
|
Selector.prototype = {
|
|
/**
|
|
* Close the selector. Returns the final value.
|
|
* Does the same as method valueOf()
|
|
* @returns {*} value
|
|
*/
|
|
done: function () {
|
|
return this.value;
|
|
},
|
|
|
|
/**
|
|
* Get a submatrix or subselection from current value.
|
|
* Only applicable when the current value has a method get.
|
|
*/
|
|
// TODO: Selector.get is deprecated since version 0.13.0, remove it some day
|
|
get: function (index) {
|
|
throw new Error('Selector.get is removed. Use Selector.subset(index) instead.')
|
|
},
|
|
|
|
/**
|
|
* Set a submatrix or subselection on current value.
|
|
* Only applicable when the current value has a method set.
|
|
*/
|
|
// TODO: Selector.get is deprecated since version 0.13.0, remove it some day
|
|
set: function (index, replacement) {
|
|
throw new Error('Selector.set is removed. Use Selector.subset(index, replacement) instead.')
|
|
},
|
|
|
|
/**
|
|
* Close the selector. Returns the final value.
|
|
* Does the same as method done()
|
|
* @returns {*} value
|
|
*/
|
|
valueOf: function () {
|
|
return this.value;
|
|
},
|
|
|
|
/**
|
|
* Get the string representation of the value in the selector
|
|
* @returns {String}
|
|
*/
|
|
toString: function () {
|
|
return string.format(this.value);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Create a proxy method for the selector
|
|
* @param {String} name
|
|
* @param {*} value The value or function to be proxied
|
|
*/
|
|
function createProxy(name, value) {
|
|
var slice = Array.prototype.slice;
|
|
if (typeof value === 'function') {
|
|
// a function
|
|
Selector.prototype[name] = function () {
|
|
var args = [this.value].concat(slice.call(arguments, 0));
|
|
return new Selector(value.apply(this, args));
|
|
}
|
|
}
|
|
else {
|
|
// a constant
|
|
Selector.prototype[name] = new Selector(value);
|
|
}
|
|
}
|
|
|
|
Selector.createProxy = createProxy;
|
|
|
|
/**
|
|
* initialise the Chain prototype with all functions and constants in math
|
|
*/
|
|
for (var prop in math) {
|
|
if (math.hasOwnProperty(prop) && prop) {
|
|
createProxy(prop, math[prop]);
|
|
}
|
|
}
|
|
|
|
util.types.addType('selector', Selector);
|
|
|
|
return Selector;
|
|
};
|
|
|
|
},{"../util/index.js":205}],3:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var Complex = require('./type/Complex.js');
|
|
|
|
math.pi = Math.PI;
|
|
math.e = Math.E;
|
|
math.tau = Math.PI * 2;
|
|
math.i = new Complex(0, 1);
|
|
|
|
math['Infinity'] = Infinity;
|
|
math['NaN'] = NaN;
|
|
math['true'] = true;
|
|
math['false'] = false;
|
|
|
|
// uppercase constants (for compatibility with built-in Math)
|
|
math.E = Math.E;
|
|
math.LN2 = Math.LN2;
|
|
math.LN10 = Math.LN10;
|
|
math.LOG2E = Math.LOG2E;
|
|
math.LOG10E = Math.LOG10E;
|
|
math.PI = Math.PI;
|
|
math.SQRT1_2 = Math.SQRT1_2;
|
|
math.SQRT2 = Math.SQRT2;
|
|
};
|
|
|
|
},{"./type/Complex.js":195}],4:[function(require,module,exports){
|
|
var Scope = require('./Scope.js');
|
|
|
|
/**
|
|
* @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
|
|
* parser.set(name, value); // set a variable in the parser
|
|
* parser.remove(name); // clear a variable from the
|
|
* // parsers scope
|
|
* parser.clear(); // clear the parsers scope
|
|
*
|
|
* // it is possible to parse an expression into a node tree:
|
|
* var node = parser.parse(expr); // parse an expression into a node tree
|
|
* var result = node.eval(); // evaluate a parsed node
|
|
*
|
|
* Example usage:
|
|
* var parser = new Parser(math);
|
|
* // 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();
|
|
*
|
|
*
|
|
* @param {Object} math Link to the math.js namespace
|
|
*/
|
|
function Parser(math) {
|
|
if (!(this instanceof Parser)) {
|
|
throw new SyntaxError(
|
|
'Parser constructor must be called with the new operator');
|
|
}
|
|
|
|
this.math = math;
|
|
this.scope = new Scope(math);
|
|
}
|
|
|
|
/**
|
|
* Parse an expression end return the parsed function node.
|
|
* The node can be evaluated via node.eval()
|
|
* @param {String} expr
|
|
* @return {Node} node
|
|
* @throws {Error}
|
|
*/
|
|
Parser.prototype.parse = function (expr) {
|
|
// TODO: validate arguments
|
|
return this.math.parse(expr, this.scope);
|
|
};
|
|
|
|
/**
|
|
* Parse and evaluate the given expression
|
|
* @param {String} expr A string containing an expression, for example "2+3"
|
|
* @return {*} result The result, or undefined when the expression was empty
|
|
* @throws {Error}
|
|
*/
|
|
Parser.prototype.eval = function (expr) {
|
|
// TODO: validate arguments
|
|
var node = this.math.parse(expr, this.scope);
|
|
return node.eval();
|
|
};
|
|
|
|
/**
|
|
* Get a variable (a function or variable) by name from the parsers scope.
|
|
* Returns undefined when not found
|
|
* @param {String} name
|
|
* @return {* | undefined} value
|
|
*/
|
|
Parser.prototype.get = function (name) {
|
|
// TODO: validate arguments
|
|
return this.scope.get(name);
|
|
};
|
|
|
|
/**
|
|
* 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 this.scope.set(name, value);
|
|
};
|
|
|
|
/**
|
|
* Remove a variable from the parsers scope
|
|
* @param {String} name
|
|
*/
|
|
Parser.prototype.remove = function (name) {
|
|
// TODO: validate arguments
|
|
this.scope.remove(name);
|
|
};
|
|
|
|
/**
|
|
* Clear the scope with variables and functions
|
|
*/
|
|
Parser.prototype.clear = function () {
|
|
this.scope.clear();
|
|
};
|
|
|
|
module.exports = Parser;
|
|
|
|
},{"./Scope.js":5}],5:[function(require,module,exports){
|
|
var Unit = require('../type/Unit.js');
|
|
|
|
/**
|
|
* Scope
|
|
* A scope stores values of symbols: variables and functions.
|
|
*
|
|
* Syntax:
|
|
* var scope = new Scope(math);
|
|
* var scope = new Scope(math, parentScope);
|
|
* var scope = new Scope(math, symbols);
|
|
* var scope = new Scope(math, parentScope, symbols);
|
|
*
|
|
* Where:
|
|
* {Object} math Link to the (static) math.js namespace
|
|
* {Scope | Object} parentScope Scope will be linked to a parent scope,
|
|
* which is traversed when resolving
|
|
* symbols.
|
|
* {Object} symbols A custom object that will be used to
|
|
* resolve and store variables.
|
|
*
|
|
* @constructor Scope
|
|
* @param {...} [math]
|
|
* @param {*} [arg1]
|
|
* @param {*} [arg2]
|
|
*/
|
|
function Scope(math, arg1, arg2) {
|
|
this.math = math;
|
|
|
|
/** @type {Scope} */
|
|
this.parentScope = null;
|
|
// TODO: rename parentScope to previousScope, add a nextScope, change Scope to a linked list node
|
|
|
|
/** @type {Scope[]} */
|
|
this.subScopes = null;
|
|
// TODO: rename subScopes to childScopes (or childNodes?)
|
|
|
|
/** @type {Object.<String, *>} */
|
|
this.symbols = {}; // variables and functions
|
|
|
|
/** @type {Object.<String, Object>} */
|
|
this.cache = {}; // cache, referring to the scope.symbols object where
|
|
// a variable was last found
|
|
|
|
// read second argument (can be parentScope or symbols map)
|
|
if (arg1) {
|
|
if (arg1 instanceof Scope) {
|
|
this.parentScope = arg1;
|
|
}
|
|
else if (arg1 instanceof Object) {
|
|
this.symbols = arg1;
|
|
}
|
|
}
|
|
|
|
// read second argument (can be symbols map)
|
|
if (arg2) {
|
|
if (arg2 instanceof Object) {
|
|
this.symbols = arg2;
|
|
}
|
|
}
|
|
}
|
|
|
|
Scope.prototype = {
|
|
/**
|
|
* Create a sub scope
|
|
* The variables in a sub scope are not accessible from the parent scope
|
|
* @return {Scope} subScope
|
|
*/
|
|
createSubScope: function () {
|
|
var subScope = new Scope(this.math, this);
|
|
if (!this.subScopes) {
|
|
this.subScopes = [];
|
|
}
|
|
this.subScopes.push(subScope);
|
|
return subScope;
|
|
},
|
|
|
|
/**
|
|
* Get a symbol value by name.
|
|
* Returns undefined if the symbol is not found in this scope or any of
|
|
* its parent scopes.
|
|
* @param {String} name
|
|
* @returns {* | undefined} value
|
|
*/
|
|
get: function (name) {
|
|
var value;
|
|
|
|
// check itself
|
|
value = this.symbols[name];
|
|
if (value !== undefined) {
|
|
return value;
|
|
}
|
|
|
|
// read from cache
|
|
var symbols = this.cache[name];
|
|
if (symbols) {
|
|
return symbols[name];
|
|
}
|
|
|
|
// check parent scope
|
|
var parent = this.parentScope;
|
|
while (parent) {
|
|
value = parent.symbols[name];
|
|
if (value !== undefined) {
|
|
this.cache[name] = parent.symbols;
|
|
return value;
|
|
}
|
|
parent = parent.parentScope;
|
|
}
|
|
|
|
// check static context
|
|
value = this.math[name];
|
|
if (value !== undefined) {
|
|
this.cache[name] = this.math;
|
|
return value;
|
|
}
|
|
|
|
// check if name is a unit
|
|
if (Unit.isPlainUnit(name)) {
|
|
value = new Unit(null, name);
|
|
this.cache[name] = {};
|
|
this.cache[name][name] = value;
|
|
return value;
|
|
}
|
|
|
|
return undefined;
|
|
},
|
|
|
|
/**
|
|
* Test whether this scope contains a symbol (will not check parent scopes)
|
|
* @param {String} name
|
|
* @return {Boolean} hasSymbol
|
|
*/
|
|
has: function (name) {
|
|
return (this.symbols[name] !== undefined);
|
|
},
|
|
|
|
/**
|
|
* Set a symbol value
|
|
* @param {String} name
|
|
* @param {*} value
|
|
* @return {*} value
|
|
*/
|
|
set: function (name, value) {
|
|
return this.symbols[name] = value;
|
|
},
|
|
|
|
/**
|
|
* Remove a symbol by name
|
|
* @param {String} name
|
|
*/
|
|
remove: function(name) {
|
|
delete this.symbols[name];
|
|
},
|
|
|
|
/**
|
|
* Clear all symbols in this scope, its sub scopes, and clear the cache.
|
|
* Parent scopes will not be cleared.
|
|
*/
|
|
clear: function () {
|
|
var symbols = this.symbols;
|
|
for (var name in symbols) {
|
|
if (symbols.hasOwnProperty(name)) {
|
|
delete symbols[name];
|
|
}
|
|
}
|
|
|
|
if (this.subScopes) {
|
|
var subScopes = this.subScopes;
|
|
for (var i = 0, iMax = subScopes.length; i < iMax; i++) {
|
|
subScopes[i].clear();
|
|
}
|
|
}
|
|
|
|
this.clearCache();
|
|
},
|
|
|
|
/**
|
|
* Clear cached links to symbols in other scopes
|
|
*/
|
|
clearCache: function () {
|
|
this.cache = {};
|
|
}
|
|
};
|
|
|
|
Scope.context = []; // static context, for example the math namespace
|
|
|
|
module.exports = Scope;
|
|
|
|
},{"../type/Unit.js":200}],6:[function(require,module,exports){
|
|
module.exports = {
|
|
'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': []
|
|
};
|
|
|
|
},{}],7:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'LN10',
|
|
'category': 'Constants',
|
|
'syntax': [
|
|
'LN10'
|
|
],
|
|
'description': 'Returns the natural logarithm of 10, approximately equal to 2.302',
|
|
'examples': [
|
|
'LN10',
|
|
'log(10)'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],8:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'LN2',
|
|
'category': 'Constants',
|
|
'syntax': [
|
|
'LN2'
|
|
],
|
|
'description': 'Returns the natural logarithm of 2, approximately equal to 0.693',
|
|
'examples': [
|
|
'LN2',
|
|
'log(2)'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],9:[function(require,module,exports){
|
|
module.exports = {
|
|
'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': []
|
|
};
|
|
|
|
},{}],10:[function(require,module,exports){
|
|
module.exports = {
|
|
'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': []
|
|
};
|
|
|
|
},{}],11:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'NaN',
|
|
'category': 'Constants',
|
|
'syntax': [
|
|
'NaN'
|
|
],
|
|
'description': 'Not a number',
|
|
'examples': [
|
|
'NaN',
|
|
'0 / 0'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],12:[function(require,module,exports){
|
|
module.exports = {
|
|
'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': []
|
|
};
|
|
|
|
},{}],13:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'SQRT2',
|
|
'category': 'Constants',
|
|
'syntax': [
|
|
'SQRT2'
|
|
],
|
|
'description': 'Returns the square root of 2, approximately equal to 1.414',
|
|
'examples': [
|
|
'SQRT2',
|
|
'sqrt(2)'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],14:[function(require,module,exports){
|
|
module.exports = {
|
|
'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']
|
|
};
|
|
|
|
},{}],15:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'false',
|
|
'category': 'Constants',
|
|
'syntax': [
|
|
'false'
|
|
],
|
|
'description': 'Boolean value false',
|
|
'examples': [
|
|
'false'
|
|
],
|
|
'seealso': ['true']
|
|
};
|
|
|
|
},{}],16:[function(require,module,exports){
|
|
module.exports = {
|
|
'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': []
|
|
};
|
|
|
|
},{}],17:[function(require,module,exports){
|
|
module.exports = {
|
|
'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']
|
|
};
|
|
|
|
},{}],18:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'tau',
|
|
'category': 'Constants',
|
|
'syntax': [
|
|
'pi'
|
|
],
|
|
'description': 'Tau is the ratio constant of a circle\'s circumference to radius, equal to 2 * pi, approximately 6.2832.',
|
|
'examples': [
|
|
'tau',
|
|
'2 * pi'
|
|
],
|
|
'seealso': ['pi']
|
|
};
|
|
|
|
},{}],19:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'true',
|
|
'category': 'Constants',
|
|
'syntax': [
|
|
'true'
|
|
],
|
|
'description': 'Boolean value true',
|
|
'examples': [
|
|
'true'
|
|
],
|
|
'seealso': ['false']
|
|
};
|
|
|
|
},{}],20:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'abs',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'abs(x)'
|
|
],
|
|
'description': 'Compute the absolute value.',
|
|
'examples': [
|
|
'abs(3.5)',
|
|
'abs(-4.2)'
|
|
],
|
|
'seealso': ['sign']
|
|
};
|
|
|
|
},{}],21:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'add',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x + y',
|
|
'add(x, y)'
|
|
],
|
|
'description': 'Add two values.',
|
|
'examples': [
|
|
'2.1 + 3.6',
|
|
'ans - 3.6',
|
|
'3 + 2i',
|
|
'"hello" + " world"',
|
|
'3 cm + 2 inch'
|
|
],
|
|
'seealso': [
|
|
'subtract'
|
|
]
|
|
};
|
|
|
|
},{}],22:[function(require,module,exports){
|
|
module.exports = {
|
|
'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']
|
|
};
|
|
|
|
},{}],23:[function(require,module,exports){
|
|
module.exports = {
|
|
'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'
|
|
]
|
|
};
|
|
|
|
},{}],24:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'divide',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x / y',
|
|
'divide(x, y)'
|
|
],
|
|
'description': 'Divide two values.',
|
|
'examples': [
|
|
'2 / 3',
|
|
'ans * 3',
|
|
'4.5 / 2',
|
|
'3 + 4 / 2',
|
|
'(3 + 4) / 2',
|
|
'18 km / 4.5'
|
|
],
|
|
'seealso': [
|
|
'multiply'
|
|
]
|
|
};
|
|
|
|
},{}],25:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'edivide',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x ./ y',
|
|
'edivide(x, y)'
|
|
],
|
|
'description': 'divide two values element wise.',
|
|
'examples': [
|
|
'a = [1, 2, 3; 4, 5, 6]',
|
|
'b = [2, 1, 1; 3, 2, 5]',
|
|
'a ./ b'
|
|
],
|
|
'seealso': [
|
|
'multiply',
|
|
'emultiply',
|
|
'divide'
|
|
]
|
|
};
|
|
|
|
},{}],26:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'emultiply',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x .* y',
|
|
'emultiply(x, y)'
|
|
],
|
|
'description': 'multiply two values element wise.',
|
|
'examples': [
|
|
'a = [1, 2, 3; 4, 5, 6]',
|
|
'b = [2, 1, 1; 3, 2, 5]',
|
|
'a .* b'
|
|
],
|
|
'seealso': [
|
|
'multiply',
|
|
'divide',
|
|
'edivide'
|
|
]
|
|
};
|
|
|
|
},{}],27:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'epow',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x .^ y',
|
|
'epow(x, y)'
|
|
],
|
|
'description':
|
|
'Calculates the power of x to y element wise.',
|
|
'examples': [
|
|
'a = [1, 2, 3; 4, 5, 6]',
|
|
'a .^ 2'
|
|
],
|
|
'seealso': [
|
|
'pow'
|
|
]
|
|
};
|
|
|
|
},{}],28:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'equal',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x == y',
|
|
'equal(x, y)'
|
|
],
|
|
'description':
|
|
'Check equality of two values. Returns 1 if the values are equal, and 0 if not.',
|
|
'examples': [
|
|
'2+2 == 3',
|
|
'2+2 == 4',
|
|
'a = 3.2',
|
|
'b = 6-2.8',
|
|
'a == b',
|
|
'50cm == 0.5m'
|
|
],
|
|
'seealso': [
|
|
'unequal', 'smaller', 'larger', 'smallereq', 'largereq'
|
|
]
|
|
};
|
|
|
|
},{}],29:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'exp',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'exp(x)'
|
|
],
|
|
'description': 'Calculate the exponent of a value.',
|
|
'examples': [
|
|
'exp(1.3)',
|
|
'e ^ 1.3',
|
|
'log(exp(1.3))',
|
|
'x = 2.4',
|
|
'(exp(i*x) == cos(x) + i*sin(x)) # Euler\'s formula'
|
|
],
|
|
'seealso': [
|
|
'square',
|
|
'multiply',
|
|
'log'
|
|
]
|
|
};
|
|
|
|
},{}],30:[function(require,module,exports){
|
|
module.exports = {
|
|
'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']
|
|
};
|
|
|
|
},{}],31:[function(require,module,exports){
|
|
module.exports = {
|
|
'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']
|
|
};
|
|
|
|
},{}],32:[function(require,module,exports){
|
|
module.exports = {
|
|
'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' ]
|
|
};
|
|
|
|
},{}],33:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'larger',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x > y',
|
|
'larger(x, y)'
|
|
],
|
|
'description':
|
|
'Check if value x is larger than y. Returns 1 if x is larger than y, and 0 if not.',
|
|
'examples': [
|
|
'2 > 3',
|
|
'5 > 2*2',
|
|
'a = 3.3',
|
|
'b = 6-2.8',
|
|
'(a > b)',
|
|
'(b < a)',
|
|
'5 cm > 2 inch'
|
|
],
|
|
'seealso': [
|
|
'equal', 'unequal', 'smaller', 'smallereq', 'largereq'
|
|
]
|
|
};
|
|
|
|
},{}],34:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'largereq',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x >= y',
|
|
'largereq(x, y)'
|
|
],
|
|
'description':
|
|
'Check if value x is larger or equal to y. Returns 1 if x is larger or equal to y, and 0 if not.',
|
|
'examples': [
|
|
'2 > 1+1',
|
|
'2 >= 1+1',
|
|
'a = 3.2',
|
|
'b = 6-2.8',
|
|
'(a > b)'
|
|
],
|
|
'seealso': [
|
|
'equal', 'unequal', 'smallereq', 'smaller', 'largereq'
|
|
]
|
|
};
|
|
|
|
},{}],35:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'lcm',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'lcm(x, y)'
|
|
],
|
|
'description': 'Compute the least common multiple.',
|
|
'examples': [
|
|
'lcm(4, 6)',
|
|
'lcm(6, 21)',
|
|
'lcm(6, 21, 5)'
|
|
],
|
|
'seealso': [ 'gcd' ]
|
|
};
|
|
|
|
},{}],36:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'log',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'log(x)',
|
|
'log(x, base)'
|
|
],
|
|
'description': 'Compute the logarithm of a value. If no base is provided, the natural logarithm of x is calculated. If base if provided, the logarithm is calculated for the specified base. log(x, base) is defined as log(x) / log(base).',
|
|
'examples': [
|
|
'log(3.5)',
|
|
'a = log(2.4)',
|
|
'exp(a)',
|
|
'10 ^ 3',
|
|
'log(1000, 10)',
|
|
'log(1000) / log(10)',
|
|
'b = logb(1024, 2)',
|
|
'2 ^ b'
|
|
],
|
|
'seealso': [
|
|
'exp',
|
|
'log10'
|
|
]
|
|
};
|
|
},{}],37:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'log10',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'log10(x)'
|
|
],
|
|
'description': 'Compute the 10-base logarithm of a value.',
|
|
'examples': [
|
|
'log10(1000)',
|
|
'10 ^ 3',
|
|
'log10(0.01)',
|
|
'log(1000) / log(10)',
|
|
'log(1000, 10)'
|
|
],
|
|
'seealso': [
|
|
'exp',
|
|
'log'
|
|
]
|
|
};
|
|
|
|
},{}],38:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'mod',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x % y',
|
|
'x mod y',
|
|
'mod(x, y)'
|
|
],
|
|
'description':
|
|
'Calculates the modulus, the remainder of an integer division.',
|
|
'examples': [
|
|
'7 % 3',
|
|
'11 % 2',
|
|
'10 mod 4',
|
|
'function isOdd(x) = x % 2',
|
|
'isOdd(2)',
|
|
'isOdd(3)'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],39:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'multiply',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x * y',
|
|
'multiply(x, y)'
|
|
],
|
|
'description': 'multiply two values.',
|
|
'examples': [
|
|
'2.1 * 3.6',
|
|
'ans / 3.6',
|
|
'2 * 3 + 4',
|
|
'2 * (3 + 4)',
|
|
'3 * 2.1 km'
|
|
],
|
|
'seealso': [
|
|
'divide'
|
|
]
|
|
};
|
|
|
|
},{}],40:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'pow',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x ^ y',
|
|
'pow(x, y)'
|
|
],
|
|
'description':
|
|
'Calculates the power of x to y, x^y.',
|
|
'examples': [
|
|
'2^3 = 8',
|
|
'2*2*2',
|
|
'1 + e ^ (pi * i)'
|
|
],
|
|
'seealso': [
|
|
'unequal', 'smaller', 'larger', 'smallereq', 'largereq'
|
|
]
|
|
};
|
|
|
|
},{}],41:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'round',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'round(x)',
|
|
'round(x, n)'
|
|
],
|
|
'description':
|
|
'round a value towards the nearest integer.If x is complex, both real and imaginary part are rounded towards the nearest integer. When n is specified, the value is rounded to n decimals.',
|
|
'examples': [
|
|
'round(3.2)',
|
|
'round(3.8)',
|
|
'round(-4.2)',
|
|
'round(-4.8)',
|
|
'round(pi, 3)',
|
|
'round(123.45678, 2)'
|
|
],
|
|
'seealso': ['ceil', 'floor', 'fix']
|
|
};
|
|
|
|
},{}],42:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'sign',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'sign(x)'
|
|
],
|
|
'description':
|
|
'Compute the sign of a value. The sign of a value x is 1 when x>1, -1 when x<0, and 0 when x=0.',
|
|
'examples': [
|
|
'sign(3.5)',
|
|
'sign(-4.2)',
|
|
'sign(0)'
|
|
],
|
|
'seealso': [
|
|
'abs'
|
|
]
|
|
};
|
|
|
|
},{}],43:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'smaller',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x < y',
|
|
'smaller(x, y)'
|
|
],
|
|
'description':
|
|
'Check if value x is smaller than value y. Returns 1 if x is smaller than y, and 0 if not.',
|
|
'examples': [
|
|
'2 < 3',
|
|
'5 < 2*2',
|
|
'a = 3.3',
|
|
'b = 6-2.8',
|
|
'(a < b)',
|
|
'5 cm < 2 inch'
|
|
],
|
|
'seealso': [
|
|
'equal', 'unequal', 'larger', 'smallereq', 'largereq'
|
|
]
|
|
};
|
|
|
|
},{}],44:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'smallereq',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x <= y',
|
|
'smallereq(x, y)'
|
|
],
|
|
'description':
|
|
'Check if value x is smaller or equal to value y. Returns 1 if x is smaller than y, and 0 if not.',
|
|
'examples': [
|
|
'2 < 1+1',
|
|
'2 <= 1+1',
|
|
'a = 3.2',
|
|
'b = 6-2.8',
|
|
'(a < b)'
|
|
],
|
|
'seealso': [
|
|
'equal', 'unequal', 'larger', 'smaller', 'largereq'
|
|
]
|
|
};
|
|
|
|
},{}],45:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'sqrt',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'sqrt(x)'
|
|
],
|
|
'description':
|
|
'Compute the square root value. If x = y * y, then y is the square root of x.',
|
|
'examples': [
|
|
'sqrt(25)',
|
|
'5 * 5',
|
|
'sqrt(-1)'
|
|
],
|
|
'seealso': [
|
|
'square',
|
|
'multiply'
|
|
]
|
|
};
|
|
|
|
},{}],46:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'square',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'square(x)'
|
|
],
|
|
'description':
|
|
'Compute the square of a value. The square of x is x * x.',
|
|
'examples': [
|
|
'square(3)',
|
|
'sqrt(9)',
|
|
'3^2',
|
|
'3 * 3'
|
|
],
|
|
'seealso': [
|
|
'multiply',
|
|
'pow',
|
|
'sqrt',
|
|
'cube'
|
|
]
|
|
};
|
|
|
|
},{}],47:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'subtract',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x - y',
|
|
'subtract(x, y)'
|
|
],
|
|
'description': 'subtract two values.',
|
|
'examples': [
|
|
'5.3 - 2',
|
|
'ans + 2',
|
|
'2/3 - 1/6',
|
|
'2 * 3 - 3',
|
|
'2.1 km - 500m'
|
|
],
|
|
'seealso': [
|
|
'add'
|
|
]
|
|
};
|
|
|
|
},{}],48:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'unary',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'-x',
|
|
'unary(x)'
|
|
],
|
|
'description':
|
|
'Inverse the sign of a value.',
|
|
'examples': [
|
|
'-4.5',
|
|
'-(-5.6)'
|
|
],
|
|
'seealso': [
|
|
'add', 'subtract'
|
|
]
|
|
};
|
|
|
|
},{}],49:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'unequal',
|
|
'category': 'Operators',
|
|
'syntax': [
|
|
'x != y',
|
|
'unequal(x, y)'
|
|
],
|
|
'description':
|
|
'Check unequality of two values. Returns 1 if the values are unequal, and 0 if they are equal.',
|
|
'examples': [
|
|
'2+2 != 3',
|
|
'2+2 != 4',
|
|
'a = 3.2',
|
|
'b = 6-2.8',
|
|
'a != b',
|
|
'50cm != 0.5m',
|
|
'5 cm != 2 inch'
|
|
],
|
|
'seealso': [
|
|
'equal', 'smaller', 'larger', 'smallereq', 'largereq'
|
|
]
|
|
};
|
|
|
|
},{}],50:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'xgcd',
|
|
'category': 'Arithmetic',
|
|
'syntax': [
|
|
'xgcd(a, b)'
|
|
],
|
|
'description': 'Calculate the extended greatest common divisor for two values',
|
|
'examples': [
|
|
'xgcd(8, 12)',
|
|
'gcd(8, 12)',
|
|
'xgcd(36163, 21199)'
|
|
],
|
|
'seealso': [ 'gcd', 'lcm' ]
|
|
};
|
|
|
|
},{}],51:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'arg',
|
|
'category': 'Complex',
|
|
'syntax': [
|
|
'arg(x)'
|
|
],
|
|
'description':
|
|
'Compute the argument of a complex value. If x = a+bi, the argument is computed as atan2(b, a).',
|
|
'examples': [
|
|
'arg(2 + 2i)',
|
|
'atan2(3, 2)',
|
|
'arg(2 - 3i)'
|
|
],
|
|
'seealso': [
|
|
're',
|
|
'im',
|
|
'conj',
|
|
'abs'
|
|
]
|
|
};
|
|
|
|
},{}],52:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'conj',
|
|
'category': 'Complex',
|
|
'syntax': [
|
|
'conj(x)'
|
|
],
|
|
'description':
|
|
'Compute the complex conjugate of a complex value. If x = a+bi, the complex conjugate is a-bi.',
|
|
'examples': [
|
|
'conj(2 + 3i)',
|
|
'conj(2 - 3i)',
|
|
'conj(-5.2i)'
|
|
],
|
|
'seealso': [
|
|
're',
|
|
'im',
|
|
'abs',
|
|
'arg'
|
|
]
|
|
};
|
|
|
|
},{}],53:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'im',
|
|
'category': 'Complex',
|
|
'syntax': [
|
|
'im(x)'
|
|
],
|
|
'description': 'Get the imaginary part of a complex number.',
|
|
'examples': [
|
|
'im(2 + 3i)',
|
|
're(2 + 3i)',
|
|
'im(-5.2i)',
|
|
'im(2.4)'
|
|
],
|
|
'seealso': [
|
|
're',
|
|
'conj',
|
|
'abs',
|
|
'arg'
|
|
]
|
|
};
|
|
|
|
},{}],54:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 're',
|
|
'category': 'Complex',
|
|
'syntax': [
|
|
're(x)'
|
|
],
|
|
'description': 'Get the real part of a complex number.',
|
|
'examples': [
|
|
're(2 + 3i)',
|
|
'im(2 + 3i)',
|
|
're(-5.2i)',
|
|
're(2.4)'
|
|
],
|
|
'seealso': [
|
|
'im',
|
|
'conj',
|
|
'abs',
|
|
'arg'
|
|
]
|
|
};
|
|
|
|
},{}],55:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'boolean',
|
|
'category': 'Type',
|
|
'syntax': [
|
|
'x',
|
|
'boolean(x)'
|
|
],
|
|
'description':
|
|
'Convert a string or number into a boolean.',
|
|
'examples': [
|
|
'boolean(0)',
|
|
'boolean(1)',
|
|
'boolean(3)',
|
|
'boolean("true")',
|
|
'boolean("false")',
|
|
'boolean([1, 0, 1, 1])'
|
|
],
|
|
'seealso': [
|
|
'complex', 'index', 'matrix', 'number', 'string', 'unit'
|
|
]
|
|
};
|
|
|
|
},{}],56:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'complex',
|
|
'category': 'Type',
|
|
'syntax': [
|
|
'complex()',
|
|
'complex(re, im)',
|
|
'complex(string)'
|
|
],
|
|
'description':
|
|
'Create a complex number.',
|
|
'examples': [
|
|
'complex()',
|
|
'complex(2, 3)',
|
|
'complex("7 - 2i")'
|
|
],
|
|
'seealso': [
|
|
'boolean', 'index', 'matrix', 'number', 'string', 'unit'
|
|
]
|
|
};
|
|
|
|
},{}],57:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'index',
|
|
'category': 'Type',
|
|
'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': [
|
|
'boolean', 'complex', 'matrix,', 'number', 'range', 'string', 'unit'
|
|
]
|
|
};
|
|
|
|
},{}],58:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'matrix',
|
|
'category': 'Type',
|
|
'syntax': [
|
|
'[]',
|
|
'[a1, b1, ...; a2, b2, ...]',
|
|
'matrix()',
|
|
'matrix([...])'
|
|
],
|
|
'description':
|
|
'Create a matrix.',
|
|
'examples': [
|
|
'[]',
|
|
'[1, 2, 3]',
|
|
'[1, 2, 3; 4, 5, 6]',
|
|
'matrix()',
|
|
'matrix([3, 4])'
|
|
],
|
|
'seealso': [
|
|
'boolean', 'complex', 'index', 'number', 'string', 'unit'
|
|
]
|
|
};
|
|
|
|
},{}],59:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'number',
|
|
'category': 'Type',
|
|
'syntax': [
|
|
'x',
|
|
'number(x)'
|
|
],
|
|
'description':
|
|
'Create a number or convert a string or boolean into a number.',
|
|
'examples': [
|
|
'2',
|
|
'2e3',
|
|
'4.05',
|
|
'number(2)',
|
|
'number("7.2")',
|
|
'number(true)',
|
|
'number([true, false, true, true])'
|
|
],
|
|
'seealso': [
|
|
'boolean', 'complex', 'index', 'matrix', 'string', 'unit'
|
|
]
|
|
};
|
|
|
|
},{}],60:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'string',
|
|
'category': 'Type',
|
|
'syntax': [
|
|
'"text"',
|
|
'string(x)'
|
|
],
|
|
'description':
|
|
'Create a string or convert a value to a string',
|
|
'examples': [
|
|
'"Hello World!"',
|
|
'string(4.2)',
|
|
'string(3 + 2i)'
|
|
],
|
|
'seealso': [
|
|
'boolean', 'complex', 'index', 'matrix', 'number', 'unit'
|
|
]
|
|
};
|
|
|
|
},{}],61:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'unit',
|
|
'category': 'Type',
|
|
'syntax': [
|
|
'value unit',
|
|
'unit(value, unit)',
|
|
'unit(string)'
|
|
],
|
|
'description':
|
|
'Create a unit.',
|
|
'examples': [
|
|
'5.5 mm',
|
|
'3 inch',
|
|
'unit(7.1, "kilogram")',
|
|
'unit("23 deg")'
|
|
],
|
|
'seealso': [
|
|
'boolean', 'complex', 'index', 'matrix', 'number', 'string'
|
|
]
|
|
};
|
|
|
|
},{}],62:[function(require,module,exports){
|
|
module.exports = {
|
|
'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': []
|
|
};
|
|
|
|
},{}],63:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'help',
|
|
'category': 'Expression',
|
|
'syntax': [
|
|
'help(object)',
|
|
'help(string)'
|
|
],
|
|
'description': 'Display documentation on a function or data type.',
|
|
'examples': [
|
|
'help(sqrt)',
|
|
'help("complex")'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],64:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'concat',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'concat(a, b, c, ...)',
|
|
'concat(a, b, c, ..., dim)'
|
|
],
|
|
'description': 'Concatenate matrices. By default, the matrices are concatenated by the first dimension. The dimension on which to concatenate can be provided as last argument.',
|
|
'examples': [
|
|
'a = [1, 2; 5, 6]',
|
|
'b = [3, 4; 7, 8]',
|
|
'concat(a, b)',
|
|
'[a, b]',
|
|
'concat(a, b, 2)',
|
|
'[a; b]'
|
|
],
|
|
'seealso': [
|
|
'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],65:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'det',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'det(x)'
|
|
],
|
|
'description': 'Calculate the determinant of a matrix',
|
|
'examples': [
|
|
'det([1, 2; 3, 4])',
|
|
'det([-2, 2, 3; -1, 1, 3; 2, 0, -1])'
|
|
],
|
|
'seealso': [
|
|
'concat', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],66:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'diag',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'diag(x)',
|
|
'diag(x, k)'
|
|
],
|
|
'description': 'Create a diagonal matrix or retrieve the diagonal of a matrix. When x is a vector, a matrix with the vector values on the diagonal will be returned. When x is a matrix, a vector with the diagonal values of the matrix is returned.When k is provided, the k-th diagonal will be filled in or retrieved, if k is positive, the values are placed on the super diagonal. When k is negative, the values are placed on the sub diagonal.',
|
|
'examples': [
|
|
'diag(1: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', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],67:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'eye',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'eye(n)',
|
|
'eye(m, n)',
|
|
'eye([m, n])',
|
|
'eye'
|
|
],
|
|
'description': 'Returns the identity matrix with size m-by-n. The matrix has ones on the diagonal and zeros elsewhere.',
|
|
'examples': [
|
|
'eye(3)',
|
|
'eye(3, 5)',
|
|
'a = [1, 2, 3; 4, 5, 6]',
|
|
'eye(size(a))'
|
|
],
|
|
'seealso': [
|
|
'concat', 'det', 'diag', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],68:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'inv',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'inv(x)'
|
|
],
|
|
'description': 'Calculate the inverse of a matrix',
|
|
'examples': [
|
|
'inv([1, 2; 3, 4])',
|
|
'inv(4)',
|
|
'1 / 4'
|
|
],
|
|
'seealso': [
|
|
'concat', 'det', 'diag', 'eye', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],69:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'ones',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'ones(n)',
|
|
'ones(m, n)',
|
|
'ones(m, n, p, ...)',
|
|
'ones([m, n])',
|
|
'ones([m, n, p, ...])',
|
|
'ones'
|
|
],
|
|
'description': 'Create a matrix containing ones.',
|
|
'examples': [
|
|
'ones(3)',
|
|
'ones(3, 5)',
|
|
'ones([2,3]) * 4.5',
|
|
'a = [1, 2, 3; 4, 5, 6]',
|
|
'ones(size(a))'
|
|
],
|
|
'seealso': [
|
|
'concat', 'det', 'diag', 'eye', 'inv', 'range', 'size', 'squeeze', 'subset', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],70:[function(require,module,exports){
|
|
module.exports = {
|
|
'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', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],71:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'size',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'size(x)'
|
|
],
|
|
'description': 'Calculate the size of a matrix.',
|
|
'examples': [
|
|
'size(2.3)',
|
|
'size("hello world")',
|
|
'a = [1, 2; 3, 4; 5, 6]',
|
|
'size(a)',
|
|
'size(1:6)'
|
|
],
|
|
'seealso': [
|
|
'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'squeeze', 'subset', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],72:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'squeeze',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'squeeze(x)'
|
|
],
|
|
'description': 'Remove singleton dimensions from a matrix.',
|
|
'examples': [
|
|
'a = zeros(1,3,2)',
|
|
'size(squeeze(a))',
|
|
'b = zeros(3,1,1)',
|
|
'size(squeeze(b))'
|
|
],
|
|
'seealso': [
|
|
'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'subset', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],73:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'subset',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'value(index)',
|
|
'value(index) = replacement',
|
|
'subset(value, [index])',
|
|
'subset(value, [index], replacement)'
|
|
],
|
|
'description': 'Get or set a subset of a matrix or string. ' +
|
|
'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', 'transpose', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],74:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'transpose',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'x\'',
|
|
'transpose(x)'
|
|
],
|
|
'description': 'Transpose a matrix',
|
|
'examples': [
|
|
'a = [1, 2, 3; 4, 5, 6]',
|
|
'a\'',
|
|
'transpose(a)'
|
|
],
|
|
'seealso': [
|
|
'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'zeros'
|
|
]
|
|
};
|
|
|
|
},{}],75:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'zeros',
|
|
'category': 'Matrix',
|
|
'syntax': [
|
|
'zeros(n)',
|
|
'zeros(m, n)',
|
|
'zeros(m, n, p, ...)',
|
|
'zeros([m, n])',
|
|
'zeros([m, n, p, ...])',
|
|
'zeros'
|
|
],
|
|
'description': 'Create a matrix containing zeros.',
|
|
'examples': [
|
|
'zeros(3)',
|
|
'zeros(3, 5)',
|
|
'a = [1, 2, 3; 4, 5, 6]',
|
|
'zeros(size(a))'
|
|
],
|
|
'seealso': [
|
|
'concat', 'det', 'diag', 'eye', 'inv', 'ones', 'range', 'size', 'squeeze', 'subset', 'transpose'
|
|
]
|
|
};
|
|
|
|
},{}],76:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'distribution',
|
|
'category': 'Probability',
|
|
'syntax': [
|
|
'distribution(name)',
|
|
'distribution(name, arg1, arg2, ...)'
|
|
],
|
|
'description':
|
|
'Create a distribution object of a specific type. ' +
|
|
'A distribution object contains functions `random([size,] [min,] [max])`, ' +
|
|
'`randomInt([size,] [min,] [max])`, and `pickRandom(array)`. ' +
|
|
'Available types of distributions: "uniform", "normal". ' +
|
|
'Note that the function distribution is currently not available via the expression parser.',
|
|
'examples': [
|
|
],
|
|
'seealso': ['random', 'randomInt']
|
|
};
|
|
|
|
},{}],77:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'factorial',
|
|
'category': 'Probability',
|
|
'syntax': [
|
|
'x!',
|
|
'factorial(x)'
|
|
],
|
|
'description': 'Compute the factorial of a value',
|
|
'examples': [
|
|
'5!',
|
|
'5*4*3*2*1',
|
|
'3!'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],78:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'pickRandom',
|
|
'category': 'Probability',
|
|
'syntax': [
|
|
'pickRandom(array)'
|
|
],
|
|
'description':
|
|
'Pick a random entry from a given array.',
|
|
'examples': [
|
|
'pickRandom(0:10)',
|
|
'pickRandom([1, 3, 1, 6])'
|
|
],
|
|
'seealso': ['distribution', 'random', 'randomInt']
|
|
};
|
|
|
|
},{}],79:[function(require,module,exports){
|
|
module.exports = {
|
|
'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': ['distribution', 'pickRandom', 'randomInt']
|
|
};
|
|
|
|
},{}],80:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'randInt',
|
|
'category': 'Probability',
|
|
'syntax': [
|
|
'randInt()',
|
|
'randInt(max)',
|
|
'randInt(min, max)',
|
|
'randInt(size)',
|
|
'randInt(size, max)',
|
|
'randInt(size, min, max)'
|
|
],
|
|
'description':
|
|
'Return a random integer number',
|
|
'examples': [
|
|
'randInt()',
|
|
'randInt(10, 20)',
|
|
'randInt([2, 3], 10)'
|
|
],
|
|
'seealso': ['distribution', 'pickRandom', 'random']
|
|
};
|
|
},{}],81:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'max',
|
|
'category': 'Statistics',
|
|
'syntax': [
|
|
'max(a, b, c, ...)'
|
|
],
|
|
'description': 'Compute the maximum value of a list of values.',
|
|
'examples': [
|
|
'max(2, 3, 4, 1)',
|
|
'max(2.7, 7.1, -4.5, 2.0, 4.1)',
|
|
'min(2.7, 7.1, -4.5, 2.0, 4.1)'
|
|
],
|
|
'seealso': [
|
|
//'sum',
|
|
//'prod',
|
|
//'avg',
|
|
//'var',
|
|
//'std',
|
|
'min'
|
|
//'median'
|
|
]
|
|
};
|
|
|
|
},{}],82:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'min',
|
|
'category': 'Statistics',
|
|
'syntax': [
|
|
'min(a, b, c, ...)'
|
|
],
|
|
'description': 'Compute the minimum value of a list of values.',
|
|
'examples': [
|
|
'min(2, 3, 4, 1)',
|
|
'min(2.7, 7.1, -4.5, 2.0, 4.1)',
|
|
'max(2.7, 7.1, -4.5, 2.0, 4.1)'
|
|
],
|
|
'seealso': [
|
|
//'sum',
|
|
//'prod',
|
|
//'avg',
|
|
//'var',
|
|
//'std',
|
|
'max'
|
|
//'median'
|
|
]
|
|
};
|
|
|
|
},{}],83:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'acos',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'acos(x)'
|
|
],
|
|
'description': 'Compute the inverse cosine of a value in radians.',
|
|
'examples': [
|
|
'acos(0.5)',
|
|
'acos(cos(2.3))'
|
|
],
|
|
'seealso': [
|
|
'cos',
|
|
'acos',
|
|
'asin'
|
|
]
|
|
};
|
|
|
|
},{}],84:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'asin',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'asin(x)'
|
|
],
|
|
'description': 'Compute the inverse sine of a value in radians.',
|
|
'examples': [
|
|
'asin(0.5)',
|
|
'asin(sin(2.3))'
|
|
],
|
|
'seealso': [
|
|
'sin',
|
|
'acos',
|
|
'asin'
|
|
]
|
|
};
|
|
|
|
},{}],85:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'atan',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'atan(x)'
|
|
],
|
|
'description': 'Compute the inverse tangent of a value in radians.',
|
|
'examples': [
|
|
'atan(0.5)',
|
|
'atan(tan(2.3))'
|
|
],
|
|
'seealso': [
|
|
'tan',
|
|
'acos',
|
|
'asin'
|
|
]
|
|
};
|
|
|
|
},{}],86:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'atan2',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'atan2(y, x)'
|
|
],
|
|
'description':
|
|
'Computes the principal value of the arc tangent of y/x in radians.',
|
|
'examples': [
|
|
'atan2(2, 2) / pi',
|
|
'angle = 60 deg in rad',
|
|
'x = cos(angle)',
|
|
'y = sin(angle)',
|
|
'atan2(y, x)'
|
|
],
|
|
'seealso': [
|
|
'sin',
|
|
'cos',
|
|
'tan'
|
|
]
|
|
};
|
|
|
|
},{}],87:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'cos',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'cos(x)'
|
|
],
|
|
'description': 'Compute the cosine of x in radians.',
|
|
'examples': [
|
|
'cos(2)',
|
|
'cos(pi / 4) ^ 2',
|
|
'cos(180 deg)',
|
|
'cos(60 deg)',
|
|
'sin(0.2)^2 + cos(0.2)^2'
|
|
],
|
|
'seealso': [
|
|
'acos',
|
|
'sin',
|
|
'tan'
|
|
]
|
|
};
|
|
|
|
},{}],88:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'cot',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'cot(x)'
|
|
],
|
|
'description': 'Compute the cotangent of x in radians. Defined as 1/tan(x)',
|
|
'examples': [
|
|
'cot(2)',
|
|
'1 / tan(2)'
|
|
],
|
|
'seealso': [
|
|
'sec',
|
|
'csc',
|
|
'tan'
|
|
]
|
|
};
|
|
|
|
},{}],89:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'csc',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'csc(x)'
|
|
],
|
|
'description': 'Compute the cosecant of x in radians. Defined as 1/sin(x)',
|
|
'examples': [
|
|
'csc(2)',
|
|
'1 / sin(2)'
|
|
],
|
|
'seealso': [
|
|
'sec',
|
|
'cot',
|
|
'sin'
|
|
]
|
|
};
|
|
|
|
},{}],90:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'sec',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'sec(x)'
|
|
],
|
|
'description': 'Compute the secant of x in radians. Defined as 1/cos(x)',
|
|
'examples': [
|
|
'sec(2)',
|
|
'1 / cos(2)'
|
|
],
|
|
'seealso': [
|
|
'cot',
|
|
'csc',
|
|
'cos'
|
|
]
|
|
};
|
|
|
|
},{}],91:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'sin',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'sin(x)'
|
|
],
|
|
'description': 'Compute the sine of x in radians.',
|
|
'examples': [
|
|
'sin(2)',
|
|
'sin(pi / 4) ^ 2',
|
|
'sin(90 deg)',
|
|
'sin(30 deg)',
|
|
'sin(0.2)^2 + cos(0.2)^2'
|
|
],
|
|
'seealso': [
|
|
'asin',
|
|
'cos',
|
|
'tan'
|
|
]
|
|
};
|
|
|
|
},{}],92:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'tan',
|
|
'category': 'Trigonometry',
|
|
'syntax': [
|
|
'tan(x)'
|
|
],
|
|
'description': 'Compute the tangent of x in radians.',
|
|
'examples': [
|
|
'tan(0.5)',
|
|
'sin(0.5) / cos(0.5)',
|
|
'tan(pi / 4)',
|
|
'tan(45 deg)'
|
|
],
|
|
'seealso': [
|
|
'atan',
|
|
'sin',
|
|
'cos'
|
|
]
|
|
};
|
|
|
|
},{}],93:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'in',
|
|
'category': 'Units',
|
|
'syntax': [
|
|
'x in unit',
|
|
'in(x, unit)'
|
|
],
|
|
'description': 'Change the unit of a value.',
|
|
'examples': [
|
|
'5 inch in cm',
|
|
'3.2kg in g',
|
|
'16 bytes in bits'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],94:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'clone',
|
|
'category': 'Utils',
|
|
'syntax': [
|
|
'clone(x)'
|
|
],
|
|
'description': 'Clone a variable. Creates a copy of primitive variables,and a deep copy of matrices',
|
|
'examples': [
|
|
'clone(3.5)',
|
|
'clone(2 - 4i)',
|
|
'clone(45 deg)',
|
|
'clone([1, 2; 3, 4])',
|
|
'clone("hello world")'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],95:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'forEach',
|
|
'category': 'Utils',
|
|
'syntax': [
|
|
'forEach(x, callback)'
|
|
],
|
|
'description': 'Iterates over all elements of a matrix/array, and executes the given callback.',
|
|
'examples': [
|
|
'forEach([1, 2, 3], function(val) { console.log(val) })'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],96:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'format',
|
|
'category': 'Utils',
|
|
'syntax': [
|
|
'format(value)'
|
|
],
|
|
'description': 'Format a value of any type as string.',
|
|
'examples': [
|
|
'format(2.3)',
|
|
'format(3 - 4i)',
|
|
'format([])'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],97:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'import',
|
|
'category': 'Utils',
|
|
'syntax': [
|
|
'import(string)'
|
|
],
|
|
'description': 'Import functions from a file.',
|
|
'examples': [
|
|
'import("numbers")',
|
|
'import("./mylib.js")'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],98:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'map',
|
|
'category': 'Utils',
|
|
'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], function(val) { return math.max(val, 1.5) })'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],99:[function(require,module,exports){
|
|
module.exports = {
|
|
'name': 'typeof',
|
|
'category': 'Utils',
|
|
'syntax': [
|
|
'typeof(x)'
|
|
],
|
|
'description': 'Get the type of a variable.',
|
|
'examples': [
|
|
'typeof(3.5)',
|
|
'typeof(2 - 4i)',
|
|
'typeof(45 deg)',
|
|
'typeof("hello world")'
|
|
],
|
|
'seealso': []
|
|
};
|
|
|
|
},{}],100:[function(require,module,exports){
|
|
// constants
|
|
exports.e = require('./constants/e.js');
|
|
exports.E = require('./constants/e.js');
|
|
exports['false'] = require('./constants/false.js');
|
|
exports.i = require('./constants/i.js');
|
|
exports['Infinity'] = require('./constants/Infinity.js');
|
|
exports.LN2 = require('./constants/LN2.js');
|
|
exports.LN10 = require('./constants/LN10.js');
|
|
exports.LOG2E = require('./constants/LOG2E.js');
|
|
exports.LOG10E = require('./constants/LOG10E.js');
|
|
exports.NaN = require('./constants/NaN.js');
|
|
exports.pi = require('./constants/pi.js');
|
|
exports.PI = require('./constants/pi.js');
|
|
exports.SQRT1_2 = require('./constants/SQRT1_2.js');
|
|
exports.SQRT2 = require('./constants/SQRT2.js');
|
|
exports.tau = require('./constants/tau.js');
|
|
exports['true'] = require('./constants/true.js');
|
|
|
|
// functions - arithmetic
|
|
exports.abs = require('./function/arithmetic/abs.js');
|
|
exports.add = require('./function/arithmetic/add.js');
|
|
exports.ceil = require('./function/arithmetic/ceil.js');
|
|
exports.cube = require('./function/arithmetic/cube.js');
|
|
exports.divide = require('./function/arithmetic/divide.js');
|
|
exports.edivide = require('./function/arithmetic/edivide.js');
|
|
exports.emultiply = require('./function/arithmetic/emultiply.js');
|
|
exports.epow = require('./function/arithmetic/epow.js');
|
|
exports.equal = require('./function/arithmetic/equal.js');
|
|
exports.exp = require('./function/arithmetic/exp.js');
|
|
exports.fix = require('./function/arithmetic/fix.js');
|
|
exports.floor = require('./function/arithmetic/floor.js');
|
|
exports.gcd = require('./function/arithmetic/gcd.js');
|
|
exports.larger = require('./function/arithmetic/larger.js');
|
|
exports.largereq = require('./function/arithmetic/largereq.js');
|
|
exports.lcm = require('./function/arithmetic/lcm.js');
|
|
exports.log = require('./function/arithmetic/log.js');
|
|
exports.log10 = require('./function/arithmetic/log10.js');
|
|
exports.mod = require('./function/arithmetic/mod.js');
|
|
exports.multiply = require('./function/arithmetic/multiply.js');
|
|
exports.pow = require('./function/arithmetic/pow.js');
|
|
exports.round = require('./function/arithmetic/round.js');
|
|
exports.sign = require('./function/arithmetic/sign.js');
|
|
exports.smaller = require('./function/arithmetic/smaller.js');
|
|
exports.smallereq = require('./function/arithmetic/smallereq.js');
|
|
exports.sqrt = require('./function/arithmetic/sqrt.js');
|
|
exports.square = require('./function/arithmetic/square.js');
|
|
exports.subtract = require('./function/arithmetic/subtract.js');
|
|
exports.unary = require('./function/arithmetic/unary.js');
|
|
exports.unequal = require('./function/arithmetic/unequal.js');
|
|
exports.xgcd = require('./function/arithmetic/xgcd.js');
|
|
|
|
// functions - complex
|
|
exports.arg = require('./function/complex/arg.js');
|
|
exports.conj = require('./function/complex/conj.js');
|
|
exports.re = require('./function/complex/re.js');
|
|
exports.im = require('./function/complex/im.js');
|
|
|
|
// functions - construction
|
|
exports.boolean = require('./function/construction/boolean.js');
|
|
exports.complex = require('./function/construction/complex.js');
|
|
exports.index = require('./function/construction/index.js');
|
|
exports.matrix = require('./function/construction/matrix.js');
|
|
exports.number = require('./function/construction/number.js');
|
|
exports.string = require('./function/construction/string.js');
|
|
exports.unit = require('./function/construction/unit.js');
|
|
|
|
// functions - epxression
|
|
exports['eval'] = require('./function/expression/eval.js');
|
|
exports.help = require('./function/expression/help.js');
|
|
|
|
// functions - matrix
|
|
exports.concat = require('./function/matrix/concat.js');
|
|
exports.det = require('./function/matrix/det.js');
|
|
exports.diag = require('./function/matrix/diag.js');
|
|
exports.eye = require('./function/matrix/eye.js');
|
|
exports.inv = require('./function/matrix/inv.js');
|
|
exports.ones = require('./function/matrix/ones.js');
|
|
exports.range = require('./function/matrix/range.js');
|
|
exports.size = require('./function/matrix/size.js');
|
|
exports.squeeze = require('./function/matrix/squeeze.js');
|
|
exports.subset = require('./function/matrix/subset.js');
|
|
exports.transpose = require('./function/matrix/transpose.js');
|
|
exports.zeros = require('./function/matrix/zeros.js');
|
|
|
|
// functions - probability
|
|
exports.factorial = require('./function/probability/factorial.js');
|
|
exports.distribution = require('./function/probability/distribution.js');
|
|
exports.pickRandom = require('./function/probability/pickRandom.js');
|
|
exports.random = require('./function/probability/random.js');
|
|
exports.randomInt = require('./function/probability/randomInt.js');
|
|
|
|
// functions - statistics
|
|
exports.min = require('./function/statistics/min.js');
|
|
exports.max = require('./function/statistics/max.js');
|
|
|
|
// functions - trigonometry
|
|
exports.acos = require('./function/trigonometry/acos.js');
|
|
exports.asin = require('./function/trigonometry/asin.js');
|
|
exports.atan = require('./function/trigonometry/atan.js');
|
|
exports.atan2 = require('./function/trigonometry/atan2.js');
|
|
exports.cos = require('./function/trigonometry/cos.js');
|
|
exports.cot = require('./function/trigonometry/cot.js');
|
|
exports.csc = require('./function/trigonometry/csc.js');
|
|
exports.sec = require('./function/trigonometry/sec.js');
|
|
exports.sin = require('./function/trigonometry/sin.js');
|
|
exports.tan = require('./function/trigonometry/tan.js');
|
|
|
|
// functions - units
|
|
exports['in'] = require('./function/units/in.js');
|
|
|
|
// functions - utils
|
|
exports.clone = require('./function/utils/clone.js');
|
|
exports.map = require('./function/utils/map.js');
|
|
exports.forEach = require('./function/utils/forEach.js');
|
|
exports.format = require('./function/utils/format.js');
|
|
exports['import'] = require('./function/utils/import.js');
|
|
exports['typeof'] = require('./function/utils/typeof.js');
|
|
|
|
},{"./constants/Infinity.js":6,"./constants/LN10.js":7,"./constants/LN2.js":8,"./constants/LOG10E.js":9,"./constants/LOG2E.js":10,"./constants/NaN.js":11,"./constants/SQRT1_2.js":12,"./constants/SQRT2.js":13,"./constants/e.js":14,"./constants/false.js":15,"./constants/i.js":16,"./constants/pi.js":17,"./constants/tau.js":18,"./constants/true.js":19,"./function/arithmetic/abs.js":20,"./function/arithmetic/add.js":21,"./function/arithmetic/ceil.js":22,"./function/arithmetic/cube.js":23,"./function/arithmetic/divide.js":24,"./function/arithmetic/edivide.js":25,"./function/arithmetic/emultiply.js":26,"./function/arithmetic/epow.js":27,"./function/arithmetic/equal.js":28,"./function/arithmetic/exp.js":29,"./function/arithmetic/fix.js":30,"./function/arithmetic/floor.js":31,"./function/arithmetic/gcd.js":32,"./function/arithmetic/larger.js":33,"./function/arithmetic/largereq.js":34,"./function/arithmetic/lcm.js":35,"./function/arithmetic/log.js":36,"./function/arithmetic/log10.js":37,"./function/arithmetic/mod.js":38,"./function/arithmetic/multiply.js":39,"./function/arithmetic/pow.js":40,"./function/arithmetic/round.js":41,"./function/arithmetic/sign.js":42,"./function/arithmetic/smaller.js":43,"./function/arithmetic/smallereq.js":44,"./function/arithmetic/sqrt.js":45,"./function/arithmetic/square.js":46,"./function/arithmetic/subtract.js":47,"./function/arithmetic/unary.js":48,"./function/arithmetic/unequal.js":49,"./function/arithmetic/xgcd.js":50,"./function/complex/arg.js":51,"./function/complex/conj.js":52,"./function/complex/im.js":53,"./function/complex/re.js":54,"./function/construction/boolean.js":55,"./function/construction/complex.js":56,"./function/construction/index.js":57,"./function/construction/matrix.js":58,"./function/construction/number.js":59,"./function/construction/string.js":60,"./function/construction/unit.js":61,"./function/expression/eval.js":62,"./function/expression/help.js":63,"./function/matrix/concat.js":64,"./function/matrix/det.js":65,"./function/matrix/diag.js":66,"./function/matrix/eye.js":67,"./function/matrix/inv.js":68,"./function/matrix/ones.js":69,"./function/matrix/range.js":70,"./function/matrix/size.js":71,"./function/matrix/squeeze.js":72,"./function/matrix/subset.js":73,"./function/matrix/transpose.js":74,"./function/matrix/zeros.js":75,"./function/probability/distribution.js":76,"./function/probability/factorial.js":77,"./function/probability/pickRandom.js":78,"./function/probability/random.js":79,"./function/probability/randomInt.js":80,"./function/statistics/max.js":81,"./function/statistics/min.js":82,"./function/trigonometry/acos.js":83,"./function/trigonometry/asin.js":84,"./function/trigonometry/atan.js":85,"./function/trigonometry/atan2.js":86,"./function/trigonometry/cos.js":87,"./function/trigonometry/cot.js":88,"./function/trigonometry/csc.js":89,"./function/trigonometry/sec.js":90,"./function/trigonometry/sin.js":91,"./function/trigonometry/tan.js":92,"./function/units/in.js":93,"./function/utils/clone.js":94,"./function/utils/forEach.js":95,"./function/utils/format.js":96,"./function/utils/import.js":97,"./function/utils/map.js":98,"./function/utils/typeof.js":99}],101:[function(require,module,exports){
|
|
var Node = require('./Node.js');
|
|
|
|
/**
|
|
* @constructor AssignmentNode
|
|
* Define a symbol, like "a = 3.2"
|
|
*
|
|
* @param {String} name Symbol name
|
|
* @param {Node} expr The expression defining the symbol
|
|
* @param {Scope} scope Scope to store the result
|
|
*/
|
|
function AssignmentNode(name, expr, scope) {
|
|
this.name = name;
|
|
this.expr = expr;
|
|
this.scope = scope;
|
|
}
|
|
|
|
AssignmentNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the assignment
|
|
* @return {*} result
|
|
*/
|
|
AssignmentNode.prototype.eval = function() {
|
|
if (this.expr === undefined) {
|
|
throw new Error('Undefined symbol ' + this.name);
|
|
}
|
|
|
|
var result = this.expr.eval();
|
|
this.scope.set(this.name, result);
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Find all nodes matching given filter
|
|
* @param {Object} filter See Node.find for a description of the filter options
|
|
* @returns {Node[]} nodes
|
|
*/
|
|
AssignmentNode.prototype.find = function (filter) {
|
|
var nodes = [];
|
|
|
|
// check itself
|
|
if (this.match(filter)) {
|
|
nodes.push(this);
|
|
}
|
|
|
|
// search in expression
|
|
if (this.expr) {
|
|
nodes = nodes.concat(this.expr.find(filter));
|
|
}
|
|
|
|
return nodes;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String}
|
|
*/
|
|
AssignmentNode.prototype.toString = function() {
|
|
return this.name + ' = ' + this.expr.toString();
|
|
};
|
|
|
|
module.exports = AssignmentNode;
|
|
},{"./Node.js":106}],102:[function(require,module,exports){
|
|
var Node = require('./Node.js');
|
|
|
|
/**
|
|
* @constructor BlockNode
|
|
* Holds a set with nodes
|
|
* @extends {Node}
|
|
*/
|
|
function BlockNode() {
|
|
this.params = [];
|
|
this.visible = [];
|
|
}
|
|
|
|
BlockNode.prototype = new Node();
|
|
|
|
/**
|
|
* Add a parameter
|
|
* @param {Node} param
|
|
* @param {Boolean} [visible] true by default
|
|
*/
|
|
BlockNode.prototype.add = function (param, visible) {
|
|
var index = this.params.length;
|
|
this.params[index] = param;
|
|
this.visible[index] = (visible != undefined) ? visible : true;
|
|
};
|
|
|
|
/**
|
|
* Evaluate the set
|
|
* @return {*[]} results
|
|
* @override
|
|
*/
|
|
BlockNode.prototype.eval = function() {
|
|
// evaluate the parameters
|
|
var results = [];
|
|
for (var i = 0, iMax = this.params.length; i < iMax; i++) {
|
|
var result = this.params[i].eval();
|
|
if (this.visible[i]) {
|
|
results.push(result);
|
|
}
|
|
}
|
|
|
|
return results;
|
|
};
|
|
|
|
/**
|
|
* Find all nodes matching given filter
|
|
* @param {Object} filter See Node.find for a description of the filter options
|
|
* @returns {Node[]} nodes
|
|
*/
|
|
BlockNode.prototype.find = function (filter) {
|
|
var nodes = [];
|
|
|
|
// check itself
|
|
if (this.match(filter)) {
|
|
nodes.push(this);
|
|
}
|
|
|
|
// search in parameters
|
|
var params = this.params;
|
|
if (params) {
|
|
for (var i = 0, len = params.length; i < len; i++) {
|
|
nodes = nodes.concat(params[i].find(filter));
|
|
}
|
|
}
|
|
|
|
return nodes;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String} str
|
|
* @override
|
|
*/
|
|
BlockNode.prototype.toString = function() {
|
|
var strings = [];
|
|
|
|
for (var i = 0, iMax = this.params.length; i < iMax; i++) {
|
|
if (this.visible[i]) {
|
|
strings.push('\n ' + this.params[i].toString());
|
|
}
|
|
}
|
|
|
|
return '[' + strings.join(',') + '\n]';
|
|
};
|
|
|
|
module.exports = BlockNode;
|
|
|
|
},{"./Node.js":106}],103:[function(require,module,exports){
|
|
var Node = require('./Node.js'),
|
|
string = require('../../util/string.js');
|
|
|
|
/**
|
|
* @constructor ConstantNode
|
|
* @param {*} value
|
|
* @extends {Node}
|
|
*/
|
|
function ConstantNode(value) {
|
|
this.value = value;
|
|
}
|
|
|
|
ConstantNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the constant (just return it)
|
|
* @return {*} value
|
|
*/
|
|
ConstantNode.prototype.eval = function () {
|
|
return this.value;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String} str
|
|
*/
|
|
ConstantNode.prototype.toString = function() {
|
|
return string.format(this.value);
|
|
};
|
|
|
|
module.exports = ConstantNode;
|
|
|
|
},{"../../util/string.js":208,"./Node.js":106}],104:[function(require,module,exports){
|
|
var Node = require('./Node.js'),
|
|
error = require('../../util/error.js');
|
|
|
|
/**
|
|
* @constructor FunctionNode
|
|
* Function assignment
|
|
*
|
|
* @param {String} name Function name
|
|
* @param {String[]} variables Variable names
|
|
* @param {Node} expr The function expression
|
|
* @param {Scope} functionScope Scope in which to write variable values
|
|
* @param {Scope} scope Scope to store the resulting function assignment
|
|
*/
|
|
function FunctionNode(name, variables, expr, functionScope, scope) {
|
|
this.name = name;
|
|
this.variables = variables;
|
|
this.expr = expr;
|
|
this.scope = scope;
|
|
|
|
// create function
|
|
this.fn = function () {
|
|
var num = variables ? variables.length : 0;
|
|
|
|
// validate correct number of arguments
|
|
if (arguments.length != num) {
|
|
throw new error.ArgumentsError(name, arguments.length, num);
|
|
}
|
|
|
|
// fill in the provided arguments in the functionScope variables
|
|
for (var i = 0; i < num; i++) {
|
|
functionScope.set(variables[i], arguments[i]);
|
|
}
|
|
|
|
// evaluate the expression
|
|
return expr.eval();
|
|
};
|
|
|
|
this.fn.toString = function() {
|
|
// TODO: what to return as toString?
|
|
return name + '(' + variables.join(', ') + ')';
|
|
//return name + '(' + variableNames.join(', ') + ') = ' + expr.toString();
|
|
};
|
|
}
|
|
|
|
FunctionNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the function assignment
|
|
* @return {function} fn
|
|
*/
|
|
FunctionNode.prototype.eval = function() {
|
|
// put the definition in the scope
|
|
this.scope.set(this.name, this.fn);
|
|
|
|
return this.fn;
|
|
};
|
|
|
|
/**
|
|
* Find all nodes matching given filter
|
|
* @param {Object} filter See Node.find for a description of the filter options
|
|
* @returns {Node[]} nodes
|
|
*/
|
|
FunctionNode.prototype.find = function (filter) {
|
|
var nodes = [];
|
|
|
|
// check itself
|
|
if (this.match(filter)) {
|
|
nodes.push(this);
|
|
}
|
|
|
|
// search in expression
|
|
if (this.expr) {
|
|
nodes = nodes.concat(this.expr.find(filter));
|
|
}
|
|
|
|
return nodes;
|
|
};
|
|
|
|
/**
|
|
* get string representation
|
|
* @return {String} str
|
|
*/
|
|
FunctionNode.prototype.toString = function() {
|
|
return this.fn.toString();
|
|
};
|
|
|
|
module.exports = FunctionNode;
|
|
|
|
},{"../../util/error.js":204,"./Node.js":106}],105:[function(require,module,exports){
|
|
var Node = require('./Node.js'),
|
|
object = require('../../util/object.js'),
|
|
string = require('../../util/string.js'),
|
|
collection = require('../../type/collection.js'),
|
|
Matrix = require('../../type/Matrix.js');
|
|
|
|
/**
|
|
* @constructor MatrixNode
|
|
* Holds an 2-dimensional array with nodes
|
|
* @param {Array[]} nodes 2 dimensional array with nodes
|
|
* @extends {Node}
|
|
*/
|
|
function MatrixNode(nodes) {
|
|
this.nodes = nodes || [];
|
|
}
|
|
|
|
MatrixNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the array
|
|
* @return {Matrix} results
|
|
* @override
|
|
*/
|
|
MatrixNode.prototype.eval = function() {
|
|
// evaluate all nodes in the 2d array, and merge the results into a matrix
|
|
var nodes = this.nodes,
|
|
results = [],
|
|
mergeNeeded = false;
|
|
|
|
for (var r = 0, rows = nodes.length; r < rows; r++) {
|
|
var nodes_r = nodes[r];
|
|
var results_r = [];
|
|
for (var c = 0, cols = nodes_r.length; c < cols; c++) {
|
|
var results_rc = nodes_r[c].eval();
|
|
if (collection.isCollection(results_rc)) {
|
|
mergeNeeded = true;
|
|
}
|
|
results_r[c] = results_rc;
|
|
}
|
|
results[r] = results_r;
|
|
}
|
|
|
|
if (mergeNeeded) {
|
|
results = merge(results);
|
|
}
|
|
|
|
return new Matrix(results);
|
|
};
|
|
|
|
/**
|
|
* Find all nodes matching given filter
|
|
* @param {Object} filter See Node.find for a description of the filter options
|
|
* @returns {Node[]} nodes
|
|
*/
|
|
MatrixNode.prototype.find = function (filter) {
|
|
var results = [];
|
|
|
|
// check itself
|
|
if (this.match(filter)) {
|
|
results.push(this);
|
|
}
|
|
|
|
// search in all nodes
|
|
var nodes = this.nodes;
|
|
for (var r = 0, rows = nodes.length; r < rows; r++) {
|
|
var nodes_r = nodes[r];
|
|
for (var c = 0, cols = nodes_r.length; c < cols; c++) {
|
|
results = results.concat(nodes_r[c].find(filter));
|
|
}
|
|
}
|
|
|
|
return results;
|
|
};
|
|
|
|
/**
|
|
* Merge nested Matrices in a two dimensional Array.
|
|
* @param {Array} array Two-dimensional array containing Matrices
|
|
* @return {Array} merged The merged array (two-dimensional)
|
|
*/
|
|
function merge (array) {
|
|
var merged = [];
|
|
var rows = array.length;
|
|
for (var r = 0; r < rows; r++) {
|
|
var array_r = array[r];
|
|
var cols = array_r.length;
|
|
var submatrix = null;
|
|
var submatrixRows = null;
|
|
for (var c = 0; c < cols; c++) {
|
|
var entry = object.clone(array_r[c]);
|
|
var size;
|
|
if (entry instanceof Matrix) {
|
|
// get the data from the matrix
|
|
size = entry.size();
|
|
entry = entry.valueOf();
|
|
if (size.length == 1) {
|
|
entry = [entry];
|
|
size = [1, size[0]];
|
|
}
|
|
else if (size.length > 2) {
|
|
throw new Error('Cannot merge a multi dimensional matrix');
|
|
}
|
|
}
|
|
else if (Array.isArray(entry)) {
|
|
// change array into a 1xn matrix
|
|
size = [1, entry.length];
|
|
entry = [entry];
|
|
}
|
|
else {
|
|
// change scalar into a 1x1 matrix
|
|
size = [1, 1];
|
|
entry = [[entry]];
|
|
}
|
|
|
|
// check the height of this row
|
|
if (submatrix == null) {
|
|
// first entry
|
|
submatrix = entry;
|
|
submatrixRows = size[0];
|
|
}
|
|
else if (size[0] == submatrixRows) {
|
|
// merge
|
|
for (var s = 0; s < submatrixRows; s++) {
|
|
submatrix[s] = submatrix[s].concat(entry[s]);
|
|
}
|
|
}
|
|
else {
|
|
// no good...
|
|
throw new Error('Dimension mismatch ' +
|
|
'(' + size[0] + ' != ' + submatrixRows + ')');
|
|
}
|
|
}
|
|
|
|
// merge the submatrix
|
|
merged = merged.concat(submatrix);
|
|
}
|
|
|
|
return merged;
|
|
}
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String} str
|
|
* @override
|
|
*/
|
|
MatrixNode.prototype.toString = function() {
|
|
return string.format(this.nodes);
|
|
};
|
|
|
|
module.exports = MatrixNode;
|
|
|
|
},{"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/object.js":207,"../../util/string.js":208,"./Node.js":106}],106:[function(require,module,exports){
|
|
/**
|
|
* Node
|
|
*/
|
|
function Node() {}
|
|
|
|
/**
|
|
* Evaluate the node
|
|
* @return {*} result
|
|
*/
|
|
Node.prototype.eval = function () {
|
|
throw new Error('Cannot evaluate a Node interface');
|
|
};
|
|
|
|
/**
|
|
* Find any node in the node tree matching given filter. For example, to
|
|
* find all nodes of type SymbolNode having name 'x':
|
|
*
|
|
* var results = Node.find({
|
|
* type: SymbolNode,
|
|
* properties: {
|
|
* name: 'x'
|
|
* }
|
|
* });
|
|
*
|
|
* @param {Object} filter Available parameters:
|
|
* {Function} type
|
|
* {Object<String, String>} properties
|
|
* @return {Node[]} nodes An array with nodes matching given filter criteria
|
|
*/
|
|
Node.prototype.find = function (filter) {
|
|
return this.match(filter) ? [this] : [];
|
|
};
|
|
|
|
/**
|
|
* Test if this object matches given filter
|
|
* @param {Object} filter Available parameters:
|
|
* {Function} type
|
|
* {Object<String, String>} properties
|
|
* @return {Boolean} matches True if there is a match
|
|
*/
|
|
Node.prototype.match = function (filter) {
|
|
var match = true;
|
|
|
|
if (filter) {
|
|
if (filter.type && !(this instanceof filter.type)) {
|
|
match = false;
|
|
}
|
|
if (match && filter.properties) {
|
|
for (var prop in filter.properties) {
|
|
if (filter.properties.hasOwnProperty(prop)) {
|
|
if (this[prop] != filter.properties[prop]) {
|
|
match = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return match;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String}
|
|
*/
|
|
Node.prototype.toString = function() {
|
|
return '';
|
|
};
|
|
|
|
module.exports = Node;
|
|
|
|
},{}],107:[function(require,module,exports){
|
|
var Node = require('./Node.js');
|
|
|
|
/**
|
|
* @constructor OperatorNode
|
|
* An operator with two arguments, like 2+3
|
|
* @param {String} name Function name, for example '+'
|
|
* @param {function} fn Function, for example math.add
|
|
* @param {Node[]} params Parameters
|
|
*/
|
|
function OperatorNode (name, fn, params) {
|
|
this.name = name;
|
|
this.fn = fn;
|
|
this.params = params;
|
|
}
|
|
|
|
OperatorNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the parameters
|
|
* @return {*} result
|
|
*/
|
|
OperatorNode.prototype.eval = function() {
|
|
return this.fn.apply(this, this.params.map(function (param) {
|
|
return param.eval();
|
|
}));
|
|
};
|
|
|
|
/**
|
|
* Find all nodes matching given filter
|
|
* @param {Object} filter See Node.find for a description of the filter options
|
|
* @returns {Node[]} nodes
|
|
*/
|
|
OperatorNode.prototype.find = function (filter) {
|
|
var nodes = [];
|
|
|
|
// check itself
|
|
if (this.match(filter)) {
|
|
nodes.push(this);
|
|
}
|
|
|
|
// search in parameters
|
|
var params = this.params;
|
|
if (params) {
|
|
for (var i = 0, len = params.length; i < len; i++) {
|
|
nodes = nodes.concat(params[i].find(filter));
|
|
}
|
|
}
|
|
|
|
return nodes;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String} str
|
|
*/
|
|
OperatorNode.prototype.toString = function() {
|
|
var params = this.params;
|
|
|
|
switch (params.length) {
|
|
case 1:
|
|
if (this.name == '-') {
|
|
// special case: unary minus
|
|
return '-' + params[0].toString();
|
|
}
|
|
else {
|
|
// for example '5!'
|
|
return params[0].toString() + this.name;
|
|
}
|
|
|
|
case 2: // for example '2+3'
|
|
var lhs = params[0].toString();
|
|
if (params[0] instanceof OperatorNode) {
|
|
lhs = '(' + lhs + ')';
|
|
}
|
|
var rhs = params[1].toString();
|
|
if (params[1] instanceof OperatorNode) {
|
|
rhs = '(' + rhs + ')';
|
|
}
|
|
return lhs + ' ' + this.name + ' ' + rhs;
|
|
|
|
default: // this should occur. format as a function call
|
|
return this.name + '(' + this.params.join(', ') + ')';
|
|
}
|
|
};
|
|
|
|
module.exports = OperatorNode;
|
|
|
|
},{"./Node.js":106}],108:[function(require,module,exports){
|
|
var number= require('../../util/number.js'),
|
|
|
|
Node = require('./Node.js'),
|
|
RangeNode = require('./RangeNode.js'),
|
|
SymbolNode = require('./SymbolNode.js'),
|
|
|
|
Index = require('../../type/Index.js'),
|
|
Range = require('../../type/Range.js'),
|
|
|
|
isNumber = number.isNumber;
|
|
|
|
/**
|
|
* @constructor ParamsNode
|
|
* invoke a list with parameters on the results of a node
|
|
* @param {Object} math The math namespace containing all functions
|
|
* @param {Node} object
|
|
* @param {Node[]} params
|
|
* @param {Scope[]} paramScopes A scope for every parameter, where the
|
|
* index variable 'end' can be defined.
|
|
*/
|
|
function ParamsNode (math, object, params, paramScopes) {
|
|
this.math = math;
|
|
|
|
this.object = object;
|
|
this.params = params;
|
|
this.paramScopes = paramScopes;
|
|
|
|
// check whether any of the params expressions uses the context symbol 'end'
|
|
this.hasContextParams = false;
|
|
if (params) {
|
|
var filter = {
|
|
type: SymbolNode,
|
|
properties: {
|
|
name: 'end'
|
|
}
|
|
};
|
|
|
|
for (var i = 0, len = params.length; i < len; i++) {
|
|
if (params[i].find(filter).length > 0) {
|
|
this.hasContextParams = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ParamsNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the parameters
|
|
* @return {*} result
|
|
*/
|
|
ParamsNode.prototype.eval = function() {
|
|
var i, len, params, results;
|
|
|
|
// evaluate the object
|
|
var object = this.object;
|
|
if (object == undefined) {
|
|
throw new Error ('Node undefined');
|
|
}
|
|
var obj = object.eval();
|
|
|
|
// evaluate the values of context parameter 'end' when needed
|
|
if (this.hasContextParams) {
|
|
var paramScopes = this.paramScopes,
|
|
size = this.math.size(obj).valueOf();
|
|
|
|
if (paramScopes && size) {
|
|
for (i = 0, len = this.params.length; i < len; i++) {
|
|
var paramScope = paramScopes[i];
|
|
if (paramScope) {
|
|
paramScope.set('end', size[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof obj === 'function') {
|
|
// evaluate the parameters
|
|
params = this.params;
|
|
results = [];
|
|
for (i = 0, len = this.params.length; i < len; i++) {
|
|
results[i] = params[i].eval();
|
|
}
|
|
|
|
// invoke a function with the parameters
|
|
return obj.apply(this, results);
|
|
}
|
|
else {
|
|
// evaluate the parameters as index
|
|
params = this.params;
|
|
results = [];
|
|
for (i = 0, len = this.params.length; i < len; i++) {
|
|
var param = params[i];
|
|
var result;
|
|
|
|
if (param instanceof RangeNode) {
|
|
result = param.toRange();
|
|
}
|
|
else {
|
|
result = param.eval();
|
|
}
|
|
|
|
// change from one-based to zero-based range
|
|
if (result instanceof Range) {
|
|
result.start --;
|
|
result.end --;
|
|
}
|
|
else if (isNumber(result)) {
|
|
// number
|
|
result--;
|
|
}
|
|
else {
|
|
throw new TypeError('Number or Range expected');
|
|
}
|
|
|
|
results[i] = result;
|
|
}
|
|
|
|
// get a subset of the object
|
|
var index = Index.create(results);
|
|
return this.math.subset(obj, index);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Find all nodes matching given filter
|
|
* @param {Object} filter See Node.find for a description of the filter options
|
|
* @returns {Node[]} nodes
|
|
*/
|
|
ParamsNode.prototype.find = function (filter) {
|
|
var nodes = [];
|
|
|
|
// check itself
|
|
if (this.match(filter)) {
|
|
nodes.push(this);
|
|
}
|
|
|
|
// search object
|
|
if (this.object) {
|
|
nodes = nodes.concat(this.object.find(filter));
|
|
}
|
|
|
|
// search in parameters
|
|
var params = this.params;
|
|
if (params) {
|
|
for (var i = 0, len = params.length; i < len; i++) {
|
|
nodes = nodes.concat(params[i].find(filter));
|
|
}
|
|
}
|
|
|
|
return nodes;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String} str
|
|
*/
|
|
ParamsNode.prototype.toString = function() {
|
|
// format the parameters like "(2, 4.2)"
|
|
var str = this.object ? this.object.toString() : '';
|
|
if (this.params) {
|
|
str += '(' + this.params.join(', ') + ')';
|
|
}
|
|
return str;
|
|
};
|
|
|
|
module.exports = ParamsNode;
|
|
|
|
},{"../../type/Index.js":197,"../../type/Range.js":199,"../../util/number.js":206,"./Node.js":106,"./RangeNode.js":109,"./SymbolNode.js":110}],109:[function(require,module,exports){
|
|
var Node = require('./Node.js'),
|
|
Range = require('../../type/Range.js');
|
|
|
|
/**
|
|
* @constructor RangeNode
|
|
* create a range
|
|
* @param {Object} math The math namespace containing all functions
|
|
* @param {Node[]} params
|
|
*/
|
|
function RangeNode (math, params) {
|
|
this.math = math;
|
|
|
|
this.start = null; // included lower-bound
|
|
this.end = null; // included upper-bound
|
|
this.step = null; // optional step
|
|
|
|
if (params.length == 2) {
|
|
this.start = params[0];
|
|
this.end = params[1];
|
|
}
|
|
else if (params.length == 3) {
|
|
this.start = params[0];
|
|
this.step = params[1];
|
|
this.end = params[2];
|
|
}
|
|
else {
|
|
// TODO: better error message
|
|
throw new SyntaxError('Wrong number of arguments');
|
|
}
|
|
}
|
|
|
|
RangeNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the range
|
|
* @return {*} result
|
|
*/
|
|
RangeNode.prototype.eval = function() {
|
|
// evaluate the parameters
|
|
var start = this.start.eval();
|
|
var step = this.step ? this.step.eval() : 1;
|
|
var end = this.end.eval();
|
|
|
|
// generate the range (upper-bound included!)
|
|
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 from a RangeNode
|
|
* @return {Range} range
|
|
*/
|
|
RangeNode.prototype.toRange = function() {
|
|
// evaluate the parameters
|
|
var start = this.start.eval();
|
|
var step = this.step ? this.step.eval() : 1;
|
|
var end = this.end.eval();
|
|
|
|
// upper-bound be included, so compensate for that
|
|
// NOTE: this only works for integer values!
|
|
end = this.math.add(end, (step > 0) ? 1 : -1);
|
|
|
|
// create the range
|
|
return new Range(start, end, step);
|
|
};
|
|
|
|
/**
|
|
* Find all nodes matching given filter
|
|
* @param {Object} filter See Node.find for a description of the filter options
|
|
* @returns {Node[]} nodes
|
|
*/
|
|
RangeNode.prototype.find = function (filter) {
|
|
var nodes = [];
|
|
|
|
// check itself
|
|
if (this.match(filter)) {
|
|
nodes.push(this);
|
|
}
|
|
|
|
// search in parameters
|
|
if (this.start) {
|
|
nodes = nodes.concat(this.start.find(filter));
|
|
}
|
|
if (this.step) {
|
|
nodes = nodes.concat(this.step.find(filter));
|
|
}
|
|
if (this.end) {
|
|
nodes = nodes.concat(this.end.find(filter));
|
|
}
|
|
|
|
return nodes;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String} str
|
|
*/
|
|
RangeNode.prototype.toString = function() {
|
|
// format the range like "start:step:end"
|
|
var str = this.start.toString();
|
|
if (this.step) {
|
|
str += ':' + this.step.toString();
|
|
}
|
|
str += ':' + this.end.toString();
|
|
|
|
return str;
|
|
};
|
|
|
|
module.exports = RangeNode;
|
|
|
|
},{"../../type/Range.js":199,"./Node.js":106}],110:[function(require,module,exports){
|
|
var Node = require('./Node.js');
|
|
|
|
/**
|
|
* @constructor SymbolNode
|
|
* A symbol node can hold and resolve a symbol
|
|
* @param {String} name
|
|
* @param {Scope} scope
|
|
* @extends {Node}
|
|
*/
|
|
function SymbolNode(name, scope) {
|
|
this.name = name;
|
|
this.scope = scope;
|
|
}
|
|
|
|
SymbolNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the symbol. Throws an error when the symbol is undefined.
|
|
* @return {*} result
|
|
* @override
|
|
*/
|
|
SymbolNode.prototype.eval = function() {
|
|
// return the value of the symbol
|
|
var value = this.scope.get(this.name);
|
|
|
|
if (value === undefined) {
|
|
throw new Error('Undefined symbol ' + this.name);
|
|
}
|
|
|
|
return value;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String} str
|
|
* @override
|
|
*/
|
|
SymbolNode.prototype.toString = function() {
|
|
return this.name;
|
|
};
|
|
|
|
module.exports = SymbolNode;
|
|
|
|
},{"./Node.js":106}],111:[function(require,module,exports){
|
|
var number= require('../../util/number.js'),
|
|
|
|
Node = require('./Node.js'),
|
|
RangeNode = require('./RangeNode.js'),
|
|
SymbolNode = require('./SymbolNode.js'),
|
|
|
|
Index = require('../../type/Index.js'),
|
|
Range = require('../../type/Range.js'),
|
|
|
|
isNumber = number.isNumber;
|
|
|
|
/**
|
|
* @constructor UpdateNode
|
|
* Update a symbol value, like a(2,3) = 4.5
|
|
*
|
|
* @param {Object} math The math namespace containing all functions
|
|
* @param {String} name Symbol name
|
|
* @param {Node[] | undefined} params One or more parameters
|
|
* @param {Scope[]} paramScopes A scope for every parameter, where the
|
|
* index variable 'end' can be defined.
|
|
* @param {Node} expr The expression defining the symbol
|
|
* @param {Scope} scope Scope to store the result
|
|
*/
|
|
function UpdateNode(math, name, params, paramScopes, expr, scope) {
|
|
this.math = math;
|
|
|
|
this.name = name;
|
|
this.params = params;
|
|
this.paramScopes = paramScopes;
|
|
this.expr = expr;
|
|
this.scope = scope;
|
|
|
|
// check whether any of the params expressions uses the context symbol 'end'
|
|
this.hasContextParams = false;
|
|
var filter = {
|
|
type: SymbolNode,
|
|
properties: {
|
|
name: 'end'
|
|
}
|
|
};
|
|
for (var i = 0, len = params.length; i < len; i++) {
|
|
if (params[i].find(filter).length > 0) {
|
|
this.hasContextParams = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
UpdateNode.prototype = new Node();
|
|
|
|
/**
|
|
* Evaluate the assignment
|
|
* @return {*} result
|
|
*/
|
|
UpdateNode.prototype.eval = function() {
|
|
if (this.expr === undefined) {
|
|
throw new Error('Undefined symbol ' + this.name);
|
|
}
|
|
|
|
var result;
|
|
|
|
// test if definition is currently undefined
|
|
var prevResult = this.scope.get(this.name);
|
|
if (prevResult == undefined) {
|
|
throw new Error('Undefined symbol ' + this.name);
|
|
}
|
|
|
|
// evaluate the values of context parameter 'end' when needed
|
|
if (this.hasContextParams) {
|
|
var paramScopes = this.paramScopes,
|
|
size = this.math.size(prevResult).valueOf();
|
|
|
|
if (paramScopes && size) {
|
|
for (var i = 0, len = this.params.length; i < len; i++) {
|
|
var paramScope = paramScopes[i];
|
|
if (paramScope) {
|
|
paramScope.set('end', size[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// change part of a matrix, for example "a=[]", "a(2,3)=4.5"
|
|
var paramResults = [];
|
|
this.params.forEach(function (param) {
|
|
var result;
|
|
|
|
if (param instanceof RangeNode) {
|
|
result = param.toRange();
|
|
}
|
|
else {
|
|
result = param.eval();
|
|
}
|
|
|
|
// change from one-based to zero-based range
|
|
if (result instanceof Range) {
|
|
result.start --;
|
|
result.end --;
|
|
}
|
|
else if (isNumber(result)) {
|
|
// number
|
|
result--;
|
|
}
|
|
else {
|
|
throw new TypeError('Number or Range expected');
|
|
}
|
|
|
|
paramResults.push(result);
|
|
});
|
|
|
|
// evaluate the expression
|
|
var exprResult = this.expr.eval();
|
|
|
|
// replace subset
|
|
var index = Index.create(paramResults);
|
|
result = this.math.subset(prevResult, index, exprResult);
|
|
|
|
this.scope.set(this.name, result);
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Find all nodes matching given filter
|
|
* @param {Object} filter See Node.find for a description of the filter options
|
|
* @returns {Node[]} nodes
|
|
*/
|
|
UpdateNode.prototype.find = function (filter) {
|
|
var nodes = [];
|
|
|
|
// check itself
|
|
if (this.match(filter)) {
|
|
nodes.push(this);
|
|
}
|
|
|
|
// search in parameters
|
|
var params = this.params;
|
|
if (params) {
|
|
for (var i = 0, len = params.length; i < len; i++) {
|
|
nodes = nodes.concat(params[i].find(filter));
|
|
}
|
|
}
|
|
|
|
// search in expression
|
|
if (this.expr) {
|
|
nodes = nodes.concat(this.expr.find(filter));
|
|
}
|
|
|
|
return nodes;
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String}
|
|
*/
|
|
UpdateNode.prototype.toString = function() {
|
|
var str = '';
|
|
|
|
str += this.name;
|
|
if (this.params && this.params.length) {
|
|
str += '(' + this.params.join(', ') + ')';
|
|
}
|
|
str += ' = ';
|
|
str += this.expr.toString();
|
|
|
|
return str;
|
|
};
|
|
|
|
module.exports = UpdateNode;
|
|
|
|
},{"../../type/Index.js":197,"../../type/Range.js":199,"../../util/number.js":206,"./Node.js":106,"./RangeNode.js":109,"./SymbolNode.js":110}],112:[function(require,module,exports){
|
|
/**
|
|
* Custom node handlers,
|
|
* (can be added to the exports object)
|
|
*/
|
|
|
|
},{}],113:[function(require,module,exports){
|
|
exports.AssignmentNode = require('./AssignmentNode.js');
|
|
exports.BlockNode = require('./BlockNode.js');
|
|
exports.ConstantNode = require('./ConstantNode.js');
|
|
exports.FunctionNode = require('./FunctionNode.js');
|
|
exports.MatrixNode = require('./MatrixNode.js');
|
|
exports.Node = require('./Node.js');
|
|
exports.OperatorNode = require('./OperatorNode.js');
|
|
exports.ParamsNode = require('./ParamsNode.js');
|
|
exports.RangeNode = require('./RangeNode.js');
|
|
exports.SymbolNode = require('./SymbolNode.js');
|
|
exports.UpdateNode = require('./UpdateNode.js');
|
|
|
|
exports.handlers = require('./handlers.js');
|
|
|
|
},{"./AssignmentNode.js":101,"./BlockNode.js":102,"./ConstantNode.js":103,"./FunctionNode.js":104,"./MatrixNode.js":105,"./Node.js":106,"./OperatorNode.js":107,"./ParamsNode.js":108,"./RangeNode.js":109,"./SymbolNode.js":110,"./UpdateNode.js":111,"./handlers.js":112}],114:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Matrix = require('../../type/Matrix.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the absolute value of a value.
|
|
*
|
|
* abs(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.abs = function abs(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('abs', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.abs(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return Math.sqrt(x.re * x.re + x.im * x.im);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, abs);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return abs(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('abs', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/index.js":205}],115:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Matrix = require('../../type/Matrix.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Add two values
|
|
*
|
|
* x + y
|
|
* add(x, y)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} y
|
|
* @return {Number | Complex | Unit | String | Array | Matrix} res
|
|
*/
|
|
math.add = function add(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('add', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
// number + number
|
|
return x + y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
// number + complex
|
|
return new Complex(
|
|
x + y.re,
|
|
y.im
|
|
)
|
|
}
|
|
}
|
|
else if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
// complex + number
|
|
return new Complex(
|
|
x.re + y,
|
|
x.im
|
|
)
|
|
}
|
|
else if (isComplex(y)) {
|
|
// complex + complex
|
|
return new Complex(
|
|
x.re + y.re,
|
|
x.im + y.im
|
|
);
|
|
}
|
|
}
|
|
else if (isUnit(x)) {
|
|
if (isUnit(y)) {
|
|
if (!x.equalBase(y)) {
|
|
throw new Error('Units do not match');
|
|
}
|
|
|
|
if (x.value == null) {
|
|
throw new Error('Unit on left hand side of operator + has an undefined value');
|
|
}
|
|
|
|
if (y.value == null) {
|
|
throw new Error('Unit on right hand side of operator + has an undefined value');
|
|
}
|
|
|
|
var res = x.clone();
|
|
res.value += y.value;
|
|
res.fixPrefix = false;
|
|
return res;
|
|
}
|
|
}
|
|
|
|
if (isString(x) || isString(y)) {
|
|
return x + y;
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, add);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive value
|
|
return add(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('add', x, y);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Matrix.js":198,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],116:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isCollection =collection.isCollection,
|
|
isComplex = Complex.isComplex;
|
|
|
|
/**
|
|
* Round a value towards plus infinity
|
|
*
|
|
* ceil(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.ceil = function ceil(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('ceil', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.ceil(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex (
|
|
Math.ceil(x.re),
|
|
Math.ceil(x.im)
|
|
);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, ceil);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return ceil(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('ceil', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],117:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Compute the cube of a value
|
|
*
|
|
* x .* x .* x
|
|
* cube(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.cube = function cube(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('cube', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return x * x * x;
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return math.multiply(math.multiply(x, x), x);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, cube);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return cube(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('cube', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],118:[function(require,module,exports){
|
|
module.exports = function(math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Matrix = require('../../type/Matrix.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Divide two values.
|
|
*
|
|
* x / y
|
|
* divide(x, y)
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex} y
|
|
* @return {Number | Complex | Unit | Array | Matrix} res
|
|
*/
|
|
math.divide = function divide(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('divide', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
// number / number
|
|
return x / y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
// number / complex
|
|
return _divideComplex(new Complex(x, 0), y);
|
|
}
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
// complex / number
|
|
return _divideComplex(x, new Complex(y, 0));
|
|
}
|
|
else if (isComplex(y)) {
|
|
// complex / complex
|
|
return _divideComplex(x, y);
|
|
}
|
|
}
|
|
|
|
if (isUnit(x)) {
|
|
if (isNumBool(y)) {
|
|
var res = x.clone();
|
|
res.value /= y;
|
|
return res;
|
|
}
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
if (isCollection(y)) {
|
|
// TODO: implement matrix right division using pseudo inverse
|
|
// http://www.mathworks.nl/help/matlab/ref/mrdivide.html
|
|
// http://www.gnu.org/software/octave/doc/interpreter/Arithmetic-Ops.html
|
|
// http://stackoverflow.com/questions/12263932/how-does-gnu-octave-matrix-division-work-getting-unexpected-behaviour
|
|
return math.multiply(x, math.inv(y));
|
|
}
|
|
else {
|
|
// matrix / scalar
|
|
return collection.map2(x, y, divide);
|
|
}
|
|
}
|
|
|
|
if (isCollection(y)) {
|
|
// TODO: implement matrix right division using pseudo inverse
|
|
return math.multiply(x, math.inv(y));
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive value
|
|
return divide(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('divide', x, y);
|
|
};
|
|
|
|
/**
|
|
* Divide two complex numbers. x / y or divide(x, y)
|
|
* @param {Complex} x
|
|
* @param {Complex} y
|
|
* @return {Complex} res
|
|
* @private
|
|
*/
|
|
function _divideComplex (x, y) {
|
|
var den = y.re * y.re + y.im * y.im;
|
|
if (den != 0) {
|
|
return new Complex(
|
|
(x.re * y.re + x.im * y.im) / den,
|
|
(x.im * y.re - x.re * y.im) / den
|
|
);
|
|
}
|
|
else {
|
|
// both y.re and y.im are zero
|
|
return new Complex(
|
|
(x.re != 0) ? (x.re / 0) : 0,
|
|
(x.im != 0) ? (x.im / 0) : 0
|
|
);
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Matrix.js":198,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],119:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
collection = require('../../type/collection.js');
|
|
|
|
/**
|
|
* Divide two values element wise.
|
|
*
|
|
* x ./ y
|
|
* edivide(x, y)
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} y
|
|
* @return {Number | Complex | Unit | Array | Matrix} res
|
|
*/
|
|
math.edivide = function edivide(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('edivide', arguments.length, 2);
|
|
}
|
|
|
|
return collection.deepMap2(x, y, math.divide);
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],120:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
collection = require('../../type/collection.js');
|
|
|
|
/**
|
|
* Multiply two values element wise.
|
|
*
|
|
* x .* y
|
|
* emultiply(x, y)
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} y
|
|
* @return {Number | Complex | Unit | Array | Matrix} res
|
|
*/
|
|
math.emultiply = function emultiply(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('emultiply', arguments.length, 2);
|
|
}
|
|
|
|
return collection.deepMap2(x, y, math.multiply);
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],121:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
collection = require('../../type/collection.js');
|
|
|
|
/**
|
|
* Calculates the power of x to y element wise
|
|
*
|
|
* x .^ y
|
|
* epow(x, y)
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} y
|
|
* @return {Number | Complex | Unit | Array | Matrix} res
|
|
*/
|
|
math.epow = function epow(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('epow', arguments.length, 2);
|
|
}
|
|
|
|
return collection.deepMap2(x, y, math.pow);
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],122:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Check if value x equals y,
|
|
*
|
|
* x == y
|
|
* equal(x, y)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
* In case of complex numbers, x.re must equal y.re, and x.im must equal y.im.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} y
|
|
* @return {Boolean | Array | Matrix} res
|
|
*/
|
|
math.equal = function equal(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('equal', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
return x == y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return (x == y.re) && (y.im == 0);
|
|
}
|
|
}
|
|
if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
return (x.re == y) && (x.im == 0);
|
|
}
|
|
else if (isComplex(y)) {
|
|
return (x.re == y.re) && (x.im == y.im);
|
|
}
|
|
}
|
|
|
|
if ((isUnit(x)) && (isUnit(y))) {
|
|
if (!x.equalBase(y)) {
|
|
throw new Error('Cannot compare units with different base');
|
|
}
|
|
return x.value == y.value;
|
|
}
|
|
|
|
if (isString(x) || isString(y)) {
|
|
return x == y;
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, equal);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return equal(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('equal', x, y);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],123:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Matrix = require('../../type/Matrix.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the exponent of a value
|
|
*
|
|
* exp(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.exp = function exp (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('exp', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.exp(x);
|
|
}
|
|
if (isComplex(x)) {
|
|
var r = Math.exp(x.re);
|
|
return new Complex(
|
|
r * Math.cos(x.im),
|
|
r * Math.sin(x.im)
|
|
);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, exp);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return exp(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('exp', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/index.js":205}],124:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Round a value towards zero
|
|
*
|
|
* fix(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.fix = function fix(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('fix', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return (x > 0) ? Math.floor(x) : Math.ceil(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex(
|
|
(x.re > 0) ? Math.floor(x.re) : Math.ceil(x.re),
|
|
(x.im > 0) ? Math.floor(x.im) : Math.ceil(x.im)
|
|
);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, fix);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return fix(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('fix', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],125:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Round a value towards minus infinity
|
|
*
|
|
* floor(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.floor = function floor(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('floor', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.floor(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex (
|
|
Math.floor(x.re),
|
|
Math.floor(x.im)
|
|
);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, floor);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return floor(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('floor', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],126:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isInteger = util.number.isInteger,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the greatest common divisor for two or more values or arrays.
|
|
*
|
|
* gcd(a, b)
|
|
* gcd(a, b, c, ...)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {... Number | Boolean | Array | Matrix} args two or more integer numbers
|
|
* @return {Number | Array | Matrix} greatest common divisor
|
|
*/
|
|
math.gcd = function gcd(args) {
|
|
var a = arguments[0],
|
|
b = arguments[1],
|
|
r; // remainder
|
|
|
|
if (arguments.length == 2) {
|
|
// two arguments
|
|
if (isNumBool(a) && isNumBool(b)) {
|
|
if (!isInteger(a) || !isInteger(b)) {
|
|
throw new Error('Parameters in function gcd must be integer numbers');
|
|
}
|
|
|
|
// http://en.wikipedia.org/wiki/Euclidean_algorithm
|
|
while (b != 0) {
|
|
r = a % b;
|
|
a = b;
|
|
b = r;
|
|
}
|
|
return (a < 0) ? -a : a;
|
|
}
|
|
|
|
// evaluate gcd element wise
|
|
if (isCollection(a) || isCollection(b)) {
|
|
return collection.map2(a, b, gcd);
|
|
}
|
|
|
|
if (a.valueOf() !== a || b.valueOf() !== b) {
|
|
// fallback on the objects primitive value
|
|
return gcd(a.valueOf(), b.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('gcd', a, b);
|
|
}
|
|
|
|
if (arguments.length > 2) {
|
|
// multiple arguments. Evaluate them iteratively
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
a = gcd(a, arguments[i]);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
// zero or one argument
|
|
throw new SyntaxError('Function gcd expects two or more arguments');
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],127:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Check if value x is larger y
|
|
*
|
|
* x > y
|
|
* larger(x, y)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
* In case of complex numbers, the absolute values of a and b are compared.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} y
|
|
* @return {Boolean | Array | Matrix} res
|
|
*/
|
|
math.larger = function larger(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('larger', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
return x > y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return x > math.abs(y);
|
|
}
|
|
}
|
|
if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
return math.abs(x) > y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return math.abs(x) > math.abs(y);
|
|
}
|
|
}
|
|
|
|
if ((isUnit(x)) && (isUnit(y))) {
|
|
if (!x.equalBase(y)) {
|
|
throw new Error('Cannot compare units with different base');
|
|
}
|
|
return x.value > y.value;
|
|
}
|
|
|
|
if (isString(x) || isString(y)) {
|
|
return x > y;
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, larger);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return larger(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('larger', x, y);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],128:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Check if value x is larger or equal to y
|
|
*
|
|
* x >= y
|
|
* largereq(x, y)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
* In case of complex numbers, the absolute values of a and b are compared.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} y
|
|
* @return {Boolean | Array | Matrix} res
|
|
*/
|
|
math.largereq = function largereq(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('largereq', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
return x >= y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return x >= math.abs(y);
|
|
}
|
|
}
|
|
if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
return math.abs(x) >= y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return math.abs(x) >= math.abs(y);
|
|
}
|
|
}
|
|
|
|
if ((isUnit(x)) && (isUnit(y))) {
|
|
if (!x.equalBase(y)) {
|
|
throw new Error('Cannot compare units with different base');
|
|
}
|
|
return x.value >= y.value;
|
|
}
|
|
|
|
if (isString(x) || isString(y)) {
|
|
return x >= y;
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, largereq);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return largereq(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('largereq', x, y);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],129:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isInteger = util.number.isInteger,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the least common multiple for two or more values or arrays.
|
|
*
|
|
* lcm(a, b)
|
|
* lcm(a, b, c, ...)
|
|
*
|
|
* lcm is defined as:
|
|
* lcm(a, b) = abs(a * b) / gcd(a, b)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {... Number | Boolean | Array | Matrix} args two or more integer numbers
|
|
* @return {Number | Array | Matrix} least common multiple
|
|
*/
|
|
math.lcm = function lcm(args) {
|
|
var a = arguments[0],
|
|
b = arguments[1],
|
|
t;
|
|
|
|
if (arguments.length == 2) {
|
|
// two arguments
|
|
if (isNumBool(a) && isNumBool(b)) {
|
|
if (!isInteger(a) || !isInteger(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 gcd here inline to reduce overhead
|
|
var prod = a * b;
|
|
while (b != 0) {
|
|
t = b;
|
|
b = a % t;
|
|
a = t;
|
|
}
|
|
return Math.abs(prod / a);
|
|
}
|
|
|
|
// evaluate lcm element wise
|
|
if (isCollection(a) || isCollection(b)) {
|
|
return collection.map2(a, b, lcm);
|
|
}
|
|
|
|
if (a.valueOf() !== a || b.valueOf() !== b) {
|
|
// fallback on the objects primitive value
|
|
return lcm(a.valueOf(), b.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('lcm', a, b);
|
|
}
|
|
|
|
if (arguments.length > 2) {
|
|
// multiple arguments. Evaluate them iteratively
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
a = lcm(a, arguments[i]);
|
|
}
|
|
return a;
|
|
}
|
|
|
|
// zero or one argument
|
|
throw new SyntaxError('Function lcm expects two or more arguments');
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],130:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the logarithm of a value
|
|
*
|
|
* log(x)
|
|
* log(x, base)
|
|
*
|
|
* base is optional. If not provided, the natural logarithm of x is calculated.
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex} [base]
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.log = function log(x, base) {
|
|
if (arguments.length == 1) {
|
|
// calculate natural logarithm, log(x)
|
|
if (isNumBool(x)) {
|
|
if (x >= 0) {
|
|
return Math.log(x);
|
|
}
|
|
else {
|
|
// negative value -> complex value computation
|
|
return log(new Complex(x, 0));
|
|
}
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex (
|
|
Math.log(Math.sqrt(x.re * x.re + x.im * x.im)),
|
|
Math.atan2(x.im, x.re)
|
|
);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, log);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive values
|
|
return log(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('log', x);
|
|
}
|
|
else if (arguments.length == 2) {
|
|
// calculate logarithm for a specified base, log(x, base)
|
|
return math.divide(log(x), log(base));
|
|
}
|
|
else {
|
|
throw new util.error.ArgumentsError('log', arguments.length, 1, 2);
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],131:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the 10-base logarithm of a value
|
|
*
|
|
* log10(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.log10 = function log10(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('log10', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (x >= 0) {
|
|
return Math.log(x) / Math.LN10;
|
|
}
|
|
else {
|
|
// negative value -> complex value computation
|
|
return log10(new Complex(x, 0));
|
|
}
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex (
|
|
Math.log(Math.sqrt(x.re * x.re + x.im * x.im)) / Math.LN10,
|
|
Math.atan2(x.im, x.re) / Math.LN10
|
|
);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, log10);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return log10(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('log10', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],132:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumber = util.number.isNumber,
|
|
isBoolean = util.boolean.isBoolean,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculates the modulus, the remainder of an integer division.
|
|
*
|
|
* x % y
|
|
* mod(x, y)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Array | Matrix} x
|
|
* @param {Number | Boolean | Array | Matrix} y
|
|
* @return {Number | Array | Matrix} res
|
|
*/
|
|
math.mod = function mod(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('mod', arguments.length, 2);
|
|
}
|
|
|
|
// see http://functions.wolfram.com/IntegerFunctions/Mod/
|
|
|
|
if (isNumber(x)) {
|
|
if (isNumber(y)) {
|
|
// number % number
|
|
return _mod(x, y);
|
|
}
|
|
else if (isBoolean(y)) {
|
|
// number % boolean
|
|
return _mod(x, Number(y));
|
|
}
|
|
}
|
|
else if (isBoolean(x)) {
|
|
if (isNumber(y)) {
|
|
// boolean % number
|
|
return _mod(Number(x), y);
|
|
}
|
|
else if (isBoolean(y)) {
|
|
// boolean % boolean
|
|
return _mod(Number(x), Number(y));
|
|
}
|
|
}
|
|
|
|
// TODO: implement mod for complex values
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, mod);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return mod(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('mod', x, y);
|
|
};
|
|
|
|
/**
|
|
* Calculate the modulus of two numbers
|
|
* @param {Number} x
|
|
* @param {Number} y
|
|
* @returns {number} res
|
|
* @private
|
|
*/
|
|
function _mod(x, y) {
|
|
if (y > 0) {
|
|
if (x > 0) {
|
|
return x % y;
|
|
}
|
|
else if (x == 0) {
|
|
return 0;
|
|
}
|
|
else { // x < 0
|
|
return x - y * Math.floor(x / y);
|
|
}
|
|
}
|
|
else if (y == 0) {
|
|
return x;
|
|
}
|
|
else { // y < 0
|
|
// TODO: implement mod for a negative divisor
|
|
throw new Error('Cannot calculate mod for a negative divisor');
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],133:[function(require,module,exports){
|
|
module.exports = function(math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Matrix = require('../../type/Matrix.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
array = util.array,
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isArray = Array.isArray,
|
|
isUnit = Unit.isUnit;
|
|
|
|
/**
|
|
* Multiply two values.
|
|
*
|
|
* x * y
|
|
* multiply(x, y)
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} y
|
|
* @return {Number | Complex | Unit | Array | Matrix} res
|
|
*/
|
|
math.multiply = function multiply(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('multiply', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
// number * number
|
|
return x * y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
// number * complex
|
|
return _multiplyComplex (new Complex(x, 0), y);
|
|
}
|
|
else if (isUnit(y)) {
|
|
res = y.clone();
|
|
res.value *= x;
|
|
return res;
|
|
}
|
|
}
|
|
else if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
// complex * number
|
|
return _multiplyComplex (x, new Complex(y, 0));
|
|
}
|
|
else if (isComplex(y)) {
|
|
// complex * complex
|
|
return _multiplyComplex (x, y);
|
|
}
|
|
}
|
|
else if (isUnit(x)) {
|
|
if (isNumBool(y)) {
|
|
res = x.clone();
|
|
res.value *= y;
|
|
return res;
|
|
}
|
|
}
|
|
else if (isArray(x)) {
|
|
if (isArray(y)) {
|
|
// matrix * matrix
|
|
var sizeX = array.size(x);
|
|
var sizeY = array.size(y);
|
|
|
|
if (sizeX.length != 2) {
|
|
throw new Error('Can only multiply a 2 dimensional matrix ' +
|
|
'(A has ' + sizeX.length + ' dimensions)');
|
|
}
|
|
if (sizeY.length != 2) {
|
|
throw new Error('Can only multiply a 2 dimensional matrix ' +
|
|
'(B has ' + sizeY.length + ' dimensions)');
|
|
}
|
|
if (sizeX[1] != sizeY[0]) {
|
|
throw new RangeError('Dimensions mismatch in multiplication. ' +
|
|
'Columns of A must match rows of B ' +
|
|
'(A is ' + sizeX[0] + 'x' + sizeX[1] +
|
|
', B is ' + sizeY[0] + 'x' + sizeY[1] + ', ' +
|
|
sizeY[1] + ' != ' + sizeY[0] + ')');
|
|
}
|
|
|
|
// TODO: performance of matrix multiplication can be improved
|
|
var res = [],
|
|
rows = sizeX[0],
|
|
cols = sizeY[1],
|
|
num = sizeX[1];
|
|
for (var r = 0; r < rows; r++) {
|
|
res[r] = [];
|
|
for (var c = 0; c < cols; c++) {
|
|
var result = null;
|
|
for (var n = 0; n < num; n++) {
|
|
var p = multiply(x[r][n], y[n][c]);
|
|
result = (result == null) ? p : math.add(result, p);
|
|
}
|
|
res[r][c] = result;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
else if (y instanceof Matrix) {
|
|
return new Matrix(multiply(x.valueOf(), y.valueOf()));
|
|
}
|
|
else {
|
|
// matrix * scalar
|
|
return collection.map2(x, y, multiply);
|
|
}
|
|
}
|
|
else if (x instanceof Matrix) {
|
|
return new Matrix(multiply(x.valueOf(), y.valueOf()));
|
|
}
|
|
|
|
if (isArray(y)) {
|
|
// scalar * matrix
|
|
return collection.map2(x, y, multiply);
|
|
}
|
|
else if (y instanceof Matrix) {
|
|
return new Matrix(multiply(x.valueOf(), y.valueOf()));
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return multiply(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('multiply', x, y);
|
|
};
|
|
|
|
/**
|
|
* Multiply two complex numbers. x * y or multiply(x, y)
|
|
* @param {Complex} x
|
|
* @param {Complex} y
|
|
* @return {Complex | Number} res
|
|
* @private
|
|
*/
|
|
function _multiplyComplex (x, y) {
|
|
// Note: we test whether x or y are pure real or pure complex,
|
|
// to prevent unnecessary NaN values. For example, Infinity*i should
|
|
// result in Infinity*i, and not in NaN+Infinity*i
|
|
|
|
if (x.im == 0) {
|
|
// x is pure real
|
|
if (y.im == 0) {
|
|
// y is pure real
|
|
return x.re * y.re;
|
|
}
|
|
else if (y.re == 0) {
|
|
// y is pure complex
|
|
return new Complex(
|
|
0,
|
|
x.re * y.im
|
|
);
|
|
}
|
|
else {
|
|
// y has a real and complex part
|
|
return new Complex(
|
|
x.re * y.re,
|
|
x.re * y.im
|
|
);
|
|
}
|
|
}
|
|
else if (x.re == 0) {
|
|
// x is pure complex
|
|
if (y.im == 0) {
|
|
// y is pure real
|
|
return new Complex(
|
|
0,
|
|
x.im * y.re
|
|
);
|
|
}
|
|
else if (y.re == 0) {
|
|
// y is pure complex
|
|
return -x.im * y.im;
|
|
}
|
|
else {
|
|
// y has a real and complex part
|
|
return new Complex(
|
|
-x.im * y.im,
|
|
x.im * y.re
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
// x has a real and complex part
|
|
if (y.im == 0) {
|
|
// y is pure real
|
|
return new Complex(
|
|
x.re * y.re,
|
|
x.im * y.re
|
|
);
|
|
}
|
|
else if (y.re == 0) {
|
|
// y is pure complex
|
|
return new Complex(
|
|
-x.im * y.im,
|
|
x.re * y.im
|
|
);
|
|
}
|
|
else {
|
|
// y has a real and complex part
|
|
return new Complex(
|
|
x.re * y.re - x.im * y.im,
|
|
x.re * y.im + x.im * y.re
|
|
);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Matrix.js":198,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],134:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Matrix = require('../../type/Matrix.js'),
|
|
|
|
array = util.array,
|
|
isNumBool = util.number.isNumBool,
|
|
isArray = Array.isArray,
|
|
isInteger = util.number.isInteger,
|
|
isComplex = Complex.isComplex;
|
|
|
|
/**
|
|
* Calculates the power of x to y
|
|
*
|
|
* x ^ y
|
|
* pow(x, y)
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex} y
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.pow = function pow(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('pow', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
if (isInteger(y) || x >= 0) {
|
|
// real value computation
|
|
return Math.pow(x, y);
|
|
}
|
|
else {
|
|
return powComplex(new Complex(x, 0), new Complex(y, 0));
|
|
}
|
|
}
|
|
else if (isComplex(y)) {
|
|
return powComplex(new Complex(x, 0), y);
|
|
}
|
|
}
|
|
else if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
return powComplex(x, new Complex(y, 0));
|
|
}
|
|
else if (isComplex(y)) {
|
|
return powComplex(x, y);
|
|
}
|
|
}
|
|
else if (isArray(x)) {
|
|
if (!isNumBool(y) || !isInteger(y) || y < 0) {
|
|
throw new TypeError('For A^b, b must be a positive integer ' +
|
|
'(value is ' + y + ')');
|
|
}
|
|
// verify that A is a 2 dimensional square matrix
|
|
var s = array.size(x);
|
|
if (s.length != 2) {
|
|
throw new Error('For A^b, A must be 2 dimensional ' +
|
|
'(A has ' + s.length + ' dimensions)');
|
|
}
|
|
if (s[0] != s[1]) {
|
|
throw new Error('For A^b, A must be square ' +
|
|
'(size is ' + s[0] + 'x' + s[1] + ')');
|
|
}
|
|
|
|
if (y == 0) {
|
|
// return the identity matrix
|
|
return math.eye(s[0]);
|
|
}
|
|
else {
|
|
// value > 0
|
|
var res = x;
|
|
for (var i = 1; i < y; i++) {
|
|
res = math.multiply(x, res);
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
else if (x instanceof Matrix) {
|
|
return new Matrix(pow(x.valueOf(), y));
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return pow(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('pow', x, y);
|
|
};
|
|
|
|
/**
|
|
* Calculates the power of x to y, x^y, for two complex numbers.
|
|
* @param {Complex} x
|
|
* @param {Complex} y
|
|
* @return {Complex} res
|
|
* @private
|
|
*/
|
|
function powComplex (x, y) {
|
|
// complex computation
|
|
// x^y = exp(log(x)*y) = exp((abs(x)+i*arg(x))*y)
|
|
var temp1 = math.log(x);
|
|
var temp2 = math.multiply(temp1, y);
|
|
return math.exp(temp2);
|
|
}
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Matrix.js":198,"../../util/index.js":205}],135:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumber = util.number.isNumber,
|
|
isInteger = util.number.isInteger,
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Round a value towards the nearest integer
|
|
*
|
|
* round(x)
|
|
* round(x, n)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @param {Number | Boolean | Array} [n] number of decimals (by default n=0)
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.round = function round(x, n) {
|
|
if (arguments.length != 1 && arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('round', arguments.length, 1, 2);
|
|
}
|
|
|
|
if (n == undefined) {
|
|
// round (x)
|
|
if (isNumBool(x)) {
|
|
return Math.round(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex (
|
|
Math.round(x.re),
|
|
Math.round(x.im)
|
|
);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, round);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return round(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('round', x);
|
|
}
|
|
else {
|
|
// round (x, n)
|
|
if (!isNumber(n) || !isInteger(n)) {
|
|
throw new TypeError('Number of decimals in function round must be an integer');
|
|
}
|
|
if (n < 0 || n > 9) {
|
|
throw new Error ('Number of decimals in function round must be in te range of 0-9');
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return roundNumber(x, n);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex (
|
|
roundNumber(x.re, n),
|
|
roundNumber(x.im, n)
|
|
);
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(n)) {
|
|
return collection.map2(x, n, round);
|
|
}
|
|
|
|
if (x.valueOf() !== x || n.valueOf() !== n) {
|
|
// fallback on the objects primitive values
|
|
return round(x.valueOf(), n.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('round', x, n);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* round a number to the given number of decimals, or to zero if decimals is
|
|
* not provided
|
|
* @param {Number} value
|
|
* @param {Number} [decimals] number of decimals, between 0 and 15 (0 by default)
|
|
* @return {Number} roundedValue
|
|
*/
|
|
function roundNumber (value, decimals) {
|
|
if (decimals) {
|
|
var p = Math.pow(10, decimals);
|
|
return Math.round(value * p) / p;
|
|
}
|
|
else {
|
|
return Math.round(value);
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],136:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
number = util.number,
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Compute the sign of a value.
|
|
*
|
|
* sign(x)
|
|
*
|
|
* The sign of a value x is 1 when x > 1, -1 when x < 0, and 0 when x == 0
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.sign = function sign(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('sign', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return number.sign(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
var abs = Math.sqrt(x.re * x.re + x.im * x.im);
|
|
return new Complex(x.re / abs, x.im / abs);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, sign);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return sign(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('sign', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],137:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Check if value x is smaller y
|
|
*
|
|
* x < y
|
|
* smaller(x, y)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
* In case of complex numbers, the absolute values of a and b are compared.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} y
|
|
* @return {Boolean | Array | Matrix} res
|
|
*/
|
|
math.smaller = function smaller(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('smaller', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
return x < y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return x < math.abs(y);
|
|
}
|
|
}
|
|
if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
return math.abs(x) < y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return math.abs(x) < math.abs(y);
|
|
}
|
|
}
|
|
|
|
if ((isUnit(x)) && (isUnit(y))) {
|
|
if (!x.equalBase(y)) {
|
|
throw new Error('Cannot compare units with different base');
|
|
}
|
|
return x.value < y.value;
|
|
}
|
|
|
|
if (isString(x) || isString(y)) {
|
|
return x < y;
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, smaller);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return smaller(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('smaller', x, y);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],138:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Check if value a is smaller or equal to b
|
|
*
|
|
* a <= b
|
|
* smallereq(a, b)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
* In case of complex numbers, the absolute values of a and b are compared.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} y
|
|
* @return {Boolean | Array | Matrix} res
|
|
*/
|
|
math.smallereq = function smallereq(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('smallereq', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
return x <= y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return x <= math.abs(y);
|
|
}
|
|
}
|
|
if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
return math.abs(x) <= y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return math.abs(x) <= math.abs(y);
|
|
}
|
|
}
|
|
|
|
if ((isUnit(x)) && (isUnit(y))) {
|
|
if (!x.equalBase(y)) {
|
|
throw new Error('Cannot compare units with different base');
|
|
}
|
|
return x.value <= y.value;
|
|
}
|
|
|
|
if (isString(x) || isString(y)) {
|
|
return x <= y;
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, smallereq);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return smallereq(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('smallereq', x, y);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],139:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the square root of a value
|
|
*
|
|
* sqrt(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.sqrt = function sqrt (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('sqrt', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (x >= 0) {
|
|
return Math.sqrt(x);
|
|
}
|
|
else {
|
|
return sqrt(new Complex(x, 0));
|
|
}
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
var r = Math.sqrt(x.re * x.re + x.im * x.im);
|
|
if (x.im >= 0) {
|
|
return new Complex(
|
|
0.5 * Math.sqrt(2.0 * (r + x.re)),
|
|
0.5 * Math.sqrt(2.0 * (r - x.re))
|
|
);
|
|
}
|
|
else {
|
|
return new Complex(
|
|
0.5 * Math.sqrt(2.0 * (r + x.re)),
|
|
-0.5 * Math.sqrt(2.0 * (r - x.re))
|
|
);
|
|
}
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, sqrt);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return sqrt(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('sqrt', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],140:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Compute the square of a value
|
|
*
|
|
* x .* x
|
|
* square(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.square = function square(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('square', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return x * x;
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return math.multiply(x, x);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, square);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return square(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('square', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],141:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Matrix = require('../../type/Matrix.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Subtract two values
|
|
*
|
|
* x - y
|
|
* subtract(x, y)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} y
|
|
* @return {Number | Complex | Unit | Array | Matrix} res
|
|
*/
|
|
math.subtract = function subtract(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('subtract', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
// number - number
|
|
return x - y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
// number - complex
|
|
return new Complex (
|
|
x - y.re,
|
|
- y.im
|
|
);
|
|
}
|
|
}
|
|
else if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
// complex - number
|
|
return new Complex (
|
|
x.re - y,
|
|
x.im
|
|
)
|
|
}
|
|
else if (isComplex(y)) {
|
|
// complex - complex
|
|
return new Complex (
|
|
x.re - y.re,
|
|
x.im - y.im
|
|
)
|
|
}
|
|
}
|
|
else if (isUnit(x)) {
|
|
if (isUnit(y)) {
|
|
if (!x.equalBase(y)) {
|
|
throw new Error('Units do not match');
|
|
}
|
|
|
|
if (x.value == null) {
|
|
throw new Error('Unit on left hand side of operator - has an undefined value');
|
|
}
|
|
|
|
if (y.value == null) {
|
|
throw new Error('Unit on right hand side of operator - has an undefined value');
|
|
}
|
|
|
|
var res = x.clone();
|
|
res.value -= y.value;
|
|
res.fixPrefix = false;
|
|
|
|
return res;
|
|
}
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, subtract);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return subtract(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('subtract', x, y);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Matrix.js":198,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],142:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Inverse the sign of a value.
|
|
*
|
|
* -x
|
|
* unary(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @return {Number | Complex | Unit | Array | Matrix} res
|
|
*/
|
|
math.unary = function unary(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('unary', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return -x;
|
|
}
|
|
else if (isComplex(x)) {
|
|
return new Complex(
|
|
-x.re,
|
|
-x.im
|
|
);
|
|
}
|
|
else if (isUnit(x)) {
|
|
var res = x.clone();
|
|
res.value = -x.value;
|
|
return res;
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, unary);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return unary(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('unary', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],143:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Check if value x unequals y, x != y
|
|
* In case of complex numbers, x.re must unequal y.re, or x.im must unequal y.im
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} x
|
|
* @param {Number | Boolean | Complex | Unit | String | Array | Matrix} y
|
|
* @return {Boolean | Array | Matrix} res
|
|
*/
|
|
math.unequal = function unequal(x, y) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('unequal', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (isNumBool(y)) {
|
|
return x != y;
|
|
}
|
|
else if (isComplex(y)) {
|
|
return (x != y.re) || (y.im != 0);
|
|
}
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
if (isNumBool(y)) {
|
|
return (x.re != y) || (x.im != 0);
|
|
}
|
|
else if (isComplex(y)) {
|
|
return (x.re != y.re) || (x.im != y.im);
|
|
}
|
|
}
|
|
|
|
if ((isUnit(x)) && (isUnit(y))) {
|
|
if (!x.equalBase(y)) {
|
|
throw new Error('Cannot compare units with different base');
|
|
}
|
|
return x.value != y.value;
|
|
}
|
|
|
|
if (isString(x) || isString(y)) {
|
|
return x != y;
|
|
}
|
|
|
|
if (isCollection(x) || isCollection(y)) {
|
|
return collection.map2(x, y, unequal);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return unequal(x.valueOf(), y.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('unequal', x, y);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],144:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isInteger = util.number.isInteger;
|
|
|
|
/**
|
|
* Calculate the extended greatest common divisor for two values.
|
|
*
|
|
* xgcd(a, b)
|
|
*
|
|
* @param {Number | Boolean} a An integer number
|
|
* @param {Number | Boolean} b An integer number
|
|
* @return {Array} An array containing 3 integers [div, m, n]
|
|
* where div = gcd(a, b) and a*m + b*n = div
|
|
*
|
|
* @see http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
|
|
*/
|
|
math.xgcd = function xgcd(a, b) {
|
|
if (arguments.length == 2) {
|
|
// two arguments
|
|
if (isNumBool(a) && isNumBool(b)) {
|
|
if (!isInteger(a) || !isInteger(b)) {
|
|
throw new Error('Parameters in function xgcd must be integer numbers');
|
|
}
|
|
|
|
return _xgcd(a, b);
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('xgcd', a, b);
|
|
}
|
|
|
|
// zero or one argument
|
|
throw new SyntaxError('Function xgcd expects two arguments');
|
|
};
|
|
|
|
/**
|
|
* Calculate xgcd for two numbers
|
|
* @param {Number} a
|
|
* @param {Number} b
|
|
* @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;
|
|
|
|
while (b) {
|
|
q = Math.floor(a / b);
|
|
r = a % b;
|
|
|
|
t = x;
|
|
x = lastx - q * x;
|
|
lastx = t;
|
|
|
|
t = y;
|
|
y = lasty - q * y;
|
|
lasty = t;
|
|
|
|
a = b;
|
|
b = r;
|
|
}
|
|
|
|
if (a < 0) {
|
|
return [-a, a ? -lastx : 0, -lasty];
|
|
}
|
|
else {
|
|
return [a, a ? lastx : 0, lasty];
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"../../util/index.js":205}],145:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isCollection =collection.isCollection,
|
|
isComplex = Complex.isComplex;
|
|
|
|
/**
|
|
* Compute the argument of a complex value.
|
|
* If x = a + bi, the argument is computed as atan2(b, a).
|
|
*
|
|
* arg(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Complex | Array | Matrix | Boolean} x
|
|
* @return {Number | Array | Matrix} res
|
|
*/
|
|
math.arg = function arg(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('arg', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.atan2(0, x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return Math.atan2(x.im, x.re);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, arg);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return arg(x.valueOf());
|
|
}
|
|
|
|
// handle other types just as non-complex values
|
|
return math.atan2(0, x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],146:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
object = util.object,
|
|
isNumBool = util.number.isNumBool,
|
|
isCollection =collection.isCollection,
|
|
isComplex = Complex.isComplex;
|
|
|
|
/**
|
|
* Compute the complex conjugate of a complex value.
|
|
* If x = a+bi, the complex conjugate is a-bi.
|
|
*
|
|
* conj(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Complex | Array | Matrix | Boolean} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.conj = function conj(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('conj', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return x;
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex(x.re, -x.im);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, conj);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return conj(x.valueOf());
|
|
}
|
|
|
|
// return a clone of the value for non-complex values
|
|
return object.clone(x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],147:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isCollection =collection.isCollection,
|
|
isComplex = Complex.isComplex;
|
|
|
|
/**
|
|
* Get the imaginary part of a complex number.
|
|
*
|
|
* im(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Complex | Array | Matrix | Boolean} x
|
|
* @return {Number | Array | Matrix} im
|
|
*/
|
|
math.im = function im(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('im', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return 0;
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return x.im;
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, im);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return im(x.valueOf());
|
|
}
|
|
|
|
// return 0 for all non-complex values
|
|
return 0;
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],148:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
object = util.object,
|
|
isNumBool = util.number.isNumBool,
|
|
isCollection =collection.isCollection,
|
|
isComplex = Complex.isComplex;
|
|
|
|
/**
|
|
* Get the real part of a complex number.
|
|
*
|
|
* re(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Complex | Array | Matrix | Boolean} x
|
|
* @return {Number | Array | Matrix} re
|
|
*/
|
|
math.re = function re(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('re', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return x;
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return x.re;
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, re);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return re(x.valueOf());
|
|
}
|
|
|
|
// return a clone of the value itself for all non-complex values
|
|
return object.clone(x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],149:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isCollection = collection.isCollection,
|
|
isNumber = util.number.isNumber,
|
|
isString = util.string.isString;
|
|
|
|
/**
|
|
* Create a boolean or convert a string or number to a boolean.
|
|
* In case of a number, true is returned for non-zero numbers, and false in
|
|
* case of zero.
|
|
* Strings can be 'true' or 'false', or can contain a number.
|
|
* @param {String | Number | Boolean | Array | Matrix} value
|
|
* @return {Boolean | Array | Matrix} bool
|
|
*/
|
|
math['boolean'] = function bool (value) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('boolean', arguments.length, 0, 1);
|
|
}
|
|
|
|
if (value === 'true' || value === true) {
|
|
return true;
|
|
}
|
|
|
|
if (value === 'false' || value === false) {
|
|
return false;
|
|
}
|
|
|
|
if (value instanceof Boolean) {
|
|
return value ? true : false;
|
|
}
|
|
|
|
if (isNumber(value)) {
|
|
return (value !== 0);
|
|
}
|
|
|
|
if (isString(value)) {
|
|
// try case insensitive
|
|
var lcase = value.toLowerCase();
|
|
if (lcase === 'true') {
|
|
return true;
|
|
}
|
|
else if (lcase === 'false') {
|
|
return false;
|
|
}
|
|
|
|
// test whether value is a valid number
|
|
var num = Number(value);
|
|
if (value != '' && !isNaN(num)) {
|
|
return (num !== 0);
|
|
}
|
|
}
|
|
|
|
if (isCollection(value)) {
|
|
return collection.map(value, bool);
|
|
}
|
|
|
|
throw new SyntaxError(value.toString() + ' is no valid boolean');
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],150:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isCollection = collection.isCollection,
|
|
isNumber = util.number.isNumber,
|
|
isBoolean = util.boolean.isBoolean,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex;
|
|
|
|
/**
|
|
* Create a complex value or convert a value to a complex value.
|
|
*
|
|
* The method accepts the following arguments:
|
|
* complex() creates a complex value with zero
|
|
* as real and imaginary part.
|
|
* complex(re : number, im : string) creates a complex value with provided
|
|
* values for real and imaginary part.
|
|
* complex(re : number) creates a complex value with provided
|
|
* real value and zero imaginary part.
|
|
* complex(arg : string) parses a string into a complex value.
|
|
* complex(array : Array) converts the elements of the array
|
|
* or matrix element wise into a
|
|
* complex value.
|
|
*
|
|
* Example usage:
|
|
* var a = math.complex(3, -4); // 3 - 4i
|
|
* a.re = 5; // a = 5 - 4i
|
|
* var i = a.im; // -4;
|
|
* var b = math.complex('2 + 6i'); // 2 + 6i
|
|
* var c = math.complex(); // 0 + 0i
|
|
* var d = math.add(a, b); // 5 + 2i
|
|
*
|
|
* @param {* | Array | Matrix} [args]
|
|
* @return {Complex | Array | Matrix} value
|
|
*/
|
|
math.complex = function complex(args) {
|
|
switch (arguments.length) {
|
|
case 0:
|
|
// no parameters. Set re and im zero
|
|
return new Complex(0, 0);
|
|
break;
|
|
|
|
case 1:
|
|
// parse string into a complex number
|
|
var arg = arguments[0];
|
|
|
|
if (isNumber(arg)) {
|
|
return new Complex(arg, 0);
|
|
}
|
|
|
|
if (isComplex(arg)) {
|
|
// create a clone
|
|
return arg.clone();
|
|
}
|
|
|
|
if (isString(arg)) {
|
|
var c = Complex.parse(arg);
|
|
if (c) {
|
|
return c;
|
|
}
|
|
else {
|
|
throw new SyntaxError('String "' + arg + '" is no valid complex number');
|
|
}
|
|
}
|
|
|
|
if (isCollection(arg)) {
|
|
return collection.map(arg, complex);
|
|
}
|
|
|
|
if (isBoolean(arg)) {
|
|
return new Complex(Number(arg), 0);
|
|
}
|
|
|
|
throw new TypeError(
|
|
'Two numbers or a single string expected in function complex');
|
|
break;
|
|
|
|
case 2:
|
|
// re and im provided
|
|
return new Complex(arguments[0], arguments[1]);
|
|
break;
|
|
|
|
default:
|
|
throw new util.error.ArgumentsError('complex', arguments.length, 0, 2);
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],151:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Index = require('../../type/Index.js');
|
|
|
|
/**
|
|
* Create an index. An Index can store ranges having start, step, and end
|
|
* for multiple dimensions.
|
|
* Matrix.get, Matrix.set, and math.subset accept an Index as input.
|
|
*
|
|
* Usage:
|
|
* var index = math.index(range1, range2, ...);
|
|
*
|
|
* Where each range can be any of:
|
|
* An array [start, end]
|
|
* An array [start, end, step]
|
|
* A number
|
|
* null, this will create select the whole dimension
|
|
*
|
|
* The parameters start, end, and step must be integer numbers.
|
|
*
|
|
* @param {...*} ranges
|
|
*/
|
|
math.index = function matrix(ranges) {
|
|
var i = new Index();
|
|
Index.apply(i, arguments);
|
|
return i;
|
|
};
|
|
};
|
|
|
|
},{"../../type/Index.js":197,"../../util/index.js":205}],152:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js');
|
|
|
|
/**
|
|
* Create a matrix. The function creates a new math.type.Matrix object.
|
|
*
|
|
* The method accepts the following arguments:
|
|
* matrix() creates an empty matrix
|
|
* matrix(data) creates a matrix with initial data.
|
|
*
|
|
* Example usage:
|
|
* var m = matrix([[1, 2], [3, 4]);
|
|
* m.size(); // [2, 2]
|
|
* m.resize([3, 2], 5);
|
|
* m.valueOf(); // [[1, 2], [3, 4], [5, 5]]
|
|
* m.get([1, 0]) // 3
|
|
*
|
|
* @param {Array | Matrix} [data] A multi dimensional array
|
|
* @return {Matrix} matrix
|
|
*/
|
|
math.matrix = function matrix(data) {
|
|
if (arguments.length > 1) {
|
|
throw new util.error.ArgumentsError('matrix', arguments.length, 0, 1);
|
|
}
|
|
|
|
return new Matrix(data);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../util/index.js":205}],153:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Create a number or convert a string to a number
|
|
* @param {String | Number | Boolean | Array | Matrix} [value]
|
|
* @return {Number | Array | Matrix} num
|
|
*/
|
|
math.number = function number (value) {
|
|
switch (arguments.length) {
|
|
case 0:
|
|
return 0;
|
|
|
|
case 1:
|
|
if (isCollection(value)) {
|
|
return collection.map(value, number);
|
|
}
|
|
|
|
var num = Number(value);
|
|
if (isNaN(num)) {
|
|
num = Number(value.valueOf());
|
|
}
|
|
if (isNaN(num)) {
|
|
throw new SyntaxError(value.toString() + ' is no valid number');
|
|
}
|
|
return num;
|
|
default:
|
|
throw new util.error.ArgumentsError('number', arguments.length, 0, 1);
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],154:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Parser = require('../../expression/Parser.js');
|
|
|
|
/**
|
|
* Create a parser. The function creates a new math.expression.Parser object.
|
|
*
|
|
* parser()
|
|
*
|
|
* Example usage:
|
|
* var parser = new math.parser();
|
|
*
|
|
* // evaluate expressions
|
|
* var a = parser.eval('sqrt(3^2 + 4^2)'); // 5
|
|
* var b = parser.eval('sqrt(-4)'); // 2i
|
|
* var c = parser.eval('2 inch in cm'); // 5.08 cm
|
|
* var d = parser.eval('cos(45 deg)'); // 0.7071067811865476
|
|
*
|
|
* // define variables and functions
|
|
* parser.eval('x = 7 / 2'); // 3.5
|
|
* parser.eval('x + 3'); // 6.5
|
|
* parser.eval('function f(x, y) = x^y'); // f(x, y)
|
|
* parser.eval('f(2, 3)'); // 8
|
|
*
|
|
* // get and set variables and functions
|
|
* var x = parser.get('x'); // 7
|
|
* var f = parser.get('f'); // function
|
|
* var g = f(3, 2); // 9
|
|
* parser.set('h', 500);
|
|
* var i = parser.eval('h / 2'); // 250
|
|
* parser.set('hello', function (name) {
|
|
* return 'hello, ' + name + '!';
|
|
* });
|
|
* parser.eval('hello("user")'); // "hello, user!"
|
|
*
|
|
* // clear defined functions and variables
|
|
* parser.clear();
|
|
*
|
|
* @return {Parser} Parser
|
|
*/
|
|
math.parser = function parser() {
|
|
return new Parser(math);
|
|
};
|
|
};
|
|
|
|
},{"../../expression/Parser.js":4,"../../util/index.js":205}],155:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
collection = require('../../type/collection.js'),
|
|
|
|
number = util.number,
|
|
isNumber = util.number.isNumber,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Create a string or convert any object into a string.
|
|
* Elements of Arrays and Matrices are processed element wise
|
|
* @param {* | Array | Matrix} [value]
|
|
* @return {String | Array | Matrix} str
|
|
*/
|
|
math.string = function string (value) {
|
|
switch (arguments.length) {
|
|
case 0:
|
|
return '';
|
|
|
|
case 1:
|
|
if (isNumber(value)) {
|
|
return number.format(value);
|
|
}
|
|
|
|
if (isCollection(value)) {
|
|
return collection.map(value, string);
|
|
}
|
|
|
|
if (value === null) {
|
|
return 'null';
|
|
}
|
|
|
|
return value.toString();
|
|
|
|
default:
|
|
throw new util.error.ArgumentsError('string', arguments.length, 0, 1);
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],156:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isCollection = collection.isCollection,
|
|
isString = util.string.isString;
|
|
|
|
/**
|
|
* Create a unit. Depending on the passed arguments, the function
|
|
* will create and return a new math.type.Unit object.
|
|
*
|
|
* The method accepts the following arguments:
|
|
* unit(unit : string)
|
|
* unit(value : number, unit : string
|
|
*
|
|
* Example usage:
|
|
* var a = math.unit(5, 'cm'); // 50 mm
|
|
* var b = math.unit('23 kg'); // 23 kg
|
|
* var c = math.in(a, math.unit('m'); // 0.05 m
|
|
*
|
|
* @param {* | Array | Matrix} args
|
|
* @return {Unit | Array | Matrix} value
|
|
*/
|
|
math.unit = function unit(args) {
|
|
switch(arguments.length) {
|
|
case 1:
|
|
// parse a string
|
|
var arg = arguments[0];
|
|
|
|
if (arg instanceof Unit) {
|
|
// create a clone of the unit
|
|
return arg.clone();
|
|
}
|
|
|
|
if (isString(arg)) {
|
|
if (Unit.isPlainUnit(arg)) {
|
|
return new Unit(null, arg); // a pure unit
|
|
}
|
|
|
|
var u = Unit.parse(arg); // a unit with value, like '5cm'
|
|
if (u) {
|
|
return u;
|
|
}
|
|
|
|
throw new SyntaxError('String "' + arg + '" is no valid unit');
|
|
}
|
|
|
|
if (isCollection(args)) {
|
|
return collection.map(args, unit);
|
|
}
|
|
|
|
throw new TypeError('A string or a number and string expected in function unit');
|
|
break;
|
|
|
|
case 2:
|
|
// a number and a unit
|
|
return new Unit(arguments[0], arguments[1]);
|
|
break;
|
|
|
|
default:
|
|
throw new util.error.ArgumentsError('unit', arguments.length, 1, 2);
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],157:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Scope = require('../../expression/Scope.js'),
|
|
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isString = util.string.isString,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Evaluate an expression.
|
|
*
|
|
* Syntax:
|
|
*
|
|
* math.eval(expr)
|
|
* math.eval(expr, scope)
|
|
* math.eval([expr1, expr2, expr3, ...])
|
|
* math.eval([expr1, expr2, expr3, ...], scope)
|
|
*
|
|
* Example:
|
|
*
|
|
* math.eval('(2+3)/4'); // 1.25
|
|
* math.eval('sqrt(3^2 + 4^2)'); // 5
|
|
* math.eval('sqrt(-4)'); // 2i
|
|
* math.eval(['a=3', 'b=4', 'a*b']);, // [3, 4, 12]
|
|
*
|
|
* var scope = {a:3, b:4};
|
|
* math.eval('a * b', scope); // 12
|
|
*
|
|
* @param {String | String[] | Matrix} expr
|
|
* @param {Scope | Object} [scope]
|
|
* @return {*} res
|
|
* @throws {Error}
|
|
*/
|
|
math.eval = function _eval (expr, scope) {
|
|
if (arguments.length != 1 && arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('eval', arguments.length, 1, 2);
|
|
}
|
|
|
|
// instantiate a scope
|
|
var evalScope;
|
|
if (scope) {
|
|
if (scope instanceof Scope) {
|
|
evalScope = scope;
|
|
}
|
|
else {
|
|
evalScope = new Scope(math, scope);
|
|
}
|
|
}
|
|
else {
|
|
evalScope = new Scope(math);
|
|
}
|
|
|
|
if (isString(expr)) {
|
|
// evaluate a single expression
|
|
var node = math.parse(expr, evalScope);
|
|
return node.eval();
|
|
}
|
|
else if (isCollection(expr)) {
|
|
// evaluate an array or matrix with expressions
|
|
return collection.map(expr, function (elem) {
|
|
var node = math.parse(elem, evalScope);
|
|
return node.eval();
|
|
});
|
|
}
|
|
else {
|
|
// oops
|
|
throw new TypeError('String or matrix expected');
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../expression/Scope.js":5,"../../type/collection.js":201,"../../util/index.js":205}],158:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Help = require('../../type/Help.js');
|
|
|
|
/**
|
|
* Retrieve help on a function or data type.
|
|
* Help files are retrieved from the documentation in math.expression.docs.
|
|
* @param {function | string | Object} search
|
|
* @return {Help} help
|
|
*/
|
|
math.help = function help(search) {
|
|
if (arguments.length != 1) {
|
|
throw new SyntaxError('Wrong number of arguments in function help ' +
|
|
'(' + arguments.length + ' provided, 1 expected)');
|
|
}
|
|
|
|
var text = null;
|
|
if ((search instanceof String) || (typeof(search) === 'string')) {
|
|
text = search;
|
|
}
|
|
else {
|
|
var prop;
|
|
for (prop in math) {
|
|
// search in functions and constants
|
|
if (math.hasOwnProperty(prop)) {
|
|
if (search === math[prop]) {
|
|
text = prop;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!text) {
|
|
// search data type
|
|
for (prop in math.type) {
|
|
if (math.type.hasOwnProperty(prop)) {
|
|
if (search === math.type[prop]) {
|
|
text = prop;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!text) {
|
|
throw new Error('Could not find search term "' + search + '"');
|
|
}
|
|
else {
|
|
var doc = math.expression.docs[text];
|
|
if (!doc) {
|
|
throw new Error('No documentation found on "' + text + '"');
|
|
}
|
|
return new Help(math, doc);
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Help.js":196,"../../util/index.js":205}],159:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
isString = util.string.isString,
|
|
isArray = Array.isArray,
|
|
|
|
// types
|
|
Complex = require('./../../type/Complex.js'),
|
|
Matrix = require('./../../type/Matrix.js'),
|
|
Unit = require('./../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
// scope and nodes
|
|
Scope = require('./../../expression/Scope.js'),
|
|
AssignmentNode = require('../../expression/node/AssignmentNode.js'),
|
|
BlockNode = require('../../expression/node/BlockNode.js'),
|
|
ConstantNode = require('../../expression/node/ConstantNode.js'),
|
|
FunctionNode = require('../../expression/node/FunctionNode.js'),
|
|
MatrixNode = require('../../expression/node/MatrixNode.js'),
|
|
OperatorNode = require('../../expression/node/OperatorNode.js'),
|
|
ParamsNode = require('../../expression/node/ParamsNode.js'),
|
|
RangeNode = require('../../expression/node/RangeNode.js'),
|
|
SymbolNode = require('../../expression/node/SymbolNode.js'),
|
|
UpdateNode = require('../../expression/node/UpdateNode.js'),
|
|
handlers = require('../../expression/node/handlers.js');
|
|
|
|
/**
|
|
* Parse an expression. Returns a node tree, which can be evaluated by
|
|
* invoking node.eval();
|
|
*
|
|
* Syntax:
|
|
*
|
|
* math.parse(expr)
|
|
* math.parse(expr, scope)
|
|
* math.parse([expr1, expr2, expr3, ...])
|
|
* math.parse([expr1, expr2, expr3, ...], scope)
|
|
*
|
|
* Example:
|
|
*
|
|
* var node = math.parse('sqrt(3^2 + 4^2)');
|
|
* node.eval(); // 5
|
|
*
|
|
* var scope = {a:3, b:4}
|
|
* var node = math.parse('a * b', scope); // 12
|
|
* node.eval(); // 12
|
|
* scope.a = 5;
|
|
* node.eval(); // 20
|
|
*
|
|
* var nodes = math.parse(['a = 3', 'b = 4', 'a * b']);
|
|
* nodes[2].eval(); // 12
|
|
*
|
|
* @param {String | String[] | Matrix} expr
|
|
* @param {Scope | Object} [scope]
|
|
* @return {Node | Node[]} node
|
|
* @throws {Error}
|
|
*/
|
|
math.parse = function parse (expr, scope) {
|
|
if (arguments.length != 1 && arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('parse', arguments.length, 1, 2);
|
|
}
|
|
|
|
// instantiate a scope
|
|
var parseScope;
|
|
if (scope) {
|
|
if (scope instanceof Scope) {
|
|
parseScope = scope;
|
|
}
|
|
else {
|
|
parseScope = new Scope(math, scope);
|
|
}
|
|
}
|
|
else {
|
|
parseScope = new Scope(math);
|
|
}
|
|
|
|
if (isString(expr)) {
|
|
// parse a single expression
|
|
expression = expr || '';
|
|
return parseStart(parseScope);
|
|
}
|
|
else if (isArray(expr) || expr instanceof Matrix) {
|
|
// parse an array or matrix with expressions
|
|
return collection.map(expr, function (elem) {
|
|
expression = elem || '';
|
|
return parseStart(parseScope);
|
|
});
|
|
}
|
|
else {
|
|
// oops
|
|
throw new TypeError('String or matrix expected');
|
|
}
|
|
};
|
|
|
|
// token types enumeration
|
|
var TOKENTYPE = {
|
|
NULL : 0,
|
|
DELIMITER : 1,
|
|
NUMBER : 2,
|
|
SYMBOL : 3,
|
|
UNKNOWN : 4
|
|
};
|
|
|
|
// map with all delimiters
|
|
var DELIMITERS = {
|
|
',': true,
|
|
'(': true,
|
|
')': true,
|
|
'[': true,
|
|
']': true,
|
|
'\"': true,
|
|
'\n': true,
|
|
';': true,
|
|
|
|
'+': true,
|
|
'-': true,
|
|
'*': true,
|
|
'.*': true,
|
|
'/': true,
|
|
'./': true,
|
|
'%': true,
|
|
'^': true,
|
|
'.^': true,
|
|
'!': true,
|
|
'\'': true,
|
|
'=': true,
|
|
':': true,
|
|
|
|
'==': true,
|
|
'!=': true,
|
|
'<': true,
|
|
'>': true,
|
|
'<=': true,
|
|
'>=': true
|
|
};
|
|
|
|
var expression = ''; // current expression
|
|
var index = 0; // current index in expr
|
|
var c = ''; // current token character in expr
|
|
var token = ''; // current token
|
|
var token_type = TOKENTYPE.NULL; // type of the token
|
|
|
|
/**
|
|
* Get the first character from the expression.
|
|
* The character is stored into the char c. If the end of the expression is
|
|
* reached, the function puts an empty string in c.
|
|
* @private
|
|
*/
|
|
function first() {
|
|
index = 0;
|
|
c = expression.charAt(0);
|
|
}
|
|
|
|
/**
|
|
* Get the next character from the expression.
|
|
* The character is stored into the char c. If the end of the expression is
|
|
* reached, the function puts an empty string in c.
|
|
* @private
|
|
*/
|
|
function next() {
|
|
index++;
|
|
c = expression.charAt(index);
|
|
}
|
|
|
|
/**
|
|
* Preview the next character from the expression.
|
|
* @return {String} cNext
|
|
* @private
|
|
*/
|
|
function nextPreview() {
|
|
return expression.charAt(index + 1);
|
|
}
|
|
|
|
/**
|
|
* Get next token in the current string expr.
|
|
* The token and token type are available as token and token_type
|
|
* @private
|
|
*/
|
|
function getToken() {
|
|
token_type = TOKENTYPE.NULL;
|
|
token = '';
|
|
|
|
// skip over whitespaces
|
|
while (c == ' ' || c == '\t') { // space or tab
|
|
next();
|
|
}
|
|
|
|
// skip comment
|
|
if (c == '#') {
|
|
while (c != '\n' && c != '') {
|
|
next();
|
|
}
|
|
}
|
|
|
|
// check for end of expression
|
|
if (c == '') {
|
|
// token is still empty
|
|
token_type = TOKENTYPE.DELIMITER;
|
|
return;
|
|
}
|
|
|
|
// check for delimiters consisting of 2 characters
|
|
var c2 = c + nextPreview();
|
|
if (DELIMITERS[c2]) {
|
|
token_type = TOKENTYPE.DELIMITER;
|
|
token = c2;
|
|
next();
|
|
next();
|
|
return;
|
|
}
|
|
|
|
// check for delimiters consisting of 1 character
|
|
if (DELIMITERS[c]) {
|
|
token_type = TOKENTYPE.DELIMITER;
|
|
token = c;
|
|
next();
|
|
return;
|
|
}
|
|
|
|
// check for a number
|
|
if (isDigitDot(c)) {
|
|
token_type = TOKENTYPE.NUMBER;
|
|
|
|
// get number, can have a single dot
|
|
if (c == '.') {
|
|
token += c;
|
|
next();
|
|
|
|
if (!isDigit(c)) {
|
|
// this is no legal number, it is just a dot
|
|
token_type = TOKENTYPE.UNKNOWN;
|
|
}
|
|
}
|
|
else {
|
|
while (isDigit(c)) {
|
|
token += c;
|
|
next();
|
|
}
|
|
if (c == '.') {
|
|
token += c;
|
|
next();
|
|
}
|
|
}
|
|
while (isDigit(c)) {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
// check for scientific notation like "2.3e-4" or "1.23e50"
|
|
if (c == 'E' || c == 'e') {
|
|
token += c;
|
|
next();
|
|
|
|
if (c == '+' || c == '-') {
|
|
token += c;
|
|
next();
|
|
}
|
|
|
|
// Scientific notation MUST be followed by an exponent
|
|
if (!isDigit(c)) {
|
|
// this is no legal number, exponent is missing.
|
|
token_type = TOKENTYPE.UNKNOWN;
|
|
}
|
|
|
|
while (isDigit(c)) {
|
|
token += c;
|
|
next();
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// check for variables or functions
|
|
if (isAlpha(c)) {
|
|
token_type = TOKENTYPE.SYMBOL;
|
|
|
|
while (isAlpha(c) || isDigit(c)) {
|
|
token += c;
|
|
next();
|
|
}
|
|
return;
|
|
}
|
|
|
|
// something unknown is found, wrong characters -> a syntax error
|
|
token_type = TOKENTYPE.UNKNOWN;
|
|
while (c != '') {
|
|
token += c;
|
|
next();
|
|
}
|
|
throw createSyntaxError('Syntax error in part "' + token + '"');
|
|
}
|
|
|
|
/**
|
|
* Check if a given name is valid
|
|
* if not, an error is thrown
|
|
* @param {String} name
|
|
* @return {boolean} valid
|
|
* @private
|
|
*/
|
|
// TODO: check for valid symbol name
|
|
function isValidSymbolName (name) {
|
|
for (var i = 0, iMax = name.length; i < iMax; i++) {
|
|
var c = name.charAt(i);
|
|
//var valid = (isAlpha(c) || (i > 0 && isDigit(c))); // TODO: allow digits in symbol name
|
|
var valid = (isAlpha(c));
|
|
if (!valid) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* checks if the given char c is a letter (upper or lower case)
|
|
* or underscore
|
|
* @param {String} c a string with one character
|
|
* @return {Boolean}
|
|
* @private
|
|
*/
|
|
function isAlpha (c) {
|
|
return ((c >= 'a' && c <= 'z') ||
|
|
(c >= 'A' && c <= 'Z') ||
|
|
c == '_');
|
|
}
|
|
|
|
/**
|
|
* checks if the given char c is a digit or dot
|
|
* @param {String} c a string with one character
|
|
* @return {Boolean}
|
|
* @private
|
|
*/
|
|
function isDigitDot (c) {
|
|
return ((c >= '0' && c <= '9') ||
|
|
c == '.');
|
|
}
|
|
|
|
/**
|
|
* checks if the given char c is a digit
|
|
* @param {String} c a string with one character
|
|
* @return {Boolean}
|
|
* @private
|
|
*/
|
|
function isDigit (c) {
|
|
return ((c >= '0' && c <= '9'));
|
|
}
|
|
|
|
/**
|
|
* Start of the parse levels below, in order of precedence
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseStart (scope) {
|
|
// get the first character in expression
|
|
first();
|
|
|
|
getToken();
|
|
|
|
var node;
|
|
if (token == '') {
|
|
// empty expression
|
|
node = new ConstantNode(undefined);
|
|
}
|
|
else {
|
|
node = parseBlock(scope);
|
|
}
|
|
|
|
// check for garbage at the end of the expression
|
|
// an expression ends with a empty character '' and token_type DELIMITER
|
|
if (token != '') {
|
|
if (token_type == TOKENTYPE.DELIMITER) {
|
|
// user entered a not existing operator like "//"
|
|
|
|
// TODO: give hints for aliases, for example with "<>" give as hint " did you mean != ?"
|
|
throw createError('Unknown operator ' + token);
|
|
}
|
|
else {
|
|
throw createSyntaxError('Unexpected part "' + token + '"');
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* Parse a block with expressions. Expressions can be separated by a newline
|
|
* character '\n', or by a semicolon ';'. In case of a semicolon, no output
|
|
* of the preceding line is returned.
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseBlock (scope) {
|
|
var node, block, visible;
|
|
|
|
if (token != '\n' && token != ';' && token != '') {
|
|
node = parseAns(scope);
|
|
}
|
|
|
|
while (token == '\n' || token == ';') {
|
|
if (!block) {
|
|
// initialize the block
|
|
block = new BlockNode();
|
|
if (node) {
|
|
visible = (token != ';');
|
|
block.add(node, visible);
|
|
}
|
|
}
|
|
|
|
getToken();
|
|
if (token != '\n' && token != ';' && token != '') {
|
|
node = parseAns(scope);
|
|
|
|
visible = (token != ';');
|
|
block.add(node, visible);
|
|
}
|
|
}
|
|
|
|
if (block) {
|
|
return block;
|
|
}
|
|
|
|
if (!node) {
|
|
node = parseAns(scope);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* Parse assignment of ans.
|
|
* Ans is assigned when the expression itself is no variable or function
|
|
* assignment
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseAns (scope) {
|
|
var expression = parseFunctionAssignment(scope);
|
|
|
|
// create a variable definition for ans
|
|
var name = 'ans';
|
|
return new AssignmentNode(name, expression, scope);
|
|
}
|
|
|
|
/**
|
|
* Parse a function assignment like "function f(a,b) = a*b"
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseFunctionAssignment (scope) {
|
|
// TODO: keyword 'function' must become a reserved keyword
|
|
// TODO: replace the 'function' keyword with an assignment operator '=>'
|
|
if (token_type == TOKENTYPE.SYMBOL && token == 'function') {
|
|
// get function name
|
|
getToken();
|
|
if (token_type != TOKENTYPE.SYMBOL) {
|
|
throw createSyntaxError('Function name expected');
|
|
}
|
|
var name = token;
|
|
|
|
// get parenthesis open
|
|
getToken();
|
|
if (token != '(') {
|
|
throw createSyntaxError('Opening parenthesis ( expected');
|
|
}
|
|
|
|
// get function variables
|
|
var functionScope = scope.createSubScope();
|
|
var variables = [];
|
|
while (true) {
|
|
getToken();
|
|
if (token_type == TOKENTYPE.SYMBOL) {
|
|
// store variable name
|
|
variables.push(token);
|
|
}
|
|
else {
|
|
throw createSyntaxError('Variable name expected');
|
|
}
|
|
|
|
getToken();
|
|
if (token == ',') {
|
|
// ok, nothing to do, read next variable
|
|
}
|
|
else if (token == ')') {
|
|
// end of variable list encountered. break loop
|
|
break;
|
|
}
|
|
else {
|
|
throw createSyntaxError('Comma , or closing parenthesis ) expected"');
|
|
}
|
|
}
|
|
|
|
getToken();
|
|
if (token != '=') {
|
|
throw createSyntaxError('Equal sign = expected');
|
|
}
|
|
|
|
// parse the expression, with the correct function scope
|
|
getToken();
|
|
var expression = parseAssignment(functionScope);
|
|
|
|
return new FunctionNode(name, variables, expression, functionScope, scope);
|
|
}
|
|
|
|
return parseAssignment(scope);
|
|
}
|
|
|
|
/**
|
|
* Assignment of a variable, can be a variable like "a=2.3" or a updating an
|
|
* existing variable like "matrix(2,3:5)=[6,7,8]"
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseAssignment (scope) {
|
|
var name, params, paramScopes, expr;
|
|
|
|
var node = parseRange(scope);
|
|
|
|
if (token == '=') {
|
|
if (node instanceof SymbolNode) {
|
|
// parse the expression, with the correct function scope
|
|
getToken();
|
|
name = node.name;
|
|
params = null;
|
|
expr = parseAssignment(scope);
|
|
return new AssignmentNode(name, expr, scope);
|
|
}
|
|
else if ((node instanceof ParamsNode) && (node.object instanceof SymbolNode)) {
|
|
// parse the expression, with the correct function scope
|
|
getToken();
|
|
name = node.object.name;
|
|
params = node.params;
|
|
paramScopes = node.paramScopes;
|
|
expr = parseAssignment(scope);
|
|
return new UpdateNode(math, name, params, paramScopes, expr, scope);
|
|
}
|
|
else {
|
|
throw createSyntaxError('Symbol expected at the left hand side ' +
|
|
'of assignment operator =');
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* parse range, "start:end", "start:step:end", ":", "start:", ":end", etc
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseRange (scope) {
|
|
var node, params = [];
|
|
|
|
if (token == ':') {
|
|
// implicit start=1 (one-based)
|
|
node = new ConstantNode(1);
|
|
}
|
|
else {
|
|
// explicit start
|
|
node = parseConditions(scope);
|
|
}
|
|
|
|
if (token == ':') {
|
|
params.push(node);
|
|
|
|
// parse step and end
|
|
while (token == ':') {
|
|
getToken();
|
|
if (token == ')' || token == ',' || token == '') {
|
|
// implicit end
|
|
params.push(new SymbolNode('end', scope));
|
|
}
|
|
else {
|
|
// explicit end
|
|
params.push(parseConditions(scope));
|
|
}
|
|
}
|
|
|
|
if (params.length) {
|
|
node = new RangeNode(math, params);
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* conditions like and, or, in
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseConditions (scope) {
|
|
var node, operators, name, fn, params;
|
|
|
|
node = parseBitwiseConditions(scope);
|
|
|
|
// TODO: precedence of And above Or?
|
|
// TODO: implement a method for unit to number conversion
|
|
operators = {
|
|
'in' : math['in']
|
|
/* TODO: implement conditions
|
|
'and' : 'and',
|
|
'&&' : 'and',
|
|
'or': 'or',
|
|
'||': 'or',
|
|
'xor': 'xor'
|
|
*/
|
|
};
|
|
|
|
while (operators[token] !== undefined) {
|
|
name = token;
|
|
fn = operators[name];
|
|
|
|
getToken();
|
|
params = [node, parseBitwiseConditions(scope)];
|
|
node = new OperatorNode(name, fn, params);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* conditional operators and bitshift
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseBitwiseConditions (scope) {
|
|
var node = parseComparison(scope);
|
|
|
|
/* TODO: implement bitwise conditions
|
|
var operators = {
|
|
'&' : bitwiseand,
|
|
'|' : bitwiseor,
|
|
// todo: bitwise xor?
|
|
'<<': bitshiftleft,
|
|
'>>': bitshiftright
|
|
};
|
|
while (operators[token] !== undefined) {
|
|
var name = token;
|
|
var fn = operators[name];
|
|
|
|
getToken();
|
|
var params = [node, parseComparison()];
|
|
node = new OperatorNode(name, fn, params);
|
|
}
|
|
*/
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* comparison operators
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseComparison (scope) {
|
|
var node, operators, name, fn, params;
|
|
|
|
node = parseAddSubtract(scope);
|
|
|
|
operators = {
|
|
'==': math.equal,
|
|
'!=': math.unequal,
|
|
'<': math.smaller,
|
|
'>': math.larger,
|
|
'<=': math.smallereq,
|
|
'>=': math.largereq
|
|
};
|
|
while (operators[token] !== undefined) {
|
|
name = token;
|
|
fn = operators[name];
|
|
|
|
getToken();
|
|
params = [node, parseAddSubtract(scope)];
|
|
node = new OperatorNode(name, fn, params);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* add or subtract
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseAddSubtract (scope) {
|
|
var node, operators, name, fn, params;
|
|
|
|
node = parseMultiplyDivide(scope);
|
|
|
|
operators = {
|
|
'+': math.add,
|
|
'-': math.subtract
|
|
};
|
|
while (operators[token] !== undefined) {
|
|
name = token;
|
|
fn = operators[name];
|
|
|
|
getToken();
|
|
params = [node, parseMultiplyDivide(scope)];
|
|
node = new OperatorNode(name, fn, params);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* multiply, divide, modulus
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseMultiplyDivide (scope) {
|
|
var node, operators, name, fn, params;
|
|
|
|
node = parseUnary(scope);
|
|
|
|
operators = {
|
|
'*': math.multiply,
|
|
'.*': math.emultiply,
|
|
'/': math.divide,
|
|
'./': math.edivide,
|
|
'%': math.mod,
|
|
'mod': math.mod
|
|
};
|
|
|
|
while (operators[token] !== undefined) {
|
|
name = token;
|
|
fn = operators[name];
|
|
|
|
getToken();
|
|
params = [node, parseUnary(scope)];
|
|
node = new OperatorNode(name, fn, params);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* Unary minus
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseUnary (scope) {
|
|
var name, fn, params;
|
|
|
|
if (token == '-') {
|
|
name = token;
|
|
fn = math.unary;
|
|
getToken();
|
|
params = [parseUnary(scope)];
|
|
|
|
return new OperatorNode(name, fn, params);
|
|
}
|
|
|
|
return parsePow(scope);
|
|
}
|
|
|
|
/**
|
|
* power
|
|
* Node: power operator is right associative
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parsePow (scope) {
|
|
var node, leftNode, nodes, ops, name, fn, params;
|
|
|
|
nodes = [
|
|
parseFactorial(scope)
|
|
];
|
|
ops = [];
|
|
|
|
// stack all operands of a chained power operator (like '2^3^3')
|
|
while (token == '^' || token == '.^') {
|
|
ops.push(token);
|
|
getToken();
|
|
nodes.push(parseFactorial(scope));
|
|
}
|
|
|
|
// evaluate the operands from right to left (right associative)
|
|
node = nodes.pop();
|
|
while (nodes.length) {
|
|
leftNode = nodes.pop();
|
|
name = ops.pop();
|
|
fn = (name == '^') ? math.pow : math.epow;
|
|
params = [leftNode, node];
|
|
node = new OperatorNode(name, fn, params);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* Factorial
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseFactorial (scope) {
|
|
var node, name, fn, params;
|
|
|
|
node = parseTranspose(scope);
|
|
|
|
while (token == '!') {
|
|
name = token;
|
|
fn = math.factorial;
|
|
getToken();
|
|
params = [node];
|
|
|
|
node = new OperatorNode(name, fn, params);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* Transpose
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseTranspose (scope) {
|
|
var node, name, fn, params;
|
|
|
|
node = parseNodeHandler(scope);
|
|
|
|
while (token == '\'') {
|
|
name = token;
|
|
fn = math.transpose;
|
|
getToken();
|
|
params = [node];
|
|
|
|
node = new OperatorNode(name, fn, params);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* Parse a custom node handler. A node handler can be used to process
|
|
* nodes in a custom way, for example for handling a plot.
|
|
*
|
|
* A handler must be defined in the namespace math.expression.node.handlers,
|
|
* and must extend math.expression.node.Node, and the handler must contain
|
|
* functions eval(), find(filter), and toString().
|
|
*
|
|
* For example:
|
|
*
|
|
* math.expression.node.handlers['plot'] = PlotHandler;
|
|
*
|
|
* The constructor of the handler is called as:
|
|
*
|
|
* node = new PlotHandler(params, paramScopes);
|
|
*
|
|
* The handler will be invoked when evaluating an expression like:
|
|
*
|
|
* node = math.parse('plot(sin(x), x)');
|
|
*
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseNodeHandler (scope) {
|
|
var params,
|
|
paramScopes,
|
|
paramScope,
|
|
handler;
|
|
|
|
if (token_type == TOKENTYPE.SYMBOL && handlers[token]) {
|
|
handler = handlers[token];
|
|
|
|
getToken();
|
|
|
|
// parse parameters
|
|
if (token == '(') {
|
|
params = [];
|
|
paramScopes = [];
|
|
|
|
getToken();
|
|
|
|
if (token != ')') {
|
|
paramScope = scope.createSubScope();
|
|
paramScopes.push(paramScope);
|
|
params.push(parseRange(paramScope));
|
|
|
|
// parse a list with parameters
|
|
while (token == ',') {
|
|
getToken();
|
|
|
|
paramScope = scope.createSubScope();
|
|
paramScopes.push(paramScope);
|
|
params.push(parseRange(paramScope));
|
|
}
|
|
}
|
|
|
|
if (token != ')') {
|
|
throw createSyntaxError('Parenthesis ) expected');
|
|
}
|
|
getToken();
|
|
}
|
|
|
|
// create a new node handler
|
|
//noinspection JSValidateTypes
|
|
return new handler(params, paramScopes);
|
|
}
|
|
|
|
return parseSymbol(scope);
|
|
}
|
|
|
|
/**
|
|
* parse symbols: functions, variables, constants, units
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseSymbol (scope) {
|
|
var node, name;
|
|
|
|
if (token_type == TOKENTYPE.SYMBOL) {
|
|
name = token;
|
|
|
|
getToken();
|
|
|
|
// create a symbol
|
|
node = new SymbolNode(name, scope);
|
|
|
|
// parse parameters
|
|
return parseParams(scope, node);
|
|
}
|
|
|
|
return parseString(scope);
|
|
}
|
|
|
|
/**
|
|
* parse parameters, enclosed in parenthesis
|
|
* @param {Scope} scope
|
|
* @param {Node} node Node on which to apply the parameters. If there
|
|
* are no parameters in the expression, the node
|
|
* itself is returned
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseParams (scope, node) {
|
|
var bracket,
|
|
params,
|
|
paramScopes,
|
|
paramScope;
|
|
|
|
while (token == '(') {
|
|
bracket = token;
|
|
params = [];
|
|
paramScopes = [];
|
|
|
|
getToken();
|
|
|
|
if (token != ')') {
|
|
paramScope = scope.createSubScope();
|
|
paramScopes.push(paramScope);
|
|
params.push(parseRange(paramScope));
|
|
|
|
// parse a list with parameters
|
|
while (token == ',') {
|
|
getToken();
|
|
|
|
paramScope = scope.createSubScope();
|
|
paramScopes.push(paramScope);
|
|
params.push(parseRange(paramScope));
|
|
}
|
|
}
|
|
|
|
if ((bracket == '(' && token != ')')) {
|
|
throw createSyntaxError('Parenthesis ) expected');
|
|
}
|
|
getToken();
|
|
|
|
node = new ParamsNode(math, node, params, paramScopes);
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* parse a string.
|
|
* A string is enclosed by double quotes
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseString (scope) {
|
|
var node, str, tPrev;
|
|
|
|
if (token == '"') {
|
|
// string "..."
|
|
str = '';
|
|
tPrev = '';
|
|
while (c != '' && (c != '\"' || tPrev == '\\')) { // also handle escape character
|
|
str += c;
|
|
tPrev = c;
|
|
next();
|
|
}
|
|
|
|
getToken();
|
|
if (token != '"') {
|
|
throw createSyntaxError('End of string " expected');
|
|
}
|
|
getToken();
|
|
|
|
// create constant
|
|
node = new ConstantNode(str);
|
|
|
|
// parse parameters
|
|
node = parseParams(scope, node);
|
|
|
|
return node;
|
|
}
|
|
|
|
return parseMatrix(scope);
|
|
}
|
|
|
|
/**
|
|
* parse the matrix
|
|
* @param {Scope} scope
|
|
* @return {Node} A MatrixNode
|
|
* @private
|
|
*/
|
|
function parseMatrix (scope) {
|
|
var array, params, r, c, rows, cols;
|
|
|
|
if (token == '[') {
|
|
// matrix [...]
|
|
|
|
// skip newlines
|
|
getToken();
|
|
while (token == '\n') {
|
|
getToken();
|
|
}
|
|
|
|
// check if this is an empty matrix "[ ]"
|
|
if (token != ']') {
|
|
// this is a non-empty matrix
|
|
params = [];
|
|
r = 0;
|
|
c = 0;
|
|
|
|
params[0] = [parseAssignment(scope)];
|
|
|
|
// the columns in the matrix are separated by commas, and the rows by dot-comma's
|
|
while (token == ',' || token == ';') {
|
|
if (token == ',') {
|
|
c++;
|
|
}
|
|
else {
|
|
r++;
|
|
c = 0;
|
|
params[r] = [];
|
|
}
|
|
|
|
// skip newlines
|
|
getToken();
|
|
while (token == '\n') {
|
|
getToken();
|
|
}
|
|
|
|
params[r][c] = parseAssignment(scope);
|
|
|
|
// skip newlines
|
|
while (token == '\n') {
|
|
getToken();
|
|
}
|
|
}
|
|
|
|
// TODO: spaces as separator for matrix columns
|
|
/*
|
|
// the columns in the matrix are separated by commas or spaces,
|
|
// and the rows by dot-comma's
|
|
while (token && token != ']') {
|
|
if (token == ';') {
|
|
r++;
|
|
c = 0;
|
|
params[r] = [];
|
|
getToken();
|
|
}
|
|
else if (token == ',') {
|
|
c++;
|
|
getToken();
|
|
}
|
|
else {
|
|
c++;
|
|
}
|
|
|
|
// skip newlines
|
|
while (token == '\n') {
|
|
getToken();
|
|
}
|
|
|
|
//TODO: math.eval('[1 -2 3]') is evaluated as '[(1-2) 3]' instead of '[(1) (-2) (3)]'
|
|
//TODO: '[(1) (-2) (3)]' doesn't work
|
|
params[r][c] = parseAssignment(scope);
|
|
|
|
// skip newlines
|
|
while (token == '\n') {
|
|
getToken();
|
|
}
|
|
}
|
|
*/
|
|
|
|
rows = params.length;
|
|
cols = (params.length > 0) ? params[0].length : 0;
|
|
|
|
// check if the number of columns matches in all rows
|
|
for (r = 1; r < rows; r++) {
|
|
if (params[r].length != cols) {
|
|
throw createError('Number of columns must match ' +
|
|
'(' + params[r].length + ' != ' + cols + ')');
|
|
}
|
|
}
|
|
|
|
if (token != ']') {
|
|
throw createSyntaxError('End of matrix ] expected');
|
|
}
|
|
|
|
getToken();
|
|
array = new MatrixNode(params);
|
|
}
|
|
else {
|
|
// this is an empty matrix "[ ]"
|
|
getToken();
|
|
array = new MatrixNode([]);
|
|
}
|
|
|
|
// parse parameters
|
|
array = parseParams(scope, array);
|
|
|
|
return array;
|
|
}
|
|
|
|
return parseNumber(scope);
|
|
}
|
|
|
|
/**
|
|
* parse a number
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseNumber (scope) {
|
|
var node, value, number;
|
|
|
|
if (token_type == TOKENTYPE.NUMBER) {
|
|
// this is a number
|
|
if (token == '.') {
|
|
number = 0;
|
|
} else {
|
|
number = Number(token);
|
|
}
|
|
getToken();
|
|
|
|
/* TODO: implicit multiplication?
|
|
// TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ?
|
|
// check for implicit multiplication
|
|
if (token_type == TOKENTYPE.VARIABLE) {
|
|
node = multiply(node, parsePow());
|
|
}
|
|
//*/
|
|
|
|
if (token_type == TOKENTYPE.SYMBOL) {
|
|
if (token == 'i' || token == 'I') {
|
|
value = new Complex(0, number);
|
|
getToken();
|
|
return new ConstantNode(value);
|
|
}
|
|
|
|
if (Unit.isPlainUnit(token)) {
|
|
value = new Unit(number, token);
|
|
getToken();
|
|
return new ConstantNode(value);
|
|
}
|
|
|
|
throw createTypeError('Unknown unit "' + token + '"');
|
|
}
|
|
|
|
// just a regular number
|
|
node = new ConstantNode(number);
|
|
|
|
// parse parameters
|
|
node = parseParams(scope, node);
|
|
|
|
return node;
|
|
}
|
|
|
|
return parseParentheses(scope);
|
|
}
|
|
|
|
/**
|
|
* parentheses
|
|
* @param {Scope} scope
|
|
* @return {Node} node
|
|
* @private
|
|
*/
|
|
function parseParentheses (scope) {
|
|
var node;
|
|
|
|
// check if it is a parenthesized expression
|
|
if (token == '(') {
|
|
// parentheses (...)
|
|
getToken();
|
|
node = parseAssignment(scope); // start again
|
|
|
|
if (token != ')') {
|
|
throw createSyntaxError('Parenthesis ) expected');
|
|
}
|
|
getToken();
|
|
|
|
/* TODO: implicit multiplication?
|
|
// TODO: how to calculate a=3; 2/2a ? is this (2/2)*a or 2/(2*a) ?
|
|
// check for implicit multiplication
|
|
if (token_type == TOKENTYPE.VARIABLE) {
|
|
node = multiply(node, parsePow());
|
|
}
|
|
//*/
|
|
|
|
// parse parameters
|
|
node = parseParams(scope, node);
|
|
|
|
return node;
|
|
}
|
|
|
|
return parseEnd(scope);
|
|
}
|
|
|
|
/**
|
|
* Evaluated when the expression is not yet ended but expected to end
|
|
* @param {Scope} scope
|
|
* @return {Node} res
|
|
* @private
|
|
*/
|
|
function parseEnd (scope) {
|
|
if (token == '') {
|
|
// syntax error or unexpected end of expression
|
|
throw createSyntaxError('Unexpected end of expression');
|
|
} else {
|
|
throw createSyntaxError('Value expected');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shortcut for getting the current row value (one based)
|
|
* Returns the line of the currently handled expression
|
|
* @private
|
|
*/
|
|
function row () {
|
|
// TODO: also register row number during parsing
|
|
return undefined;
|
|
}
|
|
|
|
/**
|
|
* Shortcut for getting the current col value (one based)
|
|
* Returns the column (position) where the last token starts
|
|
* @private
|
|
*/
|
|
function col () {
|
|
return index - token.length + 1;
|
|
}
|
|
|
|
/**
|
|
* Build up an error message
|
|
* @param {String} message
|
|
* @return {String} message with row and column information
|
|
* @private
|
|
*/
|
|
function createErrorMessage (message) {
|
|
var r = row();
|
|
var c = col();
|
|
if (r === undefined) {
|
|
if (c === undefined) {
|
|
return message;
|
|
} else {
|
|
return message + ' (char ' + c + ')';
|
|
}
|
|
} else {
|
|
return message + ' (line ' + r + ', char ' + c + ')';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create an error
|
|
* @param {String} message
|
|
* @return {SyntaxError} instantiated error
|
|
* @private
|
|
*/
|
|
function createSyntaxError (message) {
|
|
return new SyntaxError(createErrorMessage(message));
|
|
}
|
|
|
|
/**
|
|
* Create an error
|
|
* @param {String} message
|
|
* @return {TypeError} instantiated error
|
|
* @private
|
|
*/
|
|
function createTypeError(message) {
|
|
return new TypeError(createErrorMessage(message));
|
|
}
|
|
|
|
/**
|
|
* Create an error
|
|
* @param {String} message
|
|
* @return {Error} instantiated error
|
|
* @private
|
|
*/
|
|
function createError (message) {
|
|
return new Error(createErrorMessage(message));
|
|
}
|
|
};
|
|
|
|
},{"../../expression/node/AssignmentNode.js":101,"../../expression/node/BlockNode.js":102,"../../expression/node/ConstantNode.js":103,"../../expression/node/FunctionNode.js":104,"../../expression/node/MatrixNode.js":105,"../../expression/node/OperatorNode.js":107,"../../expression/node/ParamsNode.js":108,"../../expression/node/RangeNode.js":109,"../../expression/node/SymbolNode.js":110,"../../expression/node/UpdateNode.js":111,"../../expression/node/handlers.js":112,"../../type/collection.js":201,"../../util/index.js":205,"./../../expression/Scope.js":5,"./../../type/Complex.js":195,"./../../type/Matrix.js":198,"./../../type/Unit.js":200}],160:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
object = util.object,
|
|
array = util.array,
|
|
isNumber = util.number.isNumber,
|
|
isInteger = util.number.isInteger,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Concatenate two or more matrices
|
|
* Usage:
|
|
* math.concat(A, B, C, ...)
|
|
* math.concat(A, B, C, ..., dim)
|
|
*
|
|
* Where the optional dim is the zero-based number of the dimension to be
|
|
* concatenated.
|
|
*
|
|
* @param {... Array | Matrix} args
|
|
* @return {Array | Matrix} res
|
|
*/
|
|
math.concat = function concat (args) {
|
|
var i,
|
|
len = arguments.length,
|
|
dim = -1, // zero-based dimension
|
|
prevDim,
|
|
asMatrix = false,
|
|
matrices = []; // contains multi dimensional arrays
|
|
|
|
for (i = 0; i < len; i++) {
|
|
var arg = arguments[i];
|
|
|
|
// test whether we need to return a Matrix (if not we return an Array)
|
|
if (arg instanceof Matrix) {
|
|
asMatrix = true;
|
|
}
|
|
|
|
if ((i == len - 1) && isNumber(arg)) {
|
|
// last argument contains the dimension on which to concatenate
|
|
prevDim = dim;
|
|
dim = arg;
|
|
|
|
if (!isInteger(dim) || dim < 0) {
|
|
throw new TypeError('Dimension number must be a positive integer ' +
|
|
'(dim = ' + dim + ')');
|
|
}
|
|
|
|
if (i > 0 && dim > prevDim) {
|
|
throw new RangeError('Dimension out of range ' +
|
|
'(' + dim + ' > ' + prevDim + ')');
|
|
}
|
|
}
|
|
else if (isCollection(arg)) {
|
|
// this is a matrix or array
|
|
var matrix = object.clone(arg).valueOf();
|
|
var size = array.size(arg.valueOf());
|
|
matrices[i] = matrix;
|
|
prevDim = dim;
|
|
dim = size.length - 1;
|
|
|
|
// verify whether each of the matrices has the same number of dimensions
|
|
if (i > 0 && dim != prevDim) {
|
|
throw new RangeError('Dimension mismatch ' +
|
|
'(' + prevDim + ' != ' + dim + ')');
|
|
}
|
|
}
|
|
else {
|
|
throw new util.error.UnsupportedTypeError('concat', arg);
|
|
}
|
|
}
|
|
|
|
if (matrices.length == 0) {
|
|
throw new SyntaxError('At least one matrix expected');
|
|
}
|
|
|
|
var res = matrices.shift();
|
|
while (matrices.length) {
|
|
res = _concat(res, matrices.shift(), dim, 0);
|
|
}
|
|
|
|
return asMatrix ? new Matrix(res) : res;
|
|
};
|
|
|
|
/**
|
|
* Recursively concatenate two matrices.
|
|
* The contents of the matrices is not cloned.
|
|
* @param {Array} a Multi dimensional array
|
|
* @param {Array} b Multi dimensional array
|
|
* @param {Number} concatDim The dimension on which to concatenate (zero-based)
|
|
* @param {Number} dim The current dim (zero-based)
|
|
* @return {Array} c The concatenated matrix
|
|
* @private
|
|
*/
|
|
function _concat(a, b, concatDim, dim) {
|
|
if (dim < concatDim) {
|
|
// recurse into next dimension
|
|
if (a.length != b.length) {
|
|
throw new Error('Dimensions mismatch (' + a.length + ' != ' + b.length + ')');
|
|
}
|
|
|
|
var c = [];
|
|
for (var i = 0; i < a.length; i++) {
|
|
c[i] = _concat(a[i], b[i], concatDim, dim + 1);
|
|
}
|
|
return c;
|
|
}
|
|
else {
|
|
// concatenate this dimension
|
|
return a.concat(b);
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/index.js":205}],161:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
|
|
object = util.object,
|
|
array = util.array,
|
|
string = util.string;
|
|
|
|
/**
|
|
* @constructor det
|
|
* Calculate the determinant of a matrix
|
|
*
|
|
* det(x)
|
|
*
|
|
* @param {Array | Matrix} x
|
|
* @return {Number} determinant
|
|
*/
|
|
math.det = function det (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('det', arguments.length, 1);
|
|
}
|
|
|
|
var size = array.size(x.valueOf());
|
|
switch (size.length) {
|
|
case 0:
|
|
// scalar
|
|
return object.clone(x);
|
|
break;
|
|
|
|
case 1:
|
|
// vector
|
|
if (size[0] == 1) {
|
|
return object.clone(x.valueOf()[0]);
|
|
}
|
|
else {
|
|
throw new RangeError('Matrix must be square ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
// two dimensional array
|
|
var rows = size[0];
|
|
var cols = size[1];
|
|
if (rows == cols) {
|
|
return _det(x.valueOf(), rows, cols);
|
|
}
|
|
else {
|
|
throw new RangeError('Matrix must be square ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// multi dimensional array
|
|
throw new RangeError('Matrix must be two dimensional ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Calculate the determinant of a matrix
|
|
* @param {Array[]} matrix A square, two dimensional matrix
|
|
* @param {Number} rows Number of rows of the matrix (zero-based)
|
|
* @param {Number} cols Number of columns of the matrix (zero-based)
|
|
* @returns {Number} det
|
|
* @private
|
|
*/
|
|
function _det (matrix, rows, cols) {
|
|
if (rows == 1) {
|
|
// this is a 1 x 1 matrix
|
|
return matrix[0][0];
|
|
}
|
|
else if (rows == 2) {
|
|
// this is a 2 x 2 matrix
|
|
// the determinant of [a11,a12;a21,a22] is det = a11*a22-a21*a12
|
|
return math.subtract(
|
|
math.multiply(matrix[0][0], matrix[1][1]),
|
|
math.multiply(matrix[1][0], matrix[0][1])
|
|
);
|
|
}
|
|
else {
|
|
// this is an n x n matrix
|
|
var d = 1;
|
|
var lead = 0;
|
|
for (var r = 0; r < rows; r++) {
|
|
if (lead >= cols) {
|
|
break;
|
|
}
|
|
var i = r;
|
|
// Find the pivot element.
|
|
while (matrix[i][lead] == 0) {
|
|
i++;
|
|
if (i == rows) {
|
|
i = r;
|
|
lead++;
|
|
if (lead == cols) {
|
|
// We found the last pivot.
|
|
if (object.deepEqual(matrix, eye(rows).valueOf())) {
|
|
return math.round(d, 6);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (i != r) {
|
|
// Swap rows i and r, which negates the determinant.
|
|
for (var a = 0; a < cols; a++) {
|
|
var temp = matrix[i][a];
|
|
matrix[i][a] = matrix[r][a];
|
|
matrix[r][a] = temp;
|
|
}
|
|
d *= -1;
|
|
}
|
|
// Scale row r and the determinant simultaneously.
|
|
var div = matrix[r][lead];
|
|
for (var a = 0; a < cols; a++) {
|
|
matrix[r][a] = matrix[r][a] / div;
|
|
}
|
|
d *= div;
|
|
// Back-substitute upwards.
|
|
for (var j = 0; j < rows; j++) {
|
|
if (j != r) {
|
|
// Taking linear combinations does not change the det.
|
|
var c = matrix[j][lead];
|
|
for (var a = 0; a < cols; a++) {
|
|
matrix[j][a] = matrix[j][a] - matrix[r][a] * c;
|
|
}
|
|
}
|
|
}
|
|
lead++; // Now looking for a pivot further right.
|
|
}
|
|
// If reduction did not result in the identity, the matrix is singular.
|
|
if (object.deepEqual(matrix, math.eye(rows).valueOf())) {
|
|
return math.round(d, 6);
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../util/index.js":205}],162:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
|
|
object = util.object,
|
|
isNumber = util.number.isNumber,
|
|
isInteger = util.number.isInteger;
|
|
|
|
/**
|
|
* Create a diagonal matrix or retrieve the diagonal of a matrix
|
|
*
|
|
* diag(v)
|
|
* diag(v, k)
|
|
* diag(X)
|
|
* diag(X, k)
|
|
*
|
|
* TODO: more documentation on diag
|
|
*
|
|
* @param {Number | Matrix | Array} x
|
|
* @param {Number} [k]
|
|
* @return {Matrix} matrix
|
|
*/
|
|
math.diag = function diag (x, k) {
|
|
var data, vector, i, iMax;
|
|
|
|
if (arguments.length != 1 && arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('diag', arguments.length, 1, 2);
|
|
}
|
|
|
|
if (k) {
|
|
if (!isNumber(k) || !isInteger(k)) {
|
|
throw new TypeError ('Second parameter in function diag must be an integer');
|
|
}
|
|
}
|
|
else {
|
|
k = 0;
|
|
}
|
|
var kSuper = k > 0 ? k : 0;
|
|
var kSub = k < 0 ? -k : 0;
|
|
|
|
// convert to matrix
|
|
if (!(x instanceof Matrix)) {
|
|
x = new Matrix(x);
|
|
}
|
|
|
|
// get as array when the matrix is a vector
|
|
var s;
|
|
if (x.isVector()) {
|
|
x = x.toVector();
|
|
s = [x.length];
|
|
}
|
|
else {
|
|
s = x.size();
|
|
}
|
|
|
|
switch (s.length) {
|
|
case 1:
|
|
// x is a vector. create diagonal matrix
|
|
vector = x.valueOf();
|
|
var matrix = new Matrix();
|
|
matrix.resize([vector.length + kSub, vector.length + kSuper]);
|
|
data = matrix.valueOf();
|
|
iMax = vector.length;
|
|
for (i = 0; i < iMax; i++) {
|
|
data[i + kSub][i + kSuper] = object.clone(vector[i]);
|
|
}
|
|
return matrix;
|
|
break;
|
|
|
|
case 2:
|
|
// x is a matrix get diagonal from matrix
|
|
vector = [];
|
|
data = x.valueOf();
|
|
iMax = Math.min(s[0] - kSub, s[1] - kSuper);
|
|
for (i = 0; i < iMax; i++) {
|
|
vector[i] = object.clone(data[i + kSub][i + kSuper]);
|
|
}
|
|
return new Matrix(vector);
|
|
break;
|
|
|
|
default:
|
|
throw new RangeError('Matrix for function diag must be 2 dimensional');
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../util/index.js":205}],163:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumber = util.number.isNumber,
|
|
isInteger = util.number.isInteger;
|
|
|
|
/**
|
|
* Create an identity matrix with size m x n
|
|
*
|
|
* eye(m)
|
|
* eye(m, n)
|
|
*
|
|
* TODO: more documentation on eye
|
|
*
|
|
* @param {...Number | Matrix | Array} size
|
|
* @return {Matrix} matrix
|
|
*/
|
|
math.eye = function eye (size) {
|
|
var args = collection.argsToArray(arguments);
|
|
if (args.length == 0) {
|
|
args = [1, 1];
|
|
}
|
|
else if (args.length == 1) {
|
|
args[1] = args[0];
|
|
}
|
|
else if (args.length > 2) {
|
|
throw new util.error.ArgumentsError('eye', args.length, 0, 2);
|
|
}
|
|
|
|
var rows = args[0],
|
|
cols = args[1];
|
|
|
|
if (!isNumber(rows) || !isInteger(rows) || rows < 1) {
|
|
throw new Error('Parameters in function eye must be positive integers');
|
|
}
|
|
if (cols) {
|
|
if (!isNumber(cols) || !isInteger(cols) || cols < 1) {
|
|
throw new Error('Parameters in function eye must be positive integers');
|
|
}
|
|
}
|
|
|
|
// create and args the matrix
|
|
var matrix = new Matrix();
|
|
matrix.resize(args);
|
|
|
|
// fill in ones on the diagonal
|
|
var minimum = math.min(args);
|
|
var data = matrix.valueOf();
|
|
for (var d = 0; d < minimum; d++) {
|
|
data[d][d] = 1;
|
|
}
|
|
|
|
return matrix;
|
|
};
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/index.js":205}],164:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
|
|
string = util.string;
|
|
|
|
/**
|
|
* Calculate the inverse of a matrix
|
|
*
|
|
* inv(x)
|
|
*
|
|
* TODO: more documentation on inv
|
|
*
|
|
* @param {Number | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} inv
|
|
*/
|
|
math.inv = function inv (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('inv', arguments.length, 1);
|
|
}
|
|
var size = math.size(x).valueOf();
|
|
switch (size.length) {
|
|
case 0:
|
|
// scalar
|
|
return math.divide(1, x);
|
|
break;
|
|
|
|
case 1:
|
|
// vector
|
|
if (size[0] == 1) {
|
|
if (x instanceof Matrix) {
|
|
return new Matrix([
|
|
math.divide(1, x.valueOf()[0])
|
|
]);
|
|
}
|
|
else {
|
|
return [
|
|
math.divide(1, x[0])
|
|
];
|
|
}
|
|
}
|
|
else {
|
|
throw new RangeError('Matrix must be square ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
// two dimensional array
|
|
var rows = size[0];
|
|
var cols = size[1];
|
|
if (rows == cols) {
|
|
if (x instanceof Matrix) {
|
|
return new Matrix(
|
|
_inv(x.valueOf(), rows, cols)
|
|
);
|
|
}
|
|
else {
|
|
// return an Array
|
|
return _inv(x, rows, cols);
|
|
}
|
|
}
|
|
else {
|
|
throw new RangeError('Matrix must be square ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// multi dimensional array
|
|
throw new RangeError('Matrix must be two dimensional ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Calculate the inverse of a square matrix
|
|
* @param {Array[]} matrix A square matrix
|
|
* @param {Number} rows Number of rows
|
|
* @param {Number} cols Number of columns, must equal rows
|
|
* @return {Array[]} inv Inverse matrix
|
|
* @private
|
|
*/
|
|
function _inv (matrix, rows, cols){
|
|
var r, s, f, value, temp;
|
|
|
|
if (rows == 1) {
|
|
// this is a 1 x 1 matrix
|
|
value = matrix[0][0];
|
|
if (value == 0) {
|
|
throw Error('Cannot calculate inverse, determinant is zero');
|
|
}
|
|
return [[
|
|
math.divide(1, value)
|
|
]];
|
|
}
|
|
else if (rows == 2) {
|
|
// this is a 2 x 2 matrix
|
|
var d = math.det(matrix);
|
|
if (d == 0) {
|
|
throw Error('Cannot calculate inverse, determinant is zero');
|
|
}
|
|
return [
|
|
[
|
|
math.divide(matrix[1][1], d),
|
|
math.divide(math.unary(matrix[0][1]), d)
|
|
],
|
|
[
|
|
math.divide(math.unary(matrix[1][0]), d),
|
|
math.divide(matrix[0][0], d)
|
|
]
|
|
];
|
|
}
|
|
else {
|
|
// this is a matrix of 3 x 3 or larger
|
|
// calculate inverse using gauss-jordan elimination
|
|
// http://en.wikipedia.org/wiki/Gaussian_elimination
|
|
// http://mathworld.wolfram.com/MatrixInverse.html
|
|
// http://math.uww.edu/~mcfarlat/inverse.htm
|
|
|
|
// make a copy of the matrix (only the arrays, not of the elements)
|
|
var A = matrix.concat();
|
|
for (r = 0; r < rows; r++) {
|
|
A[r] = A[r].concat();
|
|
}
|
|
|
|
// create an identity matrix which in the end will contain the
|
|
// matrix inverse
|
|
var B = math.eye(rows).valueOf();
|
|
|
|
// loop over all columns, and perform row reductions
|
|
for (var c = 0; c < cols; c++) {
|
|
// element Acc should be non zero. if not, swap content
|
|
// with one of the lower rows
|
|
r = c;
|
|
while (r < rows && A[r][c] == 0) {
|
|
r++;
|
|
}
|
|
if (r == rows || A[r][c] == 0) {
|
|
throw Error('Cannot calculate inverse, determinant is zero');
|
|
}
|
|
if (r != c) {
|
|
temp = A[c]; A[c] = A[r]; A[r] = temp;
|
|
temp = B[c]; B[c] = B[r]; B[r] = temp;
|
|
}
|
|
|
|
// eliminate non-zero values on the other rows at column c
|
|
var Ac = A[c],
|
|
Bc = B[c];
|
|
for (r = 0; r < rows; r++) {
|
|
var Ar = A[r],
|
|
Br = B[r];
|
|
if(r != c) {
|
|
// eliminate value at column c and row r
|
|
if (Ar[c] != 0) {
|
|
f = math.divide(math.unary(Ar[c]), Ac[c]);
|
|
|
|
// add (f * row c) to row r to eliminate the value
|
|
// at column c
|
|
for (s = c; s < cols; s++) {
|
|
Ar[s] = math.add(Ar[s], math.multiply(f, Ac[s]));
|
|
}
|
|
for (s = 0; s < cols; s++) {
|
|
Br[s] = math.add(Br[s], math.multiply(f, Bc[s]));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// normalize value at Acc to 1,
|
|
// divide each value on row r with the value at Acc
|
|
f = Ac[c];
|
|
for (s = c; s < cols; s++) {
|
|
Ar[s] = math.divide(Ar[s], f);
|
|
}
|
|
for (s = 0; s < cols; s++) {
|
|
Br[s] = math.divide(Br[s], f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return B;
|
|
}
|
|
}
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../util/index.js":205}],165:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
array = util.array;
|
|
|
|
/**
|
|
* Create a matrix filled with ones
|
|
*
|
|
* ones(n)
|
|
* ones(m, n)
|
|
* ones([m, n])
|
|
* ones([m, n, p, ...])
|
|
*
|
|
* @param {...Number | Array} size
|
|
* @return {Array | Matrix | Number} matrix
|
|
*/
|
|
math.ones = function ones (size) {
|
|
var args = collection.argsToArray(arguments);
|
|
var asMatrix = (size instanceof Matrix);
|
|
|
|
if (args.length == 0) {
|
|
// output a scalar
|
|
return 1;
|
|
}
|
|
else {
|
|
// output an array or matrix
|
|
var res = [];
|
|
var defaultValue = 1;
|
|
array.resize(res, args, defaultValue);
|
|
return asMatrix ? new Matrix(res) : res;
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/index.js":205}],166:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
isString = util.string.isString,
|
|
isNumber = util.number.isNumber;
|
|
|
|
/**
|
|
* Create an array from a range.
|
|
*
|
|
* The method accepts the following arguments
|
|
* range(str) Create a range from a string, where the
|
|
* string contains the start, optional step,
|
|
* and end, separated by a colon.
|
|
* range(start, end) Create a range with start and end and a
|
|
* default step size of 1
|
|
* range(start, end, step) Create a range with start, step, and end.
|
|
*
|
|
* Example usage:
|
|
* 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]
|
|
*
|
|
* @param {...*} args
|
|
* @return {Array} range
|
|
*/
|
|
math.range = function range(args) {
|
|
var start, end, step;
|
|
|
|
switch (arguments.length) {
|
|
case 1:
|
|
// parse string into a range
|
|
if (isString(args)) {
|
|
var r = _parse(args);
|
|
if (!r){
|
|
throw new SyntaxError('String "' + r + '" is no valid range');
|
|
}
|
|
|
|
start = r.start;
|
|
end = r.end;
|
|
step = r.step;
|
|
}
|
|
else {
|
|
throw new TypeError(
|
|
'Two or three numbers or a single string expected in function range');
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
// range(start, end)
|
|
start = arguments[0];
|
|
end = arguments[1];
|
|
step = 1;
|
|
break;
|
|
|
|
case 3:
|
|
// range(start, end, step)
|
|
start = arguments[0];
|
|
end = arguments[1];
|
|
step = arguments[2];
|
|
break;
|
|
|
|
default:
|
|
throw new util.error.ArgumentsError('range', arguments.length, 2, 3);
|
|
}
|
|
|
|
if (!isNumber(start)) {
|
|
throw new TypeError('Parameter start must be a number');
|
|
}
|
|
if (!isNumber(end)) {
|
|
throw new TypeError('Parameter end must be a number');
|
|
}
|
|
if (!isNumber(step)) {
|
|
throw new TypeError('Parameter step must be a number');
|
|
}
|
|
|
|
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;
|
|
};
|
|
|
|
/**
|
|
* 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 {Object | null} range Object containing properties start, end, step
|
|
* @private
|
|
*/
|
|
function _parse (str) {
|
|
var args = str.split(':');
|
|
var nums = args.map(function (arg) {
|
|
return Number(arg);
|
|
});
|
|
|
|
var invalid = nums.some(function (num) {
|
|
return isNaN(num);
|
|
});
|
|
if(invalid) {
|
|
return null;
|
|
}
|
|
|
|
switch (nums.length) {
|
|
case 2:
|
|
return {
|
|
start: nums[0],
|
|
end: nums[1],
|
|
step: 1
|
|
};
|
|
|
|
case 3:
|
|
return {
|
|
start: nums[0],
|
|
end: nums[2],
|
|
step: nums[1]
|
|
};
|
|
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
},{"../../util/index.js":205}],167:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
Matrix = require('../../type/Matrix.js'),
|
|
|
|
array = util.array,
|
|
isNumber = util.number.isNumber,
|
|
isBoolean = util.boolean.isBoolean,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit;
|
|
|
|
/**
|
|
* Calculate the size of a matrix or scalar
|
|
*
|
|
* size(x)
|
|
*
|
|
* @param {Number | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.size = function size (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('size', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumber(x) || isComplex(x) || isUnit(x) || isBoolean(x) || x == null) {
|
|
return [];
|
|
}
|
|
|
|
if (isString(x)) {
|
|
return [x.length];
|
|
}
|
|
|
|
if (Array.isArray(x)) {
|
|
return array.size(x);
|
|
}
|
|
|
|
if (x instanceof Matrix) {
|
|
return new Matrix(x.size());
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return size(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('size', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Matrix.js":198,"../../type/Unit.js":200,"../../util/index.js":205}],168:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
|
|
object = util.object,
|
|
array = util.array,
|
|
isArray = Array.isArray;
|
|
|
|
/**
|
|
* Remove singleton dimensions from a matrix
|
|
*
|
|
* squeeze(x)
|
|
*
|
|
* @param {Matrix | Array} x
|
|
* @return {Matrix | Array} res
|
|
*/
|
|
math.squeeze = function squeeze (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('squeeze', arguments.length, 1);
|
|
}
|
|
|
|
if (isArray(x)) {
|
|
return array.squeeze(object.clone(x));
|
|
}
|
|
else if (x instanceof Matrix) {
|
|
return new Matrix(array.squeeze(x.toArray()));
|
|
}
|
|
else if (isArray(x.valueOf())) {
|
|
return array.squeeze(object.clone(x.valueOf()));
|
|
}
|
|
else {
|
|
// scalar
|
|
return object.clone(x);
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../util/index.js":205}],169:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
Index = require('../../type/Index.js'),
|
|
|
|
array = util.array,
|
|
isString = util.string.isString,
|
|
isArray = Array.isArray;
|
|
|
|
/**
|
|
* Get or set a subset of a matrix or string
|
|
*
|
|
* Usage:
|
|
* var subset = math.subset(value, index) // retrieve subset
|
|
* var value = math.subset(value, index, replacement) // replace subset
|
|
*
|
|
* Where:
|
|
* {Array | Matrix | String} value An array, matrix, or string
|
|
* {Index} index An index containing ranges for each
|
|
* dimension
|
|
* {*} replacement An array, matrix, or scalar
|
|
*
|
|
* @param args
|
|
* @return res
|
|
*/
|
|
math.subset = function subset (args) {
|
|
switch (arguments.length) {
|
|
case 2: // get subset
|
|
return _getSubset(arguments[0], arguments[1]);
|
|
|
|
case 3: // set subset
|
|
return _setSubset(arguments[0], arguments[1], arguments[2]);
|
|
|
|
default: // wrong number of arguments
|
|
throw new util.error.ArgumentsError('subset', arguments.length, 2, 3);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Retrieve a subset of an value such as an Array, Matrix, or String
|
|
* @param {Array | Matrix | String} value Object from which to get a subset
|
|
* @param {Index} index An index containing ranges for each
|
|
* dimension
|
|
* @returns {Array | Matrix | *} subset
|
|
* @private
|
|
*/
|
|
function _getSubset(value, index) {
|
|
var m, subset;
|
|
|
|
if (isArray(value)) {
|
|
m = new Matrix(value);
|
|
subset = m.subset(index);
|
|
return subset.valueOf();
|
|
}
|
|
else if (value instanceof Matrix) {
|
|
return value.subset(index);
|
|
}
|
|
else if (isString(value)) {
|
|
return _getSubstring(value, index);
|
|
}
|
|
else {
|
|
throw new util.error.UnsupportedTypeError('subset', value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 (!(index instanceof Index)) {
|
|
// TODO: better error message
|
|
throw new TypeError('Index expected');
|
|
}
|
|
if (index.size().length != 1) {
|
|
throw new RangeError('Dimension mismatch (' + index.size().length + ' != 1)');
|
|
}
|
|
|
|
var range = index.range(0);
|
|
|
|
var substr = '';
|
|
var strLen = str.length;
|
|
range.forEach(function (v) {
|
|
array.validateIndex(v, strLen);
|
|
substr += str.charAt(v);
|
|
});
|
|
|
|
return substr;
|
|
}
|
|
|
|
/**
|
|
* Replace a subset in an value such as an Array, Matrix, or String
|
|
* @param {Array | Matrix | String} value Object to be replaced
|
|
* @param {Index} index An index containing ranges for each
|
|
* dimension
|
|
* @param {Array | Matrix | *} replacement
|
|
* @returns {*} result
|
|
* @private
|
|
*/
|
|
function _setSubset(value, index, replacement) {
|
|
var m;
|
|
|
|
if (isArray(value)) {
|
|
m = new Matrix(math.clone(value));
|
|
m.subset(index, replacement);
|
|
return m.valueOf();
|
|
}
|
|
else if (value instanceof Matrix) {
|
|
return value.clone().subset(index, replacement);
|
|
}
|
|
else if (isString(value)) {
|
|
return _setSubstring(value, index, replacement);
|
|
}
|
|
else {
|
|
throw new util.error.UnsupportedTypeError('subset', value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* @returns {string} result
|
|
* @private
|
|
*/
|
|
function _setSubstring(str, index, replacement) {
|
|
if (!(index instanceof Index)) {
|
|
// TODO: better error message
|
|
throw new TypeError('Index expected');
|
|
}
|
|
if (index.size().length != 1) {
|
|
throw new RangeError('Dimension mismatch (' + index.size().length + ' != 1)');
|
|
}
|
|
|
|
var range = index.range(0);
|
|
var len = range.size()[0];
|
|
|
|
if (len != replacement.length) {
|
|
throw new RangeError('Dimension mismatch ' +
|
|
'(' + range.size()[0] + ' != ' + replacement.length + ')');
|
|
}
|
|
|
|
// copy the string into an array with characters
|
|
var strLen = str.length;
|
|
var chars = [];
|
|
for (var i = 0; i < strLen; i++) {
|
|
chars[i] = str.charAt(i);
|
|
}
|
|
|
|
range.forEach(function (v, i) {
|
|
array.validateIndex(v);
|
|
chars[v] = replacement.charAt(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] = ' ';
|
|
}
|
|
}
|
|
}
|
|
|
|
return chars.join('');
|
|
}
|
|
};
|
|
|
|
},{"../../type/Index.js":197,"../../type/Matrix.js":198,"../../util/index.js":205}],170:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
|
|
object = util.object,
|
|
string = util.string;
|
|
|
|
/**
|
|
* Create the transpose of a matrix
|
|
*
|
|
* transpose(x)
|
|
*
|
|
* @param {Array | Matrix} x
|
|
* @return {Array | Matrix} transpose
|
|
*/
|
|
math.transpose = function transpose (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('transpose', arguments.length, 1);
|
|
}
|
|
|
|
var size = math.size(x).valueOf();
|
|
switch (size.length) {
|
|
case 0:
|
|
// scalar
|
|
return object.clone(x);
|
|
break;
|
|
|
|
case 1:
|
|
// vector
|
|
return object.clone(x);
|
|
break;
|
|
|
|
case 2:
|
|
// two dimensional array
|
|
var rows = size[1],
|
|
cols = size[0],
|
|
asMatrix = Matrix.isMatrix(x),
|
|
data = x.valueOf(),
|
|
transposed = [],
|
|
transposedRow,
|
|
clone = object.clone;
|
|
|
|
if (rows === 0) {
|
|
// whoops
|
|
throw new RangeError('Cannot transpose a 2D matrix with no rows' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
|
|
for (var r = 0; r < rows; r++) {
|
|
transposedRow = transposed[r] = [];
|
|
for (var c = 0; c < cols; c++) {
|
|
transposedRow[c] = clone(data[c][r]);
|
|
}
|
|
}
|
|
if (cols == 0) {
|
|
transposed[0] = [];
|
|
}
|
|
return asMatrix ? new Matrix(transposed) : transposed;
|
|
break;
|
|
|
|
default:
|
|
// multi dimensional array
|
|
throw new RangeError('Matrix must be two dimensional ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../util/index.js":205}],171:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
array = util.array;
|
|
|
|
/**
|
|
* create a matrix filled with zeros
|
|
*
|
|
* zeros(n)
|
|
* zeros(m, n)
|
|
* zeros([m, n])
|
|
* zeros([m, n, p, ...])
|
|
*
|
|
* @param {...Number | Array} size
|
|
* @return {Array | Matrix | Number} matrix
|
|
*/
|
|
math.zeros = function zeros (size) {
|
|
var args = collection.argsToArray(arguments);
|
|
var asMatrix = (size instanceof Matrix);
|
|
|
|
if (args.length == 0) {
|
|
// output a scalar
|
|
return 0;
|
|
}
|
|
else {
|
|
// output an array or matrix
|
|
var res = [];
|
|
var defaultValue = 0;
|
|
array.resize(res, args, defaultValue);
|
|
return asMatrix ? new Matrix(res) : res;
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/index.js":205}],172:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumber = util.number.isNumber,
|
|
isBoolean = util.boolean.isBoolean,
|
|
isInteger = util.number.isInteger,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Compute the factorial of a value
|
|
*
|
|
* x!
|
|
* factorial(x)
|
|
*
|
|
* Factorial only supports an integer value as argument.
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @Param {Number | Array | Matrix} x
|
|
* @return {Number | Array | Matrix} res
|
|
*/
|
|
math.factorial = function factorial (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('factorial', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumber(x)) {
|
|
if (!isInteger(x) || x < 0) {
|
|
throw new TypeError('Positive integer value expected in function factorial');
|
|
}
|
|
|
|
var value = x,
|
|
res = value;
|
|
value--;
|
|
while (value > 1) {
|
|
res *= value;
|
|
value--;
|
|
}
|
|
|
|
if (res == 0) {
|
|
res = 1; // 0! is per definition 1
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
if (isBoolean(x)) {
|
|
return 1; // factorial(1) = 1, factorial(0) = 1
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, factorial);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return factorial(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('factorial', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/collection.js":201,"../../util/index.js":205}],173:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js');
|
|
|
|
/**
|
|
* Return a random number between 0 and 1
|
|
*
|
|
* random()
|
|
*
|
|
* @return {Number} res
|
|
*/
|
|
|
|
// Each distribution is a function that takes no argument and when called returns
|
|
// a number between 0 and 1.
|
|
var distributions = {
|
|
|
|
uniform: function() {
|
|
return Math.random;
|
|
},
|
|
|
|
// Implementation of normal distribution using Box-Muller transform
|
|
// ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
|
|
// We take : mean = 0.5, standard deviation = 1/6
|
|
// so that 99.7% values are in [0, 1].
|
|
normal: function() {
|
|
return function() {
|
|
var u1, u2,
|
|
picked = -1;
|
|
// We reject values outside of the interval [0, 1]
|
|
// TODO: check if it is ok to do that?
|
|
while (picked < 0 || picked > 1) {
|
|
u1 = Math.random();
|
|
u2 = Math.random();
|
|
picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5;
|
|
}
|
|
return picked;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Create a distribution object.
|
|
* @param {String} name Name of a distribution.
|
|
* Choose from 'uniform', 'normal'.
|
|
* @return {Object} distribution A distribution object containing functions:
|
|
* random([size, min, max])
|
|
* randomInt([min, max])
|
|
* pickRandom(array)
|
|
*/
|
|
math.distribution = function(name) {
|
|
if (!distributions.hasOwnProperty(name))
|
|
throw new Error('unknown distribution ' + name);
|
|
|
|
var args = Array.prototype.slice.call(arguments, 1),
|
|
distribution = distributions[name].apply(this, args);
|
|
|
|
return (function(distribution) {
|
|
|
|
// This is the public API for all distributions
|
|
var randFunctions = {
|
|
|
|
random: function(arg1, arg2, arg3) {
|
|
var size, min, max;
|
|
if (arguments.length > 3) {
|
|
throw new util.error.ArgumentsError('random', arguments.length, 0, 3);
|
|
|
|
// `random(max)` or `random(size)`
|
|
} else if (arguments.length === 1) {
|
|
if (Array.isArray(arg1))
|
|
size = arg1;
|
|
else
|
|
max = arg1;
|
|
// `random(min, max)` or `random(size, max)`
|
|
} else if (arguments.length === 2) {
|
|
if (Array.isArray(arg1))
|
|
size = arg1;
|
|
else {
|
|
min = arg1;
|
|
max = arg2;
|
|
}
|
|
// `random(size, min, max)`
|
|
} else {
|
|
size = arg1;
|
|
min = arg2;
|
|
max = arg3;
|
|
}
|
|
|
|
if (max === undefined) max = 1;
|
|
if (min === undefined) min = 0;
|
|
// TODO: output Array if size is Array, output Matrix if size is Matrix
|
|
if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _random));
|
|
else return _random(min, max);
|
|
},
|
|
|
|
randomInt: function(arg1, arg2, arg3) {
|
|
var size, min, max;
|
|
if (arguments.length > 3 || arguments.length < 1)
|
|
throw new util.error.ArgumentsError('randomInt', arguments.length, 1, 3);
|
|
|
|
// `randomInt(max)`
|
|
else if (arguments.length === 1) max = arg1;
|
|
// `randomInt(min, max)` or `randomInt(size, max)`
|
|
else if (arguments.length === 2) {
|
|
if (Object.prototype.toString.call(arg1) === '[object Array]')
|
|
size = arg1;
|
|
else {
|
|
min = arg1;
|
|
max = arg2;
|
|
}
|
|
// `randomInt(size, min, max)`
|
|
} else {
|
|
size = arg1;
|
|
min = arg2;
|
|
max = arg3;
|
|
}
|
|
|
|
if (min === undefined) min = 0;
|
|
// TODO: output Array if size is Array, output Matrix if size is Matrix
|
|
if (size !== undefined) return new Matrix(_randomDataForMatrix(size, min, max, _randomInt));
|
|
else return _randomInt(min, max);
|
|
},
|
|
|
|
pickRandom: function(possibles) {
|
|
if (arguments.length !== 1) {
|
|
throw new util.error.ArgumentsError('pickRandom', arguments.length, 1);
|
|
}
|
|
if (!Array.isArray(possibles)) {
|
|
throw new util.error.UnsupportedTypeError('pickRandom', possibles);
|
|
}
|
|
|
|
// TODO: add support for matrices
|
|
return possibles[Math.floor(Math.random() * possibles.length)];
|
|
}
|
|
|
|
};
|
|
|
|
var _random = function(min, max) {
|
|
return min + distribution() * (max - min);
|
|
};
|
|
|
|
var _randomInt = function(min, max) {
|
|
return Math.floor(min + distribution() * (max - min));
|
|
};
|
|
|
|
// This is a function for generating a random matrix recursively.
|
|
var _randomDataForMatrix = function(size, min, max, randFunc) {
|
|
var data = [], length, i;
|
|
size = size.slice(0);
|
|
|
|
if (size.length > 1) {
|
|
for (i = 0, length = size.shift(); i < length; i++)
|
|
data.push(_randomDataForMatrix(size, min, max, randFunc));
|
|
} else {
|
|
for (i = 0, length = size.shift(); i < length; i++)
|
|
data.push(randFunc(min, max));
|
|
}
|
|
|
|
return data;
|
|
};
|
|
|
|
return randFunctions;
|
|
|
|
})(distribution);
|
|
|
|
};
|
|
|
|
// Default random functions use uniform distribution
|
|
// TODO: put random functions in separate files?
|
|
var uniformRandFunctions = math.distribution('uniform');
|
|
math.random = uniformRandFunctions.random;
|
|
math.randomInt = uniformRandFunctions.randomInt;
|
|
math.pickRandom = uniformRandFunctions.pickRandom;
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../util/index.js":205}],174:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Compute the maximum value of a list of values
|
|
*
|
|
* max(a, b, c, ...)
|
|
* max([a, b, c, ...])
|
|
*
|
|
* @param {... *} args A single matrix or or multiple scalar values
|
|
* @return {*} res
|
|
*/
|
|
math.max = function max(args) {
|
|
if (arguments.length == 0) {
|
|
throw new Error('Function max requires one or more parameters (0 provided)');
|
|
}
|
|
|
|
if (isCollection(args)) {
|
|
// max([a, b, c, d, ...]])
|
|
if (arguments.length > 1) {
|
|
throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)');
|
|
}
|
|
|
|
var size = math.size(args).valueOf();
|
|
|
|
if (size.length == 1) {
|
|
// vector
|
|
if (args.length == 0) {
|
|
throw new Error('Cannot calculate max of an empty vector');
|
|
}
|
|
|
|
return _max(args.valueOf());
|
|
}
|
|
else if (size.length == 2) {
|
|
// 2 dimensional matrix
|
|
if (size[0] == 0 || size[1] == 0) {
|
|
throw new Error('Cannot calculate max of an empty matrix');
|
|
}
|
|
|
|
// TODO: make a generic collection method for this
|
|
if (Matrix.isMatrix(args)) {
|
|
return new Matrix(_max2(args.valueOf(), size[0], size[1]));
|
|
}
|
|
else {
|
|
return _max2(args, size[0], size[1]);
|
|
}
|
|
}
|
|
else {
|
|
// TODO: implement max for n-dimensional matrices
|
|
throw new RangeError('Cannot calculate max for multi dimensional matrix');
|
|
}
|
|
}
|
|
else {
|
|
// max(a, b, c, d, ...)
|
|
return _max(arguments);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Calculate the max of a one dimensional array
|
|
* @param {Array} array
|
|
* @return {Number} max
|
|
* @private
|
|
*/
|
|
function _max(array) {
|
|
var res = array[0];
|
|
for (var i = 1, iMax = array.length; i < iMax; i++) {
|
|
var value = array[i];
|
|
if (math.larger(value, res)) {
|
|
res = value;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Calculate the max of a two dimensional array
|
|
* @param {Array} array
|
|
* @param {Number} rows
|
|
* @param {Number} cols
|
|
* @return {Number[]} max
|
|
* @private
|
|
*/
|
|
function _max2(array, rows, cols) {
|
|
var res = [];
|
|
for (var c = 0; c < cols; c++) {
|
|
var max = array[0][c];
|
|
for (var r = 1; r < rows; r++) {
|
|
var value = array[r][c];
|
|
if (math.larger(value, max)) {
|
|
max = value;
|
|
}
|
|
}
|
|
res[c] = max;
|
|
}
|
|
return res;
|
|
}
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/index.js":205}],175:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Matrix = require('../../type/Matrix.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Compute the minimum value of a list of values
|
|
*
|
|
* min(a, b, c, ...)
|
|
* min([a, b, c, ...])
|
|
*
|
|
* @param {... *} args A single matrix or multiple scalars
|
|
* @return {*} res
|
|
*/
|
|
math.min = function min(args) {
|
|
if (arguments.length == 0) {
|
|
throw new Error('Function min requires one or more parameters (0 provided)');
|
|
}
|
|
|
|
if (isCollection(args)) {
|
|
// min([a, b, c, d, ...]])
|
|
if (arguments.length > 1) {
|
|
throw Error('Wrong number of parameters (1 matrix or multiple scalars expected)');
|
|
}
|
|
|
|
var size = math.size(args).valueOf();
|
|
|
|
if (size.length == 1) {
|
|
// vector
|
|
if (args.length == 0) {
|
|
throw new Error('Cannot calculate min of an empty vector');
|
|
}
|
|
|
|
return _min(args.valueOf());
|
|
}
|
|
else if (size.length == 2) {
|
|
// 2 dimensional matrix
|
|
if (size[0] == 0 || size[1] == 0) {
|
|
throw new Error('Cannot calculate min of an empty matrix');
|
|
}
|
|
|
|
// TODO: make a generic collection method for this
|
|
if (Matrix.isMatrix(args)) {
|
|
return new Matrix(_min2(args.valueOf(), size[0], size[1]));
|
|
}
|
|
else {
|
|
return _min2(args, size[0], size[1]);
|
|
}
|
|
}
|
|
else {
|
|
// TODO: implement min for n-dimensional matrices
|
|
throw new RangeError('Cannot calculate min for multi dimensional matrix');
|
|
}
|
|
}
|
|
else {
|
|
// min(a, b, c, d, ...)
|
|
return _min(arguments);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Calculate the min of a one dimensional array
|
|
* @param {Array} array
|
|
* @return {Number} min
|
|
* @private
|
|
*/
|
|
function _min(array) {
|
|
var res = array[0];
|
|
for (var i = 1, iMax = array.length; i < iMax; i++) {
|
|
var value = array[i];
|
|
if (math.smaller(value, res)) {
|
|
res = value;
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Calculate the min of a two dimensional array
|
|
* @param {Array} array
|
|
* @param {Number} rows
|
|
* @param {Number} cols
|
|
* @return {Number[]} min
|
|
* @private
|
|
*/
|
|
function _min2(array, rows, cols) {
|
|
var res = [];
|
|
for (var c = 0; c < cols; c++) {
|
|
var min = array[0][c];
|
|
for (var r = 1; r < rows; r++) {
|
|
var value = array[r][c];
|
|
if (math.smaller(value, min)) {
|
|
min = value;
|
|
}
|
|
}
|
|
res[c] = min;
|
|
}
|
|
return res;
|
|
}
|
|
};
|
|
|
|
},{"../../type/Matrix.js":198,"../../type/collection.js":201,"../../util/index.js":205}],176:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the inverse cosine of a value
|
|
*
|
|
* acos(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*
|
|
* @see http://mathworld.wolfram.com/InverseCosine.html
|
|
*/
|
|
math.acos = function acos(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('acos', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (x >= -1 && x <= 1) {
|
|
return Math.acos(x);
|
|
}
|
|
else {
|
|
return acos(new Complex(x, 0));
|
|
}
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
// acos(z) = 0.5*pi + i*log(iz + sqrt(1-z^2))
|
|
var temp1 = new Complex(
|
|
x.im * x.im - x.re * x.re + 1.0,
|
|
-2.0 * x.re * x.im
|
|
);
|
|
var temp2 = math.sqrt(temp1);
|
|
var temp3;
|
|
if (temp2 instanceof Complex) {
|
|
temp3 = new Complex(
|
|
temp2.re - x.im,
|
|
temp2.im + x.re
|
|
)
|
|
}
|
|
else {
|
|
temp3 = new Complex(
|
|
temp2 - x.im,
|
|
x.re
|
|
)
|
|
}
|
|
var temp4 = math.log(temp3);
|
|
|
|
// 0.5*pi = 1.5707963267948966192313216916398
|
|
if (temp4 instanceof Complex) {
|
|
return new Complex(
|
|
1.57079632679489661923 - temp4.im,
|
|
temp4.re
|
|
);
|
|
}
|
|
else {
|
|
return new Complex(
|
|
1.57079632679489661923,
|
|
temp4
|
|
);
|
|
}
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, acos);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return acos(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('acos', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],177:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the inverse sine of a value
|
|
*
|
|
* asin(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*
|
|
* @see http://mathworld.wolfram.com/InverseSine.html
|
|
*/
|
|
math.asin = function asin(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('asin', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
if (x >= -1 && x <= 1) {
|
|
return Math.asin(x);
|
|
}
|
|
else {
|
|
return asin(new Complex(x, 0));
|
|
}
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
// asin(z) = -i*log(iz + sqrt(1-z^2))
|
|
var re = x.re;
|
|
var im = x.im;
|
|
var temp1 = new Complex(
|
|
im * im - re * re + 1.0,
|
|
-2.0 * re * im
|
|
);
|
|
|
|
var temp2 = math.sqrt(temp1);
|
|
var temp3;
|
|
if (temp2 instanceof Complex) {
|
|
temp3 = new Complex(
|
|
temp2.re - im,
|
|
temp2.im + re
|
|
);
|
|
}
|
|
else {
|
|
temp3 = new Complex(
|
|
temp2 - im,
|
|
re
|
|
);
|
|
}
|
|
|
|
var temp4 = math.log(temp3);
|
|
|
|
if (temp4 instanceof Complex) {
|
|
return new Complex(temp4.im, -temp4.re);
|
|
}
|
|
else {
|
|
return new Complex(0, -temp4);
|
|
}
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, asin);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return asin(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('asin', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],178:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the inverse tangent of a value
|
|
*
|
|
* atan(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*
|
|
* @see http://mathworld.wolfram.com/InverseTangent.html
|
|
*/
|
|
math.atan = function atan(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('atan', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.atan(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
// atan(z) = 1/2 * i * (ln(1-iz) - ln(1+iz))
|
|
var re = x.re;
|
|
var im = x.im;
|
|
var den = re * re + (1.0 - im) * (1.0 - im);
|
|
|
|
var temp1 = new Complex(
|
|
(1.0 - im * im - re * re) / den,
|
|
(-2.0 * re) / den
|
|
);
|
|
var temp2 = math.log(temp1);
|
|
|
|
if (temp2 instanceof Complex) {
|
|
return new Complex(
|
|
-0.5 * temp2.im,
|
|
0.5 * temp2.re
|
|
);
|
|
}
|
|
else {
|
|
return new Complex(
|
|
0,
|
|
0.5 * temp2
|
|
);
|
|
}
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, atan);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return atan(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('atan', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],179:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Computes the principal value of the arc tangent of y/x in radians
|
|
*
|
|
* atan2(y, x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Array | Matrix} y
|
|
* @param {Number | Boolean | Complex | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*
|
|
* @see http://mathworld.wolfram.com/InverseTangent.html
|
|
*/
|
|
math.atan2 = function atan2(y, x) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('atan2', arguments.length, 2);
|
|
}
|
|
|
|
if (isNumBool(y)) {
|
|
if (isNumBool(x)) {
|
|
return Math.atan2(y, x);
|
|
}
|
|
/* TODO: support for complex computation of atan2
|
|
else if (isComplex(x)) {
|
|
return Math.atan2(y.re, x.re);
|
|
}
|
|
*/
|
|
}
|
|
else if (isComplex(y)) {
|
|
if (isNumBool(x)) {
|
|
return Math.atan2(y.re, x);
|
|
}
|
|
/* TODO: support for complex computation of atan2
|
|
else if (isComplex(x)) {
|
|
return Math.atan2(y.re, x.re);
|
|
}
|
|
*/
|
|
}
|
|
|
|
if (isCollection(y) || isCollection(x)) {
|
|
return collection.map2(y, x, atan2);
|
|
}
|
|
|
|
if (x.valueOf() !== x || y.valueOf() !== y) {
|
|
// fallback on the objects primitive values
|
|
return atan2(y.valueOf(), x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('atan2', y, x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/collection.js":201,"../../util/index.js":205}],180:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the cosine of a value
|
|
*
|
|
* cos(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*
|
|
* @see http://mathworld.wolfram.com/Cosine.html
|
|
*/
|
|
math.cos = function cos(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('cos', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.cos(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
// cos(z) = (exp(iz) + exp(-iz)) / 2
|
|
return new Complex(
|
|
0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp(x.im)),
|
|
0.5 * Math.sin(x.re) * (Math.exp(-x.im) - Math.exp(x.im))
|
|
);
|
|
}
|
|
|
|
if (isUnit(x)) {
|
|
if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
|
|
throw new TypeError ('Unit in function cos is no angle');
|
|
}
|
|
return Math.cos(x.value);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, cos);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return cos(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('cos', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],181:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the cotangent of a value. cot(x) is defined as 1 / tan(x)
|
|
*
|
|
* cot(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.cot = function cot(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('cot', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return 1 / Math.tan(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
var den = Math.exp(-4.0 * x.im) -
|
|
2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) + 1.0;
|
|
|
|
return new Complex(
|
|
2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den,
|
|
(Math.exp(-4.0 * x.im) - 1.0) / den
|
|
);
|
|
}
|
|
|
|
if (isUnit(x)) {
|
|
if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
|
|
throw new TypeError ('Unit in function cot is no angle');
|
|
}
|
|
return 1 / Math.tan(x.value);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, cot);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return cot(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('cot', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],182:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the cosecant of a value, csc(x) = 1/sin(x)
|
|
*
|
|
* csc(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.csc = function csc(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('csc', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return 1 / Math.sin(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
// csc(z) = 1/sin(z) = (2i) / (exp(iz) - exp(-iz))
|
|
var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) -
|
|
0.5 * Math.cos(2.0 * x.re);
|
|
|
|
return new Complex (
|
|
0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp(x.im)) / den,
|
|
0.5 * Math.cos(x.re) * (Math.exp(-x.im) - Math.exp(x.im)) / den
|
|
);
|
|
}
|
|
|
|
if (isUnit(x)) {
|
|
if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
|
|
throw new TypeError ('Unit in function csc is no angle');
|
|
}
|
|
return 1 / Math.sin(x.value);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, csc);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return csc(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('csc', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],183:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the secant of a value, sec(x) = 1/cos(x)
|
|
*
|
|
* sec(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*/
|
|
math.sec = function sec(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('sec', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return 1 / Math.cos(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
// sec(z) = 1/cos(z) = 2 / (exp(iz) + exp(-iz))
|
|
var den = 0.25 * (Math.exp(-2.0 * x.im) + Math.exp(2.0 * x.im)) +
|
|
0.5 * Math.cos(2.0 * x.re);
|
|
return new Complex(
|
|
0.5 * Math.cos(x.re) * (Math.exp(-x.im) + Math.exp( x.im)) / den,
|
|
0.5 * Math.sin(x.re) * (Math.exp( x.im) - Math.exp(-x.im)) / den
|
|
);
|
|
}
|
|
|
|
if (isUnit(x)) {
|
|
if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
|
|
throw new TypeError ('Unit in function sec is no angle');
|
|
}
|
|
return 1 / Math.cos(x.value);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, sec);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return sec(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('sec', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],184:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the sine of a value
|
|
*
|
|
* sin(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*
|
|
* @see http://mathworld.wolfram.com/Sine.html
|
|
*/
|
|
math.sin = function sin(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('sin', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.sin(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
return new Complex(
|
|
0.5 * Math.sin(x.re) * (Math.exp(-x.im) + Math.exp( x.im)),
|
|
0.5 * Math.cos(x.re) * (Math.exp( x.im) - Math.exp(-x.im))
|
|
);
|
|
}
|
|
|
|
if (isUnit(x)) {
|
|
if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
|
|
throw new TypeError ('Unit in function cos is no angle');
|
|
}
|
|
return Math.sin(x.value);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, sin);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return sin(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('sin', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],185:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isNumBool = util.number.isNumBool,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Calculate the tangent of a value
|
|
*
|
|
* tan(x)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Number | Boolean | Complex | Unit | Array | Matrix} x
|
|
* @return {Number | Complex | Array | Matrix} res
|
|
*
|
|
* @see http://mathworld.wolfram.com/Tangent.html
|
|
*/
|
|
math.tan = function tan(x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('tan', arguments.length, 1);
|
|
}
|
|
|
|
if (isNumBool(x)) {
|
|
return Math.tan(x);
|
|
}
|
|
|
|
if (isComplex(x)) {
|
|
var den = Math.exp(-4.0 * x.im) +
|
|
2.0 * Math.exp(-2.0 * x.im) * Math.cos(2.0 * x.re) +
|
|
1.0;
|
|
|
|
return new Complex(
|
|
2.0 * Math.exp(-2.0 * x.im) * Math.sin(2.0 * x.re) / den,
|
|
(1.0 - Math.exp(-4.0 * x.im)) / den
|
|
);
|
|
}
|
|
|
|
if (isUnit(x)) {
|
|
if (!x.hasBase(Unit.BASE_UNITS.ANGLE)) {
|
|
throw new TypeError ('Unit in function tan is no angle');
|
|
}
|
|
return Math.tan(x.value);
|
|
}
|
|
|
|
if (isCollection(x)) {
|
|
return collection.map(x, tan);
|
|
}
|
|
|
|
if (x.valueOf() !== x) {
|
|
// fallback on the objects primitive value
|
|
return tan(x.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('tan', x);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],186:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Unit = require('../../type/Unit.js'),
|
|
collection = require('../../type/collection.js'),
|
|
|
|
isString = util.string.isString,
|
|
isUnit = Unit.isUnit,
|
|
isCollection = collection.isCollection;
|
|
|
|
/**
|
|
* Change the unit of a value.
|
|
*
|
|
* x in unit
|
|
* in(x, unit)
|
|
*
|
|
* For matrices, the function is evaluated element wise.
|
|
*
|
|
* @param {Unit | Array | Matrix} x
|
|
* @param {Unit | Array | Matrix} unit
|
|
* @return {Unit | Array | Matrix} res
|
|
*/
|
|
math['in'] = function unit_in(x, unit) {
|
|
if (arguments.length != 2) {
|
|
throw new util.error.ArgumentsError('in', arguments.length, 2);
|
|
}
|
|
|
|
if (isUnit(x)) {
|
|
if (isUnit(unit) || isString(unit)) {
|
|
return x['in'](unit);
|
|
}
|
|
}
|
|
|
|
// TODO: add support for string, in that case, convert to unit
|
|
|
|
if (isCollection(x) || isCollection(unit)) {
|
|
return collection.map2(x, unit, unit_in);
|
|
}
|
|
|
|
if (x.valueOf() !== x || unit.valueOf() !== unit) {
|
|
// fallback on the objects primitive value
|
|
return unit_in(x.valueOf(), unit.valueOf());
|
|
}
|
|
|
|
throw new util.error.UnsupportedTypeError('in', x, unit);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Unit.js":200,"../../type/collection.js":201,"../../util/index.js":205}],187:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
object = util.object;
|
|
|
|
/**
|
|
* Clone an object
|
|
*
|
|
* clone(x)
|
|
*
|
|
* @param {*} x
|
|
* @return {*} clone
|
|
*/
|
|
math.clone = function clone (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('clone', arguments.length, 1);
|
|
}
|
|
|
|
return object.clone(x);
|
|
};
|
|
};
|
|
|
|
},{"../../util/index.js":205}],188:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var error = require('../../util/error.js'),
|
|
isMatrix = require('../../type/Matrix').isMatrix;
|
|
|
|
/**
|
|
* Execute a callback method on each entry of the matrix or the array.
|
|
* @param {Matrix/array} x The container 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/array being traversed.
|
|
*/
|
|
math.forEach = function (x, callback) {
|
|
if (arguments.length != 2) {
|
|
throw new error.ArgumentsError('forEach', arguments.length, 2);
|
|
}
|
|
|
|
if (Array.isArray(x)) {
|
|
return _forEachArray(x, callback);
|
|
} else if (isMatrix(x)) {
|
|
return x.forEach(callback);
|
|
} else {
|
|
throw new error.UnsupportedTypeError('forEach', x);
|
|
}
|
|
};
|
|
|
|
function _forEachArray (array, callback) {
|
|
var index = [];
|
|
var recurse = function (value, dim) {
|
|
if (Array.isArray(value)) {
|
|
value.forEach(function (child, i) {
|
|
index[dim] = i; // zero-based index
|
|
recurse(child, dim + 1);
|
|
});
|
|
}
|
|
else {
|
|
callback(value, index, array);
|
|
}
|
|
};
|
|
recurse(array, 0);
|
|
};
|
|
|
|
};
|
|
},{"../../type/Matrix":198,"../../util/error.js":204}],189:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
string = util.string;
|
|
|
|
/**
|
|
* Format a value of any type into a string. Interpolate values into the string.
|
|
* Numbers are rounded off to a maximum number of 5 digits by default.
|
|
* Usage:
|
|
* math.format(value)
|
|
* math.format(template, object)
|
|
*
|
|
* Example usage:
|
|
* math.format(2/7); // '0.28571'
|
|
* math.format(new Complex(2, 3)); // '2 + 3i'
|
|
* math.format('Hello $name! The date is $date', {
|
|
* name: 'user',
|
|
* date: new Date().toISOString().substring(0, 10)
|
|
* }); // 'hello user! The date is 2013-03-23'
|
|
*
|
|
* @param {String} template
|
|
* @param {Object} values
|
|
* @return {String} str
|
|
*/
|
|
math.format = function format (template, values) {
|
|
var num = arguments.length;
|
|
if (num != 1 && num != 2) {
|
|
throw new util.error.ArgumentsError('format', num, 1, 2);
|
|
}
|
|
|
|
return string.format.apply(string.format, arguments);
|
|
};
|
|
};
|
|
|
|
},{"../../util/index.js":205}],190:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js'),
|
|
|
|
Complex = require('../../type/Complex.js'),
|
|
Unit = require('../../type/Unit.js'),
|
|
|
|
isNumber = util.number.isNumber,
|
|
isString = util.string.isString,
|
|
isComplex = Complex.isComplex,
|
|
isUnit = Unit.isUnit;
|
|
|
|
/**
|
|
* Import functions from an object or a file
|
|
* @param {function | String | Object} object
|
|
* @param {Object} [options] Available options:
|
|
* {Boolean} override
|
|
* If true, existing functions will be
|
|
* overwritten. False by default.
|
|
* {Boolean} wrap
|
|
* If true (default), the functions will
|
|
* be wrapped in a wrapper function which
|
|
* converts data types like Matrix to
|
|
* primitive data types like Array.
|
|
* The wrapper is needed when extending
|
|
* math.js with libraries which do not
|
|
* support the math.js data types.
|
|
*/
|
|
// TODO: return status information
|
|
math['import'] = function math_import(object, options) {
|
|
var name;
|
|
var opts = {
|
|
override: false,
|
|
wrap: true
|
|
};
|
|
if (options && options instanceof Object) {
|
|
util.object.extend(opts, options);
|
|
}
|
|
|
|
if (isString(object)) {
|
|
// a string with a filename
|
|
if (typeof (require) !== 'undefined') {
|
|
// load the file using require
|
|
var _module = require(object);
|
|
math_import(_module);
|
|
}
|
|
else {
|
|
throw new Error('Cannot load file: require not available.');
|
|
}
|
|
}
|
|
else if (isSupportedType(object)) {
|
|
// a single function
|
|
name = object.name;
|
|
if (name) {
|
|
if (opts.override || math[name] === undefined) {
|
|
_import(name, object, opts);
|
|
}
|
|
}
|
|
else {
|
|
throw new Error('Cannot import an unnamed function or object');
|
|
}
|
|
}
|
|
else if (object instanceof Object) {
|
|
// a map with functions
|
|
for (name in object) {
|
|
if (object.hasOwnProperty(name)) {
|
|
var value = object[name];
|
|
if (isSupportedType(value)) {
|
|
_import(name, value, opts);
|
|
}
|
|
else {
|
|
math_import(value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Add a property to the math namespace and create a chain proxy for it.
|
|
* @param {String} name
|
|
* @param {*} value
|
|
* @param {Object} options See import for a description of the options
|
|
* @private
|
|
*/
|
|
function _import(name, value, options) {
|
|
if (options.override || math[name] === undefined) {
|
|
// add to math namespace
|
|
if (options.wrap && typeof value === 'function') {
|
|
// create a wrapper around the function
|
|
math[name] = function () {
|
|
var args = [];
|
|
for (var i = 0, len = arguments.length; i < len; i++) {
|
|
args[i] = arguments[i].valueOf();
|
|
}
|
|
return value.apply(math, args);
|
|
};
|
|
}
|
|
else {
|
|
// just create a link to the function or value
|
|
math[name] = value;
|
|
}
|
|
|
|
// create a proxy for the Selector
|
|
math.chaining.Selector.createProxy(name, value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check whether given object is a supported type
|
|
* @param object
|
|
* @return {Boolean}
|
|
* @private
|
|
*/
|
|
function isSupportedType(object) {
|
|
return (typeof object == 'function') ||
|
|
isNumber(object) || isString(object) ||
|
|
isComplex(object) || isUnit(object);
|
|
// TODO: add boolean?
|
|
}
|
|
};
|
|
|
|
},{"../../type/Complex.js":195,"../../type/Unit.js":200,"../../util/index.js":205}],191:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var error = require('../../util/error.js'),
|
|
isMatrix = require('../../type/Matrix').isMatrix;
|
|
|
|
/**
|
|
* Create a new matrix or array with the results of the callback function executed on
|
|
* each entry of the matrix/array.
|
|
* @param {Matrix/array} x The container 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} container
|
|
*/
|
|
math.map = function (x, callback) {
|
|
if (arguments.length != 2) {
|
|
throw new error.ArgumentsError('map', arguments.length, 2);
|
|
}
|
|
|
|
if (Array.isArray(x)) {
|
|
return _mapArray(x, callback);
|
|
} else if (isMatrix(x)) {
|
|
return x.map(callback);
|
|
} else {
|
|
throw new error.UnsupportedTypeError('map', x);
|
|
}
|
|
};
|
|
|
|
function _mapArray (arrayIn, callback) {
|
|
var index = [];
|
|
var recurse = function (value, dim) {
|
|
if (Array.isArray(value)) {
|
|
return value.map(function (child, i) {
|
|
index[dim] = i;
|
|
return recurse(child, dim + 1);
|
|
});
|
|
}
|
|
else {
|
|
return callback(value, index, arrayIn);
|
|
}
|
|
};
|
|
|
|
return recurse(arrayIn, 0);
|
|
};
|
|
};
|
|
|
|
},{"../../type/Matrix":198,"../../util/error.js":204}],192:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
/**
|
|
* Wrap any value in a Selector, allowing to perform chained operations on
|
|
* the value.
|
|
*
|
|
* All methods available in the math.js library can be called upon the selector,
|
|
* and then will be evaluated with the value itself as first argument.
|
|
* The selector can be closed by executing selector.done(), which will return
|
|
* the final value.
|
|
*
|
|
* Example usage:
|
|
* math.select(3)
|
|
* .add(4)
|
|
* .subtract(2)
|
|
* .done(); // 5
|
|
* math.select( [[1, 2], [3, 4]] )
|
|
* .set([1, 1], 8)
|
|
* .multiply(3)
|
|
* .done(); // [[24, 6], [9, 12]]
|
|
*
|
|
* The Selector has a number of special functions:
|
|
* - done() Finalize the chained operation and return the selectors value.
|
|
* - valueOf() The same as done()
|
|
* - toString() Executes math.format() onto the selectors value, returning
|
|
* a string representation of the value.
|
|
* - get(...) Get a subselection of the selectors value. Only applicable when
|
|
* the value has a method get, for example when value is a Matrix
|
|
* or Array.
|
|
* - set(...) Replace a subselection of the selectors value. Only applicable
|
|
* when the value has a method get, for example when value is a
|
|
* Matrix or Array.
|
|
*
|
|
* @param {*} value
|
|
* @return {math.chaining.Selector} selector
|
|
*/
|
|
math.select = function select(value) {
|
|
// TODO: check number of arguments
|
|
return new math.chaining.Selector(value);
|
|
};
|
|
};
|
|
|
|
},{}],193:[function(require,module,exports){
|
|
module.exports = function (math) {
|
|
var util = require('../../util/index.js');
|
|
|
|
/**
|
|
* Determine the type of a variable
|
|
*
|
|
* typeof(x)
|
|
*
|
|
* @param {*} x
|
|
* @return {String} type Lower case type, for example "number", "string",
|
|
* "array".
|
|
*/
|
|
math['typeof'] = function _typeof (x) {
|
|
if (arguments.length != 1) {
|
|
throw new util.error.ArgumentsError('typeof', arguments.length, 1);
|
|
}
|
|
|
|
return util.types.type(x);
|
|
};
|
|
};
|
|
|
|
},{"../../util/index.js":205}],194:[function(require,module,exports){
|
|
// math.js options
|
|
exports.precision = 5; // number of digits in formatted output
|
|
|
|
},{}],195:[function(require,module,exports){
|
|
var util = require('../util/index.js'),
|
|
|
|
number = util.number,
|
|
isNumber = util.number.isNumber,
|
|
isString = util.string.isString;
|
|
|
|
/**
|
|
* @constructor Complex
|
|
*
|
|
* A complex value can be constructed in the following ways:
|
|
* var a = new Complex();
|
|
* var b = new Complex(re, im);
|
|
* var c = Complex.parse(str);
|
|
*
|
|
* Example usage:
|
|
* var a = new Complex(3, -4); // 3 - 4i
|
|
* a.re = 5; // a = 5 - 4i
|
|
* var i = a.im; // -4;
|
|
* var b = Complex.parse('2 + 6i'); // 2 + 6i
|
|
* var c = new Complex(); // 0 + 0i
|
|
* var d = math.add(a, b); // 5 + 2i
|
|
*
|
|
* @param {Number} re The real part of the complex value
|
|
* @param {Number} [im] The imaginary part of the complex value
|
|
*/
|
|
function Complex(re, im) {
|
|
if (!(this instanceof Complex)) {
|
|
throw new SyntaxError(
|
|
'Complex constructor must be called with the new operator');
|
|
}
|
|
|
|
switch (arguments.length) {
|
|
case 0:
|
|
this.re = 0;
|
|
this.im = 0;
|
|
break;
|
|
|
|
case 2:
|
|
if (!isNumber(re) || !isNumber(im)) {
|
|
throw new TypeError(
|
|
'Two numbers expected in Complex constructor');
|
|
}
|
|
this.re = re;
|
|
this.im = im;
|
|
break;
|
|
|
|
default:
|
|
if (arguments.length != 0 && arguments.length != 2) {
|
|
throw new SyntaxError(
|
|
'Two or zero arguments expected in Complex constructor');
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Test whether value is a Complex value
|
|
* @param {*} value
|
|
* @return {Boolean} isComplex
|
|
*/
|
|
Complex.isComplex = function isComplex(value) {
|
|
return (value instanceof Complex);
|
|
};
|
|
|
|
// private variables and functions for the parser
|
|
var text, index, c;
|
|
|
|
function skipWhitespace() {
|
|
while (c == ' ' || c == '\t') {
|
|
next();
|
|
}
|
|
}
|
|
|
|
function isDigitDot (c) {
|
|
return ((c >= '0' && c <= '9') || c == '.');
|
|
}
|
|
|
|
function isDigit (c) {
|
|
return ((c >= '0' && c <= '9'));
|
|
}
|
|
|
|
function next() {
|
|
index++;
|
|
c = text.charAt(index);
|
|
}
|
|
|
|
function revert(oldIndex) {
|
|
index = oldIndex;
|
|
c = text.charAt(index);
|
|
}
|
|
|
|
function parseNumber () {
|
|
var number = '';
|
|
var oldIndex;
|
|
oldIndex = index;
|
|
|
|
if (c == '+') {
|
|
next();
|
|
}
|
|
else if (c == '-') {
|
|
number += c;
|
|
next();
|
|
}
|
|
|
|
if (!isDigitDot(c)) {
|
|
// a + or - must be followed by a digit
|
|
revert(oldIndex);
|
|
return null;
|
|
}
|
|
|
|
// get number, can have a single dot
|
|
if (c == '.') {
|
|
number += c;
|
|
next();
|
|
if (!isDigit(c)) {
|
|
// this is no legal number, it is just a dot
|
|
revert(oldIndex);
|
|
return null;
|
|
}
|
|
}
|
|
else {
|
|
while (isDigit(c)) {
|
|
number += c;
|
|
next();
|
|
}
|
|
if (c == '.') {
|
|
number += c;
|
|
next();
|
|
}
|
|
}
|
|
while (isDigit(c)) {
|
|
number += c;
|
|
next();
|
|
}
|
|
|
|
// check for scientific notation like "2.3e-4" or "1.23e50"
|
|
if (c == 'E' || c == 'e') {
|
|
number += c;
|
|
next();
|
|
|
|
if (c == '+' || c == '-') {
|
|
number += c;
|
|
next();
|
|
}
|
|
|
|
// Scientific notation MUST be followed by an exponent
|
|
if (!isDigit(c)) {
|
|
// this is no legal number, exponent is missing.
|
|
revert(oldIndex);
|
|
return null;
|
|
}
|
|
|
|
while (isDigit(c)) {
|
|
number += c;
|
|
next();
|
|
}
|
|
}
|
|
|
|
return number;
|
|
}
|
|
|
|
function parseComplex () {
|
|
// check for 'i', '-i', '+i'
|
|
var cnext = text.charAt(index + 1);
|
|
if (c == 'I' || c == 'i') {
|
|
next();
|
|
return '1';
|
|
}
|
|
else if ((c == '+' || c == '-') && (cnext == 'I' || cnext == 'i')) {
|
|
var number = (c == '+') ? '1' : '-1';
|
|
next();
|
|
next();
|
|
return number;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Parse a complex number from a string. For example Complex.parse("2 + 3i")
|
|
* will return a Complex value where re = 2, im = 3.
|
|
* Returns null if provided string does not contain a valid complex number.
|
|
* @param {String} str
|
|
* @returns {Complex | null} complex
|
|
*/
|
|
Complex.parse = function parse(str) {
|
|
text = str;
|
|
index = -1;
|
|
c = '';
|
|
|
|
if (!isString(text)) {
|
|
return null;
|
|
}
|
|
|
|
next();
|
|
skipWhitespace();
|
|
var first = parseNumber();
|
|
if (first) {
|
|
if (c == 'I' || c == 'i') {
|
|
// pure imaginary number
|
|
next();
|
|
skipWhitespace();
|
|
if (c) {
|
|
// garbage at the end. not good.
|
|
return null;
|
|
}
|
|
|
|
return new Complex(0, Number(first));
|
|
}
|
|
else {
|
|
// complex and real part
|
|
skipWhitespace();
|
|
var separator = c;
|
|
if (separator != '+' && separator != '-') {
|
|
// pure real number
|
|
skipWhitespace();
|
|
if (c) {
|
|
// garbage at the end. not good.
|
|
return null;
|
|
}
|
|
|
|
return new Complex(Number(first), 0);
|
|
}
|
|
else {
|
|
// complex and real part
|
|
next();
|
|
skipWhitespace();
|
|
var second = parseNumber();
|
|
if (second) {
|
|
if (c != 'I' && c != 'i') {
|
|
// 'i' missing at the end of the complex number
|
|
return null;
|
|
}
|
|
next();
|
|
}
|
|
else {
|
|
second = parseComplex();
|
|
if (!second) {
|
|
// imaginary number missing after separator
|
|
return null;
|
|
}
|
|
}
|
|
|
|
if (separator == '-') {
|
|
if (second[0] == '-') {
|
|
second = '+' + second.substring(1);
|
|
}
|
|
else {
|
|
second = '-' + second;
|
|
}
|
|
}
|
|
|
|
next();
|
|
skipWhitespace();
|
|
if (c) {
|
|
// garbage at the end. not good.
|
|
return null;
|
|
}
|
|
|
|
return new Complex(Number(first), Number(second));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// check for 'i', '-i', '+i'
|
|
first = parseComplex();
|
|
if (first) {
|
|
skipWhitespace();
|
|
if (c) {
|
|
// garbage at the end. not good.
|
|
return null;
|
|
}
|
|
|
|
return new Complex(0, Number(first));
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Create a copy of the complex value
|
|
* @return {Complex} clone
|
|
*/
|
|
Complex.prototype.clone = function () {
|
|
return new Complex(this.re, this.im);
|
|
};
|
|
|
|
/**
|
|
* Get string representation of the Complex value
|
|
* @return {String} str
|
|
*/
|
|
Complex.prototype.toString = function () {
|
|
var str = '';
|
|
var strRe = number.format(this.re);
|
|
var strIm = number.format(this.im);
|
|
|
|
if (this.im == 0) {
|
|
// real value
|
|
str = strRe;
|
|
}
|
|
else if (this.re == 0) {
|
|
// purely complex value
|
|
if (this.im == 1) {
|
|
str = 'i';
|
|
}
|
|
else if (this.im == -1) {
|
|
str = '-i';
|
|
}
|
|
else {
|
|
str = strIm + 'i';
|
|
}
|
|
}
|
|
else {
|
|
// complex value
|
|
if (this.im > 0) {
|
|
if (this.im == 1) {
|
|
str = strRe + ' + i';
|
|
}
|
|
else {
|
|
str = strRe + ' + ' + strIm + 'i';
|
|
}
|
|
}
|
|
else {
|
|
if (this.im == -1) {
|
|
str = strRe + ' - i';
|
|
}
|
|
else {
|
|
str = strRe + ' - ' +
|
|
number.format(Math.abs(this.im)) + 'i';
|
|
}
|
|
}
|
|
}
|
|
|
|
return str;
|
|
};
|
|
|
|
|
|
// exports
|
|
module.exports = Complex;
|
|
|
|
// to trick my IDE which doesn't get it
|
|
exports.isComplex = Complex.isComplex;
|
|
exports.parse = Complex.parse;
|
|
|
|
util.types.addType('complex', Complex);
|
|
|
|
},{"../util/index.js":205}],196:[function(require,module,exports){
|
|
var util = require('../util/index.js'),
|
|
object = util.object,
|
|
string = util.string;
|
|
|
|
/**
|
|
* Documentation object
|
|
* @param {Object} math The math.js namespace
|
|
* @param {Object} doc Object containing properties:
|
|
* {String} name
|
|
* {String} category
|
|
* {String[]} syntax
|
|
* {String[]} examples
|
|
* {String[]} seealso
|
|
* @constructor
|
|
*/
|
|
function Help (math, doc) {
|
|
this.math = math;
|
|
this.doc = doc;
|
|
}
|
|
|
|
/**
|
|
* Test whether a value is an instance of Help
|
|
* @param {*} value
|
|
* @return {Boolean} isHelp
|
|
*/
|
|
Help.isHelp = function isHelp (value) {
|
|
return (value instanceof Help);
|
|
};
|
|
|
|
/**
|
|
* Generate readable description from a Help object
|
|
* @return {String} readableDoc
|
|
* @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) {
|
|
var parser = this.math.parser();
|
|
desc += 'Examples:\n';
|
|
for (var i = 0; i < doc.examples.length; i++) {
|
|
var expr = doc.examples[i];
|
|
var res;
|
|
try {
|
|
res = parser.eval(expr);
|
|
}
|
|
catch (e) {
|
|
res = e;
|
|
}
|
|
desc += ' ' + expr + '\n';
|
|
if (res && !(res instanceof Help)) {
|
|
desc += ' ' + string.format(res) + '\n';
|
|
}
|
|
}
|
|
desc += '\n';
|
|
}
|
|
if (doc.seealso) {
|
|
desc += 'See also: ' + doc.seealso.join(', ') + '\n';
|
|
}
|
|
|
|
return desc;
|
|
};
|
|
|
|
// TODO: implement a toHTML function in Help
|
|
|
|
/**
|
|
* Export the help object to JSON
|
|
*/
|
|
Help.prototype.toJSON = function () {
|
|
return object.extend({}, this.doc);
|
|
};
|
|
|
|
// exports
|
|
module.exports = Help;
|
|
|
|
// to trick my IDE which doesn't get it
|
|
exports.isHelp = Help.isHelp;
|
|
|
|
util.types.addType('help', Help);
|
|
|
|
},{"../util/index.js":205}],197:[function(require,module,exports){
|
|
var util = require('../util/index'),
|
|
Range = require('./Range');
|
|
|
|
number = util.number,
|
|
|
|
isNumber = number.isNumber,
|
|
isInteger = number.isInteger,
|
|
isArray = Array.isArray,
|
|
validateIndex = util.array.validateIndex;
|
|
|
|
/**
|
|
* @Constructor Index
|
|
* Create an index. An Index can store ranges having start, step, and end
|
|
* for multiple dimensions.
|
|
* Matrix.get, Matrix.set, and math.subset accept an Index as input.
|
|
*
|
|
* Usage:
|
|
* var index = new Index(range1, range2, ...);
|
|
*
|
|
* Where each range can be any of:
|
|
* An array [start, end]
|
|
* An array [start, end, step]
|
|
* A number
|
|
* An instance of Range
|
|
*
|
|
* The parameters start, end, and step must be integer numbers.
|
|
*
|
|
* @param {...*} ranges
|
|
*/
|
|
function Index(ranges) {
|
|
if (!(this instanceof Index)) {
|
|
throw new SyntaxError(
|
|
'Index constructor must be called with the new operator');
|
|
}
|
|
|
|
this._ranges = [];
|
|
|
|
for (var i = 0, ii = arguments.length; i < ii; i++) {
|
|
var arg = arguments[i];
|
|
|
|
if (arg instanceof Range) {
|
|
this._ranges.push(arg);
|
|
}
|
|
else {
|
|
if (arg) {
|
|
arg = arg.valueOf();
|
|
}
|
|
|
|
if (isArray(arg)) {
|
|
this._ranges.push(_createRange(arg));
|
|
}
|
|
else if (isNumber(arg)) {
|
|
this._ranges.push(_createRange([arg, arg + 1]));
|
|
}
|
|
// TODO: implement support for wildcard '*'
|
|
// TODO: implement support for a string 'start:step:end'
|
|
else {
|
|
throw new TypeError('Range expected as Array, Number, or String');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse an argument into a range and validate the range
|
|
* @param {Array} arg An array with [start: Number, end: Number] and
|
|
* optional a third element step:Number
|
|
* @return {Range} range
|
|
* @private
|
|
*/
|
|
function _createRange(arg) {
|
|
// TODO: make function _createRange simpler/faster
|
|
|
|
// test whether all arguments are integers
|
|
var num = arg.length;
|
|
for (var i = 0; i < num; i++) {
|
|
if (!isNumber(arg[i]) || !isInteger(arg[i])) {
|
|
throw new TypeError('Index parameters must be integer numbers');
|
|
}
|
|
}
|
|
|
|
switch (arg.length) {
|
|
case 2:
|
|
return new Range(arg[0], arg[1]); // start, end
|
|
case 3:
|
|
return new Range(arg[0], arg[1], arg[2]); // start, end, step
|
|
default:
|
|
// TODO: improve error message
|
|
throw new SyntaxError('Wrong number of arguments in Index (2 or 3 expected)');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a clone of the index
|
|
* @return {Index} clone
|
|
*/
|
|
Index.prototype.clone = function clone () {
|
|
var index = new Index();
|
|
index._ranges = util.object.clone(this._ranges);
|
|
return index;
|
|
};
|
|
|
|
/**
|
|
* Test whether an object is an Index
|
|
* @param {*} object
|
|
* @return {Boolean} isIndex
|
|
*/
|
|
Index.isIndex = function isIndex(object) {
|
|
return (object instanceof Index);
|
|
};
|
|
|
|
/**
|
|
* Create an index from an array with ranges/numbers
|
|
* @param {Array.<Array | Number>} ranges
|
|
* @return {Index} index
|
|
* @private
|
|
*/
|
|
Index.create = function create(ranges) {
|
|
var index = new Index();
|
|
Index.apply(index, ranges);
|
|
return index;
|
|
};
|
|
|
|
/**
|
|
* Retrieve the size of the index.
|
|
* @returns {Number[]} size
|
|
*/
|
|
Index.prototype.size = function () {
|
|
var size = [];
|
|
|
|
for (var i = 0, ii = this._ranges.length; i < ii; i++) {
|
|
var range = this._ranges[i];
|
|
|
|
if (range instanceof Range) {
|
|
size.push(range.size()[0]);
|
|
}
|
|
else {
|
|
size.push(null);
|
|
}
|
|
}
|
|
|
|
return size;
|
|
};
|
|
|
|
/**
|
|
* Loop over each of the ranges of the index
|
|
* @param {function} callback Called for each range with a Range as first
|
|
* argument, the dimension as second, and the
|
|
* index object as third.
|
|
*/
|
|
Index.prototype.forEach = function (callback) {
|
|
for (var i = 0, ii = this._ranges.length; i < ii; i++) {
|
|
callback(this._ranges[i], i, this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Retrieve the range for a given dimension number from the index
|
|
* @param {Number} dim Number of the dimension
|
|
* @returns {Range | undefined} range
|
|
*/
|
|
Index.prototype.range = function (dim) {
|
|
return this._ranges[dim];
|
|
};
|
|
|
|
/**
|
|
* Expand the Index into an array.
|
|
* For example new Index([0,3], [2,7]) returns [[0,1,2], [2,3,4,5,6]]
|
|
* @returns {Array} array
|
|
*/
|
|
Index.prototype.toArray = function () {
|
|
var array = [];
|
|
for (var i = 0, ii = this._ranges.length; i < ii; i++) {
|
|
var range = this._ranges[i],
|
|
row = [],
|
|
x = range.start,
|
|
end = range.end,
|
|
step = range.step;
|
|
|
|
if (step > 0) {
|
|
while (x < end) {
|
|
row.push(x);
|
|
x += step;
|
|
}
|
|
}
|
|
else if (step < 0) {
|
|
while (x > end) {
|
|
row.push(x);
|
|
x += step;
|
|
}
|
|
}
|
|
|
|
array.push(row);
|
|
}
|
|
|
|
return array;
|
|
};
|
|
|
|
/**
|
|
* Get the primitive value of the Index, a two dimensional array.
|
|
* Equivalent to Index.toArray().
|
|
* @returns {Array} array
|
|
*/
|
|
Index.prototype.valueOf = Index.prototype.toArray;
|
|
|
|
/**
|
|
* Get the string representation of the index, for example '[2:6]' or '[0:2:10, 4:7]'
|
|
* @returns {String} str
|
|
*/
|
|
Index.prototype.toString = function () {
|
|
var strings = [];
|
|
|
|
for (var i = 0, ii = this._ranges.length; i < ii; i++) {
|
|
var range = this._ranges[i];
|
|
var str = number.format(range.start);
|
|
if (range.step != 1) {
|
|
str += ':' + number.format(range.step);
|
|
}
|
|
str += ':' + number.format(range.end);
|
|
strings.push(str);
|
|
}
|
|
|
|
return '[' + strings.join(',') + ']';
|
|
};
|
|
|
|
/**
|
|
* Test whether a multidimensional array contains a scalar
|
|
* @param array
|
|
* @returns {*}
|
|
*/
|
|
function isScalar(array) {
|
|
while (isArray(array)) {
|
|
if (array.length !== 1) {
|
|
return false;
|
|
}
|
|
array = array[0];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Retrieve the scalar value from a multidimensional matrix containing only
|
|
* a single scalar.
|
|
* @param array
|
|
* @returns {*} scalar
|
|
* @private
|
|
*/
|
|
function toScalar(array) {
|
|
while (isArray(array)) {
|
|
if (array.length !== 1) {
|
|
throw new Error('Array does not contain a single scalar');
|
|
}
|
|
array = array[0];
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
// exports
|
|
module.exports = Index;
|
|
|
|
// to trick my IDE which doesn't get it
|
|
exports.isIndex = Index.isIndex;
|
|
exports.create = Index.create;
|
|
|
|
util.types.addType('index', Index);
|
|
|
|
},{"../util/index":205,"./Range":199}],198:[function(require,module,exports){
|
|
var util = require('../util/index'),
|
|
Index = require('./Index'),
|
|
|
|
number = util.number,
|
|
string = util.string,
|
|
array = util.array,
|
|
object = util.object;
|
|
|
|
/**
|
|
* @constructor Matrix
|
|
*
|
|
* A Matrix is a wrapper around an Array. A matrix can hold a multi dimensional
|
|
* array. A matrix can be constructed as:
|
|
* var matrix = new Matrix(data)
|
|
*
|
|
* Matrix contains the functions to resize, get and set values, get the size,
|
|
* clone the matrix and to convert the matrix to a vector, array, or scalar.
|
|
* Furthermore, one can iterate over the matrix using map and forEach.
|
|
* The internal Array of the Matrix can be accessed using the method valueOf.
|
|
*
|
|
* Example usage:
|
|
* var matrix = new Matrix([[1, 2], [3, 4]);
|
|
* matix.size(); // [2, 2]
|
|
* matrix.resize([3, 2], 5);
|
|
* matrix.valueOf(); // [[1, 2], [3, 4], [5, 5]]
|
|
* matrix.subset([1,2]) // 3 (indexes are zero-based)
|
|
*
|
|
* @param {Array | Matrix} [data] A multi dimensional array
|
|
*/
|
|
function Matrix(data) {
|
|
if (!(this instanceof Matrix)) {
|
|
throw new SyntaxError(
|
|
'Matrix constructor must be called with the new operator');
|
|
}
|
|
|
|
if (data instanceof Matrix) {
|
|
// clone data from a Matrix
|
|
this._data = data.clone()._data;
|
|
}
|
|
else if (Array.isArray(data)) {
|
|
// use array as is
|
|
this._data = data;
|
|
}
|
|
else if (data != null) {
|
|
// unsupported type
|
|
throw new TypeError('Unsupported type of data (' + util.types.type(data) + ')');
|
|
}
|
|
else {
|
|
// nothing provided
|
|
this._data = [];
|
|
}
|
|
|
|
// verify the size of the array
|
|
this._size = array.size(this._data);
|
|
}
|
|
|
|
/**
|
|
* Test whether an object is a Matrix
|
|
* @param {*} object
|
|
* @return {Boolean} isMatrix
|
|
*/
|
|
Matrix.isMatrix = function isMatrix(object) {
|
|
return (object instanceof Matrix);
|
|
};
|
|
|
|
/**
|
|
* Get a subset of the matrix, or replace a subset of the matrix.
|
|
*
|
|
* Usage:
|
|
* var subset = matrix.subset(index) // retrieve subset
|
|
* var value = matrix.subset(index, replacement) // replace subset
|
|
*
|
|
* @param {Index} index
|
|
* @param {Array | Matrix | *} [replacement]
|
|
*/
|
|
Matrix.prototype.subset = function subset(index, replacement) {
|
|
switch (arguments.length) {
|
|
case 1: return _get(this, index);
|
|
case 2: return _set(this, index, replacement);
|
|
default:
|
|
throw new util.error.ArgumentsError('subset', arguments.length, 1, 2);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get a value or a submatrix of the matrix.
|
|
* @param {Index} index Zero-based index
|
|
*/
|
|
// TODO: Matrix.get is deprecated since version 0.13.0, remove it some day
|
|
Matrix.prototype.get = function get(index) {
|
|
throw new Error('Matrix.get is removed. Use matrix.subet(index) instead.');
|
|
};
|
|
|
|
|
|
/**
|
|
* Replace a value or a submatrix in the matrix.
|
|
* Indexes are zero-based.
|
|
* @param {Index} index
|
|
* @param {Matrix | Array | *} submatrix
|
|
* @return {Matrix} matrix
|
|
*/
|
|
// TODO: Matrix.set is deprecated since version 0.13.0, remove it some day
|
|
Matrix.prototype.set = function set (index, submatrix) {
|
|
throw new Error('Matrix.set is removed. Use matrix.subet(index, replacement) instead.');
|
|
};
|
|
|
|
/**
|
|
* Get a value or a submatrix of the matrix.
|
|
* @param {Matrix} matrix
|
|
* @param {Index} index Zero-based index
|
|
*/
|
|
function _get (matrix, index) {
|
|
if (!(index instanceof Index)) {
|
|
throw new TypeError('Invalid index');
|
|
}
|
|
|
|
var size = index.size();
|
|
var isScalar = !size.some(function (i) {
|
|
return (i != 1);
|
|
});
|
|
|
|
if (size.length != matrix._size.length) {
|
|
throw new RangeError('Dimension mismatch ' +
|
|
'(' + size.length + ' != ' + matrix._size.length + ')');
|
|
}
|
|
|
|
if (isScalar) {
|
|
// return a single value
|
|
switch (size.length) {
|
|
case 1: return _getScalar1D(matrix._data, index);
|
|
case 2: return _getScalar2D(matrix._data, index);
|
|
default: return _getScalar(matrix._data, index);
|
|
}
|
|
}
|
|
else {
|
|
// return a submatrix
|
|
switch (size.length) {
|
|
case 1: return new Matrix(_getSubmatrix1D(matrix._data, index));
|
|
case 2: return new Matrix(_getSubmatrix2D(matrix._data, index));
|
|
default: return new Matrix(_getSubmatrix(matrix._data, index, 0));
|
|
}
|
|
// TODO: more efficient when creating an empty matrix and setting _data and _size manually
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a single value from an array. The method tests whether:
|
|
* - index is a non-negative integer
|
|
* - index does not exceed the dimensions of array
|
|
* @param {Array} arr
|
|
* @param {Number} index Zero-based index
|
|
* @return {*} value
|
|
* @private
|
|
*/
|
|
function _getElement (arr, index) {
|
|
array.validateIndex(index, arr.length);
|
|
return arr[index]; // zero-based index
|
|
}
|
|
|
|
/**
|
|
* Get a single value from the matrix. The value will be a copy of the original
|
|
* value in the matrix.
|
|
* Index is not checked for correct number of dimensions.
|
|
* @param {Array} data
|
|
* @param {Index} index
|
|
* @return {*} scalar
|
|
* @private
|
|
*/
|
|
function _getScalar (data, index) {
|
|
index.forEach(function (range) {
|
|
data = _getElement(data, range.start);
|
|
});
|
|
return object.clone(data);
|
|
}
|
|
|
|
/**
|
|
* Get a single value from a one dimensional matrix.
|
|
* The value will be a copy of the original value in the matrix.
|
|
* Index is not checked for correct number of dimensions.
|
|
* @param {Array} data
|
|
* @param {Index} index
|
|
* @return {*} scalar
|
|
* @private
|
|
*/
|
|
function _getScalar1D (data, index) {
|
|
return _getElement(data, index.range(0).start);
|
|
}
|
|
|
|
/**
|
|
* Get a single value from a two dimensional matrix.
|
|
* The value will be a copy of the original value in the matrix.
|
|
* Index is not checked for correct number of dimensions.
|
|
* @param {Array} data
|
|
* @param {Index} index
|
|
* @return {*} scalar
|
|
* @private
|
|
*/
|
|
function _getScalar2D (data, index) {
|
|
return _getElement(_getElement(data, index.range(0).start), index.range(1).start);
|
|
}
|
|
|
|
/**
|
|
* Get a submatrix of a zero dimensional matrix.
|
|
* Index is not checked for correct number of dimensions.
|
|
* @param {Array} data
|
|
* @param {Index} index
|
|
* @return {Array} submatrix
|
|
* @private
|
|
*/
|
|
function _getSubmatrix1D (data, index) {
|
|
var range = index.range(0);
|
|
|
|
return range.map(function (i) {
|
|
return _getElement(data, i);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get a submatrix of a 2 dimensional matrix.
|
|
* Index is not checked for correct number of dimensions.
|
|
* @param {Array} data
|
|
* @param {Index} index
|
|
* @return {Array} submatrix
|
|
* @private
|
|
*/
|
|
function _getSubmatrix2D (data, index) {
|
|
var rows = index.range(0);
|
|
var cols = index.range(1);
|
|
|
|
return rows.map(function (row) {
|
|
var child = _getElement(data, row);
|
|
return cols.map(function (col) {
|
|
return _getElement(child, col);
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get a submatrix of a multi dimensional matrix.
|
|
* Index is not checked for correct number of dimensions.
|
|
* @param {Array} data
|
|
* @param {Index} index
|
|
* @param {number} dim
|
|
* @return {Array} submatrix
|
|
* @private
|
|
*/
|
|
function _getSubmatrix (data, index, dim) {
|
|
var last = (dim == index.size().length - 1);
|
|
var range = index.range(dim);
|
|
|
|
if (last) {
|
|
return range.map(function (i) {
|
|
return _getElement(data, i);
|
|
});
|
|
}
|
|
else {
|
|
return range.map(function (i) {
|
|
var child = _getElement(data, i);
|
|
return _getSubmatrix(child, index, dim + 1);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replace a value or a submatrix in the matrix.
|
|
* Indexes are zero-based.
|
|
* @param {Matrix} matrix
|
|
* @param {Index} index
|
|
* @param {Matrix | Array | *} submatrix
|
|
* @return {Matrix} matrix
|
|
*/
|
|
function _set (matrix, index, submatrix) {
|
|
if (!(index instanceof Index)) {
|
|
throw new TypeError('Invalid index');
|
|
}
|
|
|
|
var size = index.size();
|
|
var isScalar = !size.some(function (i) {
|
|
return (i != 1);
|
|
});
|
|
|
|
if (size.length < matrix._size.length) {
|
|
throw new RangeError('Dimension mismatch ' +
|
|
'(' + size.length + ' != ' + matrix._size.length + ')');
|
|
}
|
|
|
|
if (submatrix instanceof Matrix) {
|
|
submatrix = submatrix.valueOf();
|
|
}
|
|
|
|
if (isScalar) {
|
|
// set a scalar
|
|
// check whether submatrix is no matrix/array
|
|
if (array.size(submatrix.valueOf()).length != 0) {
|
|
throw new TypeError('Scalar value expected');
|
|
}
|
|
|
|
switch (index.length) {
|
|
case 1: _setScalar1D(matrix._data, matrix._size, index, submatrix); break;
|
|
case 2: _setScalar2D(matrix._data, matrix._size, index, submatrix); break;
|
|
default: _setScalar(matrix._data, matrix._size, index, submatrix); break;
|
|
}
|
|
}
|
|
else {
|
|
// set a submatrix
|
|
var newSize = matrix._size.concat();
|
|
_setSubmatrix (matrix._data, newSize, index, 0, submatrix);
|
|
if (!object.deepEqual(matrix._size, newSize)) {
|
|
_init(matrix._data);
|
|
matrix.resize(newSize);
|
|
}
|
|
}
|
|
|
|
return matrix;
|
|
}
|
|
|
|
/**
|
|
* Replace a single value in an array. The method tests whether index is a
|
|
* non-negative integer
|
|
* @param {Array} arr
|
|
* @param {Number} index Zero-based index
|
|
* @param {*} value
|
|
* @private
|
|
*/
|
|
function _setElement (arr, index, value) {
|
|
array.validateIndex(index);
|
|
if (Array.isArray(value)) {
|
|
throw new TypeError('Dimension mismatch, value expected instead of array');
|
|
}
|
|
arr[index] = value; // zero-based index
|
|
}
|
|
|
|
/**
|
|
* Replace a single value in a multi dimensional matrix
|
|
* @param {Array} data
|
|
* @param {Number[]} size
|
|
* @param {Index} index
|
|
* @param {*} value
|
|
* @private
|
|
*/
|
|
function _setScalar (data, size, index, value) {
|
|
var resized = false;
|
|
if (index.size().length > size.length) {
|
|
// dimension added
|
|
resized = true;
|
|
}
|
|
|
|
index.forEach(function (range, i) {
|
|
var v = range.start;
|
|
array.validateIndex(v);
|
|
if ((size[i] == null) || (v + 1 > size[i])) {
|
|
size[i] = v + 1; // size is index + 1 as index is zero-based
|
|
resized = true;
|
|
}
|
|
});
|
|
|
|
if (resized) {
|
|
array.resize(data, size, 0);
|
|
}
|
|
|
|
var len = size.length;
|
|
index.forEach(function (range, dim) {
|
|
var i = range.start;
|
|
if (dim < len - 1) {
|
|
data = data[i]; // zero-based index
|
|
}
|
|
else {
|
|
data[i] = value; // zero-based index
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Replace a single value in a zero dimensional matrix
|
|
* @param {Array} data
|
|
* @param {Number[]} size
|
|
* @param {Index} index
|
|
* @param {*} value
|
|
* @private
|
|
*/
|
|
function _setScalar1D (data, size, index, value) {
|
|
var row = index.range(0).start;
|
|
array.validateIndex(row);
|
|
if (row + 1 > size[0]) {
|
|
array.resize(data, [row + 1], 0); // size is index + 1 as index is zero-based
|
|
size[0] = row + 1;
|
|
}
|
|
data[row] = value; // zero-based index
|
|
}
|
|
|
|
/**
|
|
* Replace a single value in a two dimensional matrix
|
|
* @param {Array} data
|
|
* @param {Number[]} size
|
|
* @param {Index} index zero-based index
|
|
* @param {*} value
|
|
* @private
|
|
*/
|
|
function _setScalar2D (data, size, index, value) {
|
|
var row = index.range(0).start;
|
|
var col = index.range(1).start;
|
|
array.validateIndex(row);
|
|
array.validateIndex(col);
|
|
|
|
var resized = false;
|
|
if (row + 1 > (size[0] || 0)) {
|
|
size[0] = row + 1; // size is index + 1 as index is zero-based
|
|
resized = true;
|
|
}
|
|
if (col + 1 > (size[1] || 0)) {
|
|
size[1] = col + 1; // size is index + 1 as index is zero-based
|
|
resized = true;
|
|
}
|
|
if (resized) {
|
|
array.resize(data, size, 0);
|
|
}
|
|
|
|
data[row][col] = value; // zero-based index
|
|
}
|
|
|
|
/**
|
|
* Replace a submatrix of a multi dimensional matrix.
|
|
* @param {Array} data
|
|
* @param {Array} size
|
|
* @param {Index} index
|
|
* @param {number} dim
|
|
* @param {Array} submatrix
|
|
* @private
|
|
*/
|
|
function _setSubmatrix (data, size, index, dim, submatrix) {
|
|
var last = (dim == index.size().length - 1);
|
|
var range = index.range(dim);
|
|
|
|
var len = (range.size()[0]);
|
|
if (len != submatrix.length) {
|
|
throw new RangeError('Dimensions mismatch ' +
|
|
'(' + len + ' != '+ submatrix.length + ')');
|
|
}
|
|
|
|
if (last) {
|
|
range.forEach(function (dataIndex, subIndex) {
|
|
_setElement(data, dataIndex, submatrix[subIndex]);
|
|
if (dataIndex + 1 > (size[dim] || 0)) {
|
|
size[dim] = dataIndex + 1;
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
range.forEach(function (dataIndex, subIndex) {
|
|
var child = data[dataIndex];
|
|
if (!Array.isArray(child)) {
|
|
data[dataIndex] = child = [child];
|
|
}
|
|
if (dataIndex + 1 > (size[dim] || 0)) {
|
|
size[dim] = dataIndex + 1;
|
|
}
|
|
_setSubmatrix(child, size, index, dim + 1, submatrix[subIndex]);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Recursively initialize all undefined values in the array with zeros
|
|
* @param array
|
|
* @private
|
|
*/
|
|
function _init(array) {
|
|
for (var i = 0, len = array.length; i < len; i++) {
|
|
var value = array[i];
|
|
if (Array.isArray(value)) {
|
|
_init(value);
|
|
}
|
|
else if (value == undefined) {
|
|
array[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resize the matrix
|
|
* @param {Number[]} size
|
|
* @param {*} [defaultValue] Default value, filled in on new entries.
|
|
* If not provided, the matrix will be filled
|
|
* with zeros.
|
|
*/
|
|
Matrix.prototype.resize = function (size, defaultValue) {
|
|
array.resize(this._data, size, defaultValue);
|
|
this._size = object.clone(size);
|
|
};
|
|
|
|
/**
|
|
* Create a clone of the matrix
|
|
* @return {Matrix} clone
|
|
*/
|
|
Matrix.prototype.clone = function () {
|
|
var matrix = new Matrix();
|
|
matrix._data = object.clone(this._data);
|
|
matrix._size = object.clone(this._size);
|
|
return matrix;
|
|
};
|
|
|
|
/**
|
|
* Retrieve the size of the matrix.
|
|
* The size of the matrix will be validated too
|
|
* @returns {Number[]} size
|
|
*/
|
|
Matrix.prototype.size = function () {
|
|
return this._size;
|
|
};
|
|
|
|
/**
|
|
* Create a new matrix with the results of the callback function executed on
|
|
* each entry of the matrix.
|
|
* @param {function} callback The callback method is invoked with three
|
|
* parameters: the value of the element, the index
|
|
* of the element, and the Matrix being traversed.
|
|
* @return {Matrix} matrix
|
|
*/
|
|
Matrix.prototype.map = function (callback) {
|
|
var me = this;
|
|
var matrix = new Matrix();
|
|
var index = [];
|
|
var recurse = function (value, dim) {
|
|
if (Array.isArray(value)) {
|
|
return value.map(function (child, i) {
|
|
index[dim] = i; // zero-based index
|
|
return recurse(child, dim + 1);
|
|
});
|
|
}
|
|
else {
|
|
return callback(value, index, me);
|
|
}
|
|
};
|
|
matrix._data = recurse(this._data, 0);
|
|
matrix._size = object.clone(this._size);
|
|
|
|
return matrix;
|
|
};
|
|
|
|
/**
|
|
* Execute a callback method on each entry of the matrix.
|
|
* @param {function} callback The callback method is invoked with three
|
|
* parameters: the value of the element, the index
|
|
* of the element, and the Matrix being traversed.
|
|
*/
|
|
Matrix.prototype.forEach = function (callback) {
|
|
var me = this;
|
|
var index = [];
|
|
var recurse = function (value, dim) {
|
|
if (Array.isArray(value)) {
|
|
value.forEach(function (child, i) {
|
|
index[dim] = i; // zero-based index
|
|
recurse(child, dim + 1);
|
|
});
|
|
}
|
|
else {
|
|
callback(value, index, me);
|
|
}
|
|
};
|
|
recurse(this._data, 0);
|
|
};
|
|
|
|
/**
|
|
* Create a scalar with a copy of the data of the Matrix
|
|
* Will return null if the matrix does not consist of a scalar value
|
|
* @return {* | null} scalar
|
|
*/
|
|
Matrix.prototype.toScalar = function () {
|
|
var scalar = this._data;
|
|
while (Array.isArray(scalar) && scalar.length == 1) {
|
|
scalar = scalar[0];
|
|
}
|
|
|
|
if (Array.isArray(scalar)) {
|
|
return null;
|
|
}
|
|
else {
|
|
return object.clone(scalar);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Test whether the matrix is a scalar.
|
|
* @return {boolean} isScalar
|
|
*/
|
|
Matrix.prototype.isScalar = function () {
|
|
return this._size.every(function (s) {
|
|
return (s <= 1);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Create a vector with a copy of the data of the Matrix
|
|
* Returns null if the Matrix does not contain a vector
|
|
*
|
|
* A matrix is a vector when it has 0 or 1 dimensions, or has multiple
|
|
* dimensions where maximum one of the dimensions has a size larger than 1.
|
|
* return {Array | null} vector
|
|
*/
|
|
Matrix.prototype.toVector = function () {
|
|
var count = 0;
|
|
var dim = undefined;
|
|
var index = [];
|
|
this._size.forEach(function (length, i) {
|
|
if (length > 1) {
|
|
count++;
|
|
dim = i;
|
|
}
|
|
index[i] = 0;
|
|
});
|
|
|
|
if (count == 0) {
|
|
// scalar or empty
|
|
var scalar = this.toScalar();
|
|
if (scalar) {
|
|
return [scalar];
|
|
}
|
|
else {
|
|
return [];
|
|
}
|
|
}
|
|
else if (count == 1) {
|
|
// valid vector
|
|
var vector = [];
|
|
var recurse = function (data) {
|
|
if (Array.isArray(data)) {
|
|
data.forEach(recurse);
|
|
}
|
|
else {
|
|
vector.push(data);
|
|
}
|
|
};
|
|
recurse(this._data);
|
|
return vector;
|
|
}
|
|
else {
|
|
// count > 1, this is no vector
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Test if the matrix contains a vector.
|
|
* A matrix is a vector when it has 0 or 1 dimensions, or has multiple
|
|
* dimensions where maximum one of the dimensions has a size larger than 1.
|
|
* return {boolean} isVector
|
|
*/
|
|
Matrix.prototype.isVector = function () {
|
|
var count = 0;
|
|
this._size.forEach(function (length) {
|
|
if (length > 1) {
|
|
count++;
|
|
}
|
|
});
|
|
return (count <= 1);
|
|
};
|
|
|
|
/**
|
|
* Create an Array with a copy of the data of the Matrix
|
|
* @returns {Array} array
|
|
*/
|
|
Matrix.prototype.toArray = function () {
|
|
return object.clone(this._data);
|
|
};
|
|
|
|
/**
|
|
* Get the primitive value of the Matrix: a multidimensional array
|
|
* @returns {Array} array
|
|
*/
|
|
Matrix.prototype.valueOf = function () {
|
|
return this._data;
|
|
};
|
|
|
|
/**
|
|
* Get a string representation of the matrix
|
|
* @returns {String} str
|
|
*/
|
|
Matrix.prototype.toString = function () {
|
|
return string.format(this._data);
|
|
};
|
|
|
|
// exports
|
|
module.exports = Matrix;
|
|
|
|
// to trick my IDE which doesn't get it
|
|
exports.isMatrix = Matrix.isMatrix;
|
|
|
|
util.types.addType('matrix', Matrix);
|
|
|
|
},{"../util/index":205,"./Index":197}],199:[function(require,module,exports){
|
|
var util = require('../util/index.js'),
|
|
|
|
number = util.number,
|
|
string = util.string,
|
|
array = util.array;
|
|
|
|
/**
|
|
* @constructor Range
|
|
* Create a range. A range has a start, step, and end, and contains functions
|
|
* to iterate over the range.
|
|
*
|
|
* A range can be constructed as:
|
|
* var range = new Range(start, end);
|
|
* var range = new Range(start, end, step);
|
|
*
|
|
* To get the result of the range:
|
|
* range.forEach(function (x) {
|
|
* console.log(x);
|
|
* });
|
|
* range.map(function (x) {
|
|
* return math.sin(x);
|
|
* });
|
|
* range.toArray();
|
|
*
|
|
* Example usage:
|
|
* var c = new Range(2, 6); // 2:1:5
|
|
* c.toArray(); // [2, 3, 4, 5]
|
|
* var d = new Range(2, -3, -1); // 2:-1:-2
|
|
* d.toArray(); // [2, 1, 0, -1, -2]
|
|
*
|
|
* @param {Number} start included lower bound
|
|
* @param {Number} end excluded upper bound
|
|
* @param {Number} [step] step size, default value is 1
|
|
*/
|
|
function Range(start, end, step) {
|
|
if (!(this instanceof Range)) {
|
|
throw new SyntaxError(
|
|
'Range constructor must be called with the new operator');
|
|
}
|
|
|
|
if (start != null && !number.isNumber(start)) {
|
|
throw new TypeError('Parameter start must be a number');
|
|
}
|
|
if (end != null && !number.isNumber(end)) {
|
|
throw new TypeError('Parameter end must be a number');
|
|
}
|
|
if (step != null && !number.isNumber(step)) {
|
|
throw new TypeError('Parameter step must be a number');
|
|
}
|
|
|
|
this.start = (start != null) ? start : 0;
|
|
this.end = (end != null) ? end : 0;
|
|
this.step = (step != null) ? step : 1;
|
|
}
|
|
|
|
/**
|
|
* Parse a string into a range,
|
|
* The string contains the start, optional step, and end, separated by a colon.
|
|
* If the string does not contain a valid range, null is returned.
|
|
* For example str='0:2:11'.
|
|
* @param {String} str
|
|
* @return {Range | null} range
|
|
*/
|
|
Range.parse = function parse (str) {
|
|
if (!string.isString(str)) {
|
|
return null;
|
|
}
|
|
|
|
var args = str.split(':');
|
|
var nums = args.map(function (arg) {
|
|
return Number(arg);
|
|
});
|
|
|
|
var invalid = nums.some(function (num) {
|
|
return isNaN(num);
|
|
});
|
|
if(invalid) {
|
|
return null;
|
|
}
|
|
|
|
switch (nums.length) {
|
|
case 2: return new Range(nums[0], 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);
|
|
};
|
|
|
|
/**
|
|
* Test whether an object is a Range
|
|
* @param {*} object
|
|
* @return {Boolean} isRange
|
|
*/
|
|
Range.isRange = function isRange(object) {
|
|
return (object instanceof Range);
|
|
};
|
|
|
|
/**
|
|
* Retrieve the size of the range.
|
|
* @returns {Number[]} size
|
|
*/
|
|
Range.prototype.size = function () {
|
|
var len = 0,
|
|
start = Number(this.start),
|
|
step = Number(this.step),
|
|
end = Number(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];
|
|
};
|
|
|
|
/**
|
|
* Execute a callback function for each value in the range.
|
|
* @param {function} callback The callback method is invoked with three
|
|
* parameters: the value of the element, the index
|
|
* of the element, and the Matrix being traversed.
|
|
*/
|
|
Range.prototype.forEach = function (callback) {
|
|
var x = Number(this.start);
|
|
var step = Number(this.step);
|
|
var end = Number(this.end);
|
|
var i = 0;
|
|
|
|
if (step > 0) {
|
|
while (x < end) {
|
|
callback(x, i, this);
|
|
x += step;
|
|
i++;
|
|
}
|
|
}
|
|
else if (step < 0) {
|
|
while (x > end) {
|
|
callback(x, i, this);
|
|
x += step;
|
|
i++;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Execute a callback function for each value in the Range, and return the
|
|
* results as an array
|
|
* @param {function} callback The callback method is invoked with three
|
|
* parameters: the value of the element, the index
|
|
* of the element, and the Matrix being traversed.
|
|
* @returns {Array} array
|
|
*/
|
|
Range.prototype.map = function (callback) {
|
|
var array = [];
|
|
this.forEach(function (value, index, obj) {
|
|
array[index] = callback(value, index, obj);
|
|
});
|
|
return array;
|
|
};
|
|
|
|
/**
|
|
* Create an Array with a copy of the Ranges data
|
|
* @returns {Array} array
|
|
*/
|
|
Range.prototype.toArray = function () {
|
|
var array = [];
|
|
this.forEach(function (value, index) {
|
|
array[index] = value;
|
|
});
|
|
return array;
|
|
};
|
|
|
|
/**
|
|
* Create an array with a copy of the Ranges data.
|
|
* This method is equal to Range.toArray.
|
|
* @return {Array} vector
|
|
*/
|
|
Range.prototype.toVector = Range.prototype.toArray;
|
|
|
|
/**
|
|
* Test if the range contains a vector. For a range, this is always the case
|
|
* return {boolean} isVector
|
|
*/
|
|
Range.prototype.isVector = function () {
|
|
return true;
|
|
};
|
|
|
|
/**
|
|
* Create a scalar with a copy of the data of the Range
|
|
* Will return null if the range does not consist of a scalar value
|
|
* @return {* | null} scalar
|
|
*/
|
|
Range.prototype.toScalar = function () {
|
|
var array = this.toArray();
|
|
if (array.length == 1) {
|
|
return array[0];
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Test whether the matrix is a scalar.
|
|
* @return {boolean} isScalar
|
|
*/
|
|
Range.prototype.isScalar = function () {
|
|
return (this.size()[0] == 1);
|
|
};
|
|
|
|
/**
|
|
* Get the primitive value of the Range, a one dimensional array
|
|
* @returns {Array} array
|
|
*/
|
|
Range.prototype.valueOf = function () {
|
|
// TODO: implement a caching mechanism for range.valueOf()
|
|
return this.toArray();
|
|
};
|
|
|
|
/**
|
|
* Get the string representation of the range, for example '2:6' or '0:0.2:11'
|
|
* @returns {String} str
|
|
*/
|
|
Range.prototype.toString = function () {
|
|
var str = number.format(Number(this.start));
|
|
if (this.step != 1) {
|
|
str += ':' + number.format(Number(this.step));
|
|
}
|
|
str += ':' + number.format(Number(this.end));
|
|
return str;
|
|
};
|
|
|
|
|
|
// exports
|
|
module.exports = Range;
|
|
|
|
// to trick my IDE which doesn't get it
|
|
exports.isRange = Range.isRange;
|
|
exports.parse = Range.parse;
|
|
|
|
util.types.addType('range', Range);
|
|
|
|
},{"../util/index.js":205}],200:[function(require,module,exports){
|
|
var util = require('../util/index.js'),
|
|
|
|
number = util.number,
|
|
string = util.string,
|
|
isNumber = util.number.isNumber,
|
|
isString = util.string.isString;
|
|
|
|
/**
|
|
* @constructor Unit
|
|
*
|
|
* A unit can be constructed in the following ways:
|
|
* var a = new Unit(value, unit);
|
|
* var b = new Unit(null, unit);
|
|
* var c = Unit.parse(str);
|
|
*
|
|
* Example usage:
|
|
* var a = new Unit(5, 'cm'); // 50 mm
|
|
* var b = Unit.parse('23 kg'); // 23 kg
|
|
* var c = math.in(a, new Unit(null, 'm'); // 0.05 m
|
|
*
|
|
* @param {Number} [value] A value like 5.2
|
|
* @param {String} [unit] A unit like "cm" or "inch"
|
|
*/
|
|
function Unit(value, unit) {
|
|
if (!(this instanceof Unit)) {
|
|
throw new Error('Unit constructor must be called with the new operator');
|
|
}
|
|
|
|
if (value != null && !isNumber(value)) {
|
|
throw new TypeError('First parameter in Unit constructor must be a number');
|
|
}
|
|
if (unit != null && !isString(unit)) {
|
|
throw new TypeError('Second parameter in Unit constructor must be a string');
|
|
}
|
|
|
|
if (unit != null) {
|
|
// find the unit and prefix from the string
|
|
var res = _findUnit(unit);
|
|
if (!res) {
|
|
throw new SyntaxError('String "' + unit + '" is no unit');
|
|
}
|
|
this.unit = res.unit;
|
|
this.prefix = res.prefix;
|
|
}
|
|
else {
|
|
this.unit = UNIT_NONE;
|
|
this.prefix = PREFIX_NONE; // link to a list with supported prefixes
|
|
}
|
|
|
|
if (value != null) {
|
|
this.value = this._normalize(value);
|
|
this.fixPrefix = false; // is set true by the methods Unit.in and math.in
|
|
}
|
|
else {
|
|
this.value = null;
|
|
this.fixPrefix = true;
|
|
}
|
|
}
|
|
|
|
// private variables and functions for the Unit parser
|
|
var text, index, c;
|
|
|
|
function skipWhitespace() {
|
|
while (c == ' ' || c == '\t') {
|
|
next();
|
|
}
|
|
}
|
|
|
|
function isDigitDot (c) {
|
|
return ((c >= '0' && c <= '9') || c == '.');
|
|
}
|
|
|
|
function isDigit (c) {
|
|
return ((c >= '0' && c <= '9'));
|
|
}
|
|
|
|
function next() {
|
|
index++;
|
|
c = text.charAt(index);
|
|
}
|
|
|
|
function revert(oldIndex) {
|
|
index = oldIndex;
|
|
c = text.charAt(index);
|
|
}
|
|
|
|
function parseNumber () {
|
|
var number = '';
|
|
var oldIndex;
|
|
oldIndex = index;
|
|
|
|
if (c == '+') {
|
|
next();
|
|
}
|
|
else if (c == '-') {
|
|
number += c;
|
|
next();
|
|
}
|
|
|
|
if (!isDigitDot(c)) {
|
|
// a + or - must be followed by a digit
|
|
revert(oldIndex);
|
|
return null;
|
|
}
|
|
|
|
// get number, can have a single dot
|
|
if (c == '.') {
|
|
number += c;
|
|
next();
|
|
if (!isDigit(c)) {
|
|
// this is no legal number, it is just a dot
|
|
revert(oldIndex);
|
|
return null;
|
|
}
|
|
}
|
|
else {
|
|
while (isDigit(c)) {
|
|
number += c;
|
|
next();
|
|
}
|
|
if (c == '.') {
|
|
number += c;
|
|
next();
|
|
}
|
|
}
|
|
while (isDigit(c)) {
|
|
number += c;
|
|
next();
|
|
}
|
|
|
|
// check for scientific notation like "2.3e-4" or "1.23e50"
|
|
if (c == 'E' || c == 'e') {
|
|
number += c;
|
|
next();
|
|
|
|
if (c == '+' || c == '-') {
|
|
number += c;
|
|
next();
|
|
}
|
|
|
|
// Scientific notation MUST be followed by an exponent
|
|
if (!isDigit(c)) {
|
|
// this is no legal number, exponent is missing.
|
|
revert(oldIndex);
|
|
return null;
|
|
}
|
|
|
|
while (isDigit(c)) {
|
|
number += c;
|
|
next();
|
|
}
|
|
}
|
|
|
|
return number;
|
|
}
|
|
|
|
function parseUnit() {
|
|
var unit = '';
|
|
|
|
skipWhitespace();
|
|
while (c && c != ' ' && c != '\t') {
|
|
unit += c;
|
|
next();
|
|
}
|
|
|
|
return unit || null;
|
|
}
|
|
|
|
/**
|
|
* Parse a string into a unit. Returns null if the provided string does not
|
|
* contain a valid unit.
|
|
* @param {String} str A string like "5.2 inch", "4e2 kg"
|
|
* @return {Unit | null} unit
|
|
*/
|
|
Unit.parse = function parse(str) {
|
|
text = str;
|
|
index = -1;
|
|
c = '';
|
|
|
|
if (!isString(text)) {
|
|
return null;
|
|
}
|
|
|
|
next();
|
|
skipWhitespace();
|
|
var value = parseNumber();
|
|
var unit;
|
|
if (value) {
|
|
unit = parseUnit();
|
|
|
|
next();
|
|
skipWhitespace();
|
|
if (c) {
|
|
// garbage at the end. not good.
|
|
return null;
|
|
}
|
|
|
|
if (value && unit) {
|
|
return new Unit(Number(value), unit);
|
|
}
|
|
}
|
|
else {
|
|
unit = parseUnit();
|
|
|
|
next();
|
|
skipWhitespace();
|
|
if (c) {
|
|
// garbage at the end. not good.
|
|
return null;
|
|
}
|
|
|
|
return new Unit(null, unit)
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Test whether value is of type Unit
|
|
* @param {*} value
|
|
* @return {Boolean} isUnit
|
|
*/
|
|
Unit.isUnit = function isUnit(value) {
|
|
return (value instanceof Unit);
|
|
};
|
|
|
|
/**
|
|
* create a copy of this unit
|
|
* @return {Unit} clone
|
|
*/
|
|
Unit.prototype.clone = function () {
|
|
var clone = new Unit();
|
|
|
|
for (var p in this) {
|
|
if (this.hasOwnProperty(p)) {
|
|
clone[p] = this[p];
|
|
}
|
|
}
|
|
|
|
return clone;
|
|
};
|
|
|
|
/**
|
|
* Normalize a value, based on its currently set unit
|
|
* @param {Number} value
|
|
* @return {Number} normalized value
|
|
* @private
|
|
*/
|
|
Unit.prototype._normalize = function(value) {
|
|
return (value + this.unit.offset) *
|
|
this.unit.value * this.prefix.value;
|
|
};
|
|
|
|
/**
|
|
* Unnormalize a value, based on its currently set unit
|
|
* @param {Number} value
|
|
* @param {Number} [prefixValue] Optional prefix value to be used
|
|
* @return {Number} unnormalized value
|
|
* @private
|
|
*/
|
|
Unit.prototype._unnormalize = function (value, prefixValue) {
|
|
if (prefixValue == undefined) {
|
|
return value / this.unit.value / this.prefix.value -
|
|
this.unit.offset;
|
|
}
|
|
else {
|
|
return value / this.unit.value / prefixValue -
|
|
this.unit.offset;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Find a unit from a string
|
|
* @param {String} str A string like 'cm' or 'inch'
|
|
* @returns {Object | null} result When found, an object with fields unit and
|
|
* prefix is returned. Else, null is returned.
|
|
* @private
|
|
*/
|
|
function _findUnit(str) {
|
|
for (var i = 0, iMax = UNITS.length; i < iMax; i++) {
|
|
var UNIT = UNITS[i];
|
|
|
|
if (string.endsWith(str, UNIT.name) ) {
|
|
var prefixLen = (str.length - UNIT.name.length);
|
|
var prefixName = str.substring(0, prefixLen);
|
|
var prefix = UNIT.prefixes[prefixName];
|
|
if (prefix !== undefined) {
|
|
// store unit, prefix, and value
|
|
return {
|
|
unit: UNIT,
|
|
prefix: prefix
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Test if the given expression is a unit.
|
|
* The unit can have a prefix but cannot have a value.
|
|
* @param {String} unit A plain unit without value. Can have prefix, like "cm"
|
|
* @return {Boolean} true if the given string is a unit
|
|
*/
|
|
Unit.isPlainUnit = function (unit) {
|
|
return (_findUnit(unit) != null);
|
|
};
|
|
|
|
/**
|
|
* check if this unit has given base unit
|
|
* @param {BASE_UNITS | undefined} base
|
|
*/
|
|
Unit.prototype.hasBase = function(base) {
|
|
if (this.unit.base === undefined) {
|
|
return (base === undefined);
|
|
}
|
|
return (this.unit.base === base);
|
|
};
|
|
|
|
/**
|
|
* Check if this unit has a base equal to another base
|
|
* @param {Unit} other
|
|
* @return {Boolean} true if equal base
|
|
*/
|
|
Unit.prototype.equalBase = function(other) {
|
|
return (this.unit.base === other.unit.base);
|
|
};
|
|
|
|
/**
|
|
* Check if this unit equals another unit
|
|
* @param {Unit} other
|
|
* @return {Boolean} true if both units are equal
|
|
*/
|
|
Unit.prototype.equals = function(other) {
|
|
return (this.equalBase(other) && this.value == other.value);
|
|
};
|
|
|
|
/**
|
|
* Create a clone of this unit with a representation
|
|
* @param {String | Unit} plainUnit A plain unit, without value. Can have prefix, like "cm"
|
|
* @returns {Unit} unit having fixed, specified unit
|
|
*/
|
|
Unit.prototype['in'] = function (plainUnit) {
|
|
var other;
|
|
if (isString(plainUnit)) {
|
|
other = new Unit(null, plainUnit);
|
|
|
|
if (!this.equalBase(other)) {
|
|
throw new Error('Units do not match');
|
|
}
|
|
|
|
other.value = this.value;
|
|
return other;
|
|
}
|
|
else if (plainUnit instanceof Unit) {
|
|
if (!this.equalBase(plainUnit)) {
|
|
throw new Error('Units do not match');
|
|
}
|
|
if (plainUnit.value != null) {
|
|
throw new Error('Cannot convert to a unit with a value');
|
|
}
|
|
if (plainUnit.unit == null) {
|
|
throw new Error('Unit expected on the right hand side of function in');
|
|
}
|
|
|
|
other = plainUnit.clone();
|
|
other.value = this.value;
|
|
other.fixPrefix = true;
|
|
return other;
|
|
}
|
|
else {
|
|
throw new Error('String or Unit expected as parameter');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Return the value of the unit when represented with given plain unit
|
|
* @param {String | Unit} plainUnit For example 'cm' or 'inch'
|
|
* @return {Number} value
|
|
*/
|
|
Unit.prototype.toNumber = function (plainUnit) {
|
|
var other = this['in'](plainUnit);
|
|
var prefix = this.fixPrefix ? other._bestPrefix() : other.prefix;
|
|
return other._unnormalize(other.value, prefix.value);
|
|
};
|
|
|
|
/**
|
|
* Get string representation
|
|
* @return {String}
|
|
*/
|
|
Unit.prototype.toString = function() {
|
|
var value, str;
|
|
if (!this.fixPrefix) {
|
|
var bestPrefix = this._bestPrefix();
|
|
value = this._unnormalize(this.value, bestPrefix.value);
|
|
str = (this.value != null) ? number.format(value) + ' ' : '';
|
|
str += bestPrefix.name + this.unit.name;
|
|
}
|
|
else {
|
|
value = this._unnormalize(this.value);
|
|
str = (this.value != null) ? number.format(value) + ' ' : '';
|
|
str += this.prefix.name + this.unit.name;
|
|
}
|
|
return str;
|
|
};
|
|
|
|
/**
|
|
* Calculate the best prefix using current value.
|
|
* @returns {Object} prefix
|
|
* @private
|
|
*/
|
|
Unit.prototype._bestPrefix = function () {
|
|
// find the best prefix value (resulting in the value of which
|
|
// the absolute value of the log10 is closest to zero,
|
|
// though with a little offset of 1.2 for nicer values: you get a
|
|
// sequence 1mm 100mm 500mm 0.6m 1m 10m 100m 500m 0.6km 1km ...
|
|
var absValue = Math.abs(this.value / this.unit.value);
|
|
var bestPrefix = PREFIX_NONE;
|
|
var bestDiff = Math.abs(
|
|
Math.log(absValue / bestPrefix.value) / Math.LN10 - 1.2);
|
|
|
|
var prefixes = this.unit.prefixes;
|
|
for (var p in prefixes) {
|
|
if (prefixes.hasOwnProperty(p)) {
|
|
var prefix = prefixes[p];
|
|
if (prefix.scientific) {
|
|
var diff = Math.abs(
|
|
Math.log(absValue / prefix.value) / Math.LN10 - 1.2);
|
|
|
|
if (diff < bestDiff) {
|
|
bestPrefix = prefix;
|
|
bestDiff = diff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bestPrefix;
|
|
};
|
|
|
|
var PREFIXES = {
|
|
'NONE': {
|
|
'': {'name': '', 'value': 1, 'scientific': true}
|
|
},
|
|
'SHORT': {
|
|
'': {'name': '', 'value': 1, 'scientific': true},
|
|
|
|
'da': {'name': 'da', 'value': 1e1, 'scientific': false},
|
|
'h': {'name': 'h', 'value': 1e2, 'scientific': false},
|
|
'k': {'name': 'k', 'value': 1e3, 'scientific': true},
|
|
'M': {'name': 'M', 'value': 1e6, 'scientific': true},
|
|
'G': {'name': 'G', 'value': 1e9, 'scientific': true},
|
|
'T': {'name': 'T', 'value': 1e12, 'scientific': true},
|
|
'P': {'name': 'P', 'value': 1e15, 'scientific': true},
|
|
'E': {'name': 'E', 'value': 1e18, 'scientific': true},
|
|
'Z': {'name': 'Z', 'value': 1e21, 'scientific': true},
|
|
'Y': {'name': 'Y', 'value': 1e24, 'scientific': true},
|
|
|
|
'd': {'name': 'd', 'value': 1e-1, 'scientific': false},
|
|
'c': {'name': 'c', 'value': 1e-2, 'scientific': false},
|
|
'm': {'name': 'm', 'value': 1e-3, 'scientific': true},
|
|
// 'µ': {'name': 'µ', 'value': 1e-6, 'scientific': true},
|
|
'u': {'name': 'u', 'value': 1e-6, 'scientific': true},
|
|
'n': {'name': 'n', 'value': 1e-9, 'scientific': true},
|
|
'p': {'name': 'p', 'value': 1e-12, 'scientific': true},
|
|
'f': {'name': 'f', 'value': 1e-15, 'scientific': true},
|
|
'a': {'name': 'a', 'value': 1e-18, 'scientific': true},
|
|
'z': {'name': 'z', 'value': 1e-21, 'scientific': true},
|
|
'y': {'name': 'y', 'value': 1e-24, 'scientific': true}
|
|
},
|
|
'LONG': {
|
|
'': {'name': '', 'value': 1, 'scientific': true},
|
|
|
|
'deca': {'name': 'deca', 'value': 1e1, 'scientific': false},
|
|
'hecto': {'name': 'hecto', 'value': 1e2, 'scientific': false},
|
|
'kilo': {'name': 'kilo', 'value': 1e3, 'scientific': true},
|
|
'mega': {'name': 'mega', 'value': 1e6, 'scientific': true},
|
|
'giga': {'name': 'giga', 'value': 1e9, 'scientific': true},
|
|
'tera': {'name': 'tera', 'value': 1e12, 'scientific': true},
|
|
'peta': {'name': 'peta', 'value': 1e15, 'scientific': true},
|
|
'exa': {'name': 'exa', 'value': 1e18, 'scientific': true},
|
|
'zetta': {'name': 'zetta', 'value': 1e21, 'scientific': true},
|
|
'yotta': {'name': 'yotta', 'value': 1e24, 'scientific': true},
|
|
|
|
'deci': {'name': 'deci', 'value': 1e-1, 'scientific': false},
|
|
'centi': {'name': 'centi', 'value': 1e-2, 'scientific': false},
|
|
'milli': {'name': 'milli', 'value': 1e-3, 'scientific': true},
|
|
'micro': {'name': 'micro', 'value': 1e-6, 'scientific': true},
|
|
'nano': {'name': 'nano', 'value': 1e-9, 'scientific': true},
|
|
'pico': {'name': 'pico', 'value': 1e-12, 'scientific': true},
|
|
'femto': {'name': 'femto', 'value': 1e-15, 'scientific': true},
|
|
'atto': {'name': 'atto', 'value': 1e-18, 'scientific': true},
|
|
'zepto': {'name': 'zepto', 'value': 1e-21, 'scientific': true},
|
|
'yocto': {'name': 'yocto', 'value': 1e-24, 'scientific': true}
|
|
},
|
|
'BINARY_SHORT': {
|
|
'': {'name': '', 'value': 1, 'scientific': true},
|
|
'k': {'name': 'k', 'value': 1024, 'scientific': true},
|
|
'M': {'name': 'M', 'value': Math.pow(1024, 2), 'scientific': true},
|
|
'G': {'name': 'G', 'value': Math.pow(1024, 3), 'scientific': true},
|
|
'T': {'name': 'T', 'value': Math.pow(1024, 4), 'scientific': true},
|
|
'P': {'name': 'P', 'value': Math.pow(1024, 5), 'scientific': true},
|
|
'E': {'name': 'E', 'value': Math.pow(1024, 6), 'scientific': true},
|
|
'Z': {'name': 'Z', 'value': Math.pow(1024, 7), 'scientific': true},
|
|
'Y': {'name': 'Y', 'value': Math.pow(1024, 8), 'scientific': true},
|
|
|
|
'Ki': {'name': 'Ki', 'value': 1024, 'scientific': true},
|
|
'Mi': {'name': 'Mi', 'value': Math.pow(1024, 2), 'scientific': true},
|
|
'Gi': {'name': 'Gi', 'value': Math.pow(1024, 3), 'scientific': true},
|
|
'Ti': {'name': 'Ti', 'value': Math.pow(1024, 4), 'scientific': true},
|
|
'Pi': {'name': 'Pi', 'value': Math.pow(1024, 5), 'scientific': true},
|
|
'Ei': {'name': 'Ei', 'value': Math.pow(1024, 6), 'scientific': true},
|
|
'Zi': {'name': 'Zi', 'value': Math.pow(1024, 7), 'scientific': true},
|
|
'Yi': {'name': 'Yi', 'value': Math.pow(1024, 8), 'scientific': true}
|
|
},
|
|
'BINARY_LONG': {
|
|
'': {'name': '', 'value': 1, 'scientific': true},
|
|
'kilo': {'name': 'kilo', 'value': 1024, 'scientific': true},
|
|
'mega': {'name': 'mega', 'value': Math.pow(1024, 2), 'scientific': true},
|
|
'giga': {'name': 'giga', 'value': Math.pow(1024, 3), 'scientific': true},
|
|
'tera': {'name': 'tera', 'value': Math.pow(1024, 4), 'scientific': true},
|
|
'peta': {'name': 'peta', 'value': Math.pow(1024, 5), 'scientific': true},
|
|
'exa': {'name': 'exa', 'value': Math.pow(1024, 6), 'scientific': true},
|
|
'zetta': {'name': 'zetta', 'value': Math.pow(1024, 7), 'scientific': true},
|
|
'yotta': {'name': 'yotta', 'value': Math.pow(1024, 8), 'scientific': true},
|
|
|
|
'kibi': {'name': 'kibi', 'value': 1024, 'scientific': true},
|
|
'mebi': {'name': 'mebi', 'value': Math.pow(1024, 2), 'scientific': true},
|
|
'gibi': {'name': 'gibi', 'value': Math.pow(1024, 3), 'scientific': true},
|
|
'tebi': {'name': 'tebi', 'value': Math.pow(1024, 4), 'scientific': true},
|
|
'pebi': {'name': 'pebi', 'value': Math.pow(1024, 5), 'scientific': true},
|
|
'exi': {'name': 'exi', 'value': Math.pow(1024, 6), 'scientific': true},
|
|
'zebi': {'name': 'zebi', 'value': Math.pow(1024, 7), 'scientific': true},
|
|
'yobi': {'name': 'yobi', 'value': Math.pow(1024, 8), 'scientific': true}
|
|
}
|
|
};
|
|
|
|
var PREFIX_NONE = {'name': '', 'value': 1, 'scientific': true};
|
|
|
|
var BASE_UNITS = {
|
|
'NONE': {},
|
|
|
|
'LENGTH': {}, // meter
|
|
'MASS': {}, // kilogram
|
|
'TIME': {}, // second
|
|
'CURRENT': {}, // ampere
|
|
'TEMPERATURE': {}, // kelvin
|
|
'LUMINOUS_INTENSITY': {}, // candela
|
|
'AMOUNT_OF_SUBSTANCE': {}, // mole
|
|
|
|
'FORCE': {}, // Newton
|
|
'SURFACE': {}, // m2
|
|
'VOLUME': {}, // m3
|
|
'ANGLE': {}, // rad
|
|
'BIT': {} // bit (digital)
|
|
};
|
|
|
|
BASE_UNIT_NONE = {};
|
|
|
|
UNIT_NONE = {'name': '', 'base': BASE_UNIT_NONE, 'value': 1, 'offset': 0};
|
|
|
|
var UNITS = [
|
|
// length
|
|
{'name': 'meter', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
|
|
{'name': 'inch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0},
|
|
{'name': 'foot', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0},
|
|
{'name': 'yard', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0},
|
|
{'name': 'mile', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0},
|
|
{'name': 'link', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0},
|
|
{'name': 'rod', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0},
|
|
{'name': 'chain', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0},
|
|
{'name': 'angstrom', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1e-10, 'offset': 0},
|
|
|
|
{'name': 'm', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
|
|
//{'name': 'in', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0254, 'offset': 0}, not supported, In is an operator
|
|
{'name': 'ft', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.3048, 'offset': 0},
|
|
{'name': 'yd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.9144, 'offset': 0},
|
|
{'name': 'mi', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 1609.344, 'offset': 0},
|
|
{'name': 'li', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.201168, 'offset': 0},
|
|
{'name': 'rd', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 5.029210, 'offset': 0},
|
|
{'name': 'ch', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 20.1168, 'offset': 0},
|
|
{'name': 'mil', 'base': BASE_UNITS.LENGTH, 'prefixes': PREFIXES.NONE, 'value': 0.0000254, 'offset': 0}, // 1/1000 inch
|
|
|
|
// Surface
|
|
{'name': 'm2', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
|
|
{'name': 'sqin', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.00064516, 'offset': 0}, // 645.16 mm2
|
|
{'name': 'sqft', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.09290304, 'offset': 0}, // 0.09290304 m2
|
|
{'name': 'sqyd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 0.83612736, 'offset': 0}, // 0.83612736 m2
|
|
{'name': 'sqmi', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 2589988.110336, 'offset': 0}, // 2.589988110336 km2
|
|
{'name': 'sqrd', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 25.29295, 'offset': 0}, // 25.29295 m2
|
|
{'name': 'sqch', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 404.6873, 'offset': 0}, // 404.6873 m2
|
|
{'name': 'sqmil', 'base': BASE_UNITS.SURFACE, 'prefixes': PREFIXES.NONE, 'value': 6.4516e-10, 'offset': 0}, // 6.4516 * 10^-10 m2
|
|
|
|
// Volume
|
|
{'name': 'm3', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
|
|
{'name': 'L', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0}, // litre
|
|
{'name': 'litre', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0},
|
|
{'name': 'cuin', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 1.6387064e-5, 'offset': 0}, // 1.6387064e-5 m3
|
|
{'name': 'cuft', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.028316846592, 'offset': 0}, // 28.316 846 592 L
|
|
{'name': 'cuyd', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.764554857984, 'offset': 0}, // 764.554 857 984 L
|
|
{'name': 'teaspoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000005, 'offset': 0}, // 5 mL
|
|
{'name': 'tablespoon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000015, 'offset': 0}, // 15 mL
|
|
//{'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.000240, 'offset': 0}, // 240 mL // not possible, we have already another cup
|
|
|
|
// Liquid volume
|
|
{'name': 'minim', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL
|
|
{'name': 'fluiddram', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0}, // 3.696691 mL
|
|
{'name': 'fluidounce', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL
|
|
{'name': 'gill', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL
|
|
{'name': 'cup', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL
|
|
{'name': 'pint', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL
|
|
{'name': 'quart', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL
|
|
{'name': 'gallon', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L
|
|
{'name': 'beerbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L
|
|
{'name': 'oilbarrel', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L
|
|
{'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L
|
|
|
|
//{'name': 'min', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00000006161152, 'offset': 0}, // 0.06161152 mL // min is already in use as minute
|
|
{'name': 'fldr', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0000036966911, 'offset': 0}, // 3.696691 mL
|
|
{'name': 'floz', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.00002957353, 'offset': 0}, // 29.57353 mL
|
|
{'name': 'gi', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0001182941, 'offset': 0}, // 118.2941 mL
|
|
{'name': 'cp', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0002365882, 'offset': 0}, // 236.5882 mL
|
|
{'name': 'pt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0004731765, 'offset': 0}, // 473.1765 mL
|
|
{'name': 'qt', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.0009463529, 'offset': 0}, // 946.3529 mL
|
|
{'name': 'gal', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.003785412, 'offset': 0}, // 3.785412 L
|
|
{'name': 'bbl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1173478, 'offset': 0}, // 117.3478 L
|
|
{'name': 'obl', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.1589873, 'offset': 0}, // 158.9873 L
|
|
//{'name': 'hogshead', 'base': BASE_UNITS.VOLUME, 'prefixes': PREFIXES.NONE, 'value': 0.2384810, 'offset': 0}, // 238.4810 L // TODO: hh?
|
|
|
|
// Mass
|
|
{'name': 'g', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 0.001, 'offset': 0},
|
|
{'name': 'gram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.LONG, 'value': 0.001, 'offset': 0},
|
|
|
|
{'name': 'ton', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 907.18474, 'offset': 0},
|
|
{'name': 'tonne', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.SHORT, 'value': 1000, 'offset': 0},
|
|
|
|
{'name': 'grain', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0},
|
|
{'name': 'dram', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0},
|
|
{'name': 'ounce', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0},
|
|
{'name': 'poundmass', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0},
|
|
{'name': 'hundredweight', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0},
|
|
{'name': 'stick', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 115e-3, 'offset': 0},
|
|
|
|
{'name': 'gr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 64.79891e-6, 'offset': 0},
|
|
{'name': 'dr', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 1.7718451953125e-3, 'offset': 0},
|
|
{'name': 'oz', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 28.349523125e-3, 'offset': 0},
|
|
{'name': 'lbm', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 453.59237e-3, 'offset': 0},
|
|
{'name': 'cwt', 'base': BASE_UNITS.MASS, 'prefixes': PREFIXES.NONE, 'value': 45.359237, 'offset': 0},
|
|
|
|
// Time
|
|
{'name': 's', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
|
|
{'name': 'min', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0},
|
|
{'name': 'h', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0},
|
|
{'name': 'seconds', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
|
|
{'name': 'second', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
|
|
{'name': 'sec', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
|
|
{'name': 'minutes', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0},
|
|
{'name': 'minute', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 60, 'offset': 0},
|
|
{'name': 'hours', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0},
|
|
{'name': 'hour', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 3600, 'offset': 0},
|
|
{'name': 'day', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0},
|
|
{'name': 'days', 'base': BASE_UNITS.TIME, 'prefixes': PREFIXES.NONE, 'value': 86400, 'offset': 0},
|
|
|
|
// Angles
|
|
{'name': 'rad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
{'name': 'deg', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.017453292519943295769236907684888, 'offset': 0}, // deg = rad / (2*pi) * 360 = rad / 0.017453292519943295769236907684888
|
|
{'name': 'grad', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 0.015707963267948966192313216916399, 'offset': 0}, // grad = rad / (2*pi) * 400 = rad / 0.015707963267948966192313216916399
|
|
{'name': 'cycle', 'base': BASE_UNITS.ANGLE, 'prefixes': PREFIXES.NONE, 'value': 6.2831853071795864769252867665793, 'offset': 0}, // cycle = rad / (2*pi) = rad / 6.2831853071795864769252867665793
|
|
|
|
// Electric current
|
|
{'name': 'A', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
|
|
{'name': 'ampere', 'base': BASE_UNITS.CURRENT, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
|
|
|
|
// Temperature
|
|
// K(C) = °C + 273.15
|
|
// K(F) = (°F + 459.67) / 1.8
|
|
// K(R) = °R / 1.8
|
|
{'name': 'K', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
{'name': 'degC', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15},
|
|
{'name': 'degF', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67},
|
|
{'name': 'degR', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0},
|
|
{'name': 'kelvin', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
{'name': 'celsius', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 273.15},
|
|
{'name': 'fahrenheit', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 459.67},
|
|
{'name': 'rankine', 'base': BASE_UNITS.TEMPERATURE, 'prefixes': PREFIXES.NONE, 'value': 1/1.8, 'offset': 0},
|
|
|
|
// amount of substance
|
|
{'name': 'mol', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
{'name': 'mole', 'base': BASE_UNITS.AMOUNT_OF_SUBSTANCE, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
|
|
// luminous intensity
|
|
{'name': 'cd', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
{'name': 'candela', 'base': BASE_UNITS.LUMINOUS_INTENSITY, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
// TODO: units STERADIAN
|
|
//{'name': 'sr', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
//{'name': 'steradian', 'base': BASE_UNITS.STERADIAN, 'prefixes': PREFIXES.NONE, 'value': 1, 'offset': 0},
|
|
|
|
// Force
|
|
{'name': 'N', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.SHORT, 'value': 1, 'offset': 0},
|
|
{'name': 'newton', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.LONG, 'value': 1, 'offset': 0},
|
|
{'name': 'lbf', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0},
|
|
{'name': 'poundforce', 'base': BASE_UNITS.FORCE, 'prefixes': PREFIXES.NONE, 'value': 4.4482216152605, 'offset': 0},
|
|
|
|
// Binary
|
|
{'name': 'b', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 1, 'offset': 0},
|
|
{'name': 'bits', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 1, 'offset': 0},
|
|
{'name': 'B', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_SHORT, 'value': 8, 'offset': 0},
|
|
{'name': 'bytes', 'base': BASE_UNITS.BIT, 'prefixes': PREFIXES.BINARY_LONG, 'value': 8, 'offset': 0}
|
|
];
|
|
|
|
Unit.PREFIXES = PREFIXES;
|
|
Unit.BASE_UNITS = BASE_UNITS;
|
|
Unit.UNITS = UNITS;
|
|
|
|
|
|
// exports
|
|
module.exports = Unit;
|
|
|
|
// to trick my IDE which doesn't get it
|
|
exports.isUnit = Unit.isUnit;
|
|
exports.isPlainUnit = Unit.isPlainUnit;
|
|
exports.parse = Unit.parse;
|
|
|
|
util.types.addType('unit', Unit);
|
|
|
|
},{"../util/index.js":205}],201:[function(require,module,exports){
|
|
var util = require('../util/index.js'),
|
|
|
|
Matrix = require('./Matrix.js'),
|
|
|
|
isArray = Array.isArray,
|
|
isString = util.string.isString;
|
|
|
|
// utility methods for strings, objects, and arrays
|
|
|
|
/**
|
|
* Convert function arguments to an array. Arguments can have the following
|
|
* signature:
|
|
* fn()
|
|
* fn(n)
|
|
* fn(m, n, p, ...)
|
|
* fn([m, n, p, ...])
|
|
* @param {...Number | Array | Matrix} args
|
|
* @returns {Array} array
|
|
*/
|
|
exports.argsToArray = function argsToArray(args) {
|
|
var array;
|
|
if (args.length == 0) {
|
|
// fn()
|
|
array = [];
|
|
}
|
|
else if (args.length == 1) {
|
|
// fn(n)
|
|
// fn([m, n, p, ...])
|
|
array = args[0];
|
|
if (array instanceof Matrix) {
|
|
array = array.toVector();
|
|
}
|
|
if (!isArray(array)) {
|
|
array = [array];
|
|
}
|
|
}
|
|
else {
|
|
// fn(m, n, p, ...)
|
|
/* TODO: cleanup
|
|
array = [];
|
|
for (var i = 0; i < args.length; i++) {
|
|
array[i] = args[i];
|
|
}
|
|
*/
|
|
array = Array.prototype.slice.apply(args);
|
|
}
|
|
return array;
|
|
};
|
|
|
|
|
|
/**
|
|
* Test whether a value is a collection: an Array or Matrix
|
|
* @param {*} x
|
|
* @returns {boolean} isCollection
|
|
*/
|
|
exports.isCollection = function isCollection (x) {
|
|
return (isArray(x) || (x instanceof Matrix));
|
|
};
|
|
|
|
// TODO: write the map, deepMap, map2, and deepMap2 functions in a more concise way
|
|
// TODO: remove map and map2, only use deepMap and deepMap2 everywhere?
|
|
|
|
/**
|
|
* Execute function fn element wise for each element in array.
|
|
* Returns an array with the results
|
|
* @param {Array | Matrix} array
|
|
* @param {function} fn
|
|
* @return {Array | Matrix} res
|
|
*/
|
|
exports.map = function map(array, fn) {
|
|
if (array && array.map) {
|
|
return array.map(function (x) {
|
|
return fn(x);
|
|
});
|
|
}
|
|
else {
|
|
throw new TypeError('Array expected');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Execute function fn element wise for each element in array and any nested
|
|
* array
|
|
* Returns an array with the results
|
|
* @param {Array | Matrix} array
|
|
* @param {function} fn
|
|
* @return {Array | Matrix} res
|
|
*/
|
|
exports.deepMap = function deepMap(array, fn) {
|
|
if (array && array.map) {
|
|
return array.map(function (x) {
|
|
return deepMap(x, fn);
|
|
});
|
|
}
|
|
else {
|
|
return fn(array);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Execute function fn element wise for each entry in two given arrays, or
|
|
* for a (scalar) object and array pair. Returns an array with the results
|
|
* @param {Array | Matrix | Object} array1
|
|
* @param {Array | Matrix | Object} array2
|
|
* @param {function} fn
|
|
* @return {Array | Matrix} res
|
|
*/
|
|
exports.map2 = function map2(array1, array2, fn) {
|
|
var res, len, i;
|
|
|
|
// handle Matrix
|
|
if (array1 instanceof Matrix || array2 instanceof Matrix) {
|
|
return new Matrix(map2(array1.valueOf(), array2.valueOf(), fn));
|
|
}
|
|
|
|
if (isArray(array1)) {
|
|
if (isArray(array2)) {
|
|
// fn(array, array)
|
|
if (array1.length != array2.length) {
|
|
throw new RangeError('Dimension mismatch ' +
|
|
'(' + array1.length + ' != ' + array2.length + ')');
|
|
}
|
|
|
|
res = [];
|
|
len = array1.length;
|
|
for (i = 0; i < len; i++) {
|
|
res[i] = fn(array1[i], array2[i]);
|
|
}
|
|
}
|
|
else {
|
|
// fn(array, object)
|
|
res = [];
|
|
len = array1.length;
|
|
for (i = 0; i < len; i++) {
|
|
res[i] = fn(array1[i], array2);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (isArray(array2)) {
|
|
// fn(object, array)
|
|
res = [];
|
|
len = array2.length;
|
|
for (i = 0; i < len; i++) {
|
|
res[i] = fn(array1, array2[i]);
|
|
}
|
|
}
|
|
else {
|
|
// fn(object, object)
|
|
res = fn(array1, array2);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
/**
|
|
* Execute function fn element wise for each entry in two given arrays,
|
|
* and for any nested array. Objects can also be scalar objects.
|
|
* Returns an array with the results.
|
|
* @param {Array | Matrix | Object} array1
|
|
* @param {Array | Matrix | Object} array2
|
|
* @param {function} fn
|
|
* @return {Array | Matrix} res
|
|
*/
|
|
exports.deepMap2 = function deepMap2(array1, array2, fn) {
|
|
var res, len, i;
|
|
|
|
// handle Matrix
|
|
if (array1 instanceof Matrix || array2 instanceof Matrix) {
|
|
return new Matrix(deepMap2(array1.valueOf(), array2.valueOf(), fn));
|
|
}
|
|
|
|
if (isArray(array1)) {
|
|
if (isArray(array2)) {
|
|
// fn(array, array)
|
|
if (array1.length != array2.length) {
|
|
throw new RangeError('Dimension mismatch ' +
|
|
'(' + array1.length + ' != ' + array2.length + ')');
|
|
}
|
|
|
|
res = [];
|
|
len = array1.length;
|
|
for (i = 0; i < len; i++) {
|
|
res[i] = deepMap2(array1[i], array2[i], fn);
|
|
}
|
|
}
|
|
else {
|
|
// fn(array, object)
|
|
res = [];
|
|
len = array1.length;
|
|
for (i = 0; i < len; i++) {
|
|
res[i] = deepMap2(array1[i], array2, fn);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (isArray(array2)) {
|
|
// fn(object, array)
|
|
res = [];
|
|
len = array2.length;
|
|
for (i = 0; i < len; i++) {
|
|
res[i] = deepMap2(array1, array2[i], fn);
|
|
}
|
|
}
|
|
else {
|
|
// fn(object, object)
|
|
res = fn(array1, array2);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
},{"../util/index.js":205,"./Matrix.js":198}],202:[function(require,module,exports){
|
|
var number = require('./number'),
|
|
string = require('./string'),
|
|
object = require('./object'),
|
|
types = require('./types'),
|
|
isArray = Array.isArray;
|
|
|
|
/**
|
|
* Recursively calculate the size of a multi dimensional array.
|
|
* @param {Array} x
|
|
* @Return {Number[]} size
|
|
* @private
|
|
*/
|
|
function _size(x) {
|
|
if (Array.isArray(x)) {
|
|
var len = x.length;
|
|
|
|
var size = len ? _size(x[0]) : [];
|
|
size.unshift(len);
|
|
return size;
|
|
}
|
|
else {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate the size of a multi dimensional array.
|
|
* All elements in the array are checked for matching dimensions using the
|
|
* method validate
|
|
* @param {Array} x
|
|
* @Return {Number[]} size
|
|
* @throws RangeError
|
|
*/
|
|
exports.size = function size (x) {
|
|
// calculate the size
|
|
var s = _size(x);
|
|
|
|
// verify the size
|
|
exports.validate(x, s);
|
|
// TODO: don't validate here? only in a Matrix constructor?
|
|
|
|
return s;
|
|
};
|
|
|
|
/**
|
|
* Recursively validate whether each element in a multi dimensional array
|
|
* has a size corresponding to the provided size array.
|
|
* @param {Array} array Array to be validated
|
|
* @param {Number[]} size Array with the size of each dimension
|
|
* @param {Number} dim Current dimension
|
|
* @throws RangeError
|
|
* @private
|
|
*/
|
|
function _validate(array, size, dim) {
|
|
var i;
|
|
var len = array.length;
|
|
|
|
if (len != size[dim]) {
|
|
throw new RangeError('Dimension mismatch (' + len + ' != ' + size[dim] + ')');
|
|
}
|
|
|
|
if (dim < size.length - 1) {
|
|
// recursively validate each child array
|
|
var dimNext = dim + 1;
|
|
for (i = 0; i < len; i++) {
|
|
var child = array[i];
|
|
if (!Array.isArray(child)) {
|
|
throw new RangeError('Dimension mismatch ' +
|
|
'(' + (size.length - 1) + ' < ' + size.length + ')');
|
|
}
|
|
_validate(array[i], size, dimNext);
|
|
}
|
|
}
|
|
else {
|
|
// last dimension. none of the childs may be an array
|
|
for (i = 0; i < len; i++) {
|
|
if (Array.isArray(array[i])) {
|
|
throw new RangeError('Dimension mismatch ' +
|
|
'(' + (size.length + 1) + ' > ' + size.length + ')');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate whether each element in a multi dimensional array has
|
|
* a size corresponding to the provided size array.
|
|
* @param {Array} array Array to be validated
|
|
* @param {Number[]} size Array with the size of each dimension
|
|
* @throws RangeError
|
|
*/
|
|
exports.validate = function validate(array, size) {
|
|
var isScalar = (size.length == 0);
|
|
if (isScalar) {
|
|
// scalar
|
|
if (Array.isArray(array)) {
|
|
throw new RangeError('Dimension mismatch (' + array.length + ' != 0)');
|
|
}
|
|
}
|
|
else {
|
|
// array
|
|
_validate(array, size, 0);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Test whether index is an integer number with index >= 0 and index < length
|
|
* @param {*} index Zero-based index
|
|
* @param {Number} [length] Length of the array
|
|
*/
|
|
exports.validateIndex = function validateIndex (index, length) {
|
|
if (!number.isNumber(index) || !number.isInteger(index)) {
|
|
throw new TypeError('Index must be an integer (value: ' + index + ')');
|
|
}
|
|
if (index < 0) {
|
|
throw new RangeError('Index out of range (' + index + ' < 0)');
|
|
}
|
|
if (length !== undefined && index >= length) {
|
|
throw new RangeError('Index out of range (' + index + ' > ' + (length - 1) + ')');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Recursively resize a multi dimensional array
|
|
* @param {Array} array Array to be resized
|
|
* @param {Number[]} size Array with the size of each dimension
|
|
* @param {Number} dim Current dimension
|
|
* @param {*} [defaultValue] Value to be filled in in new entries,
|
|
* 0 by default.
|
|
* @private
|
|
*/
|
|
function _resize (array, size, dim, defaultValue) {
|
|
if (!Array.isArray(array)) {
|
|
throw new TypeError('Array expected');
|
|
}
|
|
|
|
var len = array.length,
|
|
newLen = size[dim];
|
|
|
|
if (len != newLen) {
|
|
if(newLen > array.length) {
|
|
// enlarge
|
|
for (var i = array.length; i < newLen; i++) {
|
|
array[i] = defaultValue ? object.clone(defaultValue) : 0;
|
|
}
|
|
}
|
|
else {
|
|
// shrink
|
|
array.length = size[dim];
|
|
}
|
|
len = array.length;
|
|
}
|
|
|
|
if (dim < size.length - 1) {
|
|
// recursively validate each child array
|
|
var dimNext = dim + 1;
|
|
for (i = 0; i < len; i++) {
|
|
child = array[i];
|
|
if (!Array.isArray(child)) {
|
|
child = [child];
|
|
array[i] = child;
|
|
}
|
|
_resize(child, size, dimNext, defaultValue);
|
|
}
|
|
}
|
|
else {
|
|
// last dimension
|
|
for (i = 0; i < len; i++) {
|
|
var child = array[i];
|
|
while (Array.isArray(child)) {
|
|
child = child[0];
|
|
}
|
|
array[i] = child;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resize a multi dimensional array
|
|
* @param {Array} array Array to be resized
|
|
* @param {Array.<Number>} size Array with the size of each dimension
|
|
* @param {*} [defaultValue] Value to be filled in in new entries,
|
|
* 0 by default
|
|
*/
|
|
exports.resize = function resize(array, size, defaultValue) {
|
|
// TODO: what to do with scalars, when size=[] ?
|
|
|
|
// check the type of size
|
|
if (!Array.isArray(size)) {
|
|
throw new TypeError('Size must be an array (size is ' + types.type(size) + ')');
|
|
}
|
|
|
|
// check whether size contains positive integers
|
|
size.forEach(function (value) {
|
|
if (!number.isNumber(value) || !number.isInteger(value) || value < 0) {
|
|
throw new TypeError('Invalid size, must contain positive integers ' +
|
|
'(size: ' + string.format(size) + ')');
|
|
}
|
|
});
|
|
|
|
/* TODO: cleanup
|
|
var hasZeros = (size.indexOf(0) != -1);
|
|
if (hasZeros) {
|
|
// array where all dimensions are zero
|
|
size.forEach(function (value) {
|
|
if (value != 0) {
|
|
throw new RangeError('Invalid size, all dimensions must be ' +
|
|
'either zero or non-zero (size: ' + string.format(size) + ')');
|
|
}
|
|
});
|
|
}
|
|
*/
|
|
|
|
// recursively resize
|
|
_resize(array, size, 0, defaultValue);
|
|
};
|
|
|
|
/**
|
|
* Squeeze a multi dimensional array
|
|
* @param {Array} array
|
|
* @return {Array} array
|
|
* @private
|
|
*/
|
|
exports.squeeze = function squeeze(array) {
|
|
while(isArray(array) && array.length === 1) {
|
|
array = array[0];
|
|
}
|
|
|
|
return array;
|
|
};
|
|
|
|
/**
|
|
* Unsqueeze a multi dimensional array: add dimensions when missing
|
|
* @param {Array} array
|
|
* @param {Number} dims Number of desired dimensions
|
|
* @return {Array} array
|
|
* @private
|
|
*/
|
|
exports.unsqueeze = function unsqueeze(array, dims) {
|
|
var size = exports.size(array);
|
|
|
|
for (var i = 0, ii = (dims - size.length); i < ii; i++) {
|
|
array = [array];
|
|
}
|
|
|
|
return array;
|
|
};
|
|
|
|
/**
|
|
* Test whether an object is an array
|
|
* @param {*} value
|
|
* @return {Boolean} isArray
|
|
*/
|
|
exports.isArray = Array.isArray;
|
|
},{"./number":206,"./object":207,"./string":208,"./types":209}],203:[function(require,module,exports){
|
|
/**
|
|
* Test whether value is a Boolean
|
|
* @param {*} value
|
|
* @return {Boolean} isBoolean
|
|
*/
|
|
exports.isBoolean = function isBoolean(value) {
|
|
return (value instanceof Boolean) || (typeof value == 'boolean');
|
|
};
|
|
|
|
},{}],204:[function(require,module,exports){
|
|
var types = require('./types.js');
|
|
|
|
/**
|
|
* Create a TypeError with message:
|
|
* 'Function <fn> does not support a parameter of type <type>';
|
|
* @param {String} name Function name
|
|
* @param {*} value1
|
|
* @param {*} [value2]
|
|
* @extends TypeError
|
|
*/
|
|
exports.UnsupportedTypeError = function UnsupportedTypeError(name, value1, value2) {
|
|
if (arguments.length == 2) {
|
|
var t = types.type(value1);
|
|
this.message = 'Function ' + name + '(' + t + ') not supported';
|
|
}
|
|
else if (arguments.length > 2) {
|
|
var args = [];
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
args.push(types.type(arguments[i]));
|
|
}
|
|
this.message = 'Function ' + name + '(' + args.join(', ') + ') not supported';
|
|
}
|
|
else {
|
|
this.message = 'Unsupported parameter in function ' + name;
|
|
}
|
|
};
|
|
|
|
exports.UnsupportedTypeError.prototype = new TypeError();
|
|
exports.UnsupportedTypeError.prototype.name = 'UnsupportedTypeError';
|
|
|
|
/**
|
|
* Create a syntax error with the message:
|
|
* 'Wrong number of arguments in function <fn> (<count> provided, <min>-<max> expected)'
|
|
* @param {String} name Function name
|
|
* @param {Number} count Actual argument count
|
|
* @param {Number} min Minimum required argument count
|
|
* @param {Number} [max] Maximum required argument count
|
|
* @extends SyntaxError
|
|
*/
|
|
exports.ArgumentsError = function ArgumentsError(name, count, min, max) {
|
|
this.message = 'Wrong number of arguments in function ' + name +
|
|
' (' + count + ' provided, ' +
|
|
min + ((max != undefined) ? ('-' + max) : '') + ' expected)';
|
|
};
|
|
|
|
exports.ArgumentsError.prototype = new SyntaxError();
|
|
exports.ArgumentsError.prototype.name = 'ArgumentError';
|
|
|
|
},{"./types.js":209}],205:[function(require,module,exports){
|
|
exports.array = require('./array');
|
|
exports.boolean = require('./boolean');
|
|
exports.error = require('./error');
|
|
exports.number = require('./number');
|
|
exports.object = require('./object');
|
|
exports.string = require('./string');
|
|
exports.types = require('./types');
|
|
|
|
},{"./array":202,"./boolean":203,"./error":204,"./number":206,"./object":207,"./string":208,"./types":209}],206:[function(require,module,exports){
|
|
var options = require('../options.js');
|
|
|
|
/**
|
|
* Test whether value is a Number
|
|
* @param {*} value
|
|
* @return {Boolean} isNumber
|
|
*/
|
|
exports.isNumber = function isNumber(value) {
|
|
return (value instanceof Number) || (typeof value == 'number');
|
|
};
|
|
|
|
/**
|
|
* Test whether value is a Number or a Boolean
|
|
* @param {*} value
|
|
* @return {Boolean} isNumberOrBoolean
|
|
*/
|
|
exports.isNumBool = function isNumBool(value) {
|
|
var type = typeof value;
|
|
return (type === 'number') || (type === 'boolean') ||
|
|
(value instanceof Number) || (value instanceof Boolean);
|
|
};
|
|
|
|
/**
|
|
* Check if a number is integer
|
|
* @param {Number | Boolean} value
|
|
* @return {Boolean} isInteger
|
|
*/
|
|
exports.isInteger = function isInteger(value) {
|
|
return (value == Math.round(value));
|
|
// Note: we use ==, not ===, as we can have Booleans as well
|
|
};
|
|
|
|
/**
|
|
* Convert a number to a formatted string representation.
|
|
* @param {Number} value The value to be formatted
|
|
* @param {Number} [precision] number of digits in formatted output
|
|
* @return {String} formattedValue The formatted value
|
|
*/
|
|
exports.format = function format(value, precision) {
|
|
if (value === Infinity) {
|
|
return 'Infinity';
|
|
}
|
|
else if (value === -Infinity) {
|
|
return '-Infinity';
|
|
}
|
|
else if (isNaN(value)) {
|
|
return 'NaN';
|
|
}
|
|
|
|
// TODO: what is a nice limit for non-scientific values?
|
|
var abs = Math.abs(value);
|
|
if ( (abs > 0.001 && abs < 100000) || abs == 0.0 ) {
|
|
// round the value to a limited number of precision
|
|
return exports.toPrecision(value, precision);
|
|
}
|
|
else {
|
|
// scientific notation
|
|
var exp = Math.round(Math.log(abs) / Math.LN10);
|
|
var v = value / (Math.pow(10.0, exp));
|
|
return exports.toPrecision(v, precision) + 'e' + exp;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Calculate the sign of a number
|
|
* @param {Number} x
|
|
* @returns {*}
|
|
*/
|
|
exports.sign = function sign (x) {
|
|
if (x > 0) {
|
|
return 1;
|
|
}
|
|
else if (x < 0) {
|
|
return -1;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Round a value to a maximum number of precision. Trailing zeros will be
|
|
* removed.
|
|
* @param {Number} value
|
|
* @param {Number} [precision] Number of digits in formatted output
|
|
* @returns {string} str
|
|
*/
|
|
exports.toPrecision = function toPrecision (value, precision) {
|
|
if (precision === undefined) {
|
|
precision = options.precision;
|
|
}
|
|
|
|
return value.toPrecision(precision).replace(_trailingZeros, function (a, b, c) {
|
|
return a.substring(0, a.length - (b.length ? 0 : 1) - c.length);
|
|
});
|
|
};
|
|
|
|
/** @private */
|
|
var _trailingZeros = /\.(\d*?)(0+)$/g;
|
|
|
|
},{"../options.js":194}],207:[function(require,module,exports){
|
|
var number = require('./number.js'),
|
|
string = require('./string.js'),
|
|
bool = require('./boolean.js');
|
|
|
|
/**
|
|
* Clone an object
|
|
*
|
|
* clone(x)
|
|
*
|
|
* @param {*} x
|
|
* @return {*} clone
|
|
*/
|
|
exports.clone = function clone(x) {
|
|
if (x == null) {
|
|
// null or undefined
|
|
return x;
|
|
}
|
|
|
|
if (typeof(x.clone) === 'function') {
|
|
return x.clone();
|
|
}
|
|
|
|
if (number.isNumber(x) || string.isString(x) || bool.isBoolean(x)) {
|
|
return x;
|
|
}
|
|
|
|
if (Array.isArray(x)) {
|
|
return x.map(function (value) {
|
|
return clone(value);
|
|
});
|
|
}
|
|
|
|
if (x instanceof Object) {
|
|
var m = {};
|
|
for (var key in x) {
|
|
if (x.hasOwnProperty(key)) {
|
|
m[key] = clone(x[key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new TypeError('Cannot clone ' + x);
|
|
};
|
|
|
|
/**
|
|
* Extend object a with the properties of object b
|
|
* @param {Object} a
|
|
* @param {Object} b
|
|
* @return {Object} a
|
|
*/
|
|
exports.extend = function extend (a, b) {
|
|
for (var prop in b) {
|
|
if (b.hasOwnProperty(prop)) {
|
|
a[prop] = b[prop];
|
|
}
|
|
}
|
|
return a;
|
|
};
|
|
|
|
/**
|
|
* Deep extend an object a with the properties of object b
|
|
* @param {Object} a
|
|
* @param {Object} b
|
|
* @returns {Object}
|
|
*/
|
|
exports.deepExtend = function deepExtend (a, b) {
|
|
for (var prop in b) {
|
|
if (b.hasOwnProperty(prop)) {
|
|
if (b[prop] && b[prop].constructor === Object) {
|
|
if (a[prop] === undefined) {
|
|
a[prop] = {};
|
|
}
|
|
if (a[prop].constructor === Object) {
|
|
deepExtend(a[prop], b[prop]);
|
|
}
|
|
else {
|
|
a[prop] = b[prop];
|
|
}
|
|
} else {
|
|
a[prop] = b[prop];
|
|
}
|
|
}
|
|
}
|
|
return a;
|
|
};
|
|
|
|
/**
|
|
* Deep test equality of all fields in two pairs of arrays or objects.
|
|
* @param {Array | Object} a
|
|
* @param {Array | Object} b
|
|
* @returns {boolean}
|
|
*/
|
|
exports.deepEqual = function deepEqual (a, b) {
|
|
var prop, i, len;
|
|
if (Array.isArray(a)) {
|
|
if (!Array.isArray(b)) {
|
|
return false;
|
|
}
|
|
|
|
for (i = 0, len = a.length; i < len; i++) {
|
|
if (!exports.deepEqual(a[i], b[i])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else if (a instanceof Object) {
|
|
if (Array.isArray(b) || !(b instanceof Object)) {
|
|
return false;
|
|
}
|
|
|
|
for (prop in a) {
|
|
if (a.hasOwnProperty(prop)) {
|
|
if (!exports.deepEqual(a[prop], b[prop])) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
for (prop in b) {
|
|
if (b.hasOwnProperty(prop)) {
|
|
if (!exports.deepEqual(a[prop], b[prop])) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
else {
|
|
return (a.valueOf() == b.valueOf());
|
|
}
|
|
};
|
|
|
|
},{"./boolean.js":203,"./number.js":206,"./string.js":208}],208:[function(require,module,exports){
|
|
var number = require('./number.js');
|
|
|
|
/**
|
|
* Test whether value is a String
|
|
* @param {*} value
|
|
* @return {Boolean} isString
|
|
*/
|
|
exports.isString = function isString(value) {
|
|
return (value instanceof String) || (typeof value == 'string');
|
|
};
|
|
|
|
/**
|
|
* Check if a text ends with a certain string.
|
|
* @param {String} text
|
|
* @param {String} search
|
|
*/
|
|
exports.endsWith = function endsWith(text, search) {
|
|
var start = text.length - search.length;
|
|
var end = text.length;
|
|
return (text.substring(start, end) === search);
|
|
};
|
|
|
|
/**
|
|
* Format a value of any type into a string. Interpolate values into the string.
|
|
* Numbers are rounded off to a maximum number of 5 digits by default.
|
|
* Usage:
|
|
* math.format(value)
|
|
* math.format(template, object)
|
|
*
|
|
* Example usage:
|
|
* math.format(2/7); // '0.28571'
|
|
* math.format(new Complex(2, 3)); // '2 + 3i'
|
|
* math.format('Hello $name! The date is $date', {
|
|
* name: 'user',
|
|
* date: new Date().toISOString().substring(0, 10)
|
|
* }); // 'hello user! The date is 2013-03-23'
|
|
*
|
|
* @param {String | *} template Template or value
|
|
* @param {Object} [values]
|
|
* @return {String} str
|
|
*/
|
|
exports.format = function format(template, values) {
|
|
var num = arguments.length;
|
|
|
|
if (num == 1) {
|
|
// just format a value as string
|
|
var value = arguments[0];
|
|
if (number.isNumber(value)) {
|
|
return number.format(value);
|
|
}
|
|
|
|
if (Array.isArray(value)) {
|
|
return formatArray(value);
|
|
}
|
|
|
|
if (exports.isString(value)) {
|
|
return '"' + value + '"';
|
|
}
|
|
|
|
if (value instanceof Object) {
|
|
return value.toString();
|
|
}
|
|
|
|
return String(value);
|
|
}
|
|
else {
|
|
if (!exports.isString(template)) {
|
|
throw new TypeError('String expected as first parameter in function format');
|
|
}
|
|
if (!(values instanceof Object)) {
|
|
throw new TypeError('Object expected as second parameter in function format');
|
|
}
|
|
|
|
// format values into a string
|
|
return template.replace(/\$([\w\.]+)/g, function (original, key) {
|
|
var keys = key.split('.');
|
|
var value = values[keys.shift()];
|
|
while (keys.length && value != undefined) {
|
|
var k = keys.shift();
|
|
value = k ? value[k] : value + '.';
|
|
}
|
|
return value != undefined ? value : original;
|
|
}
|
|
);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Recursively format an n-dimensional matrix
|
|
* Example output: "[[1, 2], [3, 4]]"
|
|
* @param {Array} array
|
|
* @returns {String} str
|
|
*/
|
|
function formatArray (array) {
|
|
if (Array.isArray(array)) {
|
|
var str = '[';
|
|
var len = array.length;
|
|
for (var i = 0; i < len; i++) {
|
|
if (i != 0) {
|
|
str += ', ';
|
|
}
|
|
str += formatArray(array[i]);
|
|
}
|
|
str += ']';
|
|
return str;
|
|
}
|
|
else {
|
|
return exports.format(array);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Recursively format an n-dimensional array, output looks like
|
|
* "[1, 2, 3]"
|
|
* @param {Array} array
|
|
* @returns {string} str
|
|
*/
|
|
/* TODO: use function formatArray2d or remove it
|
|
function formatArray2d (array) {
|
|
var str = '[';
|
|
var s = size(array);
|
|
|
|
if (s.length != 2) {
|
|
throw new RangeError('Array must be two dimensional (size: ' +
|
|
formatArray(s) + ')');
|
|
}
|
|
|
|
var rows = s[0];
|
|
var cols = s[1];
|
|
for (var r = 0; r < rows; r++) {
|
|
if (r != 0) {
|
|
str += '; ';
|
|
}
|
|
|
|
var row = array[r];
|
|
for (var c = 0; c < cols; c++) {
|
|
if (c != 0) {
|
|
str += ', ';
|
|
}
|
|
var cell = row[c];
|
|
if (cell != undefined) {
|
|
str += exports.format(cell);
|
|
}
|
|
}
|
|
}
|
|
str += ']';
|
|
|
|
return str;
|
|
}
|
|
*/
|
|
},{"./number.js":206}],209:[function(require,module,exports){
|
|
/**
|
|
* Determine the type of a variable
|
|
*
|
|
* typeof(x)
|
|
*
|
|
* @param {*} x
|
|
* @return {String} type Lower case type, for example "number", "string",
|
|
* "array".
|
|
*/
|
|
exports.type = function type (x) {
|
|
var type = typeof x,
|
|
name;
|
|
|
|
if (type === 'object') {
|
|
if (x === null) {
|
|
return 'null';
|
|
}
|
|
if (x instanceof Boolean) {
|
|
return 'boolean';
|
|
}
|
|
if (x instanceof Number) {
|
|
return 'number';
|
|
}
|
|
if (x instanceof String) {
|
|
return 'string';
|
|
}
|
|
if (Array.isArray(x)) {
|
|
return 'array';
|
|
}
|
|
if (x instanceof Date) {
|
|
return 'date';
|
|
}
|
|
if (x.constructor) {
|
|
// search data types
|
|
for (name in types) {
|
|
if (types.hasOwnProperty(name)) {
|
|
if (x.constructor == types[name]) {
|
|
return name.toLowerCase();
|
|
}
|
|
}
|
|
}
|
|
|
|
// try the constructors name as last resort
|
|
if (x.constructor.name) {
|
|
return x.constructor.name.toLowerCase();
|
|
}
|
|
}
|
|
}
|
|
|
|
return type;
|
|
};
|
|
|
|
/**
|
|
* Custom registered types, for example {'matrix': Matrix}
|
|
* @private
|
|
*/
|
|
var types = {};
|
|
|
|
/**
|
|
* Register a new type, for example addType('matrix', Matrix)
|
|
* @param {String} name Lower case name of the type
|
|
* @param {Function} type Prototype function of the type
|
|
*/
|
|
exports.addType = function addType (name, type) {
|
|
types[name] = type;
|
|
};
|
|
|
|
},{}]},{},[1])(1)
|
|
});
|
|
;/**
|
|
* Compatibility shims for legacy JavaScript engines
|
|
*/
|
|
|
|
// http://soledadpenades.com/2007/05/17/arrayindexof-in-internet-explorer/
|
|
if(!Array.prototype.indexOf) {
|
|
Array.prototype.indexOf = function(obj){
|
|
for(var i = 0; i < this.length; i++){
|
|
if(this[i] == obj){
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach
|
|
if (!Array.prototype.forEach) {
|
|
Array.prototype.forEach = function(fn, scope) {
|
|
for(var i = 0, len = this.length; i < len; ++i) {
|
|
fn.call(scope || this, this[i], i, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
|
|
if(!Array.isArray) {
|
|
Array.isArray = function (vArg) {
|
|
return Object.prototype.toString.call(vArg) === "[object Array]";
|
|
};
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
|
|
// Production steps of ECMA-262, Edition 5, 15.4.4.19
|
|
// Reference: http://es5.github.com/#x15.4.4.19
|
|
if (!Array.prototype.map) {
|
|
Array.prototype.map = function(callback, thisArg) {
|
|
|
|
var T, A, k;
|
|
|
|
if (this == null) {
|
|
throw new TypeError(" this is null or not defined");
|
|
}
|
|
|
|
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
|
|
var O = Object(this);
|
|
|
|
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
|
|
// 3. Let len be ToUint32(lenValue).
|
|
var len = O.length >>> 0;
|
|
|
|
// 4. If IsCallable(callback) is false, throw a TypeError exception.
|
|
// See: http://es5.github.com/#x9.11
|
|
if (typeof callback !== "function") {
|
|
throw new TypeError(callback + " is not a function");
|
|
}
|
|
|
|
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
|
|
if (thisArg) {
|
|
T = thisArg;
|
|
}
|
|
|
|
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
|
|
// the standard built-in constructor with that name and len is the value of len.
|
|
A = new Array(len);
|
|
|
|
// 7. Let k be 0
|
|
k = 0;
|
|
|
|
// 8. Repeat, while k < len
|
|
while(k < len) {
|
|
|
|
var kValue, mappedValue;
|
|
|
|
// a. Let Pk be ToString(k).
|
|
// This is implicit for LHS operands of the in operator
|
|
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
|
|
// This step can be combined with c
|
|
// c. If kPresent is true, then
|
|
if (k in O) {
|
|
|
|
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
|
|
kValue = O[ k ];
|
|
|
|
// ii. Let mappedValue be the result of calling the Call internal method of callback
|
|
// with T as the this value and argument list containing kValue, k, and O.
|
|
mappedValue = callback.call(T, kValue, k, O);
|
|
|
|
// iii. Call the DefineOwnProperty internal method of A with arguments
|
|
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
|
|
// and false.
|
|
|
|
// In browsers that support Object.defineProperty, use the following:
|
|
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
|
|
|
|
// For best browser support, use the following:
|
|
A[ k ] = mappedValue;
|
|
}
|
|
// d. Increase k by 1.
|
|
k++;
|
|
}
|
|
|
|
// 9. return A
|
|
return A;
|
|
};
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every
|
|
if (!Array.prototype.every) {
|
|
Array.prototype.every = function(fun /*, thisp */) {
|
|
"use strict";
|
|
|
|
if (this == null) {
|
|
throw new TypeError();
|
|
}
|
|
|
|
var t = Object(this);
|
|
var len = t.length >>> 0;
|
|
if (typeof fun != "function") {
|
|
throw new TypeError();
|
|
}
|
|
|
|
var thisp = arguments[1];
|
|
for (var i = 0; i < len; i++) {
|
|
if (i in t && !fun.call(thisp, t[i], i, t)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some
|
|
if (!Array.prototype.some) {
|
|
Array.prototype.some = function(fun /*, thisp */) {
|
|
"use strict";
|
|
|
|
if (this == null) {
|
|
throw new TypeError();
|
|
}
|
|
|
|
var t = Object(this);
|
|
var len = t.length >>> 0;
|
|
if (typeof fun != "function") {
|
|
throw new TypeError();
|
|
}
|
|
|
|
var thisp = arguments[1];
|
|
for (var i = 0; i < len; i++) {
|
|
if (i in t && fun.call(thisp, t[i], i, t)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
}
|
|
|
|
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
|
|
if (!Function.prototype.bind) {
|
|
Function.prototype.bind = function (oThis) {
|
|
if (typeof this !== "function") {
|
|
// closest thing possible to the ECMAScript 5 internal IsCallable function
|
|
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
|
|
}
|
|
|
|
var aArgs = Array.prototype.slice.call(arguments, 1),
|
|
fToBind = this,
|
|
fNOP = function () {},
|
|
fBound = function () {
|
|
return fToBind.apply(this instanceof fNOP && oThis
|
|
? this
|
|
: oThis,
|
|
aArgs.concat(Array.prototype.slice.call(arguments)));
|
|
};
|
|
|
|
fNOP.prototype = this.prototype;
|
|
fBound.prototype = new fNOP();
|
|
|
|
return fBound;
|
|
};
|
|
}
|