Intial Commit

This commit is contained in:
valki
2020-10-17 18:42:50 +02:00
commit 664c6d8ca3
5892 changed files with 759183 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
// Note: This file is used by the file ./index.js
// factory function which defines a new data type MyType
function factory(type, config, load, typed) {
// create a new data type
function MyType (value) {
this.value = value;
}
MyType.prototype.isMyType = true;
MyType.prototype.toString = function () {
return 'MyType:' + this.value;
};
// define a new data type
typed.addType({
name: 'MyType',
test: function (x) {
// test whether x is of type MyType
return x && x.isMyType;
}
});
// define conversions if applicable
typed.addConversion({
from: 'number',
to: 'MyType',
convert: function (x) {
// convert a number to MyType
return new MyType(x);
}
});
// return the construction function, this will
// be added to math.type.MyType when imported
return MyType;
}
exports.name = 'MyType';
exports.path = 'type'; // will be imported into math.type.MyType
exports.factory = factory;
exports.lazy = false; // disable lazy loading as this factory has side
// effects: it adds a type and a conversion.

View File

@@ -0,0 +1,16 @@
var math = require('../../../index');
// import the new type MyType and the function `add` in math.js
math.import(require('./MyType'));
math.import(require('./myAdd'));
// create a shortcut to the new type.
var MyType = math.type.MyType;
// use the new type
var ans1 = math.add(new MyType(2), new MyType(3)); // returns MyType(5)
console.log(ans1.toString()); // outputs 'MyType:5'
// numbers will be converted to MyType
var ans2 = math.add(new MyType(4), 7); // returns MyType(11)
console.log(ans2.toString()); // outputs 'MyType:11'

View File

@@ -0,0 +1,16 @@
// Note: This file is used by the file ./index.js
function factory (type, config, load, typed) {
// create a new typed function using MyType
// when imported in math.js, this will extend the
// existing function `add` with support for MyType
return typed('add', {
'MyType, MyType': function (a, b) {
return new type.MyType(a.value + b.value);
}
});
}
exports.name = 'add';
exports.factory = factory;

View File

@@ -0,0 +1,51 @@
// Convert from Fraction to BigNumber
//
// In the configuration of math.js one can specify the default number type to
// be `number`, `BigNumber`, or `Fraction`. Not all functions support `Fraction`
// or `BigNumber`, and if not supported these input types will be converted to
// numbers.
//
// When `Fraction` is configured, one may want to fallback to `BigNumber`
// instead of `number`. Also, one may want to be able to mix `Fraction` and
// `BigNumber` in operations like summing them up. This can be achieved by
// adding an extra conversion to the list of conversions as demonstrated in
// this example.
// Load the math.js core (contains only `import` and `config`)
var core = require('../../core');
var math = core.create();
// Configure to use fractions by default
math.config({number: 'Fraction'});
// Add a conversion from Faction -> BigNumber
// this conversion:
// - must be inserted in the conversions list before the conversion Fraction -> number
// - must be added to the conversions before loading functions into math.js
math.typed.conversions.unshift({
from: 'Fraction',
to: 'BigNumber',
convert: function (fraction) {
return new math.type.BigNumber(fraction.n).div(fraction.d);
}
});
// Import all data types, functions, constants, the expression parser, etc.
math.import(require('../../lib'));
// Operators `add` and `divide` do have support for Fractions, so the result
// will simply be a Fraction (default behavior of math.js).
var ans1 = math.eval('1/3 + 1/4');
console.log(math.typeof(ans1), math.format(ans1));
// outputs "Fraction 7/12"
// Function sqrt doesn't have Fraction support, will now fall back to BigNumber
// instead of number.
var ans2 = math.eval('sqrt(4)');
console.log(math.typeof(ans2), math.format(ans2));
// outputs "BigNumber 2"
// We can now do operations with mixed Fractions and BigNumbers
var ans3 = math.add(math.fraction(2, 5), math.bignumber(3));
console.log(math.typeof(ans3), math.format(ans3));
// outputs "BigNumber 3.4"

View File

@@ -0,0 +1,99 @@
/**
* The expression parser of math.js has support for letting functions
* parse and evaluate arguments themselves, instead of calling them with
* evaluated arguments.
*
* By adding a property `raw` with value true to a function, the function
* will be invoked with unevaluated arguments, allowing the function
* to process the arguments in a customized way.
*/
var math = require('../../index');
/**
* Calculate the numeric integration of a function
* @param {Function} f
* @param {number} start
* @param {number} end
* @param {number} [step=0.01]
*/
function integrate(f, start, end, step) {
var total = 0;
step = step || 0.01;
for (var x = start; x < end; x += step) {
total += f(x + step / 2) * step;
}
return total;
}
/**
* A transformation for the integrate function. This transformation will be
* invoked when the function is used via the expression parser of math.js.
*
* Syntax:
*
* integrate(integrand, variable, start, end)
* integrate(integrand, variable, start, end, step)
*
* Usage:
*
* math.eval('integrate(2*x, x, 0, 2)')
* math.eval('integrate(2*x, x, 0, 2, 0.01)')
*
* @param {Array.<math.expression.node.Node>} args
* Expects the following arguments: [f, x, start, end, step]
* @param {Object} math
* @param {Object} [scope]
*/
integrate.transform = function (args, math, scope) {
// determine the variable name
if (args[1] instanceof math.expression.node.SymbolNode) {
var variable = args[1].name;
}
else {
throw new Error('Second argument must be a symbol');
}
// evaluate start, end, and step
var start = args[2].compile().eval(scope);
var end = args[3].compile().eval(scope);
var step = args[4] && args[4].compile().eval(scope); // step is optional
// create a new scope, linked to the provided scope. We use this new scope
// to apply the variable.
var fnScope = Object.create(scope);
// construct a function which evaluates the first parameter f after applying
// a value for parameter x.
var fnCode = args[0].compile();
var f = function (x) {
fnScope[variable] = x;
return fnCode.eval(fnScope);
};
// execute the integration
return integrate(f, start, end, step);
};
// mark the transform function with a "rawArgs" property, so it will be called
// with uncompiled, unevaluated arguments.
integrate.transform.rawArgs = true;
// import the function into math.js. Raw functions must be imported in the
// math namespace, they can't be used via `eval(scope)`.
math.import({
integrate: integrate
});
// use the function in JavaScript
function f(x) {
return math.pow(x, 0.5);
}
console.log(math.integrate(f, 0, 1)); // outputs 0.6667254718034714
// use the function via the expression parser
console.log(math.eval('integrate(x^0.5, x, 0, 1)')); // outputs 0.6667254718034714
// use the function via the expression parser (2)
var scope = {};
math.eval('f(x) = 2 * x', scope);
console.log(math.eval('integrate(f(x), x, 0, 2)', scope)); // outputs 4.000000000000003

View File

@@ -0,0 +1,44 @@
// Load the math.js core
var core = require('../../core');
// Create a new, empty math.js instance
// It will only contain methods `import` and `config`
var math = core.create();
// load the data types you need. Let's say you just want to use fractions,
// but no matrices, complex numbers, bignumbers, and other stuff.
//
// To load all data types:
//
// math.import(require('../../lib/type'));
//
math.import(require('../../lib/type/fraction'));
// Load the functions you need.
//
// To load all functions:
//
// math.import(require('../../lib/function'));
//
// To load all functions of a specific category:
//
// math.import(require('../../lib/function/arithmetic'));
//
math.import(require('../../lib/function/arithmetic/add'));
math.import(require('../../lib/function/arithmetic/subtract'));
math.import(require('../../lib/function/arithmetic/multiply'));
math.import(require('../../lib/function/arithmetic/divide'));
math.import(require('../../lib/function/string/format'));
// Use the loaded functions
var a = math.fraction(1, 3);
var b = math.fraction(3, 7);
var c = math.add(a, b);
console.log('result:', math.format(c)); // outputs "result: 16/21"
// Now, when bundling your application for use in the browser, only the used
// parts of math.js will be bundled. For example to create a bundle using
// browserify:
//
// browserify custom_loading.js -o custom_loading.bundle.js
//

View File

@@ -0,0 +1,53 @@
var math = require('../../index');
// Filter an expression tree
console.log('Filter all symbol nodes "x" in the expression "x^2 + x/4 + 3*y"');
var node = math.parse('x^2 + x/4 + 3*y');
var filtered = node.filter(function (node) {
return node.isSymbolNode && node.name == 'x';
});
// returns an array with two entries: two SymbolNodes 'x'
filtered.forEach(function (node) {
console.log(node.type, node.toString())
});
// outputs:
// SymbolNode x
// SymbolNode x
// Traverse an expression tree
console.log();
console.log('Traverse the expression tree of expression "3 * x + 2"');
var node1 = math.parse('3 * x + 2');
node1.traverse(function (node, path, parent) {
switch (node.type) {
case 'OperatorNode': console.log(node.type, node.op); break;
case 'ConstantNode': console.log(node.type, node.value); break;
case 'SymbolNode': console.log(node.type, node.name); break;
default: console.log(node.type);
}
});
// outputs:
// OperatorNode +
// OperatorNode *
// ConstantNode 3
// SymbolNode x
// ConstantNode 2
// transform an expression tree
console.log();
console.log('Replace all symbol nodes "x" in expression "x^2 + 5*x" with a constant 3');
var node2 = math.parse('x^2 + 5*x');
var transformed = node2.transform(function (node, path, parent) {
if (node.isSymbolNode && node.name == 'x') {
return new math.expression.node.ConstantNode(3);
}
else {
return node;
}
});
console.log(transformed.toString());
// outputs: '(3 ^ 2) + (5 * 3)'

View File

@@ -0,0 +1,49 @@
/**
* Function transforms
*
* When using functions via the expression parser, it is possible to preprocess
* function arguments and post process a functions return value by writing a
* *transform* for the function. A transform is a function wrapping around a
* function to be transformed or completely replaces a function.
*/
var math = require('../../index');
// create a function
function addIt(a, b) {
return a + b;
}
// attach a transform function to the function addIt
addIt.transform = function (a, b) {
console.log('input: a=' + a + ', b=' + b);
// we can manipulate the input arguments here before executing addIt
var res = addIt(a, b);
console.log('result: ' + res);
// we can manipulate the result here before returning
return res;
};
// import the function into math.js
math.import({
addIt: addIt
});
// use the function via the expression parser
console.log('Using expression parser:');
console.log('2+4=' + math.eval('addIt(2, 4)'));
// This will output:
//
// input: a=2, b=4
// result: 6
// 2+4=6
// when used via plain JavaScript, the transform is not invoked
console.log('');
console.log('Using plain JavaScript:');
console.log('2+4=' + math.addIt(2, 4));
// This will output:
//
// 6

View File

@@ -0,0 +1,23 @@
var math = require('mathjs');
var workerpool = require('workerpool');
// disable the import function so the math.js instance cannot be changed
function noImport() {
throw new Error('function import is disabled.');
}
math.import({'import': noImport}, {override: true});
/**
* Evaluate an expression
* @param {string} expr
* @return {string} result
*/
function evaluate (expr) {
var ans = math.eval(expr);
return math.format(ans);
}
// create a worker and register public functions
workerpool.worker({
evaluate: evaluate
});

View File

@@ -0,0 +1,79 @@
/**
* This example demonstrates how to run math.js in a child process with limited
* execution time.
*
* Prerequisites:
*
* npm install express workerpool
*
* Start the server:
*
* node ./server.js
*
* Make a request to the server:
*
* GET http://localhost:8080/mathjs?expr=sqrt(16)
*
* Note that the query parameter `expr` should be properly url encoded.
*/
try {
var express = require('express');
var workerpool = require('workerpool');
}
catch (err) {
console.log('Error: To run this example, install express and workerpool first via:\n\n' +
' npm install express workerpool\n');
process.exit();
}
var app = express();
var pool = workerpool.pool(__dirname + '/math_worker.js');
var TIMEOUT = 10000; // milliseconds
/**
* GET /mathjs?expr=...
*/
app.get('/mathjs', function (req, res) {
var expr = req.query.expr;
if (expr === undefined) {
return res.status(400).send('Error: Required query parameter "expr" missing in url.');
}
pool.exec('evaluate', [expr])
.timeout(TIMEOUT)
.then(function (result) {
res.send(result);
})
.catch(function (err) {
res.status(400).send(formatError(err));
});
});
/**
* Format error messages as string
* @param {Error} err
* @return {String} message
*/
function formatError (err) {
if (err instanceof workerpool.Promise.TimeoutError) {
return 'TimeoutError: Evaluation exceeded maximum duration of ' + TIMEOUT / 1000 + ' seconds';
}
else {
return err.toString();
}
}
// handle uncaught exceptions so the application cannot crash
process.on('uncaughtException', function(err) {
console.log('Caught exception: ' + err);
console.trace();
});
// start the server
var PORT = process.env.PORT || 8080;
app.listen(PORT, function() {
console.log('Listening at http://localhost:' + PORT);
console.log('Example request:\n GET http://localhost:' + PORT + '/mathjs?expr=sqrt(16)');
});