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:

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:

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 })
Fork me on GitHub