"""
type ESM:

<script type="module"> import mathjs from 'https://cdn.jsdelivr.net/npm/mathjs@14.3.1/+esm' </script>

type default:

<script src=" https://cdn.jsdelivr.net/npm/mathjs@14.3.1/lib/browser/math.min.js "></script>
""".

mathjs.org/docs/core/configuration.html:
"""

Configuration

Math.js contains a number of configuration options. These options can be applied on a created mathjs instance and changed afterwards.

import { create, all } from 'mathjs'

// create a mathjs instance with configuration
const config = {
  relTol: 1e-12,
  absTol: 1e-15,
  matrix: 'Matrix',
  number: 'number',
  precision: 64,
  predictable: false,
  randomSeed: null
}
const math = create(all, config)

// read the applied configuration
console.log(math.config())

// change the configuration
math.config({
  number: 'BigNumber'
})

The following configuration options are available:

    relTol. The minimum relative difference used to test equality between two compared values. This value is used by all relational functions. Default value is 1e-12.

    absTol. The minimum absolute difference used to test equality between two compared values. This value is used by all relational functions. Default value is 1e-15.

    matrix. The default type of matrix output for functions. Available values are: 'Matrix' (default) or 'Array'. Where possible, the type of matrix output from functions is determined from the function input: An array as input will return an Array, a Matrix as input will return a Matrix. In case of no matrix as input, the type of output is determined by the option matrix. In case of mixed matrix inputs, a matrix will be returned always.

    number. The type used to parse strings into a numeric value or create a new numeric value internally.

    For most functions, the type of output is determined from the input: a number as input will return a number as output, a BigNumber as input returns a BigNumber as output. But for example the functions math.evaluate('2+3'), math.parse('2+3'), math.range('1:10'), and math.unit('5cm') use the number configuration setting.

    Note that math.sqrt(4) will always return the number 2 regardless of the number configuration, because the numeric type can be determined from the input value.

    Available values are: 'number' (default), 'BigNumber', 'bigint', or 'Fraction'. BigNumbers have higher precision than the default numbers of JavaScript, bigint can represent large integer numbers, and Fractions store values in terms of a numerator and denominator.

    numberFallback. When number is configured for example with value 'bigint', and a value cannot be represented as bigint like in math.evaluate('2.3'), the value will be parsed in the type configured with numberFallback. Available values: 'number' (default) or 'BigNumber'.

    precision. The maximum number of significant digits for BigNumbers. This setting only applies to BigNumbers, not to numbers. Default value is 64.

    predictable. Predictable output type of functions. When true, output type depends only on the input types. When false (default), output type can vary depending on input values. For example math.sqrt(-4) returns complex('2i') when predictable is false, and returns NaN when true. Predictable output can be needed when programmatically handling the result of a calculation, but can be inconvenient for users when evaluating dynamic equations.

    randomSeed. Set this option to seed pseudo random number generation, making it deterministic. The pseudo random number generator is reset with the seed provided each time this option is set. For example, setting it to 'a' will cause math.random() to return 0.43449421599986604 upon the first call after setting the option every time. Set to null to seed the pseudo random number generator with a random seed. Default value is null.

Examples

This section shows a number of configuration examples.
node.js

import { create, all } from 'mathjs'

const config = {
  matrix: 'Array' // Choose 'Matrix' (default) or 'Array'
}
const math = create(all, config)

// range will output an Array
math.range(0, 4) // Array [0, 1, 2, 3]

// change the configuration from Arrays to Matrices
math.config({
  matrix: 'Matrix' // Choose 'Matrix' (default) or 'Array'
})

// range will output a Matrix
math.range(0, 4) // Matrix [0, 1, 2, 3]

// create an instance of math.js with BigNumber configuration
const bigmath = create(all, {
  number: 'BigNumber', // Choose 'number' (default), 'BigNumber', or 'Fraction'
  precision: 32        // 64 by default, only applicable for BigNumbers
})

// parser will parse numbers as BigNumber now:
bigmath.evaluate('1 / 3') // BigNumber, 0.33333333333333333333333333333333

browser

<!DOCTYPE HTML>
<html>
<head>
  <script src="math.js" type="text/javascript"></script>
</head>
<body>
  <script type="text/javascript">
    // the default instance of math.js is available as 'math'

    // range will output a Matrix
    math.range(0, 4)          // Matrix [0, 1, 2, 3]

    // change the configuration of math from Matrices to Arrays
    math.config({
      matrix: 'Array'         // Choose 'Matrix' (default) or 'Array'
    })

    // range will output an Array
    math.range(0, 4)          // Array [0, 1, 2, 3]

    // create a new instance of math.js with bignumber configuration
    const bigmath = math.create({
      number: 'BigNumber',    // Choose 'number' (default), 'BigNumber', or 'Fraction'
      precision: 32           // 64 by default, only applicable for BigNumbers
    })

    // parser will parse numbers as BigNumber now:
    bigmath.evaluate('1 / 3') // BigNumber, 0.33333333333333333333333333333333
  </script>
</body>
</html>

""".

mathjs.org/docs/core/chaining.html:
"""

Chaining

Math.js supports chaining operations by wrapping a value into a Chain. A chain can be created with the function math.chain(value) (formerly math.select(value)). All functions available in the math namespace can be executed via the chain. The functions will be executed with the chain’s value as the first argument, followed by extra arguments provided by the function call itself.

math.chain(3)
    .add(4)
    .subtract(2)
    .done() // 5

math.chain( [[1, 2], [3, 4]] )
    .subset(math.index(0, 0), 8)
    .multiply(3)
    .done() // [[24, 6], [9, 12]]

API

A Chain is constructed as:

math.chain()
math.chain(value)

The Chain has all functions available in the math namespace, and has a number of special functions:

    done() Finalize the chain and return the chain’s value.
    valueOf() The same as done(), returns the chain’s value.
    toString() Executes math.format(value) onto the chain’s value, returning a string representation of the value.

Note that a “rest” or “…” parameter may not be broken across the value in the chain and a function call. For example

math.chain(3).median(4,5).done() // throws error

does not compute the median of 3, 4, and 5.
""".

mathjs.org/docs/core/extension.html:
"""

Extension

The library can easily be extended with functions and variables using the import function. The import function is available on a mathjs instance, which can be created using the create function.

import { create, all } from 'mathjs'

const math = create(all)

math.import(/* ... */)

The function import accepts an object with functions and variables, or an array with factory functions. It has the following syntax:

math.import(functions: Object [, options: Object])

Where:

    functions is an object or array containing the functions and/or values to be imported. import support regular values and functions, typed functions (see section Typed functions), and factory functions (see section Factory functions). An array is only applicable when it contains factory functions.

    options is an optional second argument with options. The following options are available:
        {boolean} override If true, existing functions will be overwritten. The default value is false.
        {boolean} silent If true, the function will not throw errors on duplicates or invalid types. Default value is false.
        {boolean} wrap If true, the functions will be wrapped in a wrapper function which converts data types like Matrix to primitive data types like Array. The wrapper is needed when extending math.js with libraries which do not support the math.js data types. The default value is false.

The following code example shows how to import a function and a value into math.js:

// define new functions and variables
math.import({
  myvalue: 42,
  hello: function (name) {
    return 'hello, ' + name + '!'
  }
})

// defined functions can be used in both JavaScript as well as the parser
math.myvalue * 2                 // 84
math.hello('user')               // 'hello, user!'

const parser = math.parser()
parser.evaluate('myvalue + 10')  // 52
parser.evaluate('hello("user")') // 'hello, user!'

Import external libraries

External libraries like numbers.js and numeric.js can be imported as follows. The libraries must be installed using npm:

$ npm install numbers
$ npm install numeric

The libraries can be easily imported into math.js using import. In order to convert math.js specific data types like Matrix to primitive types like Array, the imported functions can be wrapped by enabling {wrap: true}.

import { create, all } from 'mathjs'
import * as numbers from 'numbers'
import * as numeric from 'numeric'

// create a mathjs instance and import the numbers.js and numeric.js libraries
const math = create(all)
math.import(numbers, {wrap: true, silent: true})
math.import(numeric, {wrap: true, silent: true})

// use functions from numbers.js
math.fibonacci(7)                           // 13
math.evaluate('fibonacci(7)')               // 13

// use functions from numeric.js
math.evaluate('eig([1, 2; 4, 3])').lambda.x // [5, -1]

Typed functions

Typed functions can be created using math.typed. A typed function is a function which does type checking on the input arguments. It can have multiple signatures. And can automatically convert input types where needed.

A typed function can be created like:

const max = typed('max', {
  'number, number': function (a, b) {
    return Math.max(a, b)
  },

  'BigNumber, BigNumber': function (a, b) {
    return a.greaterThan(b) ? a : b
  }
})

Typed functions can be merged as long as there are no conflicts in the signatures. This allows for extending existing functions in math.js with support for new data types.

// 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 datatype
math.typed.addType({
  name: 'MyType',
  test: function (x) {
    // test whether x is of type MyType
    return x && x.isMyType
  }
})

// use the type in a new typed function
const add = typed('add', {
  'MyType, MyType': function (a, b) {
    return new MyType(a.value + b.value)
  }
})

// import in math.js, extend the existing function `add` with support for MyType
math.import({add: add})

// use the new type
const ans = math.add(new MyType(2), new MyType(3)) // returns MyType(5)
console.log(ans)                                 // outputs 'MyType:5'

Detailed information on typed functions is available here: https://github.com/josdejong/typed-function
Factory functions

Regular JavaScript functions can be imported in math.js using math.import:

math.import({
  myFunction: function (a, b) {
     // ...
  }
})

The function can be stored in a separate file:

export function myFunction (a, b) {
  // ...
}

Which can be imported like:

import { myFunction } from './myFunction.js'

math.import({
  myFunction
})

An issue arises when myFunction needs functionality from math.js: it doesn’t have access to the current instance of math.js when in a separate file. Factory functions can be used to solve this issue. A factory function allows to inject dependencies into a function when creating it.

A syntax of factory function is:

factory(name: string, dependencies: string[], create: function, meta?: Object): function

where:

    name is the name of the created function.
    dependencies is an array with names of the dependent functions.
    create is a function which creates the function. An object with the dependencies is passed as first argument.
    meta An optional object which can contain any meta data you want. This will be attached as a property meta on the created function. Known meta data properties used by the mathjs instance are:
        isClass: boolean If true, the created function is supposed to be a class, and for example will not be exposed in the expression parser for security reasons.
        lazy: boolean. By default, everything is imported lazily by import. only as soon as the imported function or constant is actually used, it will be constructed. A function can be forced to be created immediately by setting lazy: false in the meta data.
        isTransformFunction: boolean. If true, the created function is imported as a transform function. It will not be imported in math itself, only in the internal mathWithTransform namespace that is used by the expression parser.
        recreateOnConfigChange: boolean. If true, the imported factory will be created again when there is a change in the configuration. This is for example used for the constants like pi, which is different depending on the configsetting number which can be numbers or BigNumbers.
        formerly: string. If present, the created function will also be accessible on the instance under the name given by the value of formerly as a (deprecated) synonym for the specified name. This facility should only be used when a function is renamed, to allow temporary use of the previous name, for backward compatibility.

Here an example of a factory function which depends on multiply:

import { factory, create, all } from 'mathjs'

// create a factory function
const name = 'negativeSquare'
const dependencies = ['multiply', 'unaryMinus']
const createNegativeSquare = factory(name, dependencies, function ({ multiply, unaryMinus }) {
    return function negativeSquare (x) {
      return unaryMinus(multiply(x, x))
    }
  })

// create an instance of the function yourself:
const multiply = (a, b) => a * b
const unaryMinus = (a) => -a
const negativeSquare = createNegativeSquare({ multiply, unaryMinus })
console.log(negativeSquare(3)) // -9

// or import the factory in a mathjs instance and use it there
const math = create(all)
math.import(createNegativeSquare)
console.log(math.negativeSquare(4)) // -16
console.log(math.evaluate('negativeSquare(5)')) // -25

You may wonder why you would inject functions multiply and unaryMinus instead of just doing these calculations inside the function itself. The reason is that this makes the factory function negativeSquare work for different implementations: numbers, BigNumbers, units, etc.

import { Decimal } from 'decimal.js'

// create an instance of our negativeSquare supporting BigNumbers instead of numbers
const multiply = (a, b) => a.mul(b)
const unaryMinus = (a) => new Decimal(0).minus(a)
const negativeSquare = createNegativeSquare({ multiply, unaryMinus })

""".

mathjs.org/docs/core/serialization.html:
"""

Serialization

Math.js has a number of data types like Matrix, Complex, and Unit. These types are instantiated JavaScript objects. To be able to store these data types or send them between processes, they must be serialized. The data types of math.js can be serialized to JSON. Use cases:

    Store data in a database or on disk.
    Interchange of data between a server and a client.
    Interchange of data between a web worker and the browser.

Math.js types can be serialized using JavaScript’s built-in JSON.stringify function:

const x = math.complex('2 + 3i')
const str = JSON.stringify(x, math.replacer)
console.log(str)
// outputs a string '{"mathjs":"Complex","re":2,"im":3}'

    IMPORTANT: in most cases works, serialization correctly without passing the math.replacer function as second argument. This is because in most cases we can rely on the default behavior of JSON.stringify, which uses the .toJSON method on classes like Unit and Complex to correctly serialize them. However, there are a few special cases like the number Infinity which does require the replacer function in order to be serialized without losing information: without it, Infinity will be serialized as "null" and cannot be deserialized correctly.

    So, it’s best to always pass the math.replacer function to prevent weird edge cases.

In order to deserialize a string, containing math.js data types, JSON.parse can be used. In order to recognize the data types of math.js, JSON.parse must be called with the reviver function of math.js:

const json = '{"mathjs":"Unit","value":5,"unit":"cm","fixPrefix":false}'
const x = JSON.parse(json, math.reviver)   // Unit 5 cm

Note that if math.js is used in conjunction with other data types, it is possible to use multiple reviver functions at the same time by cascading them:

const reviver = function (key, value) {
  return reviver1(key, reviver2(key, value))
}

""".

mathjs.org/docs/expressions/parsing.html:
"""

Expression parsing and evaluation

Expressions can be parsed and evaluated in various ways:

    Using the function math.evaluate(expr [,scope]).
    Using the function math.compile(expr).
    Using the function math.parse(expr).
    By creating a parser, math.parser(), which contains a method evaluate and keeps a scope with assigned variables in memory.

Evaluate

Math.js comes with a function math.evaluate to evaluate expressions. Syntax:

math.evaluate(expr)
math.evaluate(expr, scope)
math.evaluate([expr1, expr2, expr3, ...])
math.evaluate([expr1, expr2, expr3, ...], scope)

Function evaluate accepts a single expression or an array with expressions as the first argument and has an optional second argument containing a scope with variables and functions. The scope can be a regular JavaScript Map (recommended), a plain JavaScript object, or any custom class that implements the Map interface with methods get, set, keys and has. The scope will be used to resolve symbols, and to write assigned variables and functions.

When an Object is used as scope, mathjs will internally wrap it in an ObjectWrappingMap interface since the internal functions can only use a Map interface. In case of custom defined functions like f(x) = x^2, the scope will be wrapped in a PartitionedMap, which reads and writes the function variables (like x in this example) from a temporary map, and reads and writes other variables from the original scope. The original scope is never copied, it is only wrapped around when needed.

The following code demonstrates how to evaluate expressions.

// evaluate expressions
math.evaluate('sqrt(3^2 + 4^2)')        // 5
math.evaluate('sqrt(-4)')               // 2i
math.evaluate('2 inch to cm')           // 5.08 cm
math.evaluate('cos(45 deg)')            // 0.7071067811865476

// provide a scope
let scope = {
    a: 3,
    b: 4
}
math.evaluate('a * b', scope)           // 12
math.evaluate('c = 2.3 + 4.5', scope)   // 6.8
scope.c                                 // 6.8

Compile

Math.js contains a function math.compile which compiles expressions into JavaScript code. This is a shortcut for first parsing and then compiling an expression. The syntax is:

math.compile(expr)
math.compile([expr1, expr2, expr3, ...])

Function compile accepts a single expression or an array with expressions as the argument. Function compile returns an object with a function evaluate([scope]), which can be executed to evaluate the expression against an (optional) scope:

const code = math.compile(expr)       // compile an expression
const result = code.evaluate([scope]) // evaluate the code with an optional scope

An expression needs to be compiled only once, after which the expression can be evaluated repeatedly and against different scopes. The optional scope is used to resolve symbols and to write assigned variables or functions. Parameter scope can be a regular Object, or Map.

Example usage:

// parse an expression into a node, and evaluate the node
const code1 = math.compile('sqrt(3^2 + 4^2)')
code1.evaluate()  // 5

Parse

Math.js contains a function math.parse to parse expressions into an expression tree. The syntax is:

math.parse(expr)
math.parse([expr1, expr2, expr3, ...])

Function parse accepts a single expression or an array with expressions as the argument. Function parse returns the root node of the tree, which can be successively compiled and evaluated:

const node = math.parse(expr)         // parse expression into a node tree
const code = node.compile()           // compile the node tree
const result = code.evaluate([scope]) // evaluate the code with an optional scope

The API of nodes is described in detail on the page Expression trees.

An expression needs to be parsed and compiled only once, after which the expression can be evaluated repeatedly. On evaluation, an optional scope can be provided, which is used to resolve symbols and to write assigned variables or functions. Parameter scope is a regular Object or Map.

Example usage:

// parse an expression into a node, and evaluate the node
const node1 = math.parse('sqrt(3^2 + 4^2)')
const code1 = node1.compile()
code1.evaluate() // 5

// provide a scope
const node2 = math.parse('x^a')
const code2 = node2.compile()
let scope = {
    x: 3,
    a: 2
}
code2.evaluate(scope) // 9

// change a value in the scope and re-evaluate the node
scope.a = 3
code2.evaluate(scope) // 27

Parsed expressions can be exported to text using node.toString(), and can be exported to LaTeX using node.toTex(). The LaTeX export can be used to pretty print an expression in the browser with a library like MathJax. Example usage:

// parse an expression
const node = math.parse('sqrt(x/x+1)')
node.toString()   // returns 'sqrt((x / x) + 1)'
node.toTex()      // returns '\sqrt{ {\frac{x}{x} }+{1} }'

Parser

In addition to the static functions math.evaluate and math.parse, math.js contains a parser with functions evaluate and parse, which automatically keeps a scope with assigned variables in memory. The parser also contains some convenience functions to get, set, and remove variables from memory.

A parser can be created by:

const parser = math.parser()

The parser contains the following functions:

    clear() Completely clear the parser’s scope.
    evaluate(expr) Evaluate an expression. Returns the result of the expression.
    get(name) Retrieve a variable or function from the parser’s scope.
    getAll() Retrieve an object with all defined variables in the parser’s scope.
    getAllAsMap() Retrieve a map with all defined variables in the parser’s scope.
    remove(name) Remove a variable or function from the parser’s scope.
    set(name, value) Set a variable or function in the parser’s scope.

The following code shows how to create and use a parser.

// create a parser
const parser = math.parser()

// evaluate expressions
parser.evaluate('sqrt(3^2 + 4^2)')      // 5
parser.evaluate('sqrt(-4)')             // 2i
parser.evaluate('2 inch to cm')         // 5.08 cm
parser.evaluate('cos(45 deg)')          // 0.7071067811865476

// define variables and functions
parser.evaluate('x = 7 / 2')            // 3.5
parser.evaluate('x + 3')                // 6.5
parser.evaluate('f(x, y) = x^y')        // f(x, y)
parser.evaluate('f(2, 3)')              // 8

// get and set variables and functions
const x = parser.get('x')               // x = 3.5
const f = parser.get('f')               // function
const g = f(3, 3)                       // g = 27
parser.set('h', 500)
parser.evaluate('h / 2')                // 250
parser.set('hello', function (name) {
    return 'hello, ' + name + '!'
})
parser.evaluate('hello("user")')        // "hello, user!"

// clear defined functions and variables
parser.clear()

Scope

The scope is a data-structure used to store and lookup variables and functions defined and used by expressions.

It is passed to mathjs via calls to math.evaluate or simplify.

For ease of use, it can be a Plain Javascript Object; for safety it can be a plain Map and for flexibility, any object that has the methods get/set/has/keys, seen on Map.

Some care is taken to mutate the same object that is passed into mathjs, so they can collect the definitions from mathjs scripts and expressions.

evaluate will fail if the expression uses a blacklisted symbol, preventing mathjs expressions to escape into Javascript. This is enforced by access to the scope.

For less reliance on this blacklist, scope can also be a Map, which allows mathjs expressions to define variables and functions of any name.

For more, see examples of custom scopes.
""".

mathjs.org/docs/expressions/syntax.html:
"""

Expression syntax

This page describes the syntax of expression parser of math.js. It describes how to work with the available data types, functions, operators, variables, and more.
Differences from JavaScript

The expression parser of math.js is aimed at a mathematical audience, not a programming audience. The syntax is similar to most calculators and mathematical applications. This is close to JavaScript as well, though there are a few important differences between the syntax of the expression parser and the lower level syntax of math.js. Differences are:

    No need to prefix functions and constants with the math.* namespace, you can just enter sin(pi / 4).
    Matrix indexes are one-based instead of zero-based.
    There are index and range operators which allow more conveniently getting and setting matrix indexes, like A[2:4, 1].
    Both indexes and ranges and have the upper-bound included.
    There is a differing syntax for defining functions. Example: f(x) = x^2.
    There are custom operators like x + y instead of add(x, y).
    Some operators are different. For example ^ is used for exponentiation, not bitwise xor.
    Implicit multiplication, like 2 pi, is supported and has special rules.
    Relational operators (<, >, <=, >=, ==, and !=) are chained, so the expression 5 < x < 10 is equivalent to 5 < x and x < 10.
    Multi-expression constructs like a = 1; b = 2; a + b or "a = 1;\n cos(a)\n sin(a)" (where \n denotes newline) produce a collection (“ResultSet”) of values. Those expressions terminated by ; are evaluated for side effect only and their values are suppressed from the result.

Operators

The expression parser has operators for all common arithmetic operations such as addition and multiplication. The expression parser uses conventional infix notation for operators: an operator is placed between its arguments. Round parentheses can be used to override the default precedence of operators.

// use operators
math.evaluate('2 + 3')       // 5
math.evaluate('2 * 3')       // 6

// use parentheses to override the default precedence
math.evaluate('2 + 3 * 4')   // 14
math.evaluate('(2 + 3) * 4') // 20

The following operators are available. Note that almost every operator listed also has a function form with identical meaning that can be used interchangeably. For example, x+y will always evaluate identically to add(x,y). For a full list of the equivalences, see the section on Functions below.
Operator 	Name 	Syntax 	Associativity 	Example 	Result
(, ) 	Grouping 	(x) 	None 	2 * (3 + 4) 	14
[, ] 	Matrix, Index 	[...] 	None 	[[1,2],[3,4]] 	[[1,2],[3,4]]
{, } 	Object 	{...} 	None 	{a: 1, b: 2} 	{a: 1, b: 2}
, 	Parameter separator 	x, y 	Left to right 	max(2, 1, 5) 	5
. 	Property accessor 	obj.prop 	Left to right 	obj={a: 12}; obj.a 	12
; 	Statement separator 	x; y 	Left to right 	a=2; b=3; a*b 	[6]
; 	Row separator 	[x; y] 	Left to right 	[1,2;3,4] 	[[1,2],[3,4]]
\n 	Statement separator 	x \n y 	Left to right 	a=2 \n b=3 \n a*b 	[2,3,6]
+ 	Add 	x + y 	Left to right 	4 + 5 	9
+ 	Unary plus 	+y 	Right to left 	+4 	4
- 	Subtract 	x - y 	Left to right 	7 - 3 	4
- 	Unary minus 	-y 	Right to left 	-4 	-4
* 	Multiply 	x * y 	Left to right 	2 * 3 	6
.* 	Element-wise multiply 	x .* y 	Left to right 	[1,2,3] .* [1,2,3] 	[1,4,9]
/ 	Divide 	x / y 	Left to right 	6 / 2 	3
./ 	Element-wise divide 	x ./ y 	Left to right 	[9,6,4] ./ [3,2,2] 	[3,3,2]
% 	Percentage 	x% 	None 	8% 	0.08
% 	Addition with Percentage 	x + y% 	Left to right 	100 + 3% 	103
% 	Subtraction with Percentage 	x - y% 	Left to right 	100 - 3% 	97
% mod 	Modulus 	x % y 	Left to right 	8 % 3 	2
^ 	Power 	x ^ y 	Right to left 	2 ^ 3 	8
.^ 	Element-wise power 	x .^ y 	Right to left 	[2,3] .^ [3,3] 	[8,27]
' 	Transpose 	y' 	Left to right 	[[1,2],[3,4]]' 	[[1,3],[2,4]]
! 	Factorial 	y! 	Left to right 	5! 	120
& 	Bitwise and 	x & y 	Left to right 	5 & 3 	1
~ 	Bitwise not 	~x 	Right to left 	~2 	-3
| 	Bitwise or 	x | y 	Left to right 	5 | 3 	7
^| 	Bitwise xor 	x ^| y 	Left to right 	5 ^| 2 	7
<< 	Left shift 	x << y 	Left to right 	4 << 1 	8
>> 	Right arithmetic shift 	x >> y 	Left to right 	8 >> 1 	4
>>> 	Right logical shift 	x >>> y 	Left to right 	-8 >>> 1 	2147483644
and 	Logical and 	x and y 	Left to right 	true and false 	false
not 	Logical not 	not y 	Right to left 	not true 	false
or 	Logical or 	x or y 	Left to right 	true or false 	true
xor 	Logical xor 	x xor y 	Left to right 	true xor true 	false
= 	Assignment 	x = y 	Right to left 	a = 5 	5
? : 	Conditional expression 	x ? y : z 	Right to left 	15 > 100 ? 1 : -1 	-1
: 	Range 	x : y 	Right to left 	1:4 	[1,2,3,4]
to, in 	Unit conversion 	x to y 	Left to right 	2 inch to cm 	5.08 cm
== 	Equal 	x == y 	Left to right 	2 == 4 - 2 	true
!= 	Unequal 	x != y 	Left to right 	2 != 3 	true
< 	Smaller 	x < y 	Left to right 	2 < 3 	true
> 	Larger 	x > y 	Left to right 	2 > 3 	false
<= 	Smallereq 	x <= y 	Left to right 	4 <= 3 	false
>= 	Largereq 	x >= y 	Left to right 	2 + 4 >= 6 	true
Precedence

The operators have the following precedence, from highest to lowest:
Operators 	Description
(...)
[...]
{...} 	Grouping
Matrix
Object
x(...)
x[...]
obj.prop
: 	Function call
Matrix index
Property accessor
Key/value separator
' 	Matrix transpose
! 	Factorial
^, .^ 	Exponentiation
+, -, ~, not 	Unary plus, unary minus, bitwise not, logical not
See section below 	Implicit multiplication
*, /, .*, ./,%, mod 	Multiply, divide , percentage, modulus
+, - 	Add, subtract
: 	Range
to, in 	Unit conversion
<<, >>, >>> 	Bitwise left shift, bitwise right arithmetic shift, bitwise right logical shift
==, !=, <, >, <=, >= 	Relational
& 	Bitwise and (lazily evaluated)
^| 	Bitwise xor
| 	Bitwise or (lazily evaluated)
and 	Logical and (lazily evaluated)
xor 	Logical xor
or 	Logical or (lazily evaluated)
?, : 	Conditional expression
= 	Assignment
, 	Parameter and column separator
; 	Row separator
\n, ; 	Statement separators

Lazy evaluation is used where logically possible for bitwise and logical operators. In the following example, the value of x will not even be evaluated because it cannot effect the final result:

math.evaluate('false and x')        // false, no matter what x equals

Functions

Functions are called by entering their name, followed by zero or more arguments enclosed by parentheses. All available functions are listed on the page Functions.

math.evaluate('sqrt(25)')           // 5
math.evaluate('log(10000, 3 + 7)')  // 4
math.evaluate('sin(pi / 4)')        // 0.7071067811865475

New functions can be defined by “assigning” an expression to a function call with one or more variables. Such function assignments are limited: they can only be defined on a single line.

const parser = math.parser()

parser.evaluate('f(x) = x ^ 2 - 5')
parser.evaluate('f(2)')     // -1
parser.evaluate('f(3)')     // 4

parser.evaluate('g(x, y) = x ^ y')
parser.evaluate('g(2, 3)')  // 8

Note that these function assignments do not create closures; put another way, all free variables in mathjs are dynamic:

const parser = math.parser()

parser.evaluate('x = 7')
parser.evaluate('h(y) = x + y')
parser.evaluate('h(3)')         // 10
parser.evaluate('x = 3')
parser.evaluate('h(3)')         // 6, *not* 10

It is however possible to pass functions as parameters:

const parser = math.parser()

parser.evaluate('twice(func, x) = func(func(x))')
parser.evaluate('twice(square, 2)')    // 16
parser.evaluate('f(x) = 3*x')
parser.evaluate('twice(f, 2)')         // 18

// a simplistic "numerical derivative":
parser.evaluate('eps = 1e-10')
parser.evaluate('nd(f, x) = (f(x+eps) - func(x-eps))/(2*eps)')
parser.evaluate('nd(square,2)')        // 4.000000330961484

Math.js itself heavily uses typed functions, which ensure correct inputs and throws meaningful errors when the input arguments are invalid. One can create a typed-function in the expression parser like:

const parser = math.parser()

parser.evaluate('f = typed({"number": f(x) = x ^ 2 - 5})')

Finally, as mentioned above, there is a function form for nearly every one of the mathematical operator symbols. Moreover, for some associative operators, the corresponding function allows arbitrarily many arguments. The table below gives the full correspondence.
Operator Expression 	Equivalent Function Expression
a or b 	or(a,b)
a xor b 	xor(a,b)
a and b 	and(a,b)
a \| b 	bitOr(a,b)
a ^\| b 	bitXor(a,b)
a & b 	bitAnd(a,b)
a == b 	equal(a,b)
a != b 	unequal(a,b)
a < b 	smaller(a,b)
a > b 	larger(a,b)
a <= b 	smallerEq(a,b)
a << 3 	leftShift(a,3)
a >> 3 	rightArithShift(a,3)
a >>> 3 	rightLogShift(a,3)
u to cm 	to(u, cm)
a + b + c + ... 	add(a,b,c,...)
a - b 	subtract(a,b)
a * b * c * ... 	multiply(a,b,c,...)
A .* B 	dotMultiply(A,B)
A ./ B 	dotDivide(A,B)
a mod b 	mod(a,b)
+a 	unaryPlus(a)
-a 	unaryMinus(a)
~a 	bitNot(a)
not a 	not(a)
a^b 	pow(a,b)
A .^ B 	dotPow(A,B)
a! 	factorial(a)
A' 	ctranspose(A)

Note that math.js embodies a preference for the operator forms, in that calling simplify (see Algebra) converts any instances of the function form into the corresponding operator.
Map and forEach

The map and forEach functions can be used to apply a callback function to each element of an array or matrix.

The callback functions can be functions, typed functions, inline functions (only in the parser) or compiled inline functions (only in the parser).

The callback can have the following inputs:

    value: the current value in the array or matrix.
    index: the index of the current value expressed as an array of numbers.
    array: the array or matrix being iterated.

Below is the syntax for both functions:
map

The map function applies a function to each element of an array and returns a new array with the results.

const parser = math.parser()

// Define a square function
parser.evaluate('square(x) = x ^ 2')

// Apply the square function to each element of the array
parser.evaluate('result = map([1, 2, 3, 4], square)')
// result: [1, 4, 9, 16]

// Apply an inline function to each element of the array
parser.evaluate('result = map([1, 2, 3, 4], f(x) = x ^ 2)')
// result: [1, 4, 9, 16]

// Apply a compiled inline function to each element of the array
parser.evaluate('result = map([1, 2, 3, 4], x ^ 2)')
// result: [1, 4, 9, 16]

forEach

The forEach function applies a function to each element of an array or matrix but does not return a new array. It is useful for executing side effects.

// Define a function that prints each element
math.import({consoleLog: x => console.log(x)})
const parser = math.parser()

// Define a squareConsleLog function
parser.evaluate('squareConsoleLog(x) = consoleLog(x ^ 2)')

// Apply the squareConsleLog function to each element of the array
parser.evaluate('forEach([1, 2, 3, 4], squareConsleLog)')
// Prints: 1, 4, 9, 16

// Apply an inline function to each element of the array
parser.evaluate('forEach([1, 2, 3, 4], f(x) = consoleLog(x ^ 2))')
// Prints: 1, 4, 9, 16

// Apply a compiled inline function to each element of the array
parser.evaluate('forEach([1, 2, 3, 4], consoleLog(x ^ 2))')
// Prints: 1, 4, 9, 16

These functions are useful for performing element-wise operations on arrays or matrices.
Constants and variables

Math.js has a number of built-in constants such as pi and e. All available constants are listed on he page Constants.

// use constants
math.evaluate('pi')                 // 3.141592653589793
math.evaluate('e ^ 2')              // 7.3890560989306495
math.evaluate('log(e)')             // 1
math.evaluate('e ^ (pi * i) + 1')   // ~0 (Euler)

Variables can be defined using the assignment operator =, and can be used like constants.

const parser = math.parser()

// define variables
parser.evaluate('a = 3.4')      // 3.4
parser.evaluate('b = 5 / 2')    // 2.5

// use variables
parser.evaluate('a * b')        // 8.5

Variable names must:

    Begin with an “alpha character”, which is:
        A latin letter (upper or lower case). Ascii: a-z, A-Z
        An underscore. Ascii: _
        A dollar sign. Ascii: $
        A latin letter with accents. Unicode: \u00C0 - \u02AF
        A greek letter. Unicode: \u0370 - \u03FF
        A letter-like character. Unicode: \u2100 - \u214F
        A mathematical alphanumeric symbol. Unicode: \u{1D400} - \u{1D7FF} excluding invalid code points
    Contain only alpha characters (above) and digits 0-9
    Not be any of the following: mod, to, in, and, xor, or, not, end. It is possible to assign to some of these, but that’s not recommended.

It is possible to customize the allowed alpha characters, see Customize supported characters for more information.
Data types

The expression parser supports booleans, numbers, complex numbers, units, strings, matrices, and objects.
Booleans

Booleans true and false can be used in expressions.

// use booleans
math.evaluate('true')               // true
math.evaluate('false')              // false
math.evaluate('(2 == 3) == false')  // true

Booleans can be converted to numbers and strings and vice versa using the functions number and boolean, and string.

// convert booleans
math.evaluate('number(true)')       // 1
math.evaluate('string(false)')      // "false"
math.evaluate('boolean(1)')         // true
math.evaluate('boolean("false")')   // false

Numbers

The most important and basic data type in math.js are numbers. Numbers use a point as decimal mark. Numbers can be entered with exponential notation. Examples:

// numbers in math.js
math.evaluate('2')        // 2
math.evaluate('3.14')     // 3.14
math.evaluate('1.4e3')    // 1400
math.evaluate('22e-3')    // 0.022

A number can be converted to a string and vice versa using the functions number and string.

// convert a string into a number
math.evaluate('number("2.3")')    // 2.3
math.evaluate('string(2.3)')      // "2.3"

Math.js uses regular JavaScript numbers, which are floating points with a limited precision and limited range. The limitations are described in detail on the page Numbers.

math.evaluate('1e-325')   // 0
math.evaluate('1e309')    // Infinity
math.evaluate('-1e309')   // -Infinity

When doing calculations with floats, one can very easily get round-off errors:

// round-off error due to limited floating point precision
math.evaluate('0.1 + 0.2')  // 0.30000000000000004

When outputting results, the function math.format can be used to hide these round-off errors when outputting results for the user:

const ans = math.evaluate('0.1 + 0.2')  //  0.30000000000000004
math.format(ans, {precision: 14})       // "0.3"

Numbers can be expressed as binary, octal, and hexadecimal literals:

math.evaluate('0b11')  //  3
math.evaluate('0o77')  //  63
math.evaluate('0xff')  //  255

A word size suffix can be used to change the behavior of non decimal literal evaluation:

math.evaluate('0xffi8')         // -1
math.evaluate('0xffffffffi32')  //  -1
math.evaluate('0xfffffffffi32') //  SyntaxError: String "0xfffffffff" is out of range

Non decimal numbers can include a radix point:

math.evaluate('0b1.1')         // 1.5
math.evaluate('0o1.4')         // 1.5
math.evaluate('0x1.8')         // 1.5

Numbers can be formatted as binary, octal, and hex strings using the notation option of the format function:

math.evaluate('format(3, {notation: "bin"})')    //  '0b11'
math.evaluate('format(63, {notation: "oct"})')   //  '0o77'
math.evaluate('format(255, {notation: "hex"})')  //  '0xff'
math.evaluate('format(-1, {notation: "hex"})')   //  '-0x1'
math.evaluate('format(2.3, {notation: "hex"})')  //  '0x2.4cccccccccccc'

The format function accepts a wordSize option to use in conjunction with the non binary notations:

math.evaluate('format(-1, {notation: "hex", wordSize: 8})')   //  '0xffi8'

The functions bin, oct, and hex are shorthand for the format function with notation set accordingly:

math.evaluate('bin(-1)')     // '-0b1'
math.evaluate('bin(-1, 8)')  // '0b11111111i8'

BigNumbers

Math.js supports BigNumbers for calculations with an arbitrary precision. The pros and cons of Number and BigNumber are explained in detail on the page Numbers.

BigNumbers are slower but have a higher precision. Calculations with big numbers are supported only by arithmetic functions.

BigNumbers can be created using the bignumber function:

math.evaluate('bignumber(0.1) + bignumber(0.2)') // BigNumber, 0.3

The default number type of the expression parser can be changed at instantiation of math.js. The expression parser parses numbers as BigNumber by default:

// Configure the type of number: 'number' (default), 'BigNumber', or 'Fraction'
math.config({number: 'BigNumber'})

// all numbers are parsed as BigNumber
math.evaluate('0.1 + 0.2')  // BigNumber, 0.3

BigNumbers can be converted to numbers and vice versa using the functions number and bignumber. When converting a BigNumber to a Number, the high precision of the BigNumber will be lost. When a BigNumber is too large to be represented as Number, it will be initialized as Infinity.
Complex numbers

Complex numbers can be created using the imaginary unit i, which is defined as i^2 = -1. Complex numbers have a real and complex part, which can be retrieved using the functions re and im.

const parser = math.parser()

// create complex numbers
parser.evaluate('a = 2 + 3i')   // Complex, 2 + 3i
parser.evaluate('b = 4 - i')    // Complex, 4 - i

// get real and imaginary part of a complex number
parser.evaluate('re(a)')        // Number,  2
parser.evaluate('im(a)')        // Number,  3

// calculations with complex numbers
parser.evaluate('a + b')        // Complex, 6 + 2i
parser.evaluate('a * b')        // Complex, 11 + 10i
parser.evaluate('i * i')        // Number,  -1
parser.evaluate('sqrt(-4)')     // Complex, 2i

Units

math.js supports units. Units can be used in the arithmetic operations add, subtract, multiply, divide, and exponentiation. Units can also be converted from one to another. An overview of all available units can be found on the page Units.

Units can be converted using the operator to or in.

// create a unit
math.evaluate('5.4 kg')                     // Unit, 5.4 kg

// convert a unit
math.evaluate('2 inch to cm')               // Unit, 5.08 cm
math.evaluate('20 celsius in fahrenheit')   // Unit, ~68 fahrenheit
math.evaluate('90 km/h to m/s')             // Unit, 25 m / s

// convert a unit to a number
// A second parameter with the unit for the exported number must be provided
math.evaluate('number(5 cm, mm)')           // Number, 50

// calculations with units
math.evaluate('0.5kg + 33g')                // Unit, 0.533 kg
math.evaluate('3 inch + 2 cm')              // Unit, 3.7874 inch
math.evaluate('3 inch + 2 cm')              // Unit, 3.7874 inch
math.evaluate('12 seconds * 2')             // Unit, 24 seconds
math.evaluate('sin(45 deg)')                // Number, 0.7071067811865475
math.evaluate('9.81 m/s^2 * 5 s to mi/h')   // Unit, 109.72172512527 mi / h

Strings

Strings are enclosed by double quotes “ or single quotes ‘. Strings can be concatenated using the function concat (not by adding them using + like in JavaScript). Parts of a string can be retrieved or replaced by using indexes. Strings can be converted to a number using function number, and numbers can be converted to a string using function string.

When setting the value of a character in a string, the character that has been set is returned. Likewise, when a range of characters is set, that range of characters is returned.

const parser = math.parser()

// create a string
parser.evaluate('"hello"')                        // String, "hello"

// string manipulation
parser.evaluate('a = concat("hello", " world")')  // String, "hello world"
parser.evaluate('size(a)')                        // Matrix [11]
parser.evaluate('a[1:5]')                         // String, "hello"
parser.evaluate('a[1] = "H"')                     // String, "H"
parser.evaluate('a[7:12] = "there!"')             // String, "there!"
parser.evaluate('a')                              // String, "Hello there!"

// string conversion
parser.evaluate('number("300")')                  // Number, 300
parser.evaluate('string(300)')                    // String, "300"

Strings can be used in the evaluate function, to parse expressions inside the expression parser:

math.evaluate('evaluate("2 + 3")')  // 5

Matrices

Matrices can be created by entering a series of values between square brackets, elements are separated by a comma ,. A matrix like [1, 2, 3] will create a vector, a 1-dimensional matrix with size [3]. To create a multi-dimensional matrix, matrices can be nested into each other. For easier creation of two-dimensional matrices, a semicolon ; can be used to separate rows in a matrix.

// create a matrix
math.evaluate('[1, 2, 3]')                                // Matrix, size [3]
math.evaluate('[[1, 2, 3], [4, 5, 6]]')                   // Matrix, size [2, 3]
math.evaluate('[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]')     // Matrix, size [2, 2, 2]

// create a two dimensional matrix
math.evaluate('[1, 2, 3; 4, 5, 6]')                       // Matrix, size [2, 3]

Another way to create filled matrices is using the functions zeros, ones, identity, and range.

// initialize a matrix with ones or zeros
math.evaluate('zeros(3, 2)')      // Matrix, [[0, 0], [0, 0], [0, 0]],  size [3, 2]
math.evaluate('ones(3)')          // Matrix, [1, 1, 1],                 size [3]
math.evaluate('5 * ones(2, 2)')   // Matrix, [[5, 5], [5, 5]],          size [2, 2]

// create an identity matrix
math.evaluate('identity(2)')      // Matrix, [[1, 0], [0, 1]],          size [2, 2]

// create a range
math.evaluate('1:4')              // Matrix, [1, 2, 3, 4],              size [4]
math.evaluate('0:2:10')           // Matrix, [0, 2, 4, 6, 8, 10],       size [6]

A subset can be retrieved from a matrix using indexes and a subset of a matrix can be replaced by using indexes. Indexes are enclosed in square brackets, and contain a number or a range for each of the matrix dimensions. A range can have its start and/or end undefined. When the start is undefined, the range will start at 1, when the end is undefined, the range will end at the end of the matrix.

There is a context variable end available as well to denote the end of the matrix. This variable cannot be used in multiple nested indices. In that case, end will be resolved as the end of the innermost matrix. To solve this, resolving of the nested index needs to be split in two separate operations.

IMPORTANT: matrix indexes and ranges work differently from the math.js indexes in JavaScript: They are one-based with an included upper-bound, similar to most math applications.

parser = math.parser()

// create matrices
parser.evaluate('a = [1, 2; 3, 4]')       // Matrix, [[1, 2], [3, 4]]
parser.evaluate('b = zeros(2, 2)')        // Matrix, [[0, 0], [0, 0]]
parser.evaluate('c = 5:9')                // Matrix, [5, 6, 7, 8, 9]

// replace a subset in a matrix
parser.evaluate('b[1, 1:2] = [5, 6]')     // Matrix, [[5, 6], [0, 0]]
parser.evaluate('b[2, :] = [7, 8]')       // Matrix, [[5, 6], [7, 8]]

// perform a matrix calculation
parser.evaluate('d = a * b')              // Matrix, [[19, 22], [43, 50]]

// retrieve a subset of a matrix
parser.evaluate('d[2, 1]')                // 43
parser.evaluate('d[2, 1:end]')            // Matrix, [[43, 50]]
parser.evaluate('c[end - 1 : -1 : 2]')    // Matrix, [8, 7, 6]

Objects

Objects in math.js work the same as in languages like JavaScript and Python. An object is enclosed by curly brackets {, }, and contains a set of comma separated key/value pairs. Keys and values are separated by a colon :. Keys can be a symbol like prop or a string like "prop".

math.evaluate('{a: 2 + 1, b: 4}')         // {a: 3, b: 4}
math.evaluate('{"a": 2 + 1, "b": 4}')     // {a: 3, b: 4}

Objects can contain objects:

math.evaluate('{a: 2, b: {c: 3, d: 4}}')  // {a: 2, b: {c: 3, d: 4}}

Object properties can be retrieved or replaced using dot notation or bracket notation. Unlike JavaScript, when setting a property value, the whole object is returned, not the property value

let scope = {
  obj: {
    prop: 42
  }
}

// retrieve properties
math.evaluate('obj.prop', scope)          // 42
math.evaluate('obj["prop"]', scope)       // 42

// set properties (returns the whole object, not the property value!)
math.evaluate('obj.prop = 43', scope)     // {prop: 43}
math.evaluate('obj["prop"] = 43', scope)  // {prop: 43}
scope.obj                                 // {prop: 43}

Multi-line expressions

An expression can contain multiple lines, and expressions can be spread over multiple lines. Lines can be separated by a newline character \n or by a semicolon ;. Output of statements followed by a semicolon will be hidden from the output, and empty lines are ignored. The output is returned as a ResultSet, with an entry for every visible statement.

// a multi-line expression
math.evaluate('1 * 3 \n 2 * 3 \n 3 * 3')    // ResultSet, [3, 6, 9]

// semicolon statements are hidden from the output
math.evaluate('a=3; b=4; a + b \n a * b')   // ResultSet, [7, 12]

// single expression spread over multiple lines
math.evaluate('a = 2 +\n  3')               // 5
math.evaluate('[\n  1, 2;\n  3, 4\n]')      // Matrix, [[1, 2], [3, 4]]

The results can be read from a ResultSet via the property ResultSet.entries which is an Array, or by calling ResultSet.valueOf(), which returns the array with results.
Implicit multiplication

Implicit multiplication means the multiplication of two symbols, numbers, or a grouped expression inside parentheses without using the * operator. This type of syntax allows a more natural way to enter expressions. For example:

math.evaluate('2 pi')         // 6.283185307179586
math.evaluate('(1+2)(3+4)')   // 21

Parentheses are parsed as a function call when there is a symbol or accessor on the left hand side, like sqrt(4) or obj.method(4). In other cases the parentheses are interpreted as an implicit multiplication.

Math.js will always evaluate implicit multiplication before explicit multiplication *, so that the expression x * y z is parsed as x * (y * z). Math.js also gives implicit multiplication higher precedence than division, except when the division matches the pattern [unaryPrefixOp]?[number] / [number] [symbol] or [unaryPrefixOp]?[number] / [number] [left paren]. In that special case, the division is evaluated first:

math.evaluate('20 kg / 4 kg')   // 5      Evaluated as (20 kg) / (4 kg)
math.evaluate('20 / 4 kg')      // 5 kg   Evaluated as (20 / 4) kg

The behavior of implicit multiplication can be summarized by these operator precedence rules, listed from highest to lowest precedence:

    Function calls: [symbol] [left paren]
    Explicit division / when the division matches this pattern: [+-~]?[number] / [+-~]?[number] [symbol] or [number] / [number] [left paren]
    Implicit multiplication
    All other division / and multiplication *

Implicit multiplication is tricky as there can appear to be ambiguity in how an expression will be evaluated. Experience has shown that the above rules most closely match user intent when entering expressions that could be interpreted different ways. It’s also possible that these rules could be tweaked in future major releases. Use implicit multiplication carefully. If you don’t like the uncertainty introduced by implicit multiplication, use explicit * operators and parentheses to ensure your expression is evaluated the way you intend.

Here are some more examples using implicit multiplication:
Expression 	Evaluated as 	Result
(1 + 3) pi 	(1 + 3) * pi 	12.566370614359172
(4 - 1) 2 	(4 - 1) * 2 	6
3 / 4 mm 	(3 / 4) * mm 	0.75 mm
2 + 3 i 	2 + (3 * i) 	2 + 3i
(1 + 2) (4 - 2) 	(1 + 2) * (4 - 2) 	6
sqrt(4) (1 + 2) 	sqrt(4) * (1 + 2) 	6
8 pi / 2 pi 	(8 * pi) / (2 * pi) 	4
pi / 2 pi 	pi / (2 * pi) 	0.5
1 / 2i 	(1 / 2) * i 	0.5 i
8.314 J / mol K 	8.314 J / (mol * K) 	8.314 J / (mol * K)
Comments

Comments can be added to explain or describe calculations in the text. A comment starts with a sharp sign character #, and ends at the end of the line. A line can contain a comment only, or can contain an expression followed by a comment.

const parser = math.parser()

parser.evaluate('# define some variables')
parser.evaluate('width = 3')                              // 3
parser.evaluate('height = 4')                             // 4
parser.evaluate('width * height   # calculate the area')  // 12

""".

mathjs.org/docs/expressions/expression_trees.html:
"""

Expression trees

When parsing an expression via math.parse(expr), math.js generates an expression tree and returns the root node of the tree. An expression tree can be used to analyze, manipulate, and evaluate expressions.

Example:

const node = math.parse('sqrt(2 + x)')

In this case, the expression sqrt(2 + x) is parsed as:

  FunctionNode    sqrt
                   |
  OperatorNode     +
                  / \
  ConstantNode   2   x   SymbolNode

Alternatively, this expression tree can be built by manually creating nodes:

const node1 = new math.ConstantNode(2)
const node2 = new math.SymbolNode('x')
const node3 = new math.OperatorNode('+', 'add', [node1, node2])
const node4 = new math.FunctionNode('sqrt', [node3])

The resulting expression tree with root node node4 is equal to the expression tree generated by math.parse('sqrt(2 + x)').
API
Methods

All nodes have the following methods:

    clone() : Node

    Create a shallow clone of the node. The node itself is cloned, its childs are not cloned.

    cloneDeep() : Node

    Create a deep clone of the node. Both the node as well as all its childs are cloned recursively.

    compile() : Object

    Compile an expression into optimized JavaScript code. compile returns an object with a function evaluate([scope]) to evaluate. Example:

    const node = math.parse('2 + x')   // returns the root Node of an expression tree
    const code = node.compile()        // returns {evaluate: function (scope) {...}}
    const evaluate = code.evaluate({x: 3}) // returns 5

    evaluate([scope]) : Object

    Compile and evaluate an expression, this is the equivalent of doing node.compile().evaluate(scope). Example:

    const node = math.parse('2 + x')   // returns the root Node of an expression tree
    const evaluate = node.evaluate({x: 3}) // returns 5

    equals(other: Node) : boolean

    Test whether this node equals an other node. Does a deep comparison of the values of both nodes.

    filter(callback: function) : Node[]

    Recursively filter nodes in an expression tree. The callback function is called as callback(node: Node, path: string, parent: Node) : boolean for every node in the tree, and must return a boolean. The function filter returns an array with nodes for which the test returned true. Parameter path is a string containing a relative JSON Path.

    Example:

    const node = math.parse('x^2 + x/4 + 3*y')
    const filtered = node.filter(function (node) {
      return node.isSymbolNode && node.name === 'x'
    })
    // returns an array with two entries: two SymbolNodes 'x'

    forEach(callback: function) : void

    Execute a callback for each of the child nodes of this node. The callback function is called as callback(child: Node, path: string, parent: Node): void. Parameter path is a string containing a relative JSON Path.

    See also traverse, which is a recursive version of forEach.

    Example:

    const node = math.parse('3 * x + 2')
    node.forEach(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 *
    //   ConstantNode 2

    map(callback: function) : Node[]

    Transform a node. Creates a new Node having it’s childs be the results of calling the provided callback function for each of the childs of the original node. The callback function is called as callback(child: Node, path: string, parent: Node) and must return a Node. Parameter path is a string containing a relative JSON Path.

    See also transform, which is a recursive version of map.

    toHTML(options: object): string

    Get a HTML representation of the parsed expression. Example:

    const node = math.parse('sqrt(2/3)')
    node.toHTML()
    // returns
    // <span class="math-function">sqrt</span>
    // <span class="math-paranthesis math-round-parenthesis">(</span>
    // <span class="math-number">2</span>
    // <span class="math-operator math-binary-operator math-explicit-binary-operator">/</span>
    // <span class="math-number">3</span>
    // <span class="math-paranthesis math-round-parenthesis">)</span>

    Information about the available HTML classes in HTML Classes. Information about the options in Customization.

    toString(options: object) : string

    Get a string representation of the parsed expression. This is not exactly the same as the original input. Example:

    const node = math.parse('3+4*2')
    node.toString()  // returns '3 + (4 * 2)'

    Information about the options in Customization.

    toTex(options: object): string

    Get a LaTeX representation of the expression. Example:

    const node = math.parse('sqrt(2/3)')
    node.toTex() // returns '\sqrt{\frac{2}{3}}'

    Information about the options in Customization.

    transform(callback: function)

    Recursively transform an expression tree via a transform function. Similar to Array.map, but recursively executed on all nodes in the expression tree. The callback function is a mapping function accepting a node, and returning a replacement for the node or the original node. Function callback is called as callback(node: Node, path: string, parent: Node) for every node in the tree, and must return a Node. Parameter path is a string containing a relative JSON Path.

    The transform function will stop iterating when a node is replaced by the callback function, it will not iterate over replaced nodes.

    For example, to replace all nodes of type SymbolNode having name ‘x’ with a ConstantNode with value 3:

    const node = math.parse('x^2 + 5*x')
    const transformed = node.transform(function (node, path, parent) {
      if (node.isSymbolNode && node.name === 'x') {
        return new math.ConstantNode(3)
      }
      else {
        return node
      }
    })
    transformed.toString() // returns '3 ^ 2 + 5 * 3'

    traverse(callback: function): void

    Recursively traverse all nodes in a node tree. Executes given callback for this node and each of its child nodes. Similar to Array.forEach, except recursive. The callback function is a mapping function accepting a node, and returning nothing. Function callback is called as callback(node: Node, path: string, parent: Node) for every node in the tree. Parameter path is a string containing a relative JSON Path. Example:

    const node = math.parse('3 * x + 2')
    node.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

Properties

Each Node has the following properties:

    comment: string

    A string holding a comment if there was any in the expression, or else the string will be empty string. A comment can be attached to the root node of an expression or to each of the childs nodes of a BlockNode.

    isNode: true

    Is defined with value true on Nodes. Additionally, each type of node adds it’s own flag, for example a SymbolNode as has a property isSymbolNode: true.

    type: string

    The type of the node, for example 'SymbolNode' in case of a SymbolNode.

Nodes

math.js has the following types of nodes. All nodes are available at the namespace math.
AccessorNode

Construction:

new AccessorNode(object: Node, index: IndexNode)

Properties:

    object: Node
    index: IndexNode
    name: string (read-only) The function or method name. Returns an empty string when undefined.

Examples:

const node1 = math.parse('a[3]')

const object = new math.SymbolNode('a')
const constant3 = new math.ConstantNode(3)
const index = new math.IndexNode([constant3])
const node2 = new math.AccessorNode(object, index)

ArrayNode

Construction:

new ArrayNode(items: Node[])

Properties:

    items: Node[]

Examples:

const node1 = math.parse('[1, 2, 3]')

const one    = new math.ConstantNode(1)
const two    = new math.ConstantNode(2)
const three  = new math.ConstantNode(3)
const node2  = new math.ArrayNode([one, two, three])

AssignmentNode

Construction:

new AssignmentNode(object: SymbolNode, value: Node)
new AssignmentNode(object: SymbolNode | AccessorNode, index: IndexNode, value: Node)

Properties:

    object: SymbolNode | AccessorNode
    index: IndexNode | null
    value: Node
    name: string (read-only) The function or method name. Returns an empty string when undefined.

Examples:

const node1 = math.parse('a = 3')

const object = new math.SymbolNode('a')
const value = new math.ConstantNode(3)
const node2 = new math.AssignmentNode(object, value)

BlockNode

A BlockNode is created when parsing a multi line expression like a=2;b=3 or a=2\nb=3. Evaluating a BlockNode returns a ResultSet. The results can be retrieved via ResultSet.entries or ResultSet.valueOf(), which contains an Array with the results of the visible lines (i.e. lines not ending with a semicolon).

Construction:

block = new BlockNode(Array.<{node: Node} | {node: Node, visible: boolean}>)

Properties:

    blocks: Array.<{node: Node, visible: boolean}>

Examples:

const block1 = math.parse('a=1; b=2; c=3')

const a = new math.SymbolNode('a')
const one = new math.ConstantNode(1)
const ass1 = new math.AssignmentNode(a, one)

const b = new math.SymbolNode('b')
const two = new math.ConstantNode(2)
const ass2 = new math.AssignmentNode(b, two)

const c = new math.SymbolNode('c')
const three = new math.ConstantNode(3)
const ass3 = new math.AssignmentNode(c, three)

const block2 = new BlockNode([
  {node: ass1, visible: false},
  {node: ass2, visible: false},
  {node: ass3, visible: true}
])

ConditionalNode

Construction:

new ConditionalNode(condition: Node, trueExpr: Node, falseExpr: Node)

Properties:

    condition: Node
    trueExpr: Node
    falseExpr: Node

Examples:

const node1 = math.parse('a > 0 ? a : -a')

const a         = new math.SymbolNode('a')
const zero      = new math.ConstantNode(0)
const condition = new math.OperatorNode('>', 'larger', [a, zero])
const trueExpr  = a
const falseExpr = new math.OperatorNode('-', 'unaryMinus', [a])
const node2     = new math.ConditionalNode(condition, trueExpr, falseExpr)

ConstantNode

Construction:

new ConstantNode(value: *)

Properties:

    value: *

Examples:

const node1 = math.parse('2.4')

const node2 = new math.ConstantNode(2.4)
const node3 = new math.ConstantNode('foo')

FunctionAssignmentNode

Construction:

new FunctionAssignmentNode(name: string, params: string[], expr: Node)

Properties:

    name: string
    params: string[]
    expr: Node

Examples:

const node1 = math.parse('f(x) = x^2')

const x      = new math.SymbolNode('x')
const two    = new math.ConstantNode(2)
const expr   = new math.OperatorNode('^', 'pow', [x, 2])
const node2  = new math.FunctionAssignmentNode('f', ['x'], expr)

FunctionNode

Construction:

new FunctionNode(fn: Node | string, args: Node[])

Properties:

    fn: Node | string (read-only) The object or function name which to invoke.
    args: Node[]

Static functions:

    FunctionNode.onUndefinedFunction(name: string). This function is invoked when an undefined function is evaluated. By default, the function throws an exception “Undefined function x”. The function can be overwritten to customize this behavior. See also SymbolNode.onUndefinedSymbol.

Examples:

const node1 = math.parse('sqrt(4)')

const four  = new math.ConstantNode(4)
const node3 = new math.FunctionNode(new SymbolNode('sqrt'), [four])

IndexNode

Construction:

new IndexNode(dimensions: Node[])
new IndexNode(dimensions: Node[], dotNotation: boolean)

Each dimension can be a single value, a range, or a property. The values of indices are one-based, including range end.

An optional property dotNotation can be provided describing whether this index was written using dot notation like a.b, or using bracket notation like a["b"]. Default value is false. This information is used when stringifying the IndexNode.

Properties:

    dimensions: Node[]
    dotNotation: boolean

Examples:

const node1 = math.parse('A[1:3, 2]')

const A     = new math.SymbolNode('A')
const one   = new math.ConstantNode(1)
const two   = new math.ConstantNode(2)
const three = new math.ConstantNode(3)

const range = new math.RangeNode(one, three)
const index = new math.IndexNode([range, two])
const node2 = new math.AccessorNode(A, index)

ObjectNode

Construction:

new ObjectNode(properties: Object.<string, Node>)

Properties:

    properties: Object.<string, Node>

Examples:

const node1 = math.parse('{a: 1, b: 2, c: 3}')

const a = new math.ConstantNode(1)
const b = new math.ConstantNode(2)
const c = new math.ConstantNode(3)
const node2 = new math.ObjectNode({a: a, b: b, c: c})

OperatorNode

Construction:

new OperatorNode(op: string, fn: string, args: Node[], implicit: boolean = false)

Additional methods:

    isUnary() : boolean

    Returns true when the OperatorNode contains exactly one argument, like with a unary minus:

    const a = new math.ConstantNode(2)
    const b = new math.OperatorNode('-', 'unaryMinus', [a])
    b.isUnary() // true

    isBinary() : boolean

    Returns true when the OperatorNode contains exactly two arguments, like with most regular operators:

    const a = new math.ConstantNode(2)
    const b = new math.ConstantNode(3)
    const c = new math.OperatorNode('+', 'add', [a, b])
    c.isBinary() // true

Properties:

    op: string
    fn: string
    args: Node[]
    implicit: boolean True in case of an implicit multiplication, false otherwise

Examples:

const node1 = math.parse('2.3 + 5')

const a     = new math.ConstantNode(2.3)
const b     = new math.ConstantNode(5)
const node2 = new math.OperatorNode('+', 'add', [a, b])

ParenthesisNode

Construction:

new ParenthesisNode(content: Node)

Properties:

    content: Node

Examples:

const node1 = math.parse('(1)')

const a     = new math.ConstantNode(1)
const node2 = new math.ParenthesisNode(a)

RangeNode

Construction:

new RangeNode(start: Node, end: Node [, step: Node])

Properties:

    start: Node
    end: Node
    step: Node | null

Examples:

const node1 = math.parse('1:10')
const node2 = math.parse('0:2:10')

const zero = new math.ConstantNode(0)
const one = new math.ConstantNode(1)
const two = new math.ConstantNode(2)
const ten = new math.ConstantNode(10)

const node3 = new math.RangeNode(one, ten)
const node4 = new math.RangeNode(zero, ten, two)

RelationalNode

Construction:

new RelationalNode(conditionals: string[], params: Node[])

conditionals is an array of strings, each of which may be ‘smaller’, ‘larger’, ‘smallerEq’, ‘largerEq’, ‘equal’, or ‘unequal’. The conditionals array must contain exactly one fewer item than params.

Properties:

    conditionals: string[]
    params: Node[]

A RelationalNode efficiently represents a chained conditional expression with two or more comparison operators, such as 10 < x <= 50. The expression is equivalent to 10 < x and x <= 50, except that x is evaluated only once, and evaluation stops (is “short-circuited”) once any condition tests false. Operators that are subject to chaining are <, >, <=, >=, ==, and !=. For backward compatibility, math.parse will return an OperatorNode if only a single conditional is present (such as x > 2).

Examples:


const ten = new math.ConstantNode(10)
const x = new math.SymbolNode('x')
const fifty = new math.ConstantNode(50)

const node1 = new math.RelationalNode(['smaller', 'smallerEq'], [ten, x, fifty])
const node2 = math.parse('10 < x <= 50')

SymbolNode

Construction:

new SymbolNode(name: string)

Properties:

    name: string

Static functions:

    SymbolNode.onUndefinedSymbol(name: string). This function is invoked when an undefined symbol is evaluated. By default, the function throws an exception “Undefined symbol x”. The function can be overwritten to customize this behavior. See also FunctionNode.onUndefinedFunction.

Examples:

const node = math.parse('x')

const x = new math.SymbolNode('x')

""".

mathjs.org/docs/expressions/algebra.html:
"""

Algebra (symbolic computation)

math.js has built-in support for symbolic computation (CAS). It can parse expressions into an expression tree and do algebraic operations like simplification and derivation on the tree.

    It’s worth mentioning an excellent extension on math.js here: mathsteps, a step-by-step math solver library that is focused on pedagogy (how best to teach). The math problems it focuses on are pre-algebra and algebra problems involving simplifying expressions.

Simplify

The function math.simplify simplifies an expression tree:

// simplify an expression
console.log(math.simplify('3 + 2 / 4').toString())              // '7 / 2'
console.log(math.simplify('2x + 3x').toString())                // '5 * x'
console.log(math.simplify('x^2 + x + 3 + x^2').toString())      // '2 * x ^ 2 + x + 3'
console.log(math.simplify('x * y * -x / (x ^ 2)').toString())   // '-y'

The function accepts either a string or an expression tree (Node) as input, and outputs a simplified expression tree (Node). This node tree can be transformed and evaluated as described in detail on the page Expression trees.

// work with an expression tree, evaluate results
const f = math.parse('2x + x')
const simplified = math.simplify(f)
console.log(simplified.toString())       // '3 * x'
console.log(simplified.evaluate({x: 4})) // 12

Among its other actions, calling simplify() on an expression will convert any functions that have operator equivalents to their operator form:

console.log(math.simplify('multiply(x,3)').toString)  // '3 * x'

Note that simplify has an optional argument scope that allows the definitions of variables in the expression (as numeric values, or as further expressions) to be specified and used in the simplification, e.g. continuing the previous example,

console.log(math.simplify(f, {x: 4}).toString()) // 12
console.log(math.simplify(f, {x: math.parse('y+z')}).toString()) // '3*(y+z)'

In general, simplification is an inherently dfficult problem; in fact, for certain classes of expressions and algebraic equivalences, it is undecidable whether a given expression is equivalent to zero. Moreover, simplification generally depends on the properties of the operations involved; since multiplication (for example) may have different properties (e.g., it might or might not be commutative) depending on the domain under consideration, different simplifications might be appropriate.

As a result, simplify() has an additional optional argument, options, which controls its behavior. This argument is an object specifying any of various properties concerning the simplification process. See the detailed documentation for a complete list, but currently the two most important properties are as follows. Note that the options argument may only be specified if the scope is as well.

    exactFractions - a boolean which specifies whether non-integer numerical constants should be simplified to rational numbers when possible (true), or always converted to decimal notation (false).
    context - an object whose keys are the names of operations (‘add’, ‘multiply’, etc.) and whose values specify algebraic properties of the corresponding operation (currently any of ‘total’, ‘trivial’, ‘commutative’, and ‘associative’). Simplifications will only be performed if the properties they rely on are true in the given context. For example,

    const expr = math.parse('x*y-y*x')
    console.log(math.simplify(expr).toString())  // 0; * is commutative by default
    console.log(math.simplify(expr, {}, {context: {multiply: {commutative: false}}}))
    // 'x*y-y*x'; the order of the right multiplication can't be reversed.

Note that the default context is very permissive (allows a lot of simplifications) but that there is also a math.simplify.realContext that only allows simplifications that are guaranteed to preserve the value of the expression on all real numbers:

const rational = math.parse('(x-1)*x/(x-1)')
console.log(math.simplify(expr, {}, {context: math.simplify.realContext})
  // '(x-1)*x/(x-1)'; canceling the 'x-1' makes the expression defined at 1

For more details on the theory of expression simplification, see:

    Strategies for simplifying math expressions (Stackoverflow)
    Symbolic computation - Simplification (Wikipedia)

Derivative

The function math.derivative finds the symbolic derivative of an expression:

// calculate a derivative
console.log(math.derivative('2x^2 + 3x + 4', 'x').toString())   // '4 * x + 3'
console.log(math.derivative('sin(2x)', 'x').toString())         // '2 * cos(2 * x)'

Similar to the function math.simplify, math.derivative accepts either a string or an expression tree (Node) as input, and outputs a simplified expression tree (Node).

// work with an expression tree, evaluate results
const h = math.parse('x^2 + x')
const x = math.parse('x')
const dh = math.derivative(h, x)
console.log(dh.toString())        // '2 * x + 1'
console.log(dh.evaluate({x: 3}))  // '7'

The rules used by math.derivative can be found on Wikipedia:

    Differentiation rules (Wikipedia)

Rationalize

The function math.rationalize transforms a rationalizable expression in a rational fraction. If rational fraction is one variable polynomial then converts the numerator and denominator in canonical form, with decreasing exponents, returning the coefficients of numerator.


math.rationalize('2x/y - y/(x+1)')
              // (2*x^2-y^2+2*x)/(x*y+y)
math.rationalize('(2x+1)^6')
              // 64*x^6+192*x^5+240*x^4+160*x^3+60*x^2+12*x+1
math.rationalize('2x/( (2x-1) / (3x+2) ) - 5x/ ( (3x+4) / (2x^2-5) ) + 3')
              // -20*x^4+28*x^3+104*x^2+6*x-12)/(6*x^2+5*x-4)

math.rationalize('x+x+x+y',{y:1}) // 3*x+1
math.rationalize('x+x+x+y',{})    // 3*x+y

const ret = math.rationalize('x+x+x+y',{},true)
              // ret.expression=3*x+y, ret.variables = ["x","y"]
const ret = math.rationalize('-2+5x^2',{},true)
              // ret.expression=5*x^2-2, ret.variables = ["x"], ret.coefficients=[-2,0,5]

""".

mathjs.org/docs/expressions/customization.html:
"""

Customization

Besides parsing and evaluating expressions, the expression parser supports a number of features to customize processing and evaluation of expressions and outputting expressions.

On this page:

    Function transforms
    Custom argument parsing
    Custom LaTeX handlers
    Custom HTML, LaTeX and string output
    Customize supported characters

Function transforms

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.

For example, the functions for math.js use zero-based matrix indices (as is common in programing languages), but the expression parser uses one-based indices. To enable this, all functions dealing with indices have a transform, which changes input from one-based to zero-based, and transforms output (and error message) from zero-based to one-based.

// using plain JavaScript, indices are zero-based:
const a = [[1, 2], [3, 4]]       // a 2x2 matrix
math.subset(a, math.index(0, 1)) // returns 2

// using the expression parser, indices are transformed to one-based:
const a = [[1, 2], [3, 4]] // a 2x2 matrix
let scope = {
  a: a
}
math.evaluate('subset(a, index(1, 2))', scope) // returns 2

To create a transform for a function, the transform function must be attached to the function as property transform:

import { create, all } from 'mathjs'
const math = create(all)

// 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 input here before executing addIt

  const res = addIt(a, b)

  console.log('result: ' + res)
  // we can manipulate 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.evaluate('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

Functions with a transform must be imported in the math namespace, as they need to be processed at compile time. They are not supported when passed via a scope at evaluation time.
Custom argument parsing

The expression parser of math.js has support for letting functions parse and evaluate arguments themselves, instead of calling them with evaluated arguments. This is useful for example when creating a function like plot(f(x), x) or integrate(f(x), x, start, end), where some of the arguments need to be processed in a special way. In these cases, the expression f(x) will be evaluated repeatedly by the function, and x is not evaluated but used to specify the variable looping over the function f(x).

Functions having a property rawArgs with value true are treated in a special way by the expression parser: they will be invoked with unevaluated arguments, allowing the function to process the arguments in a customized way. Raw functions are called as:

rawFunction(args: Node[], math: Object, scope: Map)

Where :

    args is an Array with nodes of the parsed arguments.
    math is the math namespace against which the expression was compiled.
    scope is a Map interface containing the variables defined in the scope passed via evaluate(scope). The passed scope is always a Map interface, and normally a PartitionedMap is used to separate local function variables like x in a custom defined function f(x) = rawFunction(x) ^ 2 from the scope variables. Note that a PartitionedMap can recursively link to another PartitionedMap.

Raw functions must be imported in the math namespace, as they need to be processed at compile time. They are not supported when passed via a scope at evaluation time.

A simple example:

function myFunction(args, math, scope) {
  // get string representation of the arguments
  const str = args.map(function (arg) {
    return arg.toString()
  })

  // evaluate the arguments
  const res = args.map(function (arg) {
    return arg.compile().evaluate(scope)
  })

  return 'arguments: ' + str.join(',') + ', evaluated: ' + res.join(',')
}

// mark the function as "rawArgs", so it will be called with unevaluated arguments
myFunction.rawArgs = true

// import the new function in the math namespace
math.import({
  myFunction: myFunction
})

// use the function
math.evaluate('myFunction(2 + 3, sqrt(4))')
// returns 'arguments: 2 + 3, sqrt(4), evaluated: 5, 2'

Custom LaTeX handlers

You can attach a toTex property to your custom functions before importing them to define their LaTeX output. This toTex property can be a handler in the format described in the next section ‘Custom LaTeX and String conversion’ or a template string similar to ES6 templates.
Template syntax

    ${name}: Gets replaced by the name of the function
    ${args}: Gets replaced by a comma separated list of the arguments of the function.
    ${args[0]}: Gets replaced by the first argument of a function
    $$: Gets replaced by $

Example

const customFunctions = {
  plus: function (a, b) {
    return a + b
  },
  minus: function (a, b) {
    return a - b
  },
  binom: function (n, k) {
    return 1
  }
}

customFunctions.plus.toTex = '${args[0]}+${args[1]}' //template string
customFunctions.binom.toTex = '\\mathrm{${name}}\\left(${args}\\right)' //template string
customFunctions.minus.toTex = function (node, options) { //handler function
  return node.args[0].toTex(options) + node.name + node.args[1].toTex(options)
}

math.import(customFunctions)

math.parse('plus(1,2)').toTex()    // '1+2'
math.parse('binom(1,2)').toTex()   // '\\mathrm{binom}\\left(1,2\\right)'
math.parse('minus(1,2)').toTex()   // '1minus2'

Custom HTML, LaTeX and string output

All expression nodes have a method toTex and toString to output an expression respectively in HTML or LaTex format or as regular text . The functions toHTML, toTex and toString accept an options argument to customise output. This object is of the following form:

{
  parenthesis: 'keep',    // parenthesis option
  handler: someHandler,   // handler to change the output
  implicit: 'hide'        // how to treat implicit multiplication
}

Parenthesis

The parenthesis option changes the way parentheses are used in the output. There are three options available:

    keep Keep the parentheses from the input and display them as is. This is the default.
    auto Only display parentheses that are necessary. Mathjs tries to get rid of as much parentheses as possible.
    all Display all parentheses that are given by the structure of the node tree. This makes the output precedence unambiguous.

There’s two ways of passing callbacks:

    Pass an object that maps function names to callbacks. Those callbacks will be used for FunctionNodes with functions of that name.
    Pass a function to toTex. This function will then be used for every node.

const expression = math.parse('(1+1+1)')

expression.toString()                      // (1 + 1 + 1)
expression.toString({parenthesis: 'keep'}) // (1 + 1 + 1)
expression.toString({parenthesis: 'auto'}) // 1 + 1 + 1
expression.toString({parenthesis: 'all'})  // (1 + 1) + 1

Handler

You can provide the toTex and toString functions of an expression with your own custom handlers that override the internal behaviour. This is especially useful to provide LaTeX/string output for your own custom functions. This can be done in two ways:

    Pass an object that maps function names to callbacks. Those callbacks will be used for FunctionNodes that contain functions with that name.
    Pass a callback directly. This callback will run for every node, so you can replace the output of anything you like.

A callback function has the following form:

function callback (node, options) {
  ...
}

Where options is the object passed to toHTML/toTex/toString. Don’t forget to pass this on to the child nodes, and node is a reference to the current node.

If a callback returns nothing, the standard output will be used. If your callback returns a string, this string will be used.

Although the following examples use toTex, it works for toString and toHTML in the same way
Examples for option 1

const customFunctions = {
  binomial: function (n, k) {
    //calculate n choose k
    // (do some stuff)
    return result
  }
}

const customLaTeX = {
  'binomial': function (node, options) { //provide toTex for your own custom function
    return '\\binom{' + node.args[0].toTex(options) + '}{' + node.args[1].toTex(options) + '}'
  },
  'factorial': function (node, options) { //override toTex for builtin functions
  	return 'factorial\\left(' + node.args[0] + '\\right)'
  }
}

You can simply use your custom toTex functions by passing them to toTex:

math.import(customFunctions)
const expression = math.parse('binomial(factorial(2),1)')
const latex = expression.toTex({handler: customLaTeX})
// latex now contains "\binom{factorial\\left(2\\right)}{1}"

Examples for option 2:

function customLaTeX(node, options) {
  if ((node.type === 'OperatorNode') && (node.fn === 'add')) {
    //don't forget to pass the options to the toTex functions
    return node.args[0].toTex(options) + ' plus ' + node.args[1].toTex(options)
  }
  else if (node.type === 'ConstantNode') {
    if (node.value === 0) {
        return '\\mbox{zero}'
    }
    else if (node.value === 1) {
        return '\\mbox{one}'
    }
    else if (node.value === 2) {
        return '\\mbox{two}'
    }
    else {
        return node.value
    }
  }
}

const expression = math.parse('1+2')
const latex = expression.toTex({handler: customLaTeX})
// latex now contains '\mbox{one} plus \mbox{two}'

Another example in conjunction with custom functions:

const customFunctions = {
  binomial: function (n, k) {
    //calculate n choose k
    // (do some stuff)
    return result
  }
}

function customLaTeX(node, options) {
  if ((node.type === 'FunctionNode') && (node.name === 'binomial')) {
      return '\\binom{' + node.args[0].toTex(options) + '}{' + node.args[1].toTex(options) + '}'
  }
}

math.import(customFunctions)
const expression = math.parse('binomial(2,1)')
const latex = expression.toTex({handler: customLaTeX})
// latex now contains "\binom{2}{1}"

Implicit multiplication

You can change the way that implicit multiplication is converted to a string or LaTeX. The two options are hide, to not show a multiplication operator for implicit multiplication and show to show it.

Example:

const node = math.parse('2a')

node.toString()                   // '2 a'
node.toString({implicit: 'hide'}) // '2 a'
node.toString({implicit: 'show'}) // '2 * a'

node.toTex()                      // '2~ a'
node.toTex({implicit: 'hide'})    // '2~ a'
node.toTex({implicit: 'show'})    // '2\\cdot a'

Customize supported characters

It is possible to customize the characters allowed in symbols and digits. The parse function exposes the following test functions:

    math.parse.isAlpha(c, cPrev, cNext)
    math.parse.isWhitespace(c, nestingLevel)
    math.parse.isDecimalMark(c, cNext)
    math.parse.isDigitDot(c)
    math.parse.isDigit(c)

The exact signature and implementation of these functions can be looked up in the source code of the parser. The allowed alpha characters are described here: Constants and variables.

For example, the phone character ☎ is not supported by default. It can be enabled by replacing the isAlpha function:

const isAlphaOriginal = math.parse.isAlpha
math.parse.isAlpha = function (c, cPrev, cNext) {
  return isAlphaOriginal(c, cPrev, cNext) || (c === '\u260E')
}

// now we can use the \u260E (phone) character in expressions
const result = math.evaluate('\u260Efoo', {'\u260Efoo': 42}) // returns 42
console.log(result)

""".

mathjs.org/docs/expressions/security.html:
"""
Less vulnerable expression parser
#

There is a small number of functions which yield the biggest security risk in the expression parser:

    import and createUnit which alter the built-in functionality and allow overriding existing functions and units, and reviver which parses values into class instances.
    evaluate, parse, simplify, derivative, and resolve which parse arbitrary input into a manipulable expression tree.

To make the expression parser less vulnerable whilst still supporting most functionality, these functions can be disabled:

import { create, all } from 'mathjs'

const math = create(all)
const limitedEvaluate = math.evaluate

math.import({
  // most important (hardly any functional impact)
  'import':     function () { throw new Error('Function import is disabled') },
  'createUnit': function () { throw new Error('Function createUnit is disabled') },
  'reviver':    function () { throw new Error('Function reviver is disabled') },

  // extra (has functional impact)
  'evaluate':   function () { throw new Error('Function evaluate is disabled') },
  'parse':      function () { throw new Error('Function parse is disabled') },
  'simplify':   function () { throw new Error('Function simplify is disabled') },
  'derivative': function () { throw new Error('Function derivative is disabled') },
  'resolve':    function () { throw new Error('Function resolve is disabled') },
}, { override: true })

console.log(limitedEvaluate('sqrt(16)'))     // Ok, 4
console.log(limitedEvaluate('parse("2+3")')) // Error: Function parse is disabled

""".

mathjs.org/docs/datatypes/numbers.html:
"""

Numbers

Math.js supports three types of numbers:

    Number for fast floating point arithmetic, described on this page.
    BigNumber for arbitrary precision arithmetic, described on the page BigNumbers.
    Fraction, which stores numbers in terms of a numerator and denominators, described on the page Fractions.

Configuration

Most functions can determine the type of output from the type of input: a number as input will return a number as output, a BigNumber as input returns a BigNumber as output. Functions which cannot determine the type of output from the input (for example math.evaluate) use the default number type, which can be configured when instantiating math.js:

math.config({
  number: 'number' // Default type of number: 
                   // 'number' (default), 'BigNumber', or 'Fraction'
})

Round-off errors

Math.js uses the built-in JavaScript Number type. A Number is a floating point number with a limited precision of 64 bits, about 16 digits. The largest integer number which can be represented by a JavaScript Number is +/- 9007199254740992 (+/- 2^53). Because of the limited precision of floating point numbers round-off errors can occur during calculations. This can be easily demonstrated:

// a round-off error
0.1 + 0.2            // 0.30000000000000004
math.add(0.1, 0.2)   // 0.30000000000000004

In most cases, round-off errors don’t matter: they have no significant impact on the results. However, it looks ugly when displaying output to a user. A solution is to limit the precision just below the actual precision of 16 digits in the displayed output:

// prevent round-off errors showing up in output
const ans = math.add(0.1, 0.2)     //  0.30000000000000004
math.format(ans, {precision: 14})  // '0.3'

Alternatives are to use Fractions which store a number as a numerator and denominator, BigNumbers which store a number with a higher precision, or bigint which can store larger integer numbers.
Minimum and maximum

A Number can store values between 5e-324 and 1.7976931348623157e+308. Values smaller than the minimum are stored as 0, and values larger than the maximum are stored as +/- Infinity.

// exceeding the maximum and minimum number
console.log(1e309)   // Infinity
console.log(1e-324)  // 0

Equality

Because of rounding errors in calculations, it is unsafe to compare JavaScript Numbers. For example executing 0.1 + 0.2 == 0.3 in JavaScript will return false, as the addition 0.1 + 0.2 introduces a round-off error and does not return exactly 0.3.

To solve this problem, the relational functions of math.js check whether the relative and absolute differences between the compared values is smaller than the configured option relTol and absTol. In pseudo code (without exceptions for 0, Infinity and NaN):

abs(a-b) <= max(relTol * max(abs(a), abs(b)), absTol)

where:

    relTol is the relative tolerance between x and y and absTol the absolute tolerance. Relative tolerance and absolute tolerance are configurable and are 1e-12 and 1e-15 respectively by default. See Configuration.
    DBL_EPSILON is the minimum positive floating point number such that 1.0 + DBL_EPSILON !== 1.0. This is a constant with a value of approximately 2.2204460492503130808472633361816e-16.

Note that the relational functions cannot be used to compare small values (< 2.22e-16). These values are all considered equal to zero.

Examples:

// compare values having a round-off error
console.log(0.1 + 0.2 === 0.3)           // false
console.log(math.equal(0.1 + 0.2, 0.3))  // true

// small values (< 2.22e-16) cannot be compared
console.log(3e-20 === 3.1e-20)           // false
console.log(math.equal(3e-20, 3.1e-20))  // true

The available relational functions are: compare, equal, larger, largerEq, smaller, smallerEq, unequal.

""".

mathjs.org/docs/datatypes/bignumbers.html:
"""

BigNumbers

For calculations with an arbitrary precision, math.js supports a BigNumber datatype. BigNumber support is powered by decimal.js.
Usage

A BigNumber can be created using the function bignumber:

math.bignumber('2.3e+500') // BigNumber, 2.3e+500

Most functions can determine the type of output from the type of input: a number as input will return a number as output, a BigNumber as input returns a BigNumber as output. Functions which cannot determine the type of output from the input (for example math.evaluate) use the default number type number, which can be configured when instantiating math.js. To configure the use of BigNumbers instead of numbers by default, configure math.js like:

math.config({
  number: 'BigNumber',      // Default type of number:
                            // 'number' (default), 'BigNumber', or 'Fraction'
  precision: 64,            // Number of significant digits for BigNumbers
  relTol: 1e-60,
  absTol: 1e-63
})

// use math
math.evaluate('0.1 + 0.2')  // BigNumber, 0.3

The default precision for BigNumber is 64 digits, and can be configured with the option precision.

Note that we also change the configuration of relTol and absTol to be close to the precision limit of our BigNumbers. relTol and absTol are used for example in relational and rounding functions (equal, larger, smaller, round, floor, etc) to determine when a value is nearly equal, see Equality. If we would leave relTol and absTol unchanged, having the default value of 1e-12 and 1e-15 respectively, we could get inaccurate and misleading results since we’re now working with a higher precision.
Support

Most functions in math.js support BigNumbers, but not all of them. For example the function random doesn’t support BigNumbers.
Round-off errors

Calculations with BigNumber are much slower than calculations with Number, but they can be executed with an arbitrary precision. By using a higher precision, it is less likely that round-off errors occur:

// round-off errors with numbers
math.add(0.1, 0.2)                                     // Number, 0.30000000000000004
math.divide(0.3, 0.2)                                  // Number, 1.4999999999999998

// no round-off errors with BigNumbers :)
math.add(math.bignumber(0.1), math.bignumber(0.2))     // BigNumber, 0.3
math.divide(math.bignumber(0.3), math.bignumber(0.2))  // BigNumber, 1.5

Limitations

It’s important to realize that BigNumbers do not solve all problems related to precision and round-off errors. Numbers with an infinite number of digits cannot be represented with a regular number nor a BigNumber. Though a BigNumber can store a much larger number of digits, the amount of digits remains limited if only to keep calculations fast enough to remain practical.

const one = math.bignumber(1)
const three = math.bignumber(3)
const third = math.divide(one, three)
console.log(third.toString())
// outputs 0.3333333333333333333333333333333333333333333333333333333333333333

const ans = math.multiply(third, three)
console.log(ans.toString())
// outputs 0.9999999999999999999999999999999999999999999999999999999999999999
// this should be 1 again, but `third` is rounded to a limited number of digits 3

Conversion

BigNumbers can be converted to numbers and vice versa using the functions number and bignumber. When converting a BigNumber to a number, the high precision of the BigNumber will be lost. When a BigNumber is too large to be represented as Number, it will be initialized as Infinity.

// converting numbers and BigNumbers
const a = math.number(0.3)                         // number, 0.3
const b = math.bignumber(a)                        // BigNumber, 0.3
const c = math.number(b)                           // number, 0.3

// exceeding the maximum of a number
const d = math.bignumber('1.2e500')                // BigNumber, 1.2e+500
const e = math.number(d)                           // number, Infinity

// loosing precision when converting to number
const f = math.bignumber('0.2222222222222222222')  // BigNumber, 0.2222222222222222222
const g = math.number(f)                           // number,    0.2222222222222222

""".

mathjs.org/docs/datatypes/bigints.html:
"""

BigInts

For calculations with large integer numbers, math.js supports the built-in bigint data type.
Usage

A bigint can be created either by adding the suffix n to a number, using the BigInt constructor function, or using the util function math.bigint:

42n
BigInt('42')
math.bigint('42')

Most functions can determine the type of output from the type of input: a number as input will return a number as output, a bigint as input returns a bigint as output. Functions which cannot determine the type of output from the input (for example math.evaluate) use the default number type number, which can be configured when instantiating math.js. To configure the use of bigint instead of numbers by default, configure math.js like:

math.config({
  number: 'bigint'
})

// use math
math.evaluate('70000000000000000123')  // bigint 70000000000000000123n

Support

All basic arithmetic functions in math.js support bigint. Since bigint can only hold integer values, it is not applicable to for example trigonometric functions. When using a bigint in a function that does not support it, like sqrt, it will convert the bigint into a regular number and then execute the function:

math.sin(2n) // number 0.9092974268256817

Conversion

There are utility functions to convert a bigint into a number or BigNumber:

// convert a number to bigint or BigNumber
math.bigint(42)                    // bigint, 42n
math.bignumber(42)                 // BigNumber, 42

// convert a bigint to a number or BigNumber
math.number(42n)                   // number, 42
math.bignumber(42n)                // BigNumber, 42

// losing digits when converting to number
math.number(70000000000000000123n) // number, 7000000000000000000

""".

mathjs.org/docs/datatypes/fractions.html:
"""

Fractions

For calculations with fractions, math.js supports a Fraction data type. Fraction support is powered by fraction.js. Unlike numbers and BigNumbers, fractions can store numbers with infinitely repeating decimals, for example 1/3 = 0.3333333..., which can be represented as 0.(3), or 2/7 which can be represented as 0.(285714).
Usage

A Fraction can be created using the function fraction:

math.fraction('1/3')   // Fraction, 1/3
math.fraction(2, 3)    // Fraction, 2/3
math.fraction('0.(3)') // Fraction, 1/3

And can be used in functions like add and multiply like:

math.add(math.fraction('1/3'), math.fraction('1/6'))      // Fraction, 1/2
math.multiply(math.fraction('1/4'), math.fraction('1/2')) // Fraction, 1/8

Note that not all functions support fractions. For example trigonometric functions doesn’t support fractions. When not supported, the functions will convert the input to numbers and return a number as result.

Most functions will determine the type of output from the type of input: a number as input will return a number as output, a Fraction as input returns a Fraction as output. Functions which cannot determine the type of output from the input (for example math.evaluate) use the default number type number, which can be configured when instantiating math.js. To configure the use of fractions instead of numbers by default, configure math.js like:

// Configure the default type of number: 'number' (default), 'BigNumber', or 'Fraction'
math.config({
  number: 'Fraction'
})

// use the expression parser
math.evaluate('0.32 + 0.08') // Fraction, 2/5

Support

The following functions support fractions:

    Arithmetic functions: abs, add, ceil, cube, divide, dotDivide, dotMultiply, fix, floor, gcd, mod, multiply, round, sign, square, subtract, unaryMinus, unaryPlus.
    Construction functions: fraction.
    Relational functions: compare, deepEqual, equal, larger, largerEq, smaller, smallerEq, unequal.
    Utils functions: format.

Conversion

Fractions can be converted to numbers and vice versa using the functions number and fraction. When converting a Fraction to a number, precision may be lost when the value cannot represented in 16 digits.

// converting numbers and fractions
const a = math.number(0.3)                       // number, 0.3
const b = math.fraction(a)                       // Fraction, 3/10
const c = math.number(b)                         // number, 0.3

// loosing precision when converting to number: a fraction can represent
// a number with an infinite number of repeating decimals, a number just
// stores about 16 digits and cuts consecutive digits.
const d = math.fraction('2/5')                   // Fraction, 2/5
const e = math.number(d)                         // number, 0.4

""".

mathjs.org/docs/datatypes/complex_numbers.html:
"""

Complex Numbers

Math.js supports the creation, manipulation, and calculations with complex numbers. Support of complex numbers is powered by the library complex.js.

In mathematics, a complex number is an expression of the form a + bi, where a and b are real numbers and i represents the imaginary number defined as i^2 = -1. (In other words, i is the square root of -1.) The real number a is called the real part of the complex number, and the real number b is the imaginary part. For example, 3 + 2i is a complex number, having real part 3 and imaginary part 2. Complex numbers are often used in applied mathematics, control theory, signal analysis, fluid dynamics and other fields.
Usage

A complex number is created using the function math.complex. This function accepts:

    two numbers representing the real and imaginary part of the value,
    a single string containing a complex value in the form a + bi where a and b respectively represent the real and imaginary part of the complex number.
    an object with either properties re and im for the real and imaginary part of the value, or two properties r and phi containing the polar coordinates of a complex value. The function returns a Complex object.

Syntax:

math.complex(re: number) : Complex
math.complex(re: number, im: number) : Complex
math.complex(complex: Complex) : Complex
math.complex({re: Number, im: Number}) : Complex
math.complex({r: number, phi: number}) : Complex
math.complex({abs: number, arg: number}) : Complex
math.complex(str: string) : Complex

Examples:

const a = math.complex(2, 3)     // Complex 2 + 3i
a.re                             // Number 2
a.im                             // Number 3

const b = math.complex('4 - 2i') // Complex 4 - 2i
b.re = 5                         // Number 5
b                                // Complex 5 - 2i

Calculations

Most functions of math.js support complex numbers. Complex and real numbers can be used together.

const a = math.complex(2, 3)     // Complex 2 + 3i
const b = math.complex('4 - 2i') // Complex 4 - 2i

math.re(a)                       // Number 2
math.im(a)                       // Number 3
math.conj(a)                     // Complex 2 - 3i

math.add(a, b)                   // Complex 6 + i
math.multiply(a, 2)              // Complex 4 + 6i
math.sqrt(-4)                    // Complex 2i

API

A Complex object created by math.complex contains the following properties and functions:
complex.re

A number containing the real part of the complex number. Can be read and replaced.
complex.im

A number containing the imaginary part of the complex number. Can be read and replaced.
complex.clone()

Create a clone of the complex number.
complex.equals(other)

Test whether a complex number equals another complex value.

Two complex numbers are equal when both their real and imaginary parts are equal.
complex.neg()

Returns a complex number with a real part and an imaginary part equal in magnitude but opposite in sign to the current complex number.
complex.conjugate()

Returns a complex number with an equal real part and an imaginary part equal in magnitude but opposite in sign to the current complex number.
complex.inverse()

Returns a complex number that is inverse of the current complex number.
complex.toVector()

Get the vector representation of the current complex number. Returns an array of size 2.
complex.toJSON()

Returns a JSON representation of the complex number, with signature {mathjs: 'Complex', re: number, im: number}. Used when serializing a complex number, see Serialization.
complex.toPolar()

Get the polar coordinates of the complex number, returns an object with properties r and phi.
complex.toString()

Returns a string representation of the complex number, formatted as a + bi where a is the real part and b the imaginary part.
complex.format([precision: number])

Get a string representation of the complex number, formatted as a + bi where a is the real part and b the imaginary part. If precision is defined, the units value will be rounded to the provided number of digits.
Static methods

The following static methods can be accessed using math.Complex
Complex.fromJSON(json)

Revive a complex number from a JSON object. Accepts An object {mathjs: 'Complex', re: number, im: number}, where the property mathjs is optional. Used when deserializing a complex number, see Serialization.
Complex.fromPolar(r: number, phi: number)

Create a complex number from polar coordinates.
Complex.compare(a: Complex, b: Complex)

Returns the comparision result of two complex number:

    Returns 1 when the real part of a is larger than the real part of b
    Returns -1 when the real part of a is smaller than the real part of b
    Returns 1 when the real parts are equal and the imaginary part of a is larger than the imaginary part of b
    Returns -1 when the real parts are equal and the imaginary part of a is smaller than the imaginary part of b
    Returns 0 when both real and imaginary parts are equal.

Example:

const a = math.complex(2, 3)   // Complex 2 + 3i
const b = math.complex(2, 1)   // Complex 2 + 1i
math.Complex.compare(a,b) // returns 1

//create from json 
const c = math.Complex.fromJSON({mathjs: 'Complex', re: 4, im: 3})  // Complex 4 + 3i

""".

mathjs.org/docs/datatypes/matrices.html:
"""

Matrices

Math.js supports multi dimensional matrices and arrays. Matrices can be created, manipulated, and used in calculations. Both regular JavaScript arrays as well as the matrix type implemented by math.js can be used interchangeably in all relevant math.js functions. math.js supports both dense and sparse matrices.
Arrays and matrices

Math.js supports two types of matrices:

    Array, a regular JavaScript array. A multi dimensional array can be created by nesting arrays.
    Matrix, a matrix implementation by math.js. A Matrix is an object wrapped around a regular JavaScript Array, providing utility functions for easy matrix manipulation such as subset, size, resize, clone, and more.

In most cases, the type of matrix output from functions is determined by the function input: An Array as input will return an Array, a Matrix as input will return a Matrix. In case of mixed input, a Matrix is returned. For functions where the type of output cannot be determined from the input, the output is determined by the configuration option matrix, which can be a string 'Matrix' (default) or 'Array'.

// create an array and a matrix
const array = [[2, 0], [-1, 3]]               // Array
const matrix = math.matrix([[7, 1], [-2, 3]]) // Matrix

// perform a calculation on an array and matrix
math.map(array, math.square)                  // Array,  [[4, 0], [1, 9]]
math.map(matrix, math.square)                 // Matrix, [[49, 1], [4, 9]]

// perform calculations with mixed array and matrix input
math.add(array, matrix)                       // Matrix, [[9, 1], [-3, 6]]
math.multiply(array, matrix)                  // Matrix, [[14, 2], [-13, 8]]

// create a matrix. Type of output of function ones is determined by the
// configuration option `matrix`
math.ones(2, 3)                               // Matrix, [[1, 1, 1], [1, 1, 1]]

Creation

A matrix can be created from an array using the function math.matrix. The provided array can contain nested arrays in order to create a multi-dimensional matrix. When called without arguments, an empty matrix will be created.

// create matrices
math.matrix()                           // Matrix, size [0]
math.matrix([0, 1, 2])                  // Matrix, size [3]
math.matrix([[0, 1], [2, 3], [4, 5]])   // Matrix, size [3, 2]

Math.js supports regular Arrays. Multiple dimensions can be created by nesting Arrays in each other.

// create arrays
[]                                      // Array, size [0]
[0, 1, 2]                               // Array, size [3]
[[0, 1], [2, 3], [4, 5]]                // Array, size [3, 2]

Matrices can contain different types of values: numbers, complex numbers, units, or strings. Different types can be mixed together in a single matrix.

// create a matrix with mixed types
const a = math.matrix([2.3, 'hello', math.complex(3, -4), math.unit('5.2 mm')]) 
a.subset(math.index(1))  // 'hello'

There are a number of functions to create a matrix with a specific size and content: ones, zeros, identity.

// zeros creates a matrix filled with zeros
math.zeros(3)           // Matrix, size [3],    [0, 0, 0]
math.zeros(3, 2)        // Matrix, size [3, 2], [[0, 0], [0, 0], [0, 0]]
math.zeros(2, 2, 2)     // Matrix, size [2, 2, 2],
                        //   [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]

// ones creates a matrix filled with ones
math.ones(3)                        // Matrix, size [3],    [1, 1, 1]
math.multiply(math.ones(2, 2), 5)   // Matrix, size [2, 2], [[5, 5], [5, 5]]

// identity creates an identity matrix
math.identity(3)      // Matrix, size [3, 3], [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
math.identity(2, 3)   // Matrix, size [2, 3], [[1, 0, 0], [0, 1, 0]]

The functions ones, zeros, and identity also accept a single array or matrix containing the dimensions for the matrix. When the input is an Array, the functions will output an Array. When the input is a Matrix, the output will be a Matrix. Note that in case of numbers as arguments, the output is determined by the option matrix as discussed in section Arrays and matrices.

// Array as input gives Array as output
math.ones([2, 3])               // Array,  size [3, 2], [[1, 1, 1], [1, 1, 1]]
math.ones(math.matrix([2, 3]))  // Matrix, size [3, 2], [[1, 1, 1], [1, 1, 1]]

Ranges can be created using the function range. The function range is called with parameters start and end, and optionally a parameter step. The start of the range is included, the end of the range is excluded.

math.range(0, 4)        // [0, 1, 2, 3]
math.range(0, 8, 2)     // [0, 2, 4, 6]
math.range(3, -1, -1)   // [3, 2, 1, 0]

Calculations

Most functions of math.js support matrices and arrays. Unary functions can be applied element-wise using via math.map(matrix, function).

// perform an element-wise operation on a matrix using math.map
const a = math.matrix([1, 4, 9, 16, 25])  // Matrix, [1, 4, 9, 16, 25]
math.map(a, math.sqrt)                    // Matrix, [1, 2, 3, 4, 5]

// use a function that has built-in matrix and array support
const b = [1, 2, 3, 4, 5] 
math.factorial(b)                         // Array,  [1, 2, 6, 24, 120]

// multiply an array with a matrix
const c = [[2, 0], [-1, 3]]               // Array
const d = math.matrix([[7, 1], [-2, 3]])  // Matrix
math.multiply(c, d)                       // Matrix, [[14, 2], [-13, 8]]

// add a number to a matrix (see broadcasting)
math.add(c, 2)                            // Array, [[4, 2], [1, 5]]

// calculate the determinant of a matrix
math.det(c)                               // 6
math.det(d)                               // 23

Broadcasting

Functions that require two or more matrix like arguments that operate elementwise automatically operate as if the arguments were the same size.

A = math.matrix([1, 2])       // Matrix, [1, 2]
math.add(A, 3)                // Matrix, [3, 4]

B = math.matrix([[3], [4]])   // Matrix, [[3], [4]]
math.add(A, B)                // Matrix, [[4, 5], [5, 6]]

Any index that is in one of the arguments, can be found as if it existed on the others when the size on that dimension is one or not existing. This is valid in N dimensions.

It’s not possible to broadcast in cases where the size in that dimension is higher than one.

math.add([1, 2], [3, 4, 5])
// Error: shape missmatch: missmatch is found in arg with shape (2) not possible to broadcast dimension 0 with size 2 to size 3

math.add([[1], [2], [3]], [[4], [5]])
// Error: shape missmatch: missmatch is found in arg with shape (2,1) not possible to broadcast dimension 0 with size 2 to size 3

Size and Dimensions

Math.js uses geometric dimensions:

    A scalar is zero-dimensional.
    A vector is one-dimensional.
    A matrix is two or multi-dimensional.

The size of a matrix can be calculated with the function size. Function size returns a Matrix or Array, depending on the configuration option matrix. Furthermore, matrices have a function size as well, which always returns an Array.

// get the size of a scalar
math.size(2.4)                                // Matrix, []
math.size(math.complex(3, 2))                 // Matrix, []
math.size(math.unit('5.3 mm'))                // Matrix, []

// get the size of a one-dimensional matrix (a vector) and a string
math.size([0, 1, 2, 3])                       // Array, [4]
math.size('hello world')                      // Matrix, [11]

// get the size of a two-dimensional matrix
const a = [[0, 1, 2, 3]]                      // Array
const b = math.matrix([[0, 1, 2], [3, 4, 5]]) // Matrix
math.size(a)                                  // Array, [1, 4]
math.size(b)                                  // Matrix, [2, 3]

// matrices have a function size (always returns an Array)
b.size()                                      // Array, [2, 3]

// get the size of a multi-dimensional matrix
const c = [[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]]]
math.size(c)                                  // Array, [2, 2, 3]

Note that the dimensions themselves do not have a meaning attached. When creating and printing a two dimensional matrix, the first dimension is normally rendered as the column, and the second dimension is rendered as the row. For example:

console.table(math.zeros([2, 4]))
// 0 0 0 0
// 0 0 0 0

If you have a matrix where the first dimension means x and the second means y, this will look confusing since x is printed as column (vertically) and y as row (horizontally).
Resizing

Matrices can be resized using their resize function. This function is called with an Array with the new size as the first argument, and accepts an optional default value. By default, new entries will be set to 0, but it is possible to pass a different default value like null to clearly indicate that the entries haven’t been explicitly set.

const a = math.matrix() // Matrix, size [0],       []
a.resize([2, 3])        // Matrix, size [2, 3],    [[0, 0, 0], [0, 0, 0]]
a.resize([2, 2, 2])     // Matrix, size [2, 2, 2],
                        //   [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]

const b = math.matrix()
b.resize([3], 7)        // Matrix, size [3],    [7, 7, 7]
b.resize([5], 9)        // Matrix, size [5],    [7, 7, 7, 9, 9]
b.resize([2])           // Matrix, size [2],    [7, 7]

Outer dimensions of a matrix can be squeezed using the function squeeze. When getting or setting a single value in a matrix using subset, the value is automatically squeezed or unsqueezed too.

// squeeze a matrix
const a = [[[0, 1, 2]]]
math.squeeze(a)             // [0, 1, 2]
math.squeeze([[3]])         // 3

// when getting/setting a single value in a matrix using subset, 
// it automatically squeeze/unsqueeze the value
const b = math.matrix([[0, 1], [2, 3]])
b.subset(math.index(1, 0))  // 2 and not [[2]]

Getting or replacing subsets

Subsets of a matrix can be retrieved or replaced using the function subset. Matrices have a subset function, which is applied to the matrix itself: Matrix.subset(index [, replacement]). For both matrices and arrays, the static function subset(matrix, index [, replacement]) can be used. When parameter replacement is provided, the function will replace a subset in the matrix, and if not, a subset of the matrix will be returned.

A subset can be defined using an Index. An Index contains a single value or a set of values for each dimension of a matrix. An Index can be created using the function index. When getting a single value from a matrix, subset will return the value itself instead of a matrix containing just this value.

The function subset normally returns a subset, but when getting or setting a single value in a matrix, the value itself is returned.

Matrix indexes in math.js are zero-based, like most programming languages including JavaScript itself. Note that mathematical applications like Matlab and Octave work differently, as they use one-based indexes.

// create some matrices
const a = [0, 1, 2, 3]
const b = [[0, 1], [2, 3]]
const c = math.zeros(2, 2)
const d = math.matrix([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
const e = math.matrix()

// get a subset
math.subset(a, math.index(1))                 // 1
math.subset(a, math.index([2, 3]))            // Array, [2, 3]
math.subset(a, math.index(math.range(0,4)))   // Array, [0, 1, 2, 3]
math.subset(b, math.index(1, 0))              // 2
math.subset(b, math.index(1, [0, 1]))         // Array, [2, 3]
math.subset(b, math.index([0, 1], 0))         // Matrix, [[0], [2]]

// get a subset
d.subset(math.index([1, 2], [0, 1]))          // Matrix, [[3, 4], [6, 7]]
d.subset(math.index(1, 2))                    // 5

// replace a subset. The subset will be applied to a clone of the matrix
math.subset(b, math.index(1, 0), 9)           // Array, [[0, 1], [9, 3]]
math.subset(b, math.index(2, [0, 1]), [4, 5]) // Array, [[0, 1], [2, 3], [4, 5]]

// replace a subset. The subset will be applied to the matrix itself
c.subset(math.index(0, 1),1)                  // Matrix, [[0, 1], [0, 0]]
c.subset(math.index(1, [0, 1]), [2, 3])       // Matrix, [[0, 1], [2, 3]]
e.resize([2, 3], 0)                           // Matrix, [[0, 0, 0], [0, 0, 0]]
e.subset(math.index(1, 2), 5)                 // Matrix, [[0, 0, 0], [0, 0, 5]]

Getting and setting a value in a matrix

There are two methods available on matrices that allow to get or set a single value inside a matrix. It is important to note that the set method will mutate the matrix.

const p = math.matrix([[1, 2], [3, 4]])
p.set([0, 1], 5)
// p is now [[1, 5], [3, 4]]
p.get([1, 0]) // 3

When setting a value at a location outside of the current matrix size using the method .set(), the matrix will be resized. By default, new items will be initialized with zero, but it is possible to specify an alternative value using the optional third argument defaultValue.
Advanced Indexing

Boolean array indexing is a technique that allows you to filter, replace, and set values in an array based on logical conditions. This can be done by creating a boolean array that represents the desired conditions, and then using that array as an index to select the elements of the original array that meet those conditions.

For example, a boolean array can be created to represent all the even numbers in an array, and then used to filter the original array to only include the even numbers. Alternatively, a boolean array can be created to represent all the elements of an array that are greater than a certain value, and then used to replace all the elements of the original array that are greater than that value with a new value.

const q = [1, 2, 3, 4]
math.subset(q, math.index([true, false, true, false]))      // Array [1, 3]

// filtering
math.subset(q, math.index(math.larger(q, 2)))               // Array [3, 4]

// filtering with no matches
math.subset(q, math.index(math.larger(q, 5)))               // Array []

// setting specific values, please note that the replacement value is broadcasted
q = math.subset(q, math.index(math.smaller(q, 3)), 0)       // q = [0, 0, 3, 4]

// replacing specific values
math.subset(q, math.index(math.equal(q, 0)), [1, 2])        // q = [1, 2, 3, 4]

The same can be accomplished in the parser in a much more compact manner. Please note that everything after # are comments.

math.evaluate(`
q = [1, 2, 3, 4]
q[[true, false, true, false]] # Matrix [1, 3]
q[q>2]                        # Matrix [3, 4]
q[q>5]                        # Matrix []
q[q <3] = 0                   # q = [0, 0, 3, 4]
q[q==0] = [1, 2]              # q = [1, 2, 3, 4]
`)

The expression inside the index can be as complex as needed as long it evaluates to an array of booleans of the same size.

math.evaluate(`
q = [1, 2, 3, 4]
r = [6, 5, 4, 3]
q[q > 3 and r < 4]     # [4]
`)

Iterating

Matrices contain functions map and forEach to iterate over all elements of the (multidimensional) matrix. The callback function of map and forEach has three parameters: value (the value of the currently iterated element), index (an array with the index value for each dimension), and matrix (the matrix being iterated). This syntax is similar to the map and forEach functions of native JavaScript Arrays, except that the index is no number but an Array with numbers for each dimension.

const a = math.matrix([[0, 1], [2, 3], [4, 5]])

// The iteration below will output the following in the console:
//    value: 0 index: [0, 0]
//    value: 1 index: [0, 1]
//    value: 2 index: [1, 0]
//    value: 3 index: [1, 1]
//    value: 4 index: [2, 0]
//    value: 5 index: [2, 1]
a.forEach(function (value, index, matrix) {
  console.log('value:', value, 'index:', index) 
}) 

// Apply a transformation on the matrix
const b = a.map(function (value, index, matrix) {
  return math.multiply(math.sin(value), math.exp(math.abs(value))) 
}) 
console.log(b.format(5))  // [[0, 2.2874], [6.7188, 2.8345], [-41.32, -142.32]]

// Create a matrix with the cumulative of all elements
let count = 0
const cum = a.map(function (value, index, matrix) {
  count += value 
  return count 
}) 
console.log(cum.toString())  // [[0, 1], [3, 6], [10, 15]]

Iterating over multiple Matrixes or Arrays

You can iterate over multiple matrices or arrays by using the map function. Mapping allows to perform element-wise operations on matrices by automatically adjusting their sizes to match each other.

To iterate over multiple matrices, you can use the map function. The map function applies a given function to each element of the matrices and returns a new matrix with the results.

Here’s an example of iterating over two matrices and adding their corresponding elements:

const a = math.matrix([[1, 2], [3, 4]]);
const b = math.matrix([[5, 6], [7, 8]]);

const result = math.map(a, b, (x, y) => x + y);

console.log(result); // [[6, 8], [10, 12]]

In this example, the map function takes matrices as the first two arguments and a callback function (x, y) => x + y as the third argument. The callback function is applied to each element of the matrices, where x represents the corresponding element from matrix a and y represents the corresponding element from matrix b. The result is a new matrix with the element-wise sum of the two matrices.

By using broadcasting and the map function, you can easily iterate over multiple matrices and perform element-wise operations.

const a = math.matrix([10, 20])
const b = math.matrix([[3, 4], [5, 6]])

const result = math.map(a, b, (x, y) => x + y)
console.log(result); // [[13, 24], [15, 26]]

It’s also possible to provide a callback with an index and the broadcasted arrays. Like (valueA, valueB, index) or even (valueA, valueB, index, broadcastedMatrixA, broadcastedMatrixB). There is no specific limit for the number of matrices N that can be mapped. Thus, the callback can have N arguments, N+1 arguments in the case of including the index, or 2N+1 arguments in the case of including the index and the broadcasted matrices in the callback.

At this moment forEach doesn’t include the same functionality.
Storage types

Math.js supports both dense matrices as well as sparse matrices. Sparse matrices are efficient for matrices largely containing zeros. In that case they save a lot of memory, and calculations can be much faster than for dense matrices.

Math.js supports two type of matrices:

    Dense matrix ('dense', default) A regular, dense matrix, supporting multi-dimensional matrices. This is the default matrix type.
    Sparse matrix ('sparse'): A two dimensional sparse matrix implementation.

The type of matrix can be selected when creating a matrix using the construction functions matrix, diag, identity, ones, and zeros.

// create sparse matrices
const m1 = math.matrix([[0, 1], [0, 0]], 'sparse')
const m2 = math.identity(1000, 1000, 'sparse')

You can also coerce an array or matrix into sparse storage format with the sparse function.

const md = math.matrix([[0, 1], [0,0]])  // dense
const ms = math.sparse(md)               // sparse

Caution: sparse called on a JavaScript array of n plain numbers produces a matrix with one column and n rows – in contrast to matrix, which produces a 1-dimensional matrix object with n entries, i.e., a vector (not a 1 by n “row vector” nor an n by 1 “column vector”, but just a plain vector of length n).

const mv = math.matrix([0, 0, 1])  // Has size [3]
const mc = math.sparse([0, 0, 1])  // A "column vector," has size [3, 1]

API

All relevant functions in math.js support Matrices and Arrays. Functions like math.add and math.subtract, math.sqrt handle matrices element wise. There is a set of functions specifically for creating or manipulating matrices, such as:

    Functions like math.matrix and math.sparse, math.ones, math.zeros, and math.identity to create a matrix.
    Functions like math.subset and math.index to get or replace a part of a matrix
    Functions like math.transpose and math.diag to manipulate matrices.

A full list of matrix functions is available on the functions reference page.

Two types of matrix classes are available in math.js, for storage of dense and sparse matrices. Although they contain public functions documented as follows, using the following API directly is not recommended. Prefer using the functions in the “math” namespace wherever possible.

    DenseMatrix
    SparseMatrix

""".

mathjs.org/docs/datatypes/units.html:
"""
Units

Math.js supports units. Units can be used to do calculations and to perform conversions.
Usage

Units can be created using the function math.unit. This function accepts either a single string argument containing a value and unit, or two arguments, the first being a numeric value and the second a string containing a unit. Most units support prefixes like k or kilo, and many units have both a full name and an abbreviation. The returned object is a Unit.

Syntax:

math.unit(value: number, valuelessUnit: string) : Unit
math.unit(value: number, valuelessUnit: Unit) : Unit
math.unit(unit: string) : Unit
math.unit(unit: Unit) : Unit

Example usage:

const a = math.unit(45, 'cm')             // Unit 450 mm
const b = math.unit('0.1 kilogram')       // Unit 100 gram
const c = math.unit('2 inch')             // Unit 2 inch
const d = math.unit('90 km/h')            // Unit 90 km/h
const e = math.unit('101325 kg/(m s^2)')  // Unit 101325 kg / (m s^2)

const f = c.to('cm')                      // Unit 5.08 cm
b.toNumber('gram')                        // Number 100
math.number(b, 'gram')                    // Number 100

c.equals(a)                               // false
c.equals(f)                               // true
c.equalBase(a)                            // true
c.equalBase(b)                            // false

f.toString()                              // String "5.08 cm"

const kph = math.unit('km/h')             // valueless Unit km/h
const mps = math.unit('m/s')              // valueless Unit m/s
const speed = math.unit(36, kph)          // Unit 36 km/h
speed.toNumber(mps)                       // Number 10

Use care when creating a unit with multiple terms in the denominator. Implicit multiplication has the same operator precedence as explicit multiplication and division, which means these three expressions are identical:

// These three are identical
const correct1 = math.unit('8.314 m^3 Pa / mol / K')           // Unit 8.314 (m^3 Pa) / (mol K)
const correct2 = math.unit('8.314 (m^3 Pa) / (mol K)')         // Unit 8.314 (m^3 Pa) / (mol K)
const correct3 = math.unit('8.314 (m^3 * Pa) / (mol * K)')     // Unit 8.314 (m^3 Pa) / (mol K)

But this expression, which omits the second / between mol and K, results in the wrong value:

// Missing the second '/' between 'mol' and 'K'
const incorrect = math.unit('8.314 m^3 Pa / mol K')            // Unit 8.314 (m^3 Pa K) / mol

The function math.unit has its own small parser. This parser differs a bit from the expression parser math.evaluate, and returns the expected result in this case:

// using math.evaluate instead of math.unit
const correct4 = math.evaluate('8.314 (m^3 * Pa) / (mol * K)') // Unit 8.314 (m^3 Pa) / (mol K)

In summary: be careful with implicit multiplication. In case of doubt, always use an explicit * and parenthesis.
Calculations

The operations that support units are add, subtract, multiply, divide, pow, abs, sqrt, square, cube, and sign. Trigonometric functions like cos are also supported when the argument is an angle.

const a = math.unit(45, 'cm')       // Unit 450 mm
const b = math.unit('0.1m')         // Unit 100 mm
math.add(a, b)                      // Unit 0.55 m
math.multiply(b, 2)                 // Unit 200 mm

const c = math.unit(45, 'deg')      // Unit 45 deg
math.cos(c)                         // Number 0.7071067811865476

// Kinetic energy of average sedan on highway
const d = math.unit('80 mi/h')      // Unit 80 mi/h
const e = math.unit('2 tonne')      // Unit 2 tonne
const f = math.multiply(0.5, math.multipy(math.pow(d, 2), e))
                                    // 1.2790064742399996 MJ

Operations with arrays are supported too:

// Force on a charged particle moving through a magnetic field
const B = math.evaluate('[1, 0, 0] T')         // [1 T, 0 T, 0 T]
const v = math.evaluate('[0, 1, 0] m/s')       // [0 m / s, 1 m / s, 0 m / s]
const q = math.evaluate('1 C')                 // 1 C

const F = math.multiply(q, math.cross(v, B))   // [0 N, 0 N, -1 N]

All arithmetic operators act on the value of the unit as it is represented in SI units. This may lead to surprising behavior when working with temperature scales like celsius (or degC) and fahrenheit (or degF). In general, you should avoid calculations using celsius and fahrenheit. Rather, use kelvin (or K) and rankine (or degR) instead. This example highlights some problems when using celsius and fahrenheit in calculations:

const T_14F = math.unit('14 degF')            // Unit 14 degF (263.15 K)
const T_28F = math.multiply(T_14F, 2)         // Unit 28 degF (270.93 K), not 526.3 K

const Tnegative = math.unit(-13, 'degF')      // Unit -13 degF (248.15 K)
const Tpositive = math.abs(Tnegative)         // Unit -13 degF (248.15 K), not 13 degF

The expression parser supports units too. This is described in the section about units on the page Syntax.
User-Defined Units

You can add your own units to Math.js using the math.createUnit function. The following example defines a new unit furlong, then uses the user-defined unit in a calculation:

math.createUnit('furlong', '220 yards')
math.evaluate('1 mile to furlong')            // 8 furlong

If you cannot express the new unit in terms of any existing unit, then the second argument can be omitted. In this case, a new base unit is created:

// A 'foo' cannot be expressed in terms of any other unit.
math.createUnit('foo')
math.evaluate('8 foo * 4 feet')               // 32 foo feet

The second argument to createUnit can also be a configuration object consisting of the following properties:

    definition A string or Unit which defines the user-defined unit in terms of existing built-in or user-defined units. If omitted, a new base unit is created.
    prefixes A string indicating which prefixes math.js should use with the new unit. Possible values are 'none', 'short', 'long', 'binary_short', or 'binary_long'. Default is 'none'.
    offset A value applied when converting to the unit. This is very helpful for temperature scales that do not share a zero with the absolute temperature scale. For example, if we were defining fahrenheit for the first time, we would use: math.createUnit('fahrenheit', {definition: '0.555556 kelvin', offset: 459.67})
    aliases An array of strings to alias the new unit. Example: math.createUnit('knot', {definition: '0.514444 m/s', aliases: ['knots', 'kt', 'kts']})
    baseName A string that specifies the name of the new dimension in case one needs to be created. Every unit in math.js has a dimension: length, time, velocity, etc. If the unit’s definition doesn’t match any existing dimension, or it is a new base unit, then createUnit will create a new dimension with the name baseName and assign it to the new unit. The default is to append '_STUFF' to the unit’s name. If the unit already matches an existing dimension, this option has no effect.

An optional options object can also be supplied as the last argument to createUnits. Currently only the override option is supported:

// Redefine the mile (would not be the first time in history)
math.createUnit('mile', '1609.347218694 m', {override: true})

Base units created without specifying a definition cannot be overridden.
Create several units at once

Multiple units can defined using a single call to createUnit by passing an object map as the first argument, where each key in the object is the name of a new unit and the value is either a string defining the unit, or an object with the configuration properties listed above. If the value is an empty string or an object lacking a definition property, a new base unit is created.

For example:

math.createUnit( {
  foo: {
    prefixes: 'long',
    baseName: 'essence-of-foo'
  },
  bar: '40 foo',
  baz: {
    definition: '1 bar/hour',
    prefixes: 'long'
  }
},
{
  override: true
})
math.evaluate('50000 kilofoo/s')  // 4.5 gigabaz

Return Value

createUnit returns the created unit, or, when multiple units are created, the last unit created. Since createUnit is also compatible with the expression parser, this allows you to do things like this:

math.evaluate('45 mile/hour to createUnit("knot", "0.514444m/s")')
// 39.103964668651976 knot

Support of custom characters in unit names

Per default, the name of a new unit:

    should start by a latin (A-Z or a-z) character
    should contain only numeric (0-9) or latin characters

It is possible to allow the usage of special characters (such as Greek alphabet, cyrillic alphabet, any Unicode symbols, etc.) by overriding the Unit.isValidAlpha static method. For example:

const isAlphaOriginal = math.Unit.isValidAlpha
const isGreekLowercaseChar = function (c) {
  const charCode = c.charCodeAt(0)
  return charCode > 944 && charCode < 970
}
math.Unit.isValidAlpha = function (c) {
  return isAlphaOriginal(c) || isGreekLowercaseChar(c)
}

math.createUnit('θ', '1 rad')
math.evaluate('1θ + 3 deg').toNumber('deg') // 60.29577951308232

Numeric type of the value of a unit

The built-in units are always created with a value being a number. To turn the value into for example a BigNumber or Fraction, you can convert the value using the function math.fraction and math.bignumber:

math.unit(math.fraction(10), 'inch').toNumeric('cm')  // Fraction 127/5
math.fraction(math.unit(10, 'inch')).toNumeric('cm')  // Fraction 127/5

math.bignumber(math.unit(10, 'inch')).toNumeric('cm') // BigNumber 25.4
math.unit(math.bignumber(10), 'inch').toNumeric('cm') // BigNumber 25.4

When using the expression parser, it is possible to configure numeric values to be parsed as Fraction or BigNumber:

math.config({ number: 'Fraction' })
math.evaluate('10 inch').toNumeric('cm') // Fraction 127/5

API

A Unit object contains the following functions:
unit.clone()

Clone the unit, returns a new unit with the same parameters.
unit.equalBase(unit)

Test whether a unit has the same base as an other unit: length, mass, etc.
unit.equals(unit)

Test whether a unit equals an other unit. Units are equal when they have the same base and same value when normalized to SI units.
unit.format([options])

Get a string representation of the unit. The function will determine the best fitting prefix for the unit. See the Format page for available options.
unit.fromJSON(json)

Revive a unit from a JSON object. Accepts An object {mathjs: 'Unit', value: number, unit: string, fixPrefix: boolean}, where the property mathjs and fixPrefix are optional. Used when deserializing a unit, see Serialization.
unit.splitUnit(parts)

Split a unit into the specified parts. For example:

const u = math.unit(1, 'm')
u.splitUnit(['ft', 'in'])    // 3 feet,3.3700787401574765 inch

unit.to(unitName)

Convert the unit to a specific unit name. Returns a clone of the unit with a fixed prefix and unit.
unit.toJSON()

Returns a JSON representation of the unit, with signature {mathjs: 'Unit', value: number, unit: string, fixPrefix: boolean}. Used when serializing a unit, see Serialization.
unit.toNumber(unitName)

Get the value of a unit when converted to the specified unit (a unit with optional prefix but without value). The type of the returned value is always number.
unit.toNumeric(unitName)

Get the value of a unit when converted to the specified unit (a unit with optional prefix but without value). The type of the returned value depends on how the unit was created and can be number, Fraction, or BigNumber.
unit.toSI()

Returns a clone of a unit represented in SI units. Works with units with or without a value.
unit.toString()

Get a string representation of the unit. The function will determine the best fitting prefix for the unit.
unit.valType()

Get the string name of the current type of the value of this Unit object, e.g. ‘number’, ‘BigNumber’, etc.
Unit reference

This section lists all available units, prefixes, and physical constants. These can be used via the Unit object, or via math.evaluate().
Reference

Math.js comes with the following built-in units.
Base 	Unit
Length 	meter (m), inch (in), foot (ft), yard (yd), mile (mi), link (li), rod (rd), chain (ch), angstrom, mil
Surface area 	m2, sqin, sqft, sqyd, sqmi, sqrd, sqch, sqmil, acre, hectare
Volume 	m3, litre (l, L, lt, liter), cc, cuin, cuft, cuyd, teaspoon, tablespoon
Liquid volume 	minim, fluiddram (fldr), fluidounce (floz), gill (gi), cup (cp), pint (pt), quart (qt), gallon (gal), beerbarrel (bbl), oilbarrel (obl), hogshead, drop (gtt)
Angles 	rad (radian), deg (degree), grad (gradian), cycle, arcsec (arcsecond), arcmin (arcminute)
Time 	second (s, secs, seconds), minute (min, mins, minutes), hour (h, hr, hrs, hours), day (days), week (weeks), month (months), year (years), decade (decades), century (centuries), millennium (millennia)
Frequency 	hertz (Hz)
Mass 	gram(g), tonne, ton, grain (gr), dram (dr), ounce (oz), poundmass (lbm, lb, lbs), hundredweight (cwt), stick, stone
Electric current 	ampere (A)
Temperature 	kelvin (K), celsius (degC), fahrenheit (degF), rankine (degR)
Amount of substance 	mole (mol)
Luminous intensity 	candela (cd)
Force 	newton (N), dyne (dyn), poundforce (lbf), kip
Energy 	joule (J), erg, Wh, BTU, electronvolt (eV)
Power 	watt (W), hp
Pressure 	Pa, psi, atm, torr, bar, mmHg, mmH2O, cmH2O
Electricity and magnetism 	ampere (A), coulomb (C), watt (W), volt (V), ohm, farad (F), weber (Wb), tesla (T), henry (H), siemens (S), electronvolt (eV)
Binary 	bits (b), bytes (B)

Note: all time units are based on the Julian year, with one month being 1/12th of a Julian year, a year being one Julian year, a decade being 10 Julian years, a century being 100, and a millennium being 1000.

Note that all relevant units can also be written in plural form, for example 5 meters instead of 5 meter or 10 seconds instead of 10 second.

Surface and volume units can alternatively be expressed in terms of length units raised to a power, for example 100 in^2 instead of 100 sqin.
Prefixes

The following decimal prefixes are available.
Name 	Abbreviation 	Value
deca 	da 	1e1
hecto 	h 	1e2
kilo 	k 	1e3
mega 	M 	1e6
giga 	G 	1e9
tera 	T 	1e12
peta 	P 	1e15
exa 	E 	1e18
zetta 	Z 	1e21
yotta 	Y 	1e24
ronna 	R 	1e27
quetta 	Q 	1e30
Name 	Abbreviation 	Value
deci 	d 	1e-1
centi 	c 	1e-2
milli 	m 	1e-3
micro 	u 	1e-6
nano 	n 	1e-9
pico 	p 	1e-12
femto 	f 	1e-15
atto 	a 	1e-18
zepto 	z 	1e-21
yocto 	y 	1e-24
ronto 	r 	1e-27
quecto 	q 	1e-30

The following binary prefixes are available. They can be used with units bits (b) and bytes (B).
Name 	Abbreviation 	Value
kibi 	Ki 	1024
mebi 	Mi 	1024^2
gibi 	Gi 	1024^3
tebi 	Ti 	1024^4
pebi 	Pi 	1024^5
exi 	Ei 	1024^6
zebi 	Zi 	1024^7
yobi 	Yi 	1024^8
Name 	Abbreviation 	Value
kilo 	k 	1e3
mega 	M 	1e6
giga 	G 	1e9
tera 	T 	1e12
peta 	P 	1e15
exa 	E 	1e18
zetta 	Z 	1e21
yotta 	Y 	1e24
Physical Constants

Math.js includes the following physical constants. See Wikipedia for more information.
Universal constants
Name 	Symbol 	Value 	Unit
speedOfLight 	c 	299792458 	m · s-1
gravitationConstant 	G 	6.6738480e-11 	m3 · kg-1 · s-2
planckConstant 	h 	6.626069311e-34 	J · s
reducedPlanckConstant 	h 	1.05457172647e-34 	J · s
Electromagnetic constants
Name 	Symbol 	Value 	Unit
magneticConstant 	μ0 	1.2566370614e-6 	N · A-2
electricConstant 	ε0 	8.854187817e-12 	F · m-1
vacuumImpedance 	Z0 	376.730313461 	&ohm;
coulomb 	κ 	8.9875517873681764e9 	N · m2 · C-2
elementaryCharge 	e 	1.60217656535e-19 	C
bohrMagneton 	μB 	9.2740096820e-24 	J · T-1
conductanceQuantum 	G0 	7.748091734625e-5 	S
inverseConductanceQuantum 	G0-1 	12906.403721742 	&ohm;
magneticFluxQuantum 	f0 	2.06783375846e-15 	Wb
nuclearMagneton 	μN 	5.0507835311e-27 	J · T-1
klitzing 	RK 	25812.807443484 	&ohm;
Atomic and nuclear constants
Name 	Symbol 	Value 	Unit
bohrRadius 	a0 	5.291772109217e-11 	m
classicalElectronRadius 	re 	2.817940326727e-15 	m
electronMass 	me 	9.1093829140e-31 	kg
fermiCoupling 	GF 	1.1663645e-5 	GeV-2
fineStructure 	α 	7.297352569824e-3 	-
hartreeEnergy 	Eh 	4.3597443419e-18 	J
protonMass 	mp 	1.67262177774e-27 	kg
deuteronMass 	md 	3.3435830926e-27 	kg
neutronMass 	mn 	1.6749271613e-27 	kg
quantumOfCirculation 	h / (2me) 	3.636947552024e-4 	m2 · s-1
rydberg 	R∞ 	10973731.56853955 	m-1
thomsonCrossSection 	  	6.65245873413e-29 	m2
weakMixingAngle 	  	0.222321 	-
efimovFactor 	  	22.7 	-
Physico-chemical constants
Name 	Symbol 	Value 	Unit
atomicMass 	mu 	1.66053892173e-27 	kg
avogadro 	NA 	6.0221412927e23 	mol-1
boltzmann 	k 	1.380648813e-23 	J · K-1
faraday 	F 	96485.336521 	C · mol-1
firstRadiation 	c1 	3.7417715317e-16 	W · m2
loschmidt 	n0 	2.686780524e25 	m-3
gasConstant 	R 	8.314462175 	J · K-1 · mol-1
molarPlanckConstant 	NA · h 	3.990312717628e-10 	J · s · mol-1
molarVolume 	Vm 	2.241396820e-10 	m3 · mol-1
sackurTetrode 	  	-1.164870823 	-
secondRadiation 	c2 	1.438777013e-2 	m · K
stefanBoltzmann 	σ 	5.67037321e-8 	W · m-2 · K-4
wienDisplacement 	b 	2.897772126e-3 	m · K

Note that the values of loschmidt and molarVolume are at T = 273.15 K and p = 101.325 kPa. The value of sackurTetrode is at T = 1 K and p = 101.325 kPa.
Adopted values
Name 	Symbol 	Value 	Unit
molarMass 	Mu 	1e-3 	kg · mol-1
molarMassC12 	M(12C) 	1.2e-2 	kg · mol-1
gravity 	gn 	9.80665 	m · s-2
atm 	atm 	101325 	Pa
Natural units
Name 	Symbol 	Value 	Unit
planckLength 	lP 	1.61619997e-35 	m
planckMass 	mP 	2.1765113e-8 	kg
planckTime 	tP 	5.3910632e-44 	s
planckCharge 	qP 	1.87554595641e-18 	C
planckTemperature 	TP 	1.41683385e+32 	K

""".

mathjs.org/docs/reference/constants.html:
"""

Constant reference

Math.js contains the following constants.
Constant 	Description 	Value
e, E 	Euler’s number, the base of the natural logarithm. 	2.718281828459045
i 	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. 	sqrt(-1)
Infinity 	Infinity, a number which is larger than the maximum number that can be handled by a floating point number. 	Infinity
LN2 	Returns the natural logarithm of 2. 	0.6931471805599453
LN10 	Returns the natural logarithm of 10. 	2.302585092994046
LOG2E 	Returns the base-2 logarithm of E. 	1.4426950408889634
LOG10E 	Returns the base-10 logarithm of E. 	0.4342944819032518
NaN 	Not a number. 	NaN
null 	Value null. 	null
phi 	Phi is the golden ratio. Two quantities are in the golden ratio if their ratio is the same as the ratio of their sum to the larger of the two quantities. Phi is defined as (1 + sqrt(5)) / 2 	1.618033988749895
pi, PI 	The number pi is a mathematical constant that is the ratio of a circle's circumference to its diameter. 	3.141592653589793
SQRT1_2 	Returns the square root of 1/2. 	0.7071067811865476
SQRT2 	Returns the square root of 2. 	1.4142135623730951
tau 	Tau is the ratio constant of a circle's circumference to radius, equal to 2 * pi. 	6.283185307179586
undefined 	An undefined value. Preferably, use null to indicate undefined values. 	undefined
version 	Returns the version number of math.js. 	For example 0.24.1

Example usage:

math.sin(math.pi / 4)          // 0.70711
math.multiply(math.i, math.i)  // -1

""".

mathjs.org/docs/custom_bundling.html:
"""

Custom bundling

Math.js is a large library containing many data types and functions. It is well possible that you only need a small portion of the library. Math.js allows for picking just the functions and data types you need. This gives faster load times and smaller browser bundles. Math.js uses ES modules, and creating small bundles using tree-shaking works out of the box when using Webpack for example.

This page describes:

    How to use just a few functions for faster load times and smaller bundles.
    How to use light-weight, number only implementations of functions.
    What to expect from bundle sizes when using tree-shaking.

Using just a few functions

Using the function create, a mathjs instance can be created. The all object contains all functionality available in mathjs, and a mathjs instance containing everything can be created like:

import { create, all } from 'mathjs'

const math = create(all)

To create an instance with just a few functions, you have to pass the factory functions of the functions you need, and all their dependencies. For example the function add depends on the functions addScalar, equalScalar, classes DenseMatrix and SparseMatrix, and more. Because it is hard to figure out what the dependencies of a function are, and the dependencies of the dependencies, mathjs provides ready made collections of all dependencies for every function. For example all factory functions of function add and its dependencies are available as addDependencies.

Here is a full example of loading just a few functions in a mathjs instance:

// file: custom_loading.js

import {
  create,
  fractionDependencies,
  addDependencies,
  divideDependencies,
  formatDependencies
} from 'mathjs'

const config = {
  // optionally, you can specify configuration
}

// Create just the functions we need
const { fraction, add, divide, format } = create({
  fractionDependencies,
  addDependencies,
  divideDependencies,
  formatDependencies
}, config)

// Use the created functions
const a = fraction(1, 3)
const b = fraction(3, 7)
const c = add(a, b)
const d = divide(a, b)
console.log('c =', format(c)) // outputs "c = 16/21"
console.log('d =', format(d)) // outputs "d = 7/9"

This example can be bundled using for example Webpack:

npx webpack custom_loading.js -o custom_loading.bundle.js --mode=production

Only the used parts of mathjs will be bundled thanks to tree-shaking.
Numbers only

The functions of mathjs support multiple data types out of the box, like numbers, bignumbers, complex numbers, units, and matrices. Quite commonly however, only support for numbers is needed and the other data-types are overkill.

To accomodate for this use case where just the JavaScript number type suffices, mathjs offers light-weight, number-only implementations of all relevant functions. These are available by importing from 'mathjs/number' instead of 'mathjs':

// use light-weight, number-only implementations of functions
import { create, all } from 'mathjs/number'

const math = create(all)
console.log(math.add(2, 3)) // 5

Bundle size

When using just a few functions of mathjs instead of the whole library, you may expect the size of the bundle to be just a small fraction of the complete library. However, to create the function add supporting all data types, all these data types must be included: Unit, BigNumber, Complex, DenseMatrix, SparseMatrix, etc. A rough idea of the size of different parts of mathjs:

    About 5% is coming from core functionality like create, import, factory, typed-function, etc.
    About 30% of the bundle size comes from the data classes Complex, BigNumber, Fraction, Unit, SparseMatrix, DenseMatrix.
    About 25% of the bundle size comes from the expression parser. Half of this comes from the embedded docs.
    About 40% comes from the about 200 built-in functions and some constants.

To get a better insight in what is in your JavaScript bundle, you can use a tool like source-map-explorer.

""".

mathjs.org/history.html:
"""
History
2024-03-06, 14.3.1

    Fix: #3350 cannot import a constant that is a complex number.

2024-02-28, 14.3.0

    Feat: improved performance of function flatten (#3354). Thanks @dvd101x.
    Feat: improved performance of DenseMatrix Symbol.iterator (#3395). Thanks @dvd101x.
    Feat: improved performance of functions map and forEach (#3399). Thanks @dvd101x.
    Fix: #3390 issue in callback optimization and add error handling for invalid argument types (#3394). Thanks @dvd101x.
    Fix: #3356 add missing eigsDependencies export to TypeScript definitions (#3397). Thanks @porst17.
    Fix: #3406 infer the correct type for multi-dimensional arrays in function multiply (#3408). Thanks @orelbn.
    Fix: #3387 use utility math.isNaN for consistent max and min results (#3389). Thanks @orelbn.

2024-02-05, 14.2.1

    Fix: #3377 remove redundant dependency @lambdatest/node-tunnel.

2024-01-30, 14.2.0

    Feat: #3041, #3340 rename apply to mapSlices (#3357). Function apply is still available but is now marked deprecated. Thanks @gwhitney.
    Fix: #3247 don’t override type-native floor/ceil within tolerance of value (#3369). Thanks @gwhitney.
    Fix: #3360 add bigint support to matrix indices and ranges (#3361). Thanks @gwhitney.
    Fix: #3115 type definitions for matrixFrom* (#3371). Thanks @Hudsxn and @gwhitney.

2025-01-24, 14.1.0

    Feat: implement bigint support in functions log, log2, log10, larger, smaller, max, min (#3345). Thanks @gwhitney.
    Fix: #3342 hexadecimal input not turned into a bigint (#3348).
    Fix randomInt() not working (#3345).
    Docs: fixed description of sign in the embedded docs (#3338). Thanks @witer33.

2024-12-11, 14.0.1

    Fix: make derivative much faster (#3322). Thanks @paulftw.
    Fix: #3317 export Fraction type from the fraction.js library instead of using a custom interface (#3330). Thanks @fchu.

2024-11-20, 14.0.0

!!! BE CAREFUL: BREAKING CHANGES !!!

    Feat: Upgrade to fraction.js@5, using bigint under the hood (#3283).
    Feat: Implement support for Unit in functions ceil, floor, and fix. Possible breaking changes in the type definitions of arrays and matrices due to the introduction of generics (#3269). Thanks @orelbn.
    Feat: Implement support for log(x: Fraction, base: Fraction).
    Fix: #3301 precedence of % (mod) being higher than * and / (#3311). Thanks @nkumawat34.
    Fix: #3222 prevent math.import(...) from overriding units unless you specify { override: true } (#3225).
    Fix: #3219 let functions dotDivide, dotPow, bitXor, xor, equal, larger, largerEq, smaller, smallerEq, and unequal return a sparse matrix when the input is two sparse matrices (#3307). Thanks @Aakash-Rana.
    Fix: Improve type definitions of arrays (#3306). Thanks @orelbn.

2024-11-20, 13.2.3

    Fix: #3260 improve type definitions and documentation on the callback indices of map, filter, and forEach.
    Fix: #3323 support functions in function clone.
    Docs: fix a broken link in the documentation (#3316). Thanks @emmanuel-ferdman.

2024-11-13, 13.2.2

    Fix: #1455 implicit multiplication of a fraction with unit in is incorrect (#3315). Thanks @nkumawat34.

2024-11-06, 13.2.1

    Update to the latest version of complex.js.
    Fix Index.dimension(dim) accepting non-numeric input.
    Fix: #3290 should validate variables names in method Parser.set (#3308). Thanks @nkumawat34.

2024-10-02, 13.2.0

    Feat: improve performance of functions map, filter and forEach (#3256). Thanks @dvd101x.
    Feat: improve performance of the methods map() and forEach() of DenseMatrix (#3251). Thanks @Galm007.
    Fix: #3253 cannot use identifiers containing special characters in function derivative.
    Fix: improve the type definitions of ConstantNode to support all data types (#3257). Thanks @smith120bh.
    Fix: #3259 function symbolicEqual missing in the TypeScript definitions.
    Fix: #3246 function leafCount missing in the TypeScript definitions.
    Fix: #3267 implicit multiplication with a negative number and unit in.
    Docs: fix broken links on the Configuration page. Thanks @vassudanagunta.
    Docs: document the syntax of map and forEach in the expression parser (#3272). Thanks @dvd101x.

2024-08-27, 13.1.1

    Fix security vulnerability in the CLI and web API allowing to call functions import, createUnit and reviver, allowing to get access to the internal math namespace and allowing arbitrary code execution. Thanks @StarlightPWN.
    Fix security vulnerability: when overwriting a rawArgs function with a non-rawArgs function, it was still called with raw arguments. This was both a functional issue and a security issue. Thanks @StarlightPWN.
    Fix security vulnerability: ensure that ObjectWrappingMap cannot delete unsafe properties. Thanks @StarlightPWN.
    Fix: not being able to use methods and properties on arrays inside the expression parser.

2024-08-26, 13.1.0

    Feat: support multiple inputs in function map (#3228, #3196). Thanks @dvd101x.
    Feat: add matrix datatypes in more cases (#3235). Thanks @dvd101x.
    Feat: export util functions isMap, isPartitionedMap, and isObjectWrappingMap.
    Fix: #3241 function map not always working with matrices (#3242). Thanks @dvd101x.
    Fix: #3244 fix broken link to ResultSet in the docs about classes.
    Docs: add a link to the documentation page about the syntax expression from the function evaluate (see #3238).
    Docs: improve the documentation of scope and fix the example custom_scope_objects.js (#3150)
    Docs: spelling fixes in the embedded docs (#3252). Thanks @dvd101x.

2024-07-19, 13.0.3

    Fix: #3232 fix type definitions of function format to support notations hex, bin, and oct.
    Fix: use more precise definitions for US liquid volume units (#3229). Thanks @Vistinum.
    Fix: #2286 types static methods and members for Unit class (#3230). Thanks @orelbn.

2024-07-04, 13.0.2

    Fix an error in the type definitions of quantileSeq (#3223). Thanks @domdomegg.

2024-06-28, 13.0.1

    Fix: #3227 generated bundle containing catch blocks without parameters.
    Fix: #2348 update type definitions of the Parser methods (#3226). Thanks @orelbn.

2024-05-31, 13.0.0

Breaking changes:

    Change isZero, isPositive, and isNegative to respect config.epsilon (#3139, #2838).
    Change the behavior of the internal nearlyEqual to align with Python and Julia (#3152, #2838)
    Upgrade to fraction.js@4.3.7, see https://github.com/rawify/Fraction.js/issues/68.
    Dropped support for JavaScript engines that do not fully support ES6 or bigint, or are not actively maintained. ES2020 is now the minimum required EcmaScript version.

Non-breaking changes:

    Implemented support for bigint (#3207, #3207)
    Implemented a new config option config.numberFallback needed for bigint (#3207).
    Internal: refactored tooling to ES modules and upgraded all devDependencies.

2024-05-31, 12.4.3

    Fix: serialization of Units without a value, see #1240.
    Fix: outdated, incorrect documentation about the order of precedence for operator modulus %. See #3189.
    Fix: #3197 improve quantileSeq type definitions (#3198). Thanks @domdomegg.

2024-04-24, 12.4.2

    Fix #3192: function isNaN returns false for NaN units in a matrix or array (#3193). Thanks @lgerin.
    Fix: #3180 fix type definitions of functions add and multiply to allow more than two arguments.
    Docs: correct the docs about traverse returning void (#3177). Thanks @rohildshah.

2024-03-13, 12.4.1

    Docs: implement an interactive version of the Lorenz example, and show the chart full screen (#3151). Thanks @dvd101x.
    Fix #3172: simplify "true and true".
    Fix #3163: toTex wrongly returning Infinity for large BigNumbers.
    Fix #3162: add license information about CSParse (#3164).
    Fix #3175: cannot delete units using math.Unit.deleteUnit.
    Fix: faster startup time of the CLI and REPL by loading the bundle.
    Fix: remove using polyfill.io inside the example pretty_printing_with_mathjax.html (#3167). Thanks @SukkaW.

2024-02-22, 12.4.0

    Feat: implement support for trailing commas in matrices (#3154, #2968). Thanks @dvd101x.
    Feat: improve the performance of multiply a lot by adding matrix type inferencing (#3149). Thanks @RandomGamingDev.
    Fix: #3100 function round not handling round-off errors (#3136). Thanks @BrianFugate.
    Fix: PartitionedMap and ObjectWrappingMap missing a property Symbol.iterator, causing problems when trying new Map(scope) (#3156).
    Fix: type definitions of function mode (#3153). Thanks @rich-martinez.
    Docs: describe method getAllAsMap in the Parser docs (#3158, #3157). Thanks @dvd101x.

2024-02-08, 12.3.2

    Improved the performance of custom defined functions in the expression parser (#3150).
    Fix: #3143 cannot use and and or inside a function definition. Regression since v12.1.0 (#3150).

2024-02-01, 12.3.1

    Improved the typings of the arguments of ArrayNode, FunctionNode, IndexNode, OperatorNode, and RelationalNode (#3123). Thanks @sylee957.
    Added a fully featured code editor example with CodeMirror and Katex (#3027). Thanks @dvd101x.
    Fix: #3114 build warnings related to a number of wrong /* #__PURE__ */ annotations.
    Fix: #3142 support BigNumber values for the options of function format: precision, wordSize, lowerExp, upperExp. Support BigNumber values for the option wordSize in the functions hex, bin, and oct.
    Fix: #3125 type definitions of function hypot (#3144). Thanks @silentmissile.
    Fix: #3141 help(config) altering the actual config when evaluating the examples.
    Docs: #3145 fix documentation about REPL, it does require a build step nowadays.

2024-01-12, 12.3.0

    Implement support new metric prefixes: ronna (R), quetta (Q), ronto (r), and quecto (q) (#3113, #3112). Thanks @AlexEdgcomb.
    Fix a bug converting a unitless unit (#3117). Thanks @costerwi.
    Fix: #3097 toSI() wrongly converting degC (#3118). Thanks @costerwi.

2023-12-20, 12.2.1

    Fix #3109: method Node.toHTML not accepting a custom handler.

2023-12-08, 12.2.0

    Feat: lazy evaluation of operators and, or, &, | (#3090, #3101, #2766). Thanks @smith120bh.
    Fix: passing a 4th argument with a scope to raw functions.
    Fix: #3096 embedded docs of eigs throwing an error.

2023-11-17, 12.1.0

    Feat: Extend function round with support for units (#2761, #3095).
    Feat: Extend function mod with support for negative divisors in when using BigNumber or Fraction (#3087).
    Fix: #3092 a typo in an error message when converting a string into a number.
    Fix: #3094 function derivative mutates the input expression when it fails.

2023-10-26, 12.0.0

Breaking changes:

    Fix #2879, #2927, #3014: change the confusing interface of eigs (#3037), thanks @gwhitney. Before, functions eigs returned an object:

    { values: MathCollection; vectors: MathCollection }

    where vectors was a 2d matrix of which the columns contained the vectors. This is changed to eigs returning an object:

    { 
      values: MathCollection
      eigenvectors: Array<{
        value: number | BigNumber
        vector: MathCollection
      }>
    }

    Where eigenvectors is an array containing an object with the corresponding eigenvalue and vector.
    Refactored the TypeScript type definitions to make them work with a NodeNext module resolution (#3079, #2919).
        Type MathJsStatic is renamed to MathJsInstance.
        Type FactoryDependencies is deprecated, use MathJsFactory instead, and import dependency maps directly from the library.
    Change the assignment operator of .toTex() output from := to = (see #2980, #2987).
    Drop official support for Node.js 14 and 16.

Features:

    Function eigs now has an option to turn off calculation of eigenvectors (#3057, #2180). Thanks @gwhitney.

Fixes:

    Find eigenvectors of defective matrices (#3037). Thanks @gwhitney.

2023-10-26, 11.12.0

    Implemented function subtractScalar (#3081, #2643), thanks @vrushaket.
    Fix #3073: function format not escaping control characters and double quotes (#3082).
    Fix: function clone not throwing an error when passing an unsupported type like a function.
    Fix: #2960 add type definition of function symbolicEqual (#3035), thanks @juancodeaudio.

2023-10-11, 11.11.2

    Fix #3025: improve handling of matrices and error handling in function corr (#3030). Thanks @vrushaket.
    Fix #3074: improve error message when using function max in derivative.
    Fix #3073: fix parsing quotes inside a string.
    Fix #2027: cannot use named operators like to or mod as property name.

2023-09-20, 11.11.1

    Fix #2989: use one-based indices in print in the parser (#3009). Thanks @dvd101x.
    Fix #2936: mod sometimes giving wrong results due to internal round-off errors (#3011). Thanks @praisennamonu1.
    Internal refactor of quantileSeq, and fixed the embedded help (#3003). Thanks @dvd101x.
    Updated dependencies and devDependencies.

2023-09-05, 11.11.0

    Implement function corr to calculate the correlation between two matrices (#3015, #2624). Thanks @vrushaket.
    Lock fraction.js at version 4.3.4 for now, see #3024, 3022, https://github.com/rawify/Fraction.js/issues/68.

2023-08-31, 11.10.1

    Upgrade to fraction.js@4.3.4, see #3022.
    Fix #3020: lruQueue using the global hasOwnProperty which may be polluted.
    Add support for prefixes for the unit erg, and restrict prefixes of the unit joule to only long prefixes like kilo and no short prefixes like k (#3019). Thanks @costerwi.
    Add a new browser example examples/browser/lorenz.html that uses solveODE and plots the result in a chart (#3018). Thanks @dvd101x.

2023-08-23, 11.10.0

    Extend function quantileSeq with support for a dimension (#3002). Thanks @dvd101x.
    Implement #2735: Support indexing with an array of booleans, for example a[[true, false, true]] and a[a > 2] (#2994). Thanks @dvd101x.
    Implement function zeta (#2950, #2975, #2904). Thanks @Bobingstern.
    Fix #2990: DenseMatrix can mutate input arrays (#2991).

2023-07-24, 11.9.1

    Fix a security vulnerability in FunctionNode and SymbolNode allowing arbitrary code execution via math.evaluate. Thanks Harry Chen.
    Fix #3001: mathjs bundle containing new Function(...) (CSP issue).

2023-07-19, 11.9.0

    Implement function solveODE (#2958). Thanks @dvd101x.
    Implement functions zpk2tf and freqz (#2988, #2969). Thanks @alykhaled.
    Implement support for units in function range (#2997). Thanks @dvd101x.
    Fix #2974: simplify puts plus and minus signs next to each other (#2981). Thanks @MaybePixem.
    Fix #2973: fixes and improvements in the embedded docs (#2976). Thanks @dvd101x.
    Fix #2996: two errors in the examples in the documentation about Expression trees.
    Fix round-off errors near zero when converting temperatures (#2962). Thanks @costerwi.
    Refactored function range, reducing the amount of code (#2995). Thanks @dvd101x.

2023-06-20, 11.8.2

    Fix #2971: improve typings of statistics functions min, max, mean, median, mode, std, sum, prod, variance. Fixes a regression introduced in v11.8.1.
    Fix #2972: type definitions of Unit.divide(Unit) have a wrong return type.

2023-06-13, 11.8.1

    Fix #2964: issue in function distance when calculate the distance from a point to a line (#2965). Thanks @Kiku-CN.
    Fix math.format not working correctly for engineering notation when using BigNumbers and for fixed notation with precision: 0 configured (#2956). Thanks @mgreminger.
    Fix #2880: not possible to map cube root cbrt.
    Fix #2938: make the syntax description of all functions consistent in the docs (#2941). Thanks @dvd101x.
    Fix #2954: improve the TypeScript definitions the return type of functions min and max (#2955). Thanks @Maxim-Mazurok.
    Fix #2959: typo in an example in the docs. Thanks @kunalagrwl.
    Drop official support for Node.js 14, has reached end of life.

2023-04-03, 11.8.0

    Extended functions fraction, bignumber, and number with support for units, see #2918 (#2926).
    Implemented aliases amp and amps for unit ampere (#2917). Thanks @veggiesaurus.
    Improve TypeScript definitions of function gcd (#2922). Thanks @brunoSnoww.
    Fix #2923: improve docs of the function distance (#2924). Thanks @tmtron.

2023-03-15, 11.7.0

    Implement #2567: accept array as parameter for function gcd (#2878). Thanks @jakubriegel.
    Fix #2908: improvements in the docs and examples of functions partitionSelect, diff, expm1, round, nthRoots, sign, rigthArithShift, setIsSubset, setSize, and the docs about units. Thanks @tmtron.
    Fix #2907: determinant of empty matrix should be 1.
    Refactor index.d.ts by writing function declarations using a generic, reducing a lot of repetition (#2913). Thanks @brunoSnoww.

2023-02-24, 11.6.0

    Implement broadcasting for the following functions and their corresponding operator: add, dotDivide, dotMultiply, dotPow, gcd, lcm, mod, nthRoot, subtract, bitAnd, bitOr, bitXor, leftShift, rightArithShift, rightLogShift, and, or, xor, compare, compareText, equal, larger, largerEq, smaller, smallerEq, unequal, atan2 and to (#2895, #2753). Thanks @dvd101x.
    Implement support for non-power-of-2 fft (#2900, #2577). Thanks @cyavictor88.
    Fix #2888: update type definitions of function unit to allow creating a unit from a fraction or complex number.
    Fix #2892: an error in the examples of the embedded help of function sort.
    Fix #2891: functions column and row sometimes returning a scalar number.
    Fix #2896: define the fourth argument of function intersect as optional in the TypeScript definitions. Thanks @wodndb.
    Fix: quantileSeq not accepting a matrix as second argument prob (see #2902).
    Fix broken examples in functions to, distance, getMatrixDataType, subset, and max (see #2902).

2023-01-31, 11.5.1

    Add type definitions for function rotationMatrix (#2860). Thanks @brunoSnoww.
    Add type signature for lusolve(LUDecomposition, ...) (#2864). Thanks @evanmiller.
    Fix #2873: the rocket_trajectory_optimization.html example being partly broken. Thanks @dvd101x.
    Fix #2871: coverage report broken (#2877). Thanks @bornova.
    Fix #2883: update documentation for stat functions, describe missing syntax.
    Fix #2884: fix examples in the embedded docs of function pow and some other functions.
    Fix type definition of function complex for one numeric input (#2886), thanks @ariymarkowitz.
    Fix type definitions of map() and forEach() (#2887), thanks @xiaohk.
    Fix #2606: improve type definitions of dotMultiply, dotPow and dotDivide (#2890). Thanks @brunoSnoww.

2022-12-05, 11.5.0

    Improve simplify rule matches in non-commutative contexts (#2841). Thanks @samueltlg.
    Simplify: add rules and restructure tests for non-commutative contexts (#2847). Thanks @samueltlg.
    Fix function reshape mutating the input in case of a matrix (see #2854).
    Fix TypeScript types for multiply() with number[] and number[][] (#2852). Thanks @hfhchan.

2022-11-18, 11.4.0

    Implemented more wildcards to describe rules for simplify, making it easier for example to describe unary minus (#1915). Thanks @thatcomputerguy0101.
    Implemented functions schur, sylvester, and lyap (#2646). Thanks @egidioln.
    Implemented function polynomialRoot, and use it in a benchmark (#2839). Thanks @gwhitney.
    Fix #2825 partly: improve simplifying operations on constants in non-commutative contexts (#2827). Thanks @samueltlg.
    Fix #2840: a bug in the docs and type definitions of Node.traverse and Node.forEach, they do return void.

2022-11-07, 11.3.3

    Fix #2830: Prevent inserting zero values when creating a SparseMatrix from a DenseMatrix (#2836). Thanks @AlexandreAlvesDB.
    Fix #2835: a regression in the type definitions of FunctionNode, introduced in v11.3.2. See #2733. Thanks @dsteve.

2022-10-25, 11.3.2

    Add generics to remaining Node type definitions (#2733). Thanks @mattvague.
    Allow unit prefixes for (absolute) temperatures kelvin, rankine, celsius, and fahrenheit (#2824). Thanks @jfeist

2022-10-19, 11.3.1

    Fix #2809: code completion issues in some IDE’s (#2812).
    Fix #2818: throw an error when a function assignment has duplicate parameter names (#2819).
    Update decimal.js to version 10.4.2.

2022-10-11, 11.3.0

    Allow creating new subclasses of Node in TypeScript (#2772). Note that this disables being able to narrow MathNodes by using the .type property. Use typeguards like isOperatorNode(...) instead (see #2810). Thanks @mattvague.
    Fix #2793: flatten() cloning entries of array/Matrix (#2799).
    Fix #2627: TypeScript definitions of pinv missing (#2804). Thanks @HanchaiN.
    Update dependencies to decimal.js@10.4.1.

2022-09-13, 11.2.1

    Fix doc generator being broken, not generating a function reference.

2022-09-12, 11.2.0

    Implement function isRelationalNode (#2731). Thanks @isaacbyr.
    Added missing types 'largerEq' and 'or' in OperatorNodeMap in the TypeScript definitions. Thanks @ajinkyac03.
    Fixed typos in min func type defs (#2768). Thanks @mabdullahadeel.
    Improved the TypeScript definitions for pickRandom. Thanks @mattvague.
    Fixed documentation of unit min which means minutes, not minim (#2773). Thanks @jasonhornsby.

2022-08-23, 11.1.0

    Add Unit constructor from value and pure (valueless) Unit (#2628). Thanks @costerwi
    Fix #2144: examples/advanced/custom_loading.js was broken.
    Fix JSON replacer function missing in the TypeScript definitions. Thanks @mattvague.
    Update dependencies to typed-function@4.1.0 and decimal.js@10.4.0.

2022-07-25, version 11.0.1

    Fix #2632: TypeScript issue of simplifyConstant and simplifyCore not having a return type defined.

2022-07-23, version 11.0.0

!!! BE CAREFUL: BREAKING CHANGES !!!

Breaking changes:

    Dropped official support for IE11.
    Upgraded to typed-function@3, see josdejong/typed-function/HISTORY.md. Thanks @gwhitney. Most importantly:
        Conversions now have preference over any.
        The this variable is no longer bound to the typed function itself.
        The properties typed.types, typed.conversions, and typed.ignore have been removed.
        There are new static functions available like typed.referTo, typed.referToSelf, typed.addTypes, typed.addConversions.
    Implement amended “Rule 2” for implicit multiplication (#2370, #2460): when having a division followed by an implicit multiplication, the division gets higher precedence over the implicit multiplication when (a) the numerator is a constant with optionally a prefix operator (-, +, ~), and (b) the denominator is a constant. For example: formerly -1 / 2 x was interpreted as -1 / (2 * x) and now it is interpreted as (-1 / 2) * x. Thanks @gwhitney.
    Drop elementwise matrix support for trigonometric functions, exp, log, gamma, square, sqrt, cube, and cbrt to prevent confusion with standard matrix functions (#2440, #2465). Instead, use math.map(matrix, fn). Thanks @gwhitney.
    Simplify: convert equivalent function calls into operators, for example, add(2, x) will now be simplified into 2 + x (#2415, #2466). Thanks @gwhitney.
    Removed the automatic conversion from number to string (#2482). Thanks @gwhitney.
    Fix #2412: let function diff return an empty matrix when the input contains only one element (#2422).
    Internal refactoring in the simplifyCore logic (#2490, #2484, #2459). The function simplifyCore will no longer (partially) merge constants, that behavior has been moved to simplifyConstant. The combination of simplifyConstant and simplifyCore is still close to the old behavior of simplifyCore, but there are some differences. To reproduce the same behavior as the old simplifyCore, you can use math.simplify(expr, [math.simplifyCore, math.simplifyConstant]). Thanks to the refactoring, simplify is more thorough in reducing constants. Thanks @gwhitney.
    Disable support for splitting rest parameters in chained calculations (#2485, #2474). For example: math.chain(3).max(4, 2).done() will now throw an error rather than return 4, because the rest parameter of math.max(...number) has been split between the contents of the chain and the arguments to the max call. Thanks @gwhitney.
    Function typeOf now returns function (lowercase) for a function instead of Function (#2560). Thanks @gwhitney.

Non-breaking changes:

    Fix #2600: improve the TypeScript definitions of simplify. Thanks @laureen-m and @mattvague.
    Fix #2607: improve type definition of createUnit. Thanks @egziko.
    Fix #2608: clarify the docs on the need to configure a smaller epsilon when using BigNumbers.
    Fix #2613: describe matrix methods get and set in the docs.
    Fix link to math.rationalize in the docs (#2616). Thanks @nukisman.
    Fix #2621: add TypeScript definitions for count (#2622). Thanks @Hansuku.
    Improved TypeScript definitions of multiply (#2623). Thanks @Windrill.

2022-06-28, version 10.6.4

    Improve TypeScript definitions of the factory function, thanks @mattvague.

2022-06-24, version 10.6.3

    Revert the TypeScript definition fixes for factory applied in v10.6.2, they give some complications.
    
    ...

""".



EXAMPLES:

mathjs.org/examples/algebra.js.html:
"""

// algebra
//
// math.js has support for symbolic computation (CAS). It can parse
// expressions in an expression tree and do algebraic operations like
// simplification and derivation on this tree.
import { simplify, parse, derivative } from 'mathjs'

// simplify an expression
console.log('simplify expressions')
console.log(simplify('3 + 2 / 4').toString()) // '7 / 2'
console.log(simplify('2x + 3x').toString()) // '5 * x'
console.log(simplify('2 * 3 * x', { x: 4 }).toString()) // '24'
console.log(simplify('x^2 + x + 3 + x^2').toString()) // '2 * x ^ 2 + x + 3'
console.log(simplify('x * y * -x / (x ^ 2)').toString()) // '-y'

// work with an expression tree, evaluate results
const f = parse('2x + x')
const simplified = simplify(f)
console.log(simplified.toString()) // '3 * x'
console.log(simplified.evaluate({ x: 4 })) // 12
console.log()

// calculate a derivative
console.log('calculate derivatives')
console.log(derivative('2x^2 + 3x + 4', 'x').toString()) // '4 * x + 3'
console.log(derivative('sin(2x)', 'x').toString()) // '2 * cos(2 * x)'

// work with an expression tree, evaluate results
const h = parse('x^2 + x')
const dh = derivative(h, 'x')
console.log(dh.toString()) // '2 * x + 1'
console.log(dh.evaluate({ x: 3 })) // '7'

""".

mathjs.org/examples/basic_usage.js.html:
"""

// basic usage
import {
  add,
  atan2,
  chain,
  derivative,
  e,
  evaluate,
  format,
  log,
  matrix,
  multiply,
  pi,
  pow,
  round,
  sqrt,
  subtract,
  unit
} from 'mathjs'

// functions and constants
console.log('functions and constants')
print(round(e, 3)) // 2.718
print(atan2(3, -3) / pi) // 0.75
print(log(10000, 10)) // 4
print(sqrt(-4)) // 2i
print(pow([[-1, 2], [3, 1]], 2)) // [[7, 0], [0, 7]]
print(derivative('x^2 + x', 'x')) // 2 * x + 1
console.log()

// expressions
console.log('expressions')
print(evaluate('1.2 * (2 + 4.5)')) // 7.8
print(evaluate('12.7 cm to inch')) // 5 inch
print(evaluate('sin(45 deg) ^ 2')) // 0.5
print(evaluate('9 / 3 + 2i')) // 3 + 2i
print(evaluate('det([-1, 2; 3, 1])')) // -7
console.log()

// chained operations
console.log('chained operations')
const a = chain(3)
  .add(4)
  .multiply(2)
  .done()
print(a) // 14
console.log()

// mixed use of different data types in functions
console.log('mixed use of data types')
print(add(4, [5, 6])) // number + Array, [9, 10]
print(multiply(unit('5 mm'), 3)) // Unit * number,  15 mm
print(subtract([2, 3, 4], 5)) // Array - number, [-3, -2, -1]
print(add(matrix([2, 3]), [4, 5])) // Matrix + Array, [6, 8]
console.log()

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  const precision = 14
  console.log(format(value, precision))
}

""".

mathjs.org/examples/bignumbers.js.html:
"""

// BigNumbers
import { create, all } from 'mathjs'

// configure the default type of numbers as BigNumbers
const config = {
  // Default type of number
  // Available options: 'number' (default), 'BigNumber', or 'Fraction'
  number: 'BigNumber',

  // Number of significant digits for BigNumbers
  precision: 20
}
const math = create(all, config)

console.log('round-off errors with numbers')
print(math.add(0.1, 0.2)) // number, 0.30000000000000004
print(math.divide(0.3, 0.2)) // number, 1.4999999999999998
console.log()

console.log('no round-off errors with BigNumbers')
print(math.add(math.bignumber(0.1), math.bignumber(0.2))) // BigNumber, 0.3
print(math.divide(math.bignumber(0.3), math.bignumber(0.2))) // BigNumber, 1.5
console.log()

console.log('create BigNumbers from strings when exceeding the range of a number')
print(math.bignumber(1.2e+500)) // BigNumber, Infinity      WRONG
print(math.bignumber('1.2e+500')) // BigNumber, 1.2e+500
console.log()

console.log('BigNumbers still have a limited precision and are no silve bullet')
const third = math.divide(math.bignumber(1), math.bignumber(3))
const total = math.add(third, third, third)
print(total) // BigNumber, 0.99999999999999999999
console.log()

// one can work conveniently with BigNumbers using the expression parser.
// note though that BigNumbers are only supported in arithmetic functions
console.log('use BigNumbers in the expression parser')
print(math.evaluate('0.1 + 0.2')) // BigNumber, 0.3
print(math.evaluate('0.3 / 0.2')) // BigNumber, 1.5
console.log()

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  console.log(math.format(value))
}

""".

mathjs.org/examples/chaining.js.html:
"""

// chaining
import { chain, format, index, pi } from 'mathjs'

// create a chained operation using the function `chain(value)`
// end a chain using done(). Let's calculate (3 + 4) * 2
const a = chain(3)
  .add(4)
  .multiply(2)
  .done()
print(a) // 14

// Another example, calculate square(sin(pi / 4))
const b = chain(pi)
  .divide(4)
  .sin()
  .square()
  .done()
print(b) // 0.5

// A chain has a few special methods: done, toString, valueOf, get, and set.
// these are demonstrated in the following examples

// toString will return a string representation of the chain's value
const myChain = chain(2).divide(3)
const str = myChain.toString()
print(str) // "0.6666666666666666"

// a chain has a function .valueOf(), which returns the value hold by the chain.
// This allows using it in regular operations. The function valueOf() acts the
// same as function done().
print(myChain.valueOf()) // 0.66666666666667
print(myChain + 2) // 2.6666666666667

// the function subset can be used to get or replace sub matrices
const array = [[1, 2], [3, 4]]
const v = chain(array)
  .subset(index(1, 0))
  .done()
print(v) // 3

const m = chain(array)
  .subset(index(0, 0), 8)
  .multiply(3)
  .done()
print(m) // [[24, 6], [9, 12]]

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  const precision = 14
  console.log(format(value, precision))
}

""".

mathjs.org/examples/complex_numbers.js.html:
"""

// complex numbers
import { complex, add, multiply, sin, sqrt, pi, equal, sort, format } from 'mathjs'

// create a complex number with a numeric real and complex part
console.log('create and manipulate complex numbers')
const a = complex(2, 3)
print(a) // 2 + 3i

// read the real and complex parts of the complex number
print(a.re) // 2
print(a.im) // 3

// clone a complex value
const clone = a.clone()
print(clone) // 2 + 3i

// adjust the complex value
a.re = 5
print(a) // 5 + 3i

// create a complex number by providing a string with real and complex parts
const b = complex('3-7i')
print(b) // 3 - 7i
console.log()

// perform operations with complex numbers
console.log('perform operations')
print(add(a, b)) // 8 - 4i
print(multiply(a, b)) // 36 - 26i
print(sin(a)) // -9.6541254768548 + 2.8416922956064i

// some operations will return a complex number depending on the arguments
print(sqrt(4)) // 2
print(sqrt(-4)) // 2i
console.log()

// create a complex number from polar coordinates
console.log('create complex numbers with polar coordinates')
const c = complex({ r: sqrt(2), phi: pi / 4 })
print(c) // 1 + i

// get polar coordinates of a complex number
const d = complex(3, 4)
console.log(d.abs(), d.arg()) // radius = 5, phi = 0.9272952180016122
console.log()

// comparision operations
// note that there is no mathematical ordering defined for complex numbers
// we can only check equality. To sort a list with complex numbers,
// the natural sorting can be used
console.log('\ncomparision and sorting operations')
console.log('equal', equal(a, b)) // returns false
const values = [a, b, c]
console.log('values:', format(values, 14)) // [5 + 3i, 3 - 7i, 1 + i]
sort(values, 'natural')
console.log('sorted:', format(values, 14)) // [1 + i, 3 - 7i, 5 + 3i]

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  const precision = 14
  console.log(format(value, precision))
}

""".

mathjs.org/examples/expressions.js.html:
"""

/**
 * Expressions can be evaluated in various ways:
 *
 * 1. using the function evaluate
 * 2. using the function parse
 * 3. using a parser. A parser contains functions evaluate and parse,
 *    and keeps a scope with assigned variables in memory
 */
import { compile, evaluate, format, parse, parser } from 'mathjs'

// 1. using the function evaluate
//
// Function `evaluate` accepts a single expression or an array with
// expressions as first argument, and has an optional second argument
// containing a scope with variables and functions. The scope is a regular
// JavaScript Object. The scope will be used to resolve symbols, and to write
// assigned variables or function.
console.log('1. USING FUNCTION MATH.EVAL')

// evaluate expressions
console.log('\nevaluate expressions')
print(evaluate('sqrt(3^2 + 4^2)')) // 5
print(evaluate('sqrt(-4)')) // 2i
print(evaluate('2 inch to cm')) // 5.08 cm
print(evaluate('cos(45 deg)')) // 0.70711

// evaluate multiple expressions at once
console.log('\nevaluate multiple expressions at once')
print(evaluate([
  'f = 3',
  'g = 4',
  'f * g'
])) // [3, 4, 12]

// provide a scope (just a regular JavaScript Object)
console.log('\nevaluate expressions providing a scope with variables and functions')
const scope = {
  a: 3,
  b: 4
}

// variables can be read from the scope
print(evaluate('a * b', scope)) // 12

// variable assignments are written to the scope
print(evaluate('c = 2.3 + 4.5', scope)) // 6.8
print(scope.c) // 6.8

// scope can contain both variables and functions
scope.hello = function (name) {
  return 'hello, ' + name + '!'
}
print(evaluate('hello("hero")', scope)) // "hello, hero!"

// define a function as an expression
const f = evaluate('f(x) = x ^ a', scope)
print(f(2)) // 8
print(scope.f(2)) // 8

// 2. using function parse
//
// Function `parse` parses expressions into a node tree. The syntax is
// similar to function `evaluate`.
// Function `parse` accepts a single expression or an array with
// expressions as first argument. The function returns a node tree, which
// then can be compiled against math, and then evaluated against an (optional
// scope. This scope is a regular JavaScript Object. The scope will be used
// to resolve symbols, and to write assigned variables or function.
console.log('\n2. USING FUNCTION MATH.PARSE')

// parse an expression
console.log('\nparse an expression into a node tree')
const node1 = parse('sqrt(3^2 + 4^2)')
print(node1.toString()) // "sqrt((3 ^ 2) + (4 ^ 2))"

// compile and evaluate the compiled code
// you could also do this in two steps: node1.compile().evaluate()
print(node1.evaluate()) // 5

// provide a scope
console.log('\nprovide a scope')
const node2 = parse('x^a')
const code2 = node2.compile()
print(node2.toString()) // "x ^ a"
const scope2 = {
  x: 3,
  a: 2
}
print(code2.evaluate(scope2)) // 9

// change a value in the scope and re-evaluate the node
scope2.a = 3
print(code2.evaluate(scope2)) // 27

// 3. using function compile
//
// Function `compile` compiles expressions into a node tree. The syntax is
// similar to function `evaluate`.
// Function `compile` accepts a single expression or an array with
// expressions as first argument, and returns an object with a function evaluate
// to evaluate the compiled expression. On evaluation, an optional scope can
// be provided. This scope will be used to resolve symbols, and to write
// assigned variables or function.
console.log('\n3. USING FUNCTION MATH.COMPILE')

// parse an expression
console.log('\ncompile an expression')
const code3 = compile('sqrt(3^2 + 4^2)')

// evaluate the compiled code
print(code3.evaluate()) // 5

// provide a scope for the variable assignment
console.log('\nprovide a scope')
const code4 = compile('a = a + 3')
const scope3 = {
  a: 7
}
code4.evaluate(scope3)
print(scope3.a) // 10

// 4. using a parser
//
// In addition to the static functions `evaluate` and `parse`, js
// contains a parser with functions `evaluate` and `parse`, which automatically
// keeps a scope with assigned variables in memory. The parser also contains
// some convenience methods to get, set, and remove variables from memory.
console.log('\n4. USING A PARSER')
const myParser = parser()

// evaluate with parser
console.log('\nevaluate expressions')
print(myParser.evaluate('sqrt(3^2 + 4^2)')) // 5
print(myParser.evaluate('sqrt(-4)')) // 2i
print(myParser.evaluate('2 inch to cm')) // 5.08 cm
print(myParser.evaluate('cos(45 deg)')) // 0.70710678118655

// define variables and functions
console.log('\ndefine variables and functions')
print(myParser.evaluate('x = 7 / 2')) // 3.5
print(myParser.evaluate('x + 3')) // 6.5
print(myParser.evaluate('f2(x, y) = x^y')) // f2(x, y)
print(myParser.evaluate('f2(2, 3)')) // 8

// manipulate matrices
// Note that matrix indexes in the expression parser are one-based with the
// upper-bound included. On a JavaScript level however, js uses zero-based
// indexes with an excluded upper-bound.
console.log('\nmanipulate matrices')
print(myParser.evaluate('k = [1, 2; 3, 4]')) // [[1, 2], [3, 4]]
print(myParser.evaluate('l = zeros(2, 2)')) // [[0, 0], [0, 0]]
print(myParser.evaluate('l[1, 1:2] = [5, 6]')) // [5, 6]
print(myParser.evaluate('l')) // [[5, 6], [0, 0]]
print(myParser.evaluate('l[2, :] = [7, 8]')) // [7, 8]
print(myParser.evaluate('l')) // [[5, 6], [7, 8]]
print(myParser.evaluate('m = k * l')) // [[19, 22], [43, 50]]
print(myParser.evaluate('n = m[2, 1]')) // 43
print(myParser.evaluate('n = m[:, 1]')) // [[19], [43]]

// get and set variables and functions
console.log('\nget and set variables and function in the scope of the parser')
const x = myParser.get('x')
console.log('x =', x) // x = 3.5
const f2 = myParser.get('f2')
console.log('f2 =', format(f2)) // f2 = f2(x, y)
const h = f2(3, 3)
console.log('h =', h) // h = 27

myParser.set('i', 500)
print(myParser.evaluate('i / 2')) // 250
myParser.set('hello', function (name) {
  return 'hello, ' + name + '!'
})
print(myParser.evaluate('hello("hero")')) // "hello, hero!"

// clear defined functions and variables
myParser.clear()

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  const precision = 14
  console.log(format(value, precision))
}

""".

mathjs.org/examples/fractions.js.html:
"""

// Fractions
import { create, all } from 'mathjs'

// configure the default type of numbers as Fractions
const config = {
  // Default type of number
  // Available options: 'number' (default), 'BigNumber', or 'Fraction'
  number: 'Fraction'
}

// create a mathjs instance with everything included
const math = create(all, config)

console.log('basic usage')
printRatio(math.fraction(0.125)) // Fraction, 1/8
printRatio(math.fraction(0.32)) // Fraction, 8/25
printRatio(math.fraction('1/3')) // Fraction, 1/3
printRatio(math.fraction('0.(3)')) // Fraction, 1/3
printRatio(math.fraction(2, 3)) // Fraction, 2/3
printRatio(math.fraction('0.(285714)')) // Fraction, 2/7
console.log()

console.log('round-off errors with numbers')
print(math.add(0.1, 0.2)) // number, 0.30000000000000004
print(math.divide(0.3, 0.2)) // number, 1.4999999999999998
console.log()

console.log('no round-off errors with fractions :)')
print(math.add(math.fraction(0.1), math.fraction(0.2))) // Fraction, 0.3
print(math.divide(math.fraction(0.3), math.fraction(0.2))) // Fraction, 1.5
console.log()

console.log('represent an infinite number of repeating digits')
print(math.fraction('1/3')) // Fraction, 0.(3)
print(math.fraction('2/7')) // Fraction, 0.(285714)
print(math.fraction('23/11')) // Fraction, 2.(09)
console.log()

// one can work conveniently with fractions using the expression parser.
// note though that Fractions are only supported by basic arithmetic functions
console.log('use fractions in the expression parser')
printRatio(math.evaluate('0.1 + 0.2')) // Fraction,  3/10
printRatio(math.evaluate('0.3 / 0.2')) // Fraction,  3/2
printRatio(math.evaluate('23 / 11')) // Fraction, 23/11
console.log()

// output formatting
console.log('output formatting of fractions')
const a = math.fraction('2/3')
console.log(math.format(a)) // Fraction,  2/3
console.log(math.format(a, { fraction: 'ratio' })) // Fraction,  2/3
console.log(math.format(a, { fraction: 'decimal' })) // Fraction,  0.(6)
console.log(a.toString()) // Fraction,  0.(6)
console.log()

/**
 * Helper function to output a value in the console.
 * Fractions will be formatted as ratio, like '1/3'.
 * @param {*} value
 */
function printRatio (value) {
  console.log(math.format(value, { fraction: 'ratio' }))
}

/**
 * Helper function to output a value in the console.
 * Fractions will be formatted as decimal, like '0.(3)'.
 * @param {*} value
 */
function print (value) {
  console.log(math.format(value, { fraction: 'decimal' }))
}

""".

mathjs.org/examples/import.js.html:
"""

/**
 * Math.js can easily be extended with functions and variables using the
 * `import` function. The function `import` accepts a module name or an object
 * containing functions and variables.
 */
import { create, all } from 'mathjs'
const math = create(all)

/**
 * Define new functions and variables
 */
math.import({
  myConstant: 42,
  hello: function (name) {
    return 'hello, ' + name + '!'
  }
})

// defined methods can be used in both JavaScript as well as the parser
print(math.myConstant * 2) // 84
print(math.hello('user')) // 'hello, user!'

print(math.evaluate('myConstant + 10')) // 52
print(math.evaluate('hello("user")')) // 'hello, user!'

/**
 * Import the math library numbers.js, https://github.com/sjkaliski/numbers.js
 * The library must be installed first using npm:
 *     npm install numbers
 */
try {
  // load the numbers.js library
  const numbers = require('numbers')

  // import the numbers.js library into math.js
  math.import(numbers, { wrap: true, silent: true })

  if (math.fibonacci) {
    // calculate fibonacci
    print(math.fibonacci(7)) // 13
    print(math.evaluate('fibonacci(7)')) // 13
  }
} catch (err) {
  console.log('Warning: To use numbers.js, the library must ' +
      'be installed first via `npm install numbers`.')
}

/**
 * Import the math library numeric.js, https://github.com/sloisel/numeric
 * The library must be installed first using npm:
 *     npm install numeric
 */
try {
  // load the numeric.js library
  const numeric = require('numeric')

  // import the numeric.js library into math.js
  math.import(numeric, { wrap: true, silent: true })

  if (math.eig) {
    // calculate eigenvalues of a matrix
    print(math.evaluate('eig([1, 2; 4, 3])').lambda.x) // [5, -1]

    // solve AX = b
    const A = math.evaluate('[1, 2, 3; 2, -1, 1; 3, 0, -1]')
    const b = [9, 8, 3]
    print(math.solve(A, b)) // [2, -1, 3]
  }
} catch (err) {
  console.log('Warning: To use numeric.js, the library must ' +
      'be installed first via `npm install numeric`.')
}

/**
 * By default, the function import does not allow overriding existing functions.
 * Existing functions can be overridden by specifying option `override: true`
 */
math.import({
  pi: 3.14
}, {
  override: true
})

print(math.pi) // returns 3.14 instead of 3.141592653589793

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  const precision = 14
  console.log(math.format(value, precision))
}

""".

mathjs.org/examples/matrices.js.html:
"""

// matrices
import { diag, factorial, format, index, map, matrix, multiply, ones, range, sqrt } from 'mathjs'

// create matrices and arrays. a matrix is just a wrapper around an Array,
// providing some handy utilities.
console.log('create a matrix')
const a = matrix([1, 4, 9, 16, 25])
print(a) // [1, 4, 9, 16, 25]
const b = matrix(ones([2, 3]))
print(b) // [[1, 1, 1], [1, 1, 1]]
print(b.size()) // [2, 3]

// the Array data of a Matrix can be retrieved using valueOf()
const array = a.valueOf()
print(array) // [1, 4, 9, 16, 25]

// Matrices can be cloned
const clone = a.clone()
print(clone) // [1, 4, 9, 16, 25]
console.log()

// perform operations with matrices
console.log('perform operations')
print(map(a, sqrt)) // [1, 2, 3, 4, 5]
const c = [1, 2, 3, 4, 5]
print(factorial(c)) // [1, 2, 6, 24, 120]
console.log()

// create and manipulate matrices. Arrays and Matrices can be used mixed.
console.log('manipulate matrices')
const d = [[1, 2], [3, 4]]
print(d) // [[1, 2], [3, 4]]
const e = matrix([[5, 6], [1, 1]])
print(e) // [[5, 6], [1, 1]]

// set a submatrix
// Matrix indexes are zero-based.
e.subset(index(1, [0, 1]), [[7, 8]])
print(e) // [[5, 6], [7, 8]]
const f = multiply(d, e)
print(f) // [[19, 22], [43, 50]]
const g = f.subset(index(1, 0))
print(g) // 43
console.log()

// get a sub matrix
// Matrix indexes are zero-based.
console.log('get a sub matrix')
const h = diag(range(1, 4))
print(h) // [[1, 0, 0], [0, 2, 0], [0, 0, 3]]
print(h.subset(index([1, 2], [1, 2]))) // [[2, 0], [0, 3]]
const i = range(1, 6)
print(i) // [1, 2, 3, 4, 5]
print(i.subset(index(range(1, 4)))) // [2, 3, 4]
console.log()

// replace a single value in a matrix
// this will mutate the matrix
console.log('set and get a value')
const p = matrix([[1, 2], [3, 4]])
p.set([0, 1], 5)
print(p) // [[1, 5], [3, 4]]
const p21 = p.get([1, 0])
print(p21) // 3
console.log()

// resize a multi dimensional matrix
console.log('resizing a matrix')
const j = matrix()
let defaultValue = 0
j.resize([2, 2, 2], defaultValue)
print(j) // [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]
print(j.size()) // [2, 2, 2]
j.resize([2, 2])
print(j) // [[0, 0], [0, 0]]
print(j.size()) // [2, 2]
console.log()

// setting a value outside the matrices range will resize the matrix.
// new elements will be initialized with zero.
console.log('set a value outside a matrices range')
const k = matrix()
k.subset(index(2), 6)
print(k) // [0, 0, 6]
console.log()

console.log('set a value outside a matrices range, setting other new entries to null')
const m = matrix()
defaultValue = null
m.subset(index(2), 6, defaultValue)
print(m) // [null, null, 6]
console.log()

// create ranges
console.log('create ranges')
print(range(1, 6)) // [1, 2, 3, 4, 5]
print(range(0, 18, 3)) // [0, 3, 6, 9, 12, 15]
print(range('2:-1:-3')) // [2, 1, 0, -1, -2]
print(factorial(range('1:6'))) // [1, 2, 6, 24, 120]
console.log()

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  const precision = 14
  console.log(format(value, precision))
}

""".

mathjs.org/examples/objects.js.html:
"""

// objects
import { evaluate, format } from 'mathjs'

// create an object. Keys can be symbols or strings
print(evaluate('{x: 2 + 1, y: 4}')) // {"x": 3, "y": 4}
print(evaluate('{"name": "John"}')) // {"name": "John"}

// create an object containing an object
print(evaluate('{a: 2, b: {c: 3, d: 4}}')) // {"a": 2, "b": {"c": 3, "d": 4}}

const scope = {
  obj: {
    prop: 42
  }
}

// retrieve properties using dot notation or bracket notation
print(evaluate('obj.prop', scope)) // 42
print(evaluate('obj["prop"]', scope)) // 42

// set properties (returns the whole object, not the property value!)
print(evaluate('obj.prop = 43', scope)) // 43
print(evaluate('obj["prop"] = 43', scope)) // 43
print(scope.obj) // {"prop": 43}

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  const precision = 14
  console.log(format(value, precision))
}

""".

mathjs.org/examples/serialization.js.html:
"""

// serialization
import { complex, replacer, reviver, typeOf } from 'mathjs'

// serialize a math.js data type into a JSON string
// the replacer function is needed to correctly stringify a value like Infinity
const x = complex('2+3i')
const str1 = JSON.stringify(x, replacer)
console.log(str1)
// outputs {"mathjs":"Complex","re":2,"im":3}

// deserialize a JSON string into a math.js data type
// note that the reviver of math.js is needed for this:
const str2 = '{"mathjs":"Unit","value":5,"unit":"cm"}'
const y = JSON.parse(str2, reviver)
console.log(typeOf(y)) // 'Unit'
console.log(y.toString()) // 5 cm

""".

mathjs.org/examples/sparse_matrices.js.html:
"""

// Sparse matrices
import { identity, multiply, transpose, complex } from 'mathjs'

// create a sparse matrix
console.log('creating a 1000x1000 sparse matrix...')
const a = identity(1000, 1000, 'sparse')

// do operations with a sparse matrix
console.log('doing some operations on the sparse matrix...')
const b = multiply(a, a)
const c = multiply(b, complex(2, 2))
const d = transpose(c)
const e = multiply(d, a)
console.log('size(e)=', e.size())

// we will not print the output, but doing the same operations
// with a dense matrix are very slow, try it for yourself.
console.log('already done')
console.log('now try this with a dense matrix :)')

""".

mathjs.org/examples/units.js.html:
"""

// units
import { add, cross, divide, evaluate, format as _format, multiply, number, pow, to, unit } from 'mathjs'

// units can be created by providing a value and unit name, or by providing
// a string with a valued unit.
console.log('create units')
const a = unit(45, 'cm')
const b = unit('0.1m')
print(a) // 45 cm
print(b) // 0.1 m
console.log()

// units can be added, subtracted, and multiplied or divided by numbers and by other units
console.log('perform operations')
print(add(a, b)) // 55 cm
print(multiply(b, 2)) // 0.2 m
print(divide(unit('1 m'), unit('1 s'))) // 1 m / s
print(pow(unit('12 in'), 3)) // 1728 in^3
console.log()

// units can be converted to a specific type, or to a number
console.log('convert to another type or to a number')
print(b.to('cm')) // 10 cm  Alternatively: to(b, 'cm')
print(to(b, 'inch')) // 3.9370078740157 inch
print(b.toNumber('cm')) // 10
print(number(b, 'cm')) // 10
console.log()

// the expression parser supports units too
console.log('parse expressions')
print(evaluate('2 inch to cm')) // 5.08 cm
print(evaluate('cos(45 deg)')) // 0.70710678118655
print(evaluate('90 km/h to m/s')) // 25 m / s
console.log()

// convert a unit to a number
// A second parameter with the unit for the exported number must be provided
print(evaluate('number(5 cm, mm)')) // number, 50
console.log()

// simplify units
console.log('simplify units')
print(evaluate('100000 N / m^2')) // 100 kPa
print(evaluate('9.81 m/s^2 * 100 kg * 40 m')) // 39.24 kJ
console.log()

// example engineering calculations
console.log('compute molar volume of ideal gas at 65 Fahrenheit, 14.7 psi in L/mol')
const Rg = unit('8.314 N m / (mol K)')
const T = unit('65 degF')
const P = unit('14.7 psi')
const v = divide(multiply(Rg, T), P)
console.log('gas constant (Rg) = ', format(Rg))
console.log('P = ' + format(P))
console.log('T = ' + format(T))
console.log('v = Rg * T / P = ' + format(to(v, 'L/mol')))
// 23.910432393453 L / mol
console.log()

console.log('compute speed of fluid flowing out of hole in a container')
const g = unit('9.81 m / s^2')
const h = unit('1 m')
const v2 = pow(multiply(2, multiply(g, h)), 0.5) // Can also use sqrt
console.log('g = ' + format(g))
console.log('h = ' + format(h))
console.log('v = (2 g h) ^ 0.5 = ' + format(v2))
// 4.42944691807 m / s
console.log()

console.log('electrical power consumption:')
const expr1 = '460 V * 20 A * 30 days to kWh'
console.log(expr1 + ' = ' + evaluate(expr1)) // 6624 kWh
console.log()

console.log('circuit design:')
const expr2 = '24 V / (6 mA)'
console.log(expr2 + ' = ' + evaluate(expr2)) // 4 kohm
console.log()

console.log('operations on arrays:')
const B = evaluate('[1, 0, 0] T')
const v3 = evaluate('[0, 1, 0] m/s')
const q = evaluate('1 C')
const F = multiply(q, cross(v3, B))
console.log('B (magnetic field strength) = ' + format(B)) // [1 T, 0 T, 0 T]
console.log('v (particle velocity) = ' + format(v3)) // [0 m / s, 1 m / s, 0 m / s]
console.log('q (particle charge) = ' + format(q)) // 1 C
console.log('F (force) = q (v cross B) = ' + format(F)) // [0 N, 0 N, -1 N]

/**
 * Helper function to output a value in the console. Value will be formatted.
 * @param {*} value
 */
function print (value) {
  console.log(format(value))
}

/**
 * Helper function to format an output a value.
 * @param {*} value
 * @return {string} Returns the formatted value
 */
function format (value) {
  const precision = 14
  return _format(value, precision)
}

""".

Browser examples:

mathjs.org/examples/browser/angle_configuration.html.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>math.js | angle configuration</title>
  <style>
    body, input, select {
      font: 11pt sans-serif;
    }
    input, select, th, #result {
      padding: 5px 10px;
    }
    th {
      text-align: left;
    }
  </style>

  <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>
</head>
<body>

<p>
  This code example extends the trigonometric functions of math.js with configurable angles: degrees, radians, or gradians.
</p>

<table>
  <tr>
    <th>Angles</th>
    <td>
      <select id="angles">
        <option value="deg">deg</option>
        <option value="grad">grad</option>
        <option value="rad">rad</option>
      </select>
    </td>
  </tr>
  <tr>
    <th>Expression</th>
    <td>
      <input id="expression" type="text" value="sin(45)" />
      <input id="evaluate" type="button" value="Evaluate">
    </td>
  </tr>
  <tr>
    <th>Result</th>
    <td id="result"></td>
  </tr>
</table>

<script>
  let replacements = {}

  // our extended configuration options
  const config = {
    angles: 'deg' // 'rad', 'deg', 'grad'
  }

  // create trigonometric functions replacing the input depending on angle config
  const fns1 = ['sin', 'cos', 'tan', 'sec', 'cot', 'csc']
  fns1.forEach(function(name) {
    const fn = math[name] // the original function

    const fnNumber = function (x) {
      // convert from configured type of angles to radians
      switch (config.angles) {
        case 'deg':
          return fn(x / 360 * 2 * Math.PI)
        case 'grad':
          return fn(x / 400 * 2 * Math.PI)
        default:
          return fn(x)
      }
    }

    // create a typed-function which check the input types
    replacements[name] = math.typed(name, {
      'number': fnNumber,
      'Array | Matrix': function (x) {
        return math.map(x, fnNumber)
      }
    })
  })

  // create trigonometric functions replacing the output depending on angle config
  const fns2 = ['asin', 'acos', 'atan', 'atan2', 'acot', 'acsc', 'asec']
  fns2.forEach(function(name) {
    const fn = math[name] // the original function

    const fnNumber = function (x) {
      const result = fn(x)

      if (typeof result === 'number') {
        // convert to radians to configured type of angles
        switch(config.angles) {
          case 'deg':  return result / 2 / Math.PI * 360
          case 'grad': return result / 2 / Math.PI * 400
          default: return result
        }
      }

      return result
    }

    // create a typed-function which check the input types
    replacements[name] = math.typed(name, {
      'number': fnNumber,
      'Array | Matrix': function (x) {
        return math.map(x, fnNumber)
      }
    })
  })

  // import all replacements into math.js, override existing trigonometric functions
  math.import(replacements, {override: true})

  // pointers to the input elements
  const expression = document.getElementById('expression')
  const evaluate   = document.getElementById('evaluate')
  const result     = document.getElementById('result')
  const angles     = document.getElementById('angles')

  // attach event handlers for select box and button
  angles.onchange = function () {
    config.angles = this.value
    config.angles = this.value
  }
  evaluate.onclick = function () {
    result.innerHTML = math.evaluate(expression.value)
  }
</script>


</body>
</html>

""".

mathjs.org/examples/browser/basic_usage.html.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>math.js | basic usage</title>
  <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>
</head>
<body>

<script>
  function print(value) {
    const precision = 14
    document.write(math.format(value, precision) + '<br>')
  }

  // functions and constants
  print(math.round(math.e, 3))            // 2.718
  print(math.atan2(3, -3) / math.pi)      // 0.75
  print(math.log(10000, 10))              // 4
  print(math.sqrt(-4))                    // 2i
  print(math.pow([[-1, 2], [3, 1]], 2))   // [[7, 0], [0, 7]]
  print(math.derivative('x^2 + x', 'x'))  // 2 * x + 1

  // expressions
  print(math.evaluate('12 / (2.3 + 0.7)'))    // 4
  print(math.evaluate('12.7 cm to inch'))     // 5 inch
  print(math.evaluate('9 / 3 + 2i'))          // 3 + 2i
  print(math.evaluate('det([-1, 2; 3, 1])'))  // -7

  // chained operations
  const a = math.chain(3)
      .add(4)
      .multiply(2)
      .done()
  print(a)  // 14
</script>

</body>
</html>

""".

mathjs.org/examples/browser/currency_conversion.html.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>math.js | currency conversion</title>

  <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>

  <style>
    body,
    html,
    input {
      font-size: 11pt;
      font-family: verdana, arial, sans-serif;
      color: #4d4d4d;
      max-width: 600px;
    }

    h1 {
      font-size: 120%;
    }

    input {
      padding: 5px;
      width: 400px;
    }
    button {
      padding: 5px;
    }
  </style>
</head>
<body>

<h1>Currency conversion with math.js</h1>

<p>
  This example demonstrates how you can fetch actual currencies from <a href="https://fixer.io">fixer.io</a> and use them in math.js.
</p>

<p>
  Create a (free) account at <a href="https://fixer.io">fixer.io</a> and fill in your API access key below:
</p>

<form id="fetchForm">
    <input type="text" id="apiKey" placeholder="fixer.io API access key..." />
    <button type="submit" id="ok">Fetch currencies</button>
</form>

<p id="info">
</p>
<div id="form" style="display: none;">
  <p>
    <label for="expr">Enter an expression with currencies:</label>
  </p>
  <p>
    <input id="expr" value="5 EUR + 2 * 3 EUR in USD" /><br/>
  </p>
  <p id="result"></p>
</div>

<script>
  const accessKey = document.getElementById('apiKey')
  const fetchForm = document.getElementById('fetchForm')

  fetchForm.onsubmit = function (event) {
    event.preventDefault()

    document.getElementById('info').innerHTML = 'Fetching currencies...'

    fetchAndImportCurrencies(accessKey.value)
      .then(function (currencies) {
        document.getElementById('expr').oninput = evaluate
        document.getElementById('form').style.display = ''
        document.getElementById('info').innerHTML = 'Available currencies: ' + currencies.join(', ')

        evaluate()
      })
      .catch(function (err) {
        console.error(err)
        document.getElementById('info').innerHTML = '<span style="color: red;">' + err.toString() + '</span>'
      })
  }

  function fetchAndImportCurrencies (accessKey) {
    // fetch actual currency conversion rates
    return fetch('http://data.fixer.io/api/latest?access_key=' + accessKey)
      .then(function (response) {
        return response.json()
      })
      .then(function (data) {
        if (data.success) {
          // import the currencies
          math.createUnit(data.base)
          Object.keys(data.rates)
            .filter(function (currency) {
              return currency !== data.base
            })
            .forEach(function (currency) {
              math.createUnit(currency, math.unit(1 / data.rates[currency], data.base))
            })

          // return an array with all available currencies
          return Object.keys(data.rates).concat(data.base)
        }
        else {
          throw new Error(data.error.info)
        }
      })
  }

  function evaluate () {
    const expr = document.getElementById('expr')
    const result = document.getElementById('result')

    try {
      const resultStr = math.format(math.evaluate(expr.value), {notation: 'fixed', precision: 2})
      result.innerHTML = '<span style="color: dodgerblue;">' + resultStr + '</span>'
    }
    catch (err) {
      result.innerHTML = '<span style="color: red;">' + err.toString() + '</span>'
    }
  }
</script>
</body>
</html>

""".

mathjs.org/examples/browser/custom_separators.html.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>math.js | custom separators</title>
  <style>
    body, input, select {
      font: 11pt sans-serif;
    }
    input, select, th, #result {
      padding: 5px 10px;
    }
    th {
      text-align: left;
    }
  </style>

  <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>
</head>
<body>

<p>
  This code example shows how to apply custom separators for function arguments and decimal separator.
</p>

<table>
  <tr>
    <th>Argument separator</th>
    <td>
      <input id="args" type="text" value=";">
    </td>
  </tr>
  <tr>
    <th>Decimal separator</th>
    <td>
      <input id="decimals" type="text" value=",">
    </td>
  </tr>
  <tr>
    <th>Expression</th>
    <td>
      <input id="expression" type="text" value="sum(3,4; 2,1; 2,0)" />
      <input id="evaluate" type="button" value="Evaluate">
    </td>
  </tr>
  <tr>
    <th>Result</th>
    <td id="result"></td>
  </tr>
</table>

<script>
  // pointers to the input elements
  const expression = document.getElementById('expression')
  const evaluate   = document.getElementById('evaluate')
  const result     = document.getElementById('result')
  const args       = document.getElementById('args')
  const decimals   = document.getElementById('decimals')

  // attach event handler to the button
  evaluate.onclick = function () {
    // replace the custom separators in the input with the default separators
    const expr = expression.value
        .replace(new RegExp('\\' + decimals.value + '|\\' + args.value, 'g'), function (match) {
          return match === decimals.value ? '.': ','
        })

    // do the actual evaluation
    const res = math.evaluate(expr)

    // replace the default separators in the output with custom separators
    result.innerHTML = res.toString()
        .replace(new RegExp(',|\\.', 'g'), function (match) {
          return match === '.' ? decimals.value : args.value
        })
  }
</script>


</body>
</html>

""".

mathjs.org/examples/browser/lorenz.html.html:
"""

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>math.js | Lorenz Attractor</title>
    <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>

    <script src="https://cdn.plot.ly/plotly-2.25.2.min.js" charset="utf-8"></script>
    <style>
        html, body {
            width: 100%;
            height: 100vh;
            padding: 0;
            margin: 0;
        } 
        body {
            display: flex;
            flex-direction: column;
        }

        #LorenzGraph {
            flex: 1;
        }
    </style>
</head>

<body>
    <div id="LorenzGraph"></div>
</body>
<script defer>

    // define the constants for the Lorenz attractor
    const sigma = 10
    const beta = 2.7
    const rho = 28

    // solve the Lorenz attractor
    const sol = math.solveODE(lorenz, [0, 100], [1, 1, 1])

    // make colors that represents time differences in the solution
    const diff = math.diff(sol.t)
    const color = [diff[0], ...diff]

    // render the plot using plotly
    Plotly.newPlot('LorenzGraph',
        [{
            x: sol.y.map(u => u[0]),
            y: sol.y.map(u => u[1]),
            z: sol.y.map(u => u[2]),
            line: { color, colorscale: 'Jet' },
            type: "scatter3d",
            mode: "lines"
        }],
        {
            responsive: true,
            uirevision: 'true',
            title:"Lorenz Attractor",
        }
    )

    // define the lorenz attractor
    function lorenz(t, u) {
        const [x, y, z] = u
        return [
            sigma * (y - x),
            x * (rho - z) - y,
            x * y - beta * z
        ]
    }
</script>

</html>

""".

mathjs.org/examples/browser/lorenz_interactive.html.html:
"""

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>math.js | Lorenz Attractor</title>
    <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>

    <script src="https://cdn.plot.ly/plotly-2.28.0.min.js" charset="utf-8"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.js"
        integrity="sha512-LQNxIMR5rXv7o+b1l8+N1EZMfhG7iFZ9HhnbJkTp4zjNr5Wvst75AqUeFDxeRUa7l5vEDyUiAip//r+EFLLCyA=="
        crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css"
        integrity="sha512-fHwaWebuwA7NSF5Qg/af4UeDx9XqUpYpOGgubo3yWu+b2IQR4UeQwbb42Ti7gVAjNtVoI/I9TEoYeu9omwcC6g=="
        crossorigin="anonymous" referrerpolicy="no-referrer" />
    <style>
        body,
        html {
            width: 100%;
            height: 100vh;
            padding: 0;
            margin: 0;
        }

        body {
            display: flex;
            flex-direction: column;
        }

        #LorenzGraph {
            flex: 1;
        }

        #inputsDiv {
            z-index: 1;
            position: absolute;
            background: white;
        }
    </style>
</head>

<body>
    <div id="LorenzGraph"></div>
    <div id="inputsDiv">
        <fieldset name="inputs" id="inputs">
            <legend for="inputs">Inputs:</legend>
            <table>
                <tr>
                    <td>
                        <label for="sigma" id="sigmaLabel">sigma</label>
                    </td>
                    <td>
                        <input type="range" id="sigma" name="sigma" value=10 min=9 max=11 step=0.01>
                    </td>
                    <td>
                        <label for="beta" id="betaLabel">beta</label>
                    </td>
                    <td>
                        <input type="range" id="beta" name="beta" value=8/3 min=2 max=4 step=0.01>
                    </td>
                    <td>
                        <label for="rho" id="rhoLabel">rho</label>
                    </td>
                    <td>
                        <input type="range" id="rho" name="rho" value=28 min=20 max=30 step=0.01>
                    </td>
                </tr>
                <tr>
                    <td>
                        <label for="x0" id="x0Label">x0</label>
                    </td>
                    <td>
                        <input type="range" id="x0" name="x0" value=1 min=-5 max=5 step=0.01>
                    </td>
                    <td>
                        <label for="y0" id="y0Label">y0</label>
                    </td>
                    <td>
                        <input type="range" id="y0" name="y0" value=1 min=-5 max=5 step=0.01>

                    </td>
                    <td>
                        <label for="z0" id="z0Label">z0</label>
                    </td>
                    <td>
                        <input type="range" id="z0" name="z0" value=0 min=-5 max=5 step=0.01>
                    </td>
                </tr>
                <tr>
                    <td>
                        <label for="epsilon" id="epsilonLabel">epsilon</label>
                    </td>
                    <td>
                        <input type="range" id="epsilon" name="epsilon" value=0.01 min=0.0001 max=0.1 step=0.0001>
                    </td>
                </tr>
            </table>
        </fieldset>
    </div>
</body>
<script defer>
    katex.render(String.raw`\sigma`, document.querySelector("#sigmaLabel"))
    katex.render(String.raw`\beta`, document.querySelector("#betaLabel"))
    katex.render(String.raw`\rho`, document.querySelector("#rhoLabel"))
    katex.render(String.raw`x_0`, document.querySelector("#x0Label"))
    katex.render(String.raw`y_0`, document.querySelector("#y0Label"))
    katex.render(String.raw`z_0`, document.querySelector("#z0Label"))
    katex.render(String.raw`\epsilon`, document.querySelector("#epsilonLabel"))

    const inputs = document.querySelector("#inputs")

    // define the constants for the Lorenz attractor
    const sigma = document.querySelector("#sigma")
    const beta = document.querySelector("#beta")
    const rho = document.querySelector("#rho")

    // define the initial location
    const x0 = document.querySelector('#x0')
    const y0 = document.querySelector('#y0')
    const z0 = document.querySelector('#z0')

    // define the tolerance for the solution
    const epsilon = document.querySelector('#epsilon')

    const layout = {
        interactive: true,
        title: 'Lorenz Attractor',
        uirevision: 'true',
        sliders: [{
            name: 'sigma',
            currentvalue: {
                xanchor: 'right',
                prefix: 'color: ',
                font: {
                    color: '#888',
                    size: 20
                }
            },
            steps: [{ label: 'g', method: "updateSolution" }, { label: 'f' }]
        }]
    }

    const t_span = [0, 100]

    inputs.addEventListener("change", updateSolution)

    let trace
    // solve the Lorenz attractor with the initial values
    updateSolution()

    // crates a trace in the format needed for plotly
    function createTrace(sol) {
        // make colors that represents time differences in the solution
        const diff = math.diff(sol.t)
        const color = [diff[0], ...diff]
        const trace = [{
            x: sol.y.map(u => u[0]),
            y: sol.y.map(u => u[1]),
            z: sol.y.map(u => u[2]),
            line: {
                color,
                colorscale: 'Jet'
            },
            type: "scatter3d",
            mode: "lines"
        }]
        return trace
    }

    function createLorenz(sigma, rho, beta) {
        // define the lorenz attractor as a function of t and u in the format needed for solveODE
        return function lorenz(t, u) {
            const [x, y, z] = u
            // return x', y', z'
            return [
                sigma * (y - x),
                x * (rho - z) - y,
                x * y - beta * z
            ]
        }
    }

    function updateSolution() {
        const y_0 = [x0.value, y0.value, z0.value]
        const sol = math.solveODE(createLorenz(sigma.value, rho.value, beta.value), t_span, y_0, { tol: epsilon.value })
        trace = createTrace(sol)
        // reactively render the plot on update
        Plotly.react('LorenzGraph', trace, layout)
    }

</script>

</html>

""".

mathjs.org/examples/browser/plot.html.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>math.js | plot</title>
  <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>

  <script src="https://cdn.plot.ly/plotly-1.35.2.min.js"></script>

  <style>
    input[type=text] {
      width: 300px;
    }
    input {
      padding: 6px;
    }
    body, html, input {
      font-family: sans-serif;
      font-size: 11pt;

    }
    form {
      margin: 20px 0;
    }
  </style>
</head>
<body>

<form id="form">
  <label for="eq">Enter an equation:</label>
  <input type="text" id="eq" value="4 * sin(x) + 5 * cos(x/2)" />
  <input type="submit" value="Draw" />
</form>

<div id="plot"></div>

<p>
  Used plot library: <a href="https://plot.ly/javascript/">Plotly</a>
</p>

<script>
  function draw() {
    try {
      // compile the expression once
      const expression = document.getElementById('eq').value
      const expr = math.compile(expression)

      // evaluate the expression repeatedly for different values of x
      const xValues = math.range(-10, 10, 0.5).toArray()
      const yValues = xValues.map(function (x) {
        return expr.evaluate({x: x})
      })

      // render the plot using plotly
      const trace1 = {
        x: xValues,
        y: yValues,
        type: 'scatter'
      }
      const data = [trace1]
      Plotly.newPlot('plot', data)
    }
    catch (err) {
      console.error(err)
      alert(err)
    }
  }

  document.getElementById('form').onsubmit = function (event) {
    event.preventDefault()
    draw()
  }

  draw()
</script>

</body>
</html>

""".

mathjs.org/examples/browser/pretty_printing_with_mathjax.html.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>math.js | pretty printing with MathJax</title>

  <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>

  <style>
    body,
    html,
    table td,
    table th,
    input[type=text] {
      font-size: 11pt;
      font-family: verdana, arial, sans-serif;
    }

    h1 {
      font-size: 11pt;
    }

    input[type=text] {
      padding: 5px;
      width: 400px;
    }

    table {
      border-collapse: collapse;
    }

    table td,
    table th {
      padding: 5px;
      border: 1px solid lightgray;
    }

    table th {
      background-color: lightgray;
    }

  </style>
</head>
<body>

<h1>
  Expression evaluation with math.js, pretty printing with MathJax
</h1>

<table>
  <tr>
    <th>Expression</th>
    <td><input type="text" id="expr"/></td>
  </tr>
  <tr>
    <th>Pretty print</th>
    <td><div id="pretty"></div></td>
  </tr>
  <tr>
    <th>Result</th>
    <td><div id="result"></div></td>
  </tr>
</table>
<b>Parenthesis option:</b>
<input type="radio" name="parenthesis" value="keep" onclick="parenthesis = 'keep'; expr.oninput();" checked>keep
<input type="radio" name="parenthesis" value="auto" onclick="parenthesis = 'auto'; expr.oninput();">auto
<input type="radio" name="parenthesis" value="all" onclick="parenthesis = 'all'; expr.oninput();">all
<br/>
<b>Implicit multiplication:</b>
<input type="radio" name="implicit" value="hide" onclick="implicit = 'hide'; expr.oninput();" checked>hide
<input type="radio" name="implicit" value="show" onclick="implicit = 'show'; expr.oninput();">show


<script>
  const expr = document.getElementById('expr')
  const pretty = document.getElementById('pretty')
  const result = document.getElementById('result')
  let parenthesis = 'keep'
  let implicit = 'hide'

  const mj = function (tex) {
    return MathJax.tex2svg(tex, {em: 16, ex: 6, display: false});
  }

  // initialize with an example expression
  expr.value = 'sqrt(75 / 3) + det([[-1, 2], [3, 1]]) - sin(pi / 4)^2'
  pretty.innerHTML = '';
  pretty.appendChild(mj(math.parse(expr.value).toTex({parenthesis: parenthesis})));
  result.innerHTML = math.format(math.evaluate(expr.value))

  expr.oninput = function () {
    let node = null

    try {
      // parse the expression
      node = math.parse(expr.value)

      // evaluate the result of the expression
      result.innerHTML = math.format(node.compile().evaluate())
    }
    catch (err) {
      result.innerHTML = '<span style="color: red;">' + err.toString() + '</span>'
    }

    try {
      // export the expression to LaTeX
      const latex = node ? node.toTex({parenthesis: parenthesis, implicit: implicit}) : ''
      console.log('LaTeX expression:', latex)

      // display and re-render the expression
      MathJax.typesetClear();
      pretty.innerHTML = '';
      pretty.appendChild(mj(latex));
    }
    catch (err) {}
  }
</script>

</body>
</html>

""".

mathjs.org/examples/browser/printing_html.html.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title>math.js | printing HTML</title>

	<script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>

	<style>
		body {
			font-size: 11pt;
			font-family: verdana, arial, sans-serif;
		}

		h1 {
			font-size: 1rem;
		}

		fieldset {
			display: inline;
			margin: 0 50px 10px 0;
			padding: 0;
			border: none;
		}

		input[type=text] {
			font-size: 11pt;
			font-family: verdana, arial, sans-serif;
			padding: 5px;
			width: calc(100% - 14px);
		}

		label {
			margin: 0 5px 0 0;
		}

		table {
			width: 100%;
			border-collapse: collapse;
		}

		table td,
		table th {
			padding: 5px;
			border: 1px solid LightGrey;
		}

		table th {
			background-color: LightGrey;
		}

		/* style the HTML output */
		.math-function {
			color: Purple;
			font-weight: bold;
		}

		.math-number {
			color: Blue;
		}

		.math-boolean {
			color: Green;
		}

		.math-string {
			color: Grey;
		}

		.math-string::before,
		.math-string::after {
			content: "\"";
		}

		.math-property {
			font-style: italic;
		}

		.math-explicit-binary-operator::before,
		.math-explicit-binary-operator::after {
			content: " ";
		}

		.math-separator::after,
		.math-assignment-operator::after {
			content: " ";
		}
	</style>
</head>
<body>
<h1>Expression evaluation and HTML code generation with math.js</h1>
<form>
	<fieldset>
		Parenthesis option:
		<label><input type="radio" name="parenthesis" value="keep" checked>keep</label>
		<label><input type="radio" name="parenthesis" value="auto">auto</label>
		<label><input type="radio" name="parenthesis" value="all">all</label>
	</fieldset>
	<fieldset>
		Implicit multiplication:
		<label><input type="radio" name="implicit" value="hide" checked>hide</label>
		<label><input type="radio" name="implicit" value="show">show</label>
	</fieldset>
</form>
<table>
	<tr>
		<th>Expression</th>
		<td><input type="text" id="expr"/></td>
	</tr>
	<tr>
		<th>Result</th>
		<td><div id="result"></div></td>
	</tr>
	<tr>
		<th>HTML output</th>
		<td><div id="output">$$$$</div></td>
	</tr>
	<tr>
		<th>HTML code</th>
		<td><div id="code">$$$$</div></td>
	</tr>
</table>
<script>
  const expr = document.getElementById('expr')
  const output = document.getElementById('output')
  const code = document.getElementById('code')
  const result = document.getElementById('result')
  let options = {parenthesis: 'keep', implicit: 'hide'}

  // initialize with an example expression
  expr.value = 'sqrt(75/3)+det([[-1,2],[3,1]])-sin(pi/4)^2'

  function print () {
    let parsed = null

    try {
      // parse the expression
      parsed = math.parse(expr.value)

      // evaluate the result of the expression
      result.innerHTML = math.format(parsed.compile().evaluate())

      // print the HTML output
      const html = math.parse(expr.value).toHTML(options)
      output.innerHTML = html

      // print the HTML code
      code.innerHTML = html.replace(/</g, '&lt;').
      replace(/>/g, '&gt;').
      replace(/&lt;\/span&gt;/g, '&lt;/span&gt;<br />')
    }
    catch (err) {
      result.innerHTML = '<span style="color: red;">' + err.toString() + '</span>'
    }
  }

  window.onload = print
  expr.oninput = print

  // make the controls work
  const controls = document.querySelectorAll('input[type=radio]')
  controls.forEach(function (control) {
    control.onclick = function() {
      options[control.name] = control.value
      print()
    }
  })
</script>
</body>
</html>

""".

mathjs.org/examples/browser/requirejs_loading.html.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>math.js | require.js loading</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.20/require.min.js"></script>
</head>
<body>

<script>
  // load math.js using require.js
  require(['https://unpkg.com/mathjs@14.3.1/lib/browser/math.js'], function (math) {
    // evaluate some expression
    const result = math.evaluate('1.2 * (2 + 4.5)')
    document.write(result)
  })
</script>

</body>
</html>

""".

mathjs.org/examples/browser/rocket_trajectory_optimization.html.html:
"""

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>math.js | rocket trajectory optimization</title>

  <script src="https://unpkg.com/mathjs@14.3.1/lib/browser/math.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>

  <style>
    body {
      font-family: sans-serif;
    }

    #canvas-grid {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
      gap: 5%;
      margin-top: 5%;
    }

    #canvas-grid>div {
      overflow: hidden;
    }
  </style>
</head>

<body>
  <h1>Rocket trajectory optimization</h1>
  <p>
    This example simulates the launch of a SpaceX Falcon 9 modeled using a system of ordinary differential equations.
  </p>

  <canvas id="canvas" width="1600" height="600"></canvas>
  <div id="canvas-grid"></div>

  <script>
    // Solve ODE `dx/dt = f(x,t), x(0) = x0` numerically.
    function ndsolve(f, x0, dt, tmax) {
      let x = x0.clone()  // Current values of variables
      const result = [x]  // Contains entire solution
      const nsteps = math.divide(tmax, dt)   // Number of time steps
      for (let i = 0; i < nsteps; i++) {
        // Compute derivatives
        const dxdt = f.map(func => func(...x.toArray()))
        // Euler method to compute next time step
        const dx = math.multiply(dxdt, dt)
        x = math.add(x, dx)
        result.push(x)
      }
      return math.matrix(result)
    }

    // Import the numerical ODE solver
    math.import({ ndsolve })

    // Create a math.js context for our simulation. Everything else occurs in the context of the expression parser!
    const sim = math.parser()

    sim.evaluate("G = 6.67408e-11 m^3 kg^-1 s^-2")  // Gravitational constant
    sim.evaluate("mbody = 5.9724e24 kg")            // Mass of Earth
    sim.evaluate("mu = G * mbody")                  // Standard gravitational parameter
    sim.evaluate("g0 = 9.80665 m/s^2")              // Standard gravity: used for calculating prop consumption (dmdt)
    sim.evaluate("r0 = 6371 km")                    // Mean radius of Earth
    sim.evaluate("t0 = 0 s")                        // Simulation start
    sim.evaluate("dt = 0.5 s")                      // Simulation timestep
    sim.evaluate("tfinal = 149.5 s")                // Simulation duration
    sim.evaluate("isp_sea = 282 s")                 // Specific impulse (at sea level)
    sim.evaluate("isp_vac = 311 s")                 // Specific impulse (in vacuum)
    sim.evaluate("gamma0 = 89.99970 deg")           // Initial pitch angle (90 deg is vertical)
    sim.evaluate("v0 = 1 m/s")                      // Initial velocity (must be non-zero because ODE is ill-conditioned)
    sim.evaluate("phi0 = 0 deg")                    // Initial orbital reference angle
    sim.evaluate("m1 = 433100 kg")                  // First stage mass
    sim.evaluate("m2 = 111500 kg")                  // Second stage mass
    sim.evaluate("m3 = 1700 kg")                    // Third stage / fairing mass
    sim.evaluate("mp = 5000 kg")                    // Payload mass
    sim.evaluate("m0 = m1+m2+m3+mp")                // Initial mass of rocket
    sim.evaluate("dm = 2750 kg/s")                  // Mass flow rate
    sim.evaluate("A = (3.66 m)^2 * pi")             // Area of the rocket
    sim.evaluate("dragCoef = 0.2")                  // Drag coefficient

    // Define the equations of motion. We just thrust into current direction of motion, e.g. making a gravity turn.
    sim.evaluate("gravity(r) = mu / r^2")
    sim.evaluate("angVel(r, v, gamma) = v/r * cos(gamma) * rad")   // Angular velocity of rocket around moon
    sim.evaluate("density(r) = 1.2250 kg/m^3 * exp(-g0 * (r - r0) / (83246.8 m^2/s^2))") // Assume constant temperature
    sim.evaluate("drag(r, v) = 1/2 * density(r) .* v.^2 * A * dragCoef")
    sim.evaluate("isp(r) = isp_vac + (isp_sea - isp_vac) * density(r)/density(r0)") // pressure ~ density for constant temperature
    sim.evaluate("thrust(isp) = g0 * isp * dm")
    // It is important to maintain the same argument order for each of these functions.
    sim.evaluate("drdt(r, v, m, phi, gamma, t) = v sin(gamma)")
    sim.evaluate("dvdt(r, v, m, phi, gamma, t) = - gravity(r) * sin(gamma) + (thrust(isp(r)) - drag(r, v)) / m")
    sim.evaluate("dmdt(r, v, m, phi, gamma, t) = - dm")
    sim.evaluate("dphidt(r, v, m, phi, gamma, t) = angVel(r, v, gamma)")
    sim.evaluate("dgammadt(r, v, m, phi, gamma, t) = angVel(r, v, gamma) - gravity(r) * cos(gamma) / v * rad")
    sim.evaluate("dtdt(r, v, m, phi, gamma, t) = 1")

    // Remember to maintain the same variable order in the call to ndsolve.
    sim.evaluate("result_stage1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], [r0, v0, m0, phi0, gamma0, t0], dt, tfinal)")

    // Reset initial conditions for interstage flight
    sim.evaluate("dm = 0 kg/s")
    sim.evaluate("tfinal = 10 s")
    sim.evaluate("x = flatten(result_stage1[end,:])")
    sim.evaluate("x[3] = m2+m3+mp") // New mass after stage seperation
    sim.evaluate("result_interstage = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")

    // Reset initial conditions for stage 2 flight
    sim.evaluate("dm = 270.8 kg/s")
    sim.evaluate("isp_vac = 348 s")
    sim.evaluate("tfinal = 350 s")
    sim.evaluate("x = flatten(result_interstage[end,:])")
    sim.evaluate("result_stage2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")

    // Reset initial conditions for unpowered flight
    sim.evaluate("dm = 0 kg/s")
    sim.evaluate("tfinal = 900 s")
    sim.evaluate("dt = 10 s")
    sim.evaluate("x = flatten(result_stage2[end,:])")
    sim.evaluate("result_unpowered1 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")

    // Reset initial conditions for final orbit insertion
    sim.evaluate("dm = 270.8 kg/s")
    sim.evaluate("tfinal = 39 s")
    sim.evaluate("dt = 0.5 s")
    sim.evaluate("x = flatten(result_unpowered1[end,:])")
    sim.evaluate("result_insertion = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")

    // Reset initial conditions for unpowered flight
    sim.evaluate("dm = 0 kg/s")
    sim.evaluate("tfinal = 250 s")
    sim.evaluate("dt = 10 s")
    sim.evaluate("x = flatten(result_insertion[end,:])")
    sim.evaluate("result_unpowered2 = ndsolve([drdt, dvdt, dmdt, dphidt, dgammadt, dtdt], x, dt, tfinal)")

    // Now it's time to prepare results for plotting
    const resultNames = ['stage1', 'interstage', 'stage2', 'unpowered1', 'insertion', 'unpowered2']
      .map(stageName => `result_${stageName}`)

    // Concat result matrices
    sim.set('result',
      math.concat(
        ...resultNames.map(resultName =>
          sim.evaluate(`${resultName}[:end-1, :]`)  // Avoid overlap
        ),
        0 // Concat in row-dimension
      )
    )

    const mainDatasets = resultNames.map((resultName, i) => ({
      label: resultName.slice(7),
      data: sim.evaluate(
        'concat('
        + `(${resultName}[:,4] - phi0) * r0 / rad / km,`  // Surface distance from start (in km)
        + `(${resultName}[:,1] - r0) / km`                // Height above surface (in km)
        + ')'
      ).toArray().map(([x, y]) => ({ x, y })),
      borderColor: i % 2 ? '#999' : '#dc3912',
      fill: false,
      pointRadius: 0,
    }))
    new Chart(document.getElementById('canvas'), {
      type: 'line',
      data: { datasets: mainDatasets },
      options: getMainChartOptions()
    })

    createChart([{
      label: 'velocity (in m/s)',
      data: sim.evaluate("result[:,[2,6]]")
        .toArray()
        .map(([v, t]) => ({ x: t.toNumber('s'), y: v.toNumber('m/s') }))
    }])
    createChart([{
      label: 'height (in km)',
      data: sim.evaluate("concat((result[:, 1] - r0), result[:, 6])")
        .toArray()
        .map(([r, t]) => ({ x: t.toNumber('s'), y: r.toNumber('km') })),
    }])
    createChart([{
      label: 'gamma (in deg)',
      data: sim.evaluate("result[:, [5,6]]")
        .toArray()
        .map(([gamma, t]) => ({ x: t.toNumber('s'), y: gamma.toNumber('deg') })),
    }])
    createChart([{
      label: 'acceleration (in m/s^2)',
      data: sim.evaluate("concat(diff(result[:, 2]) ./ diff(result[:, 6]), result[:end-1, 6])")
        .toArray()
        .map(([acc, t]) => ({ x: t.toNumber('s'), y: acc.toNumber('m/s^2') })),
    }])
    createChart([{
      label: 'drag acceleration (in m/s^2)',
      data: sim.evaluate('result')
        .toArray()
        .map(([r, v, m, phi, gamma, t]) => ({
          x: t.toNumber('s'),
          y: sim.evaluate(`drag(${r},${v})/${m}`).toNumber('m/s^2')
        }))
    }])
    createChart(
      [
        {
          data: sim.evaluate("result[:, [1,4]]")
            .toArray()
            .map(([r, phi]) => math.rotate([r.toNumber('km'), 0], phi))
            .map(([x, y]) => ({ x, y })),
        },
        {
          data: sim.evaluate("map(0:0.25:360, function(angle) = rotate([r0/km, 0], angle))")
            .toArray()
            .map(([x, y]) => ({ x, y })),
          borderColor: "#999",
          fill: true
        }
      ],
      getEarthChartOptions()
    )

    // Helper functions for plotting data (nothing to learn about math.js from here on)
    function createChart(datasets, options = {}) {
      const container = document.createElement("div")
      document.querySelector("#canvas-grid").appendChild(container)
      const canvas = document.createElement("canvas")
      container.appendChild(canvas)
      new Chart(canvas, {
        type: 'line',
        data: {
          datasets: datasets.map(dataset => ({
            borderColor: "#dc3912",
            fill: false,
            pointRadius: 0,
            ...dataset
          }))
        },
        options: getChartOptions(options)
      })
    }

    function getMainChartOptions() {
      return {
        scales: {
          xAxes: [{
            type: 'linear',
            position: 'bottom',
            scaleLabel: {
              display: true,
              labelString: 'surface distance travelled (in km)'
            }
          }],
          yAxes: [{
            type: 'linear',
            scaleLabel: {
              display: true,
              labelString: 'height above surface (in km)'
            }
          }]
        },
        animation: false
      }
    }

    function getChartOptions(options) {
      return {
        scales: {
          xAxes: [{
            type: 'linear',
            position: 'bottom',
            scaleLabel: {
              display: true,
              labelString: 'time (in s)'
            }
          }]
        },
        animation: false,
        ...options
      }
    }

    function getEarthChartOptions() {
      return {
        aspectRatio: 1,
        scales: {
          xAxes: [{
            type: 'linear',
            position: 'bottom',
            min: -8000,
            max: 8000,
            display: false
          }],
          yAxes: [{
            type: 'linear',
            min: -8000,
            max: 8000,
            display: false
          }]
        },
        legend: { display: false }
      }
    }
  </script>
</body>

</html>

""".

mathjs.org/examples/browser/webworkers/index.html:
"""

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>math.js | web workers</title>
</head>
<body>

<p>
  In this example, a math.js parser is running in a separate
  <a href="https://www.html5rocks.com/en/tutorials/workers/basics/">web worker</a>,
  preventing the user interface from freezing during heavy calculations.
</p>

<p id="results"></p>

<script>
  /**
   * MathWorker evaluates expressions asynchronously in a web worker.
   *
   * Example usage:
   *
   *     const worker = new MathWorker()
   *     const expr = '12 / (2.3 + 0.7)'
   *     worker.evaluate(expr, function (err, result) {
   *       console.log(err, result)
   *     })
   */
  function MathWorker () {
    this.worker = new Worker('worker.js')
    this.callbacks = {}
    this.seq = 0

    // create a listener to receive responses from the web worker
    const me = this
    this.worker.addEventListener('message', function(event) {
      const response = JSON.parse(event.data)

      // find the callback corresponding to this response
      const callback = me.callbacks[response.id]
      delete me.callbacks[response.id]

      // call the requests callback with the result
      callback(response.err, response.result)
    }, false)
  }

  /**
   * Evaluate an expression
   * @param {string} expr
   * @param {Function} callback   Called as callback(err, result)
   */
  MathWorker.prototype.evaluate = function evaluate (expr, callback) {
    // build a request,
    // add an id so we can link returned responses to the right callback
    const id = this.seq++
    const request = {
      id: id,
      expr: expr
    }

    // queue the callback, it will be called when the worker returns the result
    this.callbacks[id] = callback

    // send the request to the worker
    this.worker.postMessage(JSON.stringify(request))
  }

  // create a MathWorker
  const worker = new MathWorker()

  // evaluate an expression via the worker
  worker.evaluate('12 / (2.3 + 0.7)', function (err, result) {
    document.getElementById('results').innerHTML += 'result: ' + result + '<br>'
  })

</script>

</body>
</html>


importScripts('https://unpkg.com/mathjs@14.3.1/lib/browser/math.js')

// create a parser
const parser = self.math.parser()

self.addEventListener('message', function (event) {
  const request = JSON.parse(event.data)
  let result = null
  let err = null

  try {
    // evaluate the expression
    result = parser.evaluate(request.expr)
  } catch (e) {
    // return the error
    err = e
  }

  // build a response
  const response = {
    id: request.id,
    result: self.math.format(result),
    err: err
  }

  // send the response back
  self.postMessage(JSON.stringify(response))
}, false)

""".

Advanced examples:

mathjs.org/examples/advanced/convert_fraction_to_bignumber.js.html:
"""

// 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.

// Create an empty math.js instance, with only typed
// (every instance contains `import` and `config` also out of the box)
import { create, typedDependencies, all } from 'mathjs'
const math = create({
  typedDependencies
})

// TODO: this should be much easier
const allExceptLoaded = Object.keys(all)
  .map(key => all[key])
  .filter(factory => math[factory.fn] === undefined)

// Configure to use fractions by default
math.config({ number: 'Fraction' })

// Add a conversion from Faction -> BigNumber
// This conversion will to override the existing conversion from Fraction to 
// BigNumber. It must be added *after* the default conversions are loaded
// and *before* the actual functions are imported into math.js.
math.typed.addConversion({
  from: 'Fraction',
  to: 'BigNumber',
  convert: (fraction) => new math.BigNumber(fraction.n).div(fraction.d)
}, { override: true })

// Import all data types, functions, constants, the expression parser, etc.
math.import(allExceptLoaded)

// Operators `add` and `divide` do have support for Fractions, so the result
// will simply be a Fraction (default behavior of math.js).
const ans1 = math.evaluate('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.
const ans2 = math.evaluate('sqrt(4)')
console.log(math.typeOf(ans2), math.format(ans2))
// outputs "BigNumber 2"

// We can now do operations with mixed Fractions and BigNumbers
const ans3 = math.add(math.fraction(2, 5), math.bignumber(3))
console.log(math.typeOf(ans3), math.format(ans3))
// outputs "BigNumber 3.4"

""".

mathjs.org/examples/advanced/custom_argument_parsing.js.html:
"""

/**
 * 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.
 */
import { create, all } from 'mathjs'
const math = create(all)

/**
 * 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) {
  let total = 0
  step = step || 0.01
  for (let 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.evaluate('integrate(2*x, x, 0, 2)')
 *     math.evaluate('integrate(2*x, x, 0, 2, 0.01)')
 *
 * @param {Array.<math.Node>} args
 *            Expects the following arguments: [f, x, start, end, step]
 * @param {Object} math
 * @param {Map} [scope]
 */
integrate.transform = function (args, math, scope) {
  // determine the variable name
  if (!args[1].isSymbolNode) {
    throw new Error('Second argument must be a symbol')
  }
  const variable = args[1].name

  // evaluate start, end, and step
  const start = args[2].compile().evaluate(scope)
  const end = args[3].compile().evaluate(scope)
  const step = args[4] && args[4].compile().evaluate(scope) // step is optional

  // construct a function which evaluates the first parameter f after applying
  // a value for parameter x.
  const fnCode = args[0].compile()
  const f = function (x) {
    scope.set(variable, x)
    return fnCode.evaluate(scope)
  }

  // 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 `evaluate(scope)`.
math.import({
  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.evaluate('integrate(x^0.5, x, 0, 1)')) // outputs 0.6667254718034714

// use the function via the expression parser (2)
const scope = new Map()
math.evaluate('f(x) = 2 * x', scope)
console.log(math.evaluate('integrate(f(x), x, 0, 2)', scope)) // outputs 4.000000000000003

""".

mathjs.org/examples/advanced/custom_datatype.js.html:
"""

// This example demonstrates importing a custom data type,
// and extending an existing function (add) with support for this data type.

import { all, create, factory } from 'mathjs'

const math = create(all)

// factory function which defines a new data type CustomValue
const createCustomValue = factory('CustomValue', ['typed'], ({ typed }) => {
  // create a new data type
  function CustomValue (value) {
    this.value = value
  }
  CustomValue.prototype.isCustomValue = true
  CustomValue.prototype.toString = function () {
    return 'CustomValue:' + this.value
  }

  // define a new data type with typed-function
  typed.addType({
    name: 'CustomValue',
    test: function (x) {
      // test whether x is of type CustomValue
      return x && x.isCustomValue === true
    }
  })

  return CustomValue
})

// function add which can add the CustomValue data type
// When imported in math.js, the existing function `add` with support for
// CustomValue, because both implementations are typed-functions and do not
// have conflicting signatures.
const createAddCustomValue = factory('add', ['typed', 'CustomValue'], ({ typed, CustomValue }) => {
  return typed('add', {
    'CustomValue, CustomValue': function (a, b) {
      return new CustomValue(a.value + b.value)
    }
  })
})

// import the new data type and function
math.import([
  createCustomValue,
  createAddCustomValue
])

// use the new type
const ans1 = math.add(new math.CustomValue(2), new math.CustomValue(3))
console.log(ans1.toString())
// outputs 'CustomValue:5'

// you can automatically use the new type in functions which use `add` under the hood:
const ans2 = math.sum(new math.CustomValue(6), new math.CustomValue(1), new math.CustomValue(2))
console.log(ans2.toString())
// outputs 'CustomValue:9'

""".

mathjs.org/examples/advanced/custom_evaluate_using_factories.js.html:
"""

// we use the number only implementation in order to not pull in
// the `Unit` class for example. when using as library,
// use import 'mathjs/number'
import { create, evaluateDependencies, factory } from 'mathjs/number'

// custom implementations of all functions you want to support
const add = (a, b) => a + b
const subtract = (a, b) => a - b
const multiply = (a, b) => a * b
const divide = (a, b) => a / b

// create factories for the functions, and create an evaluate function with those
// these functions will also be used by the classes like Unit.
const { evaluate } = create({
  evaluateDependencies,
  createAdd: factory('add', [], () => add),
  createSubtract: factory('subtract', [], () => subtract),
  createMultiply: factory('multiply', [], () => multiply),
  createDivide: factory('divide', [], () => divide)
})

console.log(evaluate('2 + 3 * 4')) // 14

""".

mathjs.org/examples/advanced/custom_evaluate_using_import.js.html:
"""

// we use the number only implementation in order to not pull in
// the `Unit` class for example. when using as library,
// use require('mathjs/number')
import { create, evaluateDependencies } from 'mathjs/number'

// custom implementations of all functions you want to support
const add = (a, b) => a + b
const subtract = (a, b) => a - b
const multiply = (a, b) => a * b
const divide = (a, b) => a / b

// create a mathjs instance with hardly any functions
// there are some functions created which are used internally by evaluate though,
// for example by the Unit class which has dependencies on addScalar, subtractScalar,
// multiplyScalar, etc.
const math = create(evaluateDependencies)

// import your own functions
math.import({ add, subtract, multiply, divide }, { override: true })

console.log(math.evaluate('2 + 3 * 4')) // 14

""".

mathjs.org/examples/advanced/custom_loading.js.html:
"""

import {
  addDependencies,
  create,
  divideDependencies,
  formatDependencies,
  fractionDependencies
} from 'mathjs'

const config = {
  // optionally, you can specify configuration
}

// Create just the functions we need
const { fraction, add, divide, format } = create({
  fractionDependencies,
  addDependencies,
  divideDependencies,
  formatDependencies
}, config)

// Use the created functions
const a = fraction(1, 3)
const b = fraction(3, 7)
const c = add(a, b)
const d = divide(a, b)
console.log('c =', format(c)) // outputs "c = 16/21"
console.log('d =', format(d)) // outputs "d = 7/9"

// 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 Webpack:
//
//     npx webpack-cli ./custom_loading.mjs --output-path custom_loading_bundle --mode=production
//
// Read more about what bundle sizes you can expect here:
//
//     mathjs.org/docs/custom_bundling.html

""".

mathjs.org/examples/advanced/custom_relational_functions.js.html:
"""

import { all, create, factory } from 'mathjs'

// First let's see what the default behavior is:
// strings are compared by their numerical value
console.log('default (compare string by their numerical value)')
const { evaluate } = create(all)
evaluateAndLog(evaluate, '2 < 10') // true
evaluateAndLog(evaluate, '"2" < "10"') // true
evaluateAndLog(evaluate, '"a" == "b"') // Error: Cannot convert "a" to a number
evaluateAndLog(evaluate, '"a" == "a"') // Error: Cannot convert "a" to a number
console.log('')

// Suppose we want different behavior for string comparisons. To achieve
// this we can replace the factory functions for all relational functions
// with our own. In this simple example we use the JavaScript implementation.
console.log('custom (compare strings lexically)')

const allWithCustomFunctions = {
  ...all,

  createEqual: factory('equal', [], () => function equal (a, b) {
    return a === b
  }),

  createUnequal: factory('unequal', [], () => function unequal (a, b) {
    return a !== b
  }),

  createSmaller: factory('smaller', [], () => function smaller (a, b) {
    return a < b
  }),

  createSmallerEq: factory('smallerEq', [], () => function smallerEq (a, b) {
    return a <= b
  }),

  createLarger: factory('larger', [], () => function larger (a, b) {
    return a > b
  }),

  createLargerEq: factory('largerEq', [], () => function largerEq (a, b) {
    return a >= b
  }),

  createCompare: factory('compare', [], () => function compare (a, b) {
    return a > b ? 1 : a < b ? -1 : 0
  })
}
const evaluateCustom = create(allWithCustomFunctions).evaluate
evaluateAndLog(evaluateCustom, '2 < 10') // true
evaluateAndLog(evaluateCustom, '"2" < "10"') // false
evaluateAndLog(evaluateCustom, '"a" == "b"') // false
evaluateAndLog(evaluateCustom, '"a" == "a"') // true

// helper function to evaluate an expression and print the results
function evaluateAndLog (evaluate, expression) {
  try {
    console.log(expression, evaluate(expression))
  } catch (err) {
    console.error(expression, err.toString())
  }
}

""".

mathjs.org/examples/advanced/custom_scope_objects.js.html:
"""

import { all, create } from 'mathjs'

const math = create(all)

// The expression evaluator accepts an optional scope Map or object that can
// be used to keep additional variables and functions.

// Scope can be a bare object.
function withObjectScope () {
  const scope = { x: 3 }

  math.evaluate('x', scope) // 1
  math.evaluate('y = 2 x', scope)
  math.evaluate('scalar = 1', scope)
  math.evaluate('area(length, width) = length * width * scalar', scope)
  math.evaluate('A = area(x, y)', scope)

  console.log('Object scope:', scope)
}

// Where flexibility is important, scope can duck type appear to be a Map.
function withMapScope (scope, name) {
  scope.set('x', 3)

  math.evaluate('x', scope) // 1
  math.evaluate('y = 2 x', scope)
  math.evaluate('scalar = 1', scope)
  math.evaluate('area(length, width) = length * width * scalar', scope)
  math.evaluate('A = area(x, y)', scope)

  console.log(`Map-like scope (${name}):`, scope)
}

// This is a minimal set of functions to look like a Map.
class CustomMap {
  constructor () {
    this.localScope = new Map()
  }

  get (key) {
    // Remember to sanitize your inputs, or use
    // a datastructure that isn't a footgun.
    return this.localScope.get(key)
  }

  set (key, value) {
    return this.localScope.set(key, value)
  }

  has (key) {
    return this.localScope.has(key)
  }

  keys () {
    return this.localScope.keys()
  }
}

/*
 * This is a more fully featured example, with all methods
 * used in mathjs.
 *
 */
class AdvancedCustomMap extends CustomMap {
  constructor (parent) {
    super()
    this.parentScope = parent
  }

  get (key) {
    return this.localScope.get(key) ?? this.parentScope?.get(key)
  }

  has (key) {
    return this.localScope.has(key) ?? this.parentScope?.get(key)
  }

  keys () {
    if (this.parentScope) {
      return new Set([...this.localScope.keys(), ...this.parentScope.keys()])
    } else {
      return this.localScope.keys()
    }
  }

  delete () {
    return this.localScope.delete()
  }

  clear () {
    return this.localScope.clear()
  }

  toString () {
    return this.localScope.toString()
  }
}

// Use a plain JavaScript object
withObjectScope()

// use a Map (recommended)
withMapScope(new Map(), 'Map example')

// Use a custom Map implementation
withMapScope(new CustomMap(), 'CustomMap example')

// Use a more advanced custom Map implementation
withMapScope(new AdvancedCustomMap(), 'AdvancedCustomMap example')

""".

mathjs.org/examples/advanced/expression_trees.js.html:
"""

import { parse, ConstantNode } from 'mathjs'

// Filter an expression tree
console.log('Filter all symbol nodes "x" in the expression "x^2 + x/4 + 3*y"')
const node = parse('x^2 + x/4 + 3*y')
const 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"')
const node1 = 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')
const node2 = parse('x^2 + 5*x')
const transformed = node2.transform(function (node, path, parent) {
  if (node.isSymbolNode && node.name === 'x') {
    return new ConstantNode(3)
  } else {
    return node
  }
})
console.log(transformed.toString())
// outputs: '3 ^ 2 + 5 * 3'

""".

mathjs.org/examples/advanced/function_transform.js.html:
"""

/**
 * 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.
 */
import { all, create } from 'mathjs'
const math = create(all)

// 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

  const 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.evaluate('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

""".

mathjs.org/examples/advanced/more_secure_eval.js.html:
"""

// Expression parser security
//
// Executing arbitrary expressions like enabled by the expression parser of
// mathjs involves a risk in general. When you're using mathjs to let users
// execute arbitrary expressions, it's good to take a moment to think about
// possible security and stability implications, especially when running the
// code server side.
//
// There is a small number of functions which yield the biggest security risk
// in the expression parser of math.js:
//
// - `import` and `createUnit` which alter the built-in functionality and allow
//   overriding existing functions and units.
// - `evaluate`, `parse`, `simplify`, and `derivative` which parse arbitrary input
//   into a manipulable expression tree.
//
// To make the expression parser less vulnerable whilst still supporting most
// functionality, these functions can be disabled, as demonstrated in this
// example.

import { all, create } from 'mathjs'
const math = create(all)

const limitedEvaluate = math.evaluate

math.import({
  import: function () { throw new Error('Function import is disabled') },
  createUnit: function () { throw new Error('Function createUnit is disabled') },
  evaluate: function () { throw new Error('Function evaluate is disabled') },
  parse: function () { throw new Error('Function parse is disabled') },
  simplify: function () { throw new Error('Function simplify is disabled') },
  derivative: function () { throw new Error('Function derivative is disabled') }
}, { override: true })

console.log(limitedEvaluate('sqrt(16)')) // Ok, 4
console.log(limitedEvaluate('parse("2+3")')) // Error: Function parse is disabled

""".

mathjs.org/examples/advanced/web_server/index.html:
"""

File: math_worker.js

const { create, all } = require('../../..')
const workerpool = require('workerpool')
const math = create(all)

// 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) {
  const ans = math.evaluate(expr)
  return math.format(ans)
}

// create a worker and register public functions
workerpool.worker({
  evaluate: evaluate
})

File: server.js

/**
 * 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.
 */
const path = require('path')

let express
let workerpool
try {
  express = require('express')
  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()
}

const app = express()
const pool = workerpool.pool(path.join(__dirname, '/math_worker.js'))

const TIMEOUT = 10000 // milliseconds

/**
 * GET /mathjs?expr=...
 */
app.get('/mathjs', function (req, res) {
  const 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
const 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)')
})

""".