2621 lines
63 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
AccessorNode,
addDependencies,
all,
ArrayNode,
AssignmentNode,
BigNumber,
BlockNode,
Complex,
ConditionalNode,
ConstantNode,
create,
divideDependencies,
EvalFunction,
factory,
formatDependencies,
Fraction,
fractionDependencies,
FunctionAssignmentNode,
FunctionNode,
Help,
Index,
IndexNode,
LUDecomposition,
MathArray,
MathCollection,
MathJsChain,
MathJsFunctionName,
MathNode,
MathNumericType,
MathType,
Matrix,
ObjectNode,
OperatorNode,
OperatorNodeFn,
OperatorNodeOp,
ParenthesisNode,
PolarCoordinates,
QRDecomposition,
RangeNode,
SimplifyRule,
SLUDecomposition,
SymbolNode,
MathNodeCommon,
Unit,
Node,
isSymbolNode,
MathScalarType
} from 'mathjs'
import * as assert from 'assert'
import { expectTypeOf } from 'expect-type'
// This file serves a dual purpose:
// 1) examples of how to use math.js in TypeScript
// 2) tests for the TypeScript declarations provided by math.js
/*
Basic usage examples
*/
{
const math = create(all)
const m2by2 = [
[-1, 2],
[3, 1]
]
const m2by3 = [
[1, 2, 3],
[4, 5, 6]
]
// functions and constants
math.round(math.e, 3)
math.round(100.123, 3)
math.atan2(3, -3) / math.pi
math.log(10000, 10)
math.sqrt(-4)
math.pow(m2by2, 2)
const angle = 0.2
math.add(math.pow(math.sin(angle), 2), math.pow(math.cos(angle), 2))
math.add(2, 3, 4)
math.add(2, 3, math.bignumber(4))
math.multiply(2, 3, 4)
math.multiply(2, 3, math.bignumber(4))
// std and variance check
math.std(1, 2, 3)
math.std([1, 2, 3])
math.std([1, 2, 3], 'biased')
math.std([1, 2, 3], 0, 'biased')
math.std(m2by3, 1, 'unbiased')
math.std(m2by3, 1, 'uncorrected')
math.variance(1, 2, 3)
math.variance([1, 2, 3])
math.variance([1, 2, 3], 'biased')
math.variance([1, 2, 3], 0, 'biased')
math.variance(m2by3, 1, 'unbiased')
math.variance(m2by3, 1, 'uncorrected')
// std and variance on chain
math.chain([1, 2, 3]).std('unbiased')
math.chain(m2by3).std(0, 'biased').std(0, 'uncorrected')
math.chain(m2by3).std(0, 'biased').std(0, 'uncorrected')
math.chain([1, 2, 3]).std('unbiased')
math.chain(m2by3).variance(0, 'biased')
math.chain(m2by3).variance(1, 'uncorrected').variance('unbiased')
math.variance(math.variance(m2by3, 'uncorrected'))
// count and sum check
math.count([10, 10, 10])
math.count([
[1, 2, 3],
[4, 5, 6]
])
math.count('mathjs')
math.sum(1, 2, 3, 4)
math.sum([1, 2, 3, 4])
math.sum([
[1, 2],
[3, 4],
[5, 6]
])
// expressions
math.evaluate('1.2 * (2 + 4.5)')
// chained operations
const a = math.chain(3).add(4).multiply(2).done()
assert.strictEqual(a, 14)
// mixed use of different data types in functions
assert.deepStrictEqual(math.add(4, [5, 6]), [9, 10]) // number + Array
assert.deepStrictEqual(
math.multiply(math.unit('5 mm'), 3),
math.unit('15 mm')
) // Unit * number
assert.deepStrictEqual(math.subtract([2, 3, 4], 5), [-3, -2, -1]) // Array - number
assert.deepStrictEqual(
math.add(math.matrix([2, 3]), [4, 5]),
math.matrix([6, 8])
) // Matrix + Array
// narrowed type inference
const _b: Matrix = math.add(math.matrix([2]), math.matrix([3]))
const _c: Matrix = math.subtract(math.matrix([4]), math.matrix([5]))
}
/*
Bignumbers examples
*/
{
// configure the default type of numbers as BigNumbers
const math = create(all, {
number: 'BigNumber',
precision: 20
})
{
assert.deepStrictEqual(
math.add(math.bignumber(0.1), math.bignumber(0.2)),
math.bignumber(0.3)
)
assert.deepStrictEqual(
math.divide(math.bignumber(0.3), math.bignumber(0.2)),
math.bignumber(1.5)
)
}
}
/*
Arithmetic function examples
*/
{
const math = create(all, {})
const _e: number = math.exp(1)
const _bige: BigNumber = math.exp(math.bignumber(1))
const _compe: Complex = math.exp(math.complex(1, 0))
// TODO: Typescript type declarations are not understanding typed-function's
// automatic conversions, so the following do not work:
// const _compeagain: Complex = math.exp(math.fraction(1, 1))
// const _eagain: number = math.exp('1')
// const _eanother: number = math.exp(true)
}
/*
Algebra function examples
*/
{
const math = create(all, {})
const derivVal = math.derivative('x^3 + x^2', 'x').evaluate({ x: 2 })
assert.strictEqual(derivVal, 16)
const roots = math.polynomialRoot(9, 6, 1)
assert.strictEqual(roots.length, 1) // double root, so only one of them
assert.strictEqual(roots[0], -3)
}
/*
Chaining examples
*/
{
const math = create(all, {})
const a = math.chain(3).add(4).multiply(2).done()
assert.strictEqual(a, 14)
// Another example, calculate square(sin(pi / 4))
const _b = math.chain(math.pi).divide(4).sin().square().done()
// toString will return a string representation of the chain's value
const chain = math.chain(2).divide(3)
const str: string = chain.toString()
assert.strictEqual(str, '0.6666666666666666')
chain.valueOf()
// the function subset can be used to get or replace sub matrices
const array = [
[1, 2],
[3, 4]
]
const v = math.chain(array).subset(math.index(1, 0)).done()
assert.strictEqual(v, 3)
const _m = math.chain(array).subset(math.index(0, 0), 8).multiply(3).done()
// filtering
assert.deepStrictEqual(
math
.chain([-1, 0, 1.1, 2, 3, 1000])
.filter(math.isPositive)
.filter(math.isInteger)
.filter((n) => n !== 1000)
.done(),
[2, 3]
)
const r = math.chain(-0.483).round([0, 1, 2]).floor().add(0.52).fix(1).done()
assert.deepStrictEqual(r, [0.5, -0.4, -0.4])
expectTypeOf(
math.chain('x + y').parse().resolve({ x: 1 }).done()
).toMatchTypeOf<MathNode>()
expectTypeOf(
math.chain('x + y').parse().resolve().done()
).toMatchTypeOf<MathNode>()
// bignum
expectTypeOf(math.chain(math.bignumber(12))).toMatchTypeOf<
MathJsChain<BigNumber>
>()
expectTypeOf(math.chain(12).bignumber()).toMatchTypeOf<
MathJsChain<BigNumber>
>()
expectTypeOf(math.chain([12, 13, 14]).bignumber()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// bigint
expectTypeOf(math.chain(math.bigint(12))).toMatchTypeOf<MathJsChain<bigint>>()
expectTypeOf(math.chain(12).bigint()).toMatchTypeOf<MathJsChain<bigint>>()
expectTypeOf(math.chain([12, 13, 14]).bigint()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// chain
expectTypeOf(math.chain(12).bignumber().clone()).toMatchTypeOf<
MathJsChain<BigNumber>
>()
// boolean
expectTypeOf(math.chain(math.boolean(true))).toMatchTypeOf<
MathJsChain<boolean>
>()
expectTypeOf(math.chain(true).boolean()).toMatchTypeOf<MathJsChain<boolean>>()
expectTypeOf(math.chain([12, 13, 14]).boolean()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// complex
expectTypeOf(math.chain(math.complex('123'))).toMatchTypeOf<
MathJsChain<Complex>
>()
expectTypeOf(math.chain('123').complex()).toMatchTypeOf<
MathJsChain<Complex>
>()
expectTypeOf(math.chain('123').complex(1)).toMatchTypeOf<
MathJsChain<Complex>
>()
expectTypeOf(math.chain([12, 13, 14]).complex()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// createUnit
expectTypeOf(math.chain(math.createUnit('furlong'))).toMatchTypeOf<
MathJsChain<Unit>
>()
expectTypeOf(
math.chain(
math.createUnit({
fresnel: '1234'
})
)
).toMatchTypeOf<MathJsChain<Unit>>()
// fraction
expectTypeOf(math.chain(math.fraction('123'))).toMatchTypeOf<
MathJsChain<Fraction>
>()
expectTypeOf(math.chain('123').fraction()).toMatchTypeOf<
MathJsChain<Fraction>
>()
expectTypeOf(math.chain('123').fraction(2)).toMatchTypeOf<
MathJsChain<Fraction>
>()
expectTypeOf(math.chain([12, 13, 14]).fraction()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
expectTypeOf(math.chain([12, 13, 14]).fraction()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// index
expectTypeOf(math.chain([12, 13, 14]).index()).toMatchTypeOf<
MathJsChain<Index>
>()
// matrix
expectTypeOf(math.chain([12, 13, 14, 15]).matrix()).toMatchTypeOf<
MathJsChain<Matrix>
>()
// number
expectTypeOf(math.chain('12').number()).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(math.chain([12, 13, 14]).number()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// numeric
expectTypeOf(math.chain('12').numeric('bigint')).toMatchTypeOf<
MathJsChain<bigint>
>()
expectTypeOf(math.chain(12).numeric('BigNumber')).toMatchTypeOf<
MathJsChain<BigNumber>
>()
// sparse
expectTypeOf(math.chain([12, 13, 14, 15]).sparse()).toMatchTypeOf<
MathJsChain<Matrix>
>()
// split unit
expectTypeOf(math.chain(math.unit('furlong')).splitUnit([])).toMatchTypeOf<
MathJsChain<Unit[]>
>()
// string
expectTypeOf(math.chain('test').string()).toMatchTypeOf<MathJsChain<string>>()
expectTypeOf(math.chain([1, 2, 3]).string()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// unit
expectTypeOf(math.chain(12).unit()).toMatchTypeOf<MathJsChain<Unit>>()
expectTypeOf(math.chain([1, 2, 3]).unit()).toMatchTypeOf<
MathJsChain<Unit[]>
>()
// compile
expectTypeOf(math.chain('a + b').compile()).toMatchTypeOf<
MathJsChain<EvalFunction>
>()
// evaluate
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expectTypeOf(math.chain('1 + 1').evaluate()).toMatchTypeOf<MathJsChain<any>>()
expectTypeOf(math.chain(['1 + 1', '2 + 2']).evaluate()).toMatchTypeOf<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
MathJsChain<any[]>
>()
// parse
expectTypeOf(math.chain('1 + 1').parse()).toMatchTypeOf<
MathJsChain<MathNode>
>()
expectTypeOf(math.chain(['1 + 1', '2 + 2']).parse()).toMatchTypeOf<
MathJsChain<MathNode[]>
>()
// resolve
expectTypeOf(math.chain(math.parse('1 + 1')).resolve({})).toMatchTypeOf<
MathJsChain<MathNode>
>()
expectTypeOf(
math.chain([math.parse('1 + 1'), math.parse('1 + 1')]).resolve({})
).toMatchTypeOf<MathJsChain<MathNode[]>>()
// derivative
expectTypeOf(math.chain(math.parse('x^2')).derivative('x')).toMatchTypeOf<
MathJsChain<MathNode>
>()
// lsolve
expectTypeOf(
math
.chain([
[1, 2],
[3, 4]
])
.lsolve([1, 2])
).toMatchTypeOf<MathJsChain<MathArray>>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.lsolve([1, 2])
).toMatchTypeOf<MathJsChain<Matrix>>()
// lup
expectTypeOf(
math
.chain([
[1, 2],
[3, 4]
])
.lup()
).toMatchTypeOf<MathJsChain<LUDecomposition>>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.lup()
).toMatchTypeOf<MathJsChain<LUDecomposition>>()
// lusolve
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.lusolve(math.matrix([1, 2]))
).toMatchTypeOf<MathJsChain<Matrix>>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.lusolve([1, 2])
).toMatchTypeOf<MathJsChain<Matrix>>()
expectTypeOf(
math
.chain([
[1, 2],
[3, 4]
])
.lusolve(math.matrix([1, 2]))
).toMatchTypeOf<MathJsChain<MathArray>>()
expectTypeOf(
math
.chain([
[1, 2],
[3, 4]
])
.lusolve([1, 2])
).toMatchTypeOf<MathJsChain<MathArray>>()
// qr
expectTypeOf(
math
.chain([
[1, 2],
[3, 4]
])
.qr()
).toMatchTypeOf<MathJsChain<QRDecomposition>>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.qr()
).toMatchTypeOf<MathJsChain<QRDecomposition>>()
// rationalize
expectTypeOf(math.chain('1.23').rationalize()).toMatchTypeOf<
MathJsChain<MathNode>
>()
expectTypeOf(math.chain(math.parse('1.23')).rationalize()).toMatchTypeOf<
MathJsChain<MathNode>
>()
// simplify
expectTypeOf(math.chain('a + a + b').simplify()).toMatchTypeOf<
MathJsChain<MathNode>
>()
expectTypeOf(math.chain(math.parse('a + a + b')).simplify()).toMatchTypeOf<
MathJsChain<MathNode>
>()
// slu
expectTypeOf(
math
.chain(
math.sparse([
[1, 2],
[3, 4]
])
)
.slu(2, 0.5)
).toMatchTypeOf<MathJsChain<SLUDecomposition>>()
// usolve
expectTypeOf(
math
.chain([
[1, 2],
[3, 4]
])
.usolve([1, 2])
).toMatchTypeOf<MathJsChain<MathArray>>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.usolve([1, 2])
).toMatchTypeOf<MathJsChain<Matrix>>()
// abs
expectTypeOf(math.chain(1).abs()).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(math.chain(math.bignumber(1)).abs()).toMatchTypeOf<
MathJsChain<BigNumber>
>()
expectTypeOf(math.chain(math.fraction(1, 2)).abs()).toMatchTypeOf<
MathJsChain<Fraction>
>()
expectTypeOf(math.chain(math.complex(1, 2)).abs()).toMatchTypeOf<
MathJsChain<Complex>
>()
expectTypeOf(math.chain([1, 2]).abs()).toMatchTypeOf<MathJsChain<MathArray>>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.abs()
).toMatchTypeOf<MathJsChain<Matrix>>()
expectTypeOf(math.chain(math.unit('furlong')).abs()).toMatchTypeOf<
MathJsChain<Unit>
>()
// add
expectTypeOf(math.chain(1).add(2)).toMatchTypeOf<MathJsChain<MathType>>()
expectTypeOf(math.chain([1]).add(2)).toMatchTypeOf<MathJsChain<MathType>>()
expectTypeOf(
math.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
).toMatchTypeOf<MathJsChain<Matrix>>()
// apply
expectTypeOf(math.chain([1, 2, 3]).apply(0, () => 1)).toMatchTypeOf<
MathJsChain<number[]>
>()
// cbrt
expectTypeOf(math.chain(1).cbrt()).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(math.chain(math.bignumber(1)).cbrt()).toMatchTypeOf<
MathJsChain<BigNumber>
>()
expectTypeOf(math.chain(math.complex(1, 2)).cbrt()).toMatchTypeOf<
MathJsChain<Complex>
>()
// @ts-expect-error ... verify cbrt does not run on arrays.
assert.throws(() => math.chain([1, 2]).cbrt(), TypeError)
assert.throws(
() =>
// @ts-expect-error ... verify cbrt does not run on matrices.
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.cbrt(),
TypeError
)
// ceil
expectTypeOf(math.chain(1).ceil()).toMatchTypeOf<
MathJsChain<MathNumericType>
>()
expectTypeOf(math.chain([1]).ceil()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// fix
expectTypeOf(math.chain(1).fix()).toMatchTypeOf<
MathJsChain<MathNumericType>
>()
expectTypeOf(math.chain([1]).fix()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// floor
expectTypeOf(math.chain(1).floor()).toMatchTypeOf<
MathJsChain<MathNumericType>
>()
expectTypeOf(math.chain([1]).floor()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
// round
expectTypeOf(math.chain(1).round()).toMatchTypeOf<
MathJsChain<MathNumericType>
>()
expectTypeOf(math.chain([1]).round()).toMatchTypeOf<
MathJsChain<MathCollection>
>()
expectTypeOf(
math.chain(math.unit('5.2cm')).round(math.unit('cm'))
).toMatchTypeOf<MathJsChain<Unit>>()
// cube
expectTypeOf(math.chain(1).cube()).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(math.chain(math.bignumber(1)).cube()).toMatchTypeOf<
MathJsChain<BigNumber>
>()
expectTypeOf(math.chain(math.fraction(1, 2)).cube()).toMatchTypeOf<
MathJsChain<Fraction>
>()
expectTypeOf(math.chain(math.complex(1, 2)).cube()).toMatchTypeOf<
MathJsChain<Complex>
>()
// @ts-expect-error ... verify cube does not run on arrays.
assert.throws(() => math.chain([1, 2]).cube(), TypeError)
assert.throws(
() =>
// @ts-expect-error ... verify cube does not run on matrices.
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.cube(),
TypeError
)
expectTypeOf(math.chain(math.unit('furlong')).cube()).toMatchTypeOf<
MathJsChain<Unit>
>()
// divide
expectTypeOf(
math.chain(math.unit('furlong')).divide(math.unit('femtosecond'))
).toMatchTypeOf<MathJsChain<number | Unit>>()
expectTypeOf(math.chain(math.unit('furlong')).divide(6)).toMatchTypeOf<
MathJsChain<Unit>
>()
expectTypeOf(math.chain(2).divide(6)).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(math.chain([1, 2, 3]).divide(6)).toMatchTypeOf<
MathJsChain<MathType>
>()
// dotDivide
expectTypeOf(math.chain(1).dotDivide(2)).toMatchTypeOf<
MathJsChain<MathNumericType>
>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.dotDivide(2)
).toMatchTypeOf<MathJsChain<Matrix>>()
// dotMultiply
expectTypeOf(math.chain(1).dotMultiply(2)).toMatchTypeOf<
MathJsChain<MathNumericType>
>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.dotMultiply(2)
).toMatchTypeOf<MathJsChain<Matrix>>()
// dotPow
expectTypeOf(math.chain(1).dotPow(2)).toMatchTypeOf<
MathJsChain<MathNumericType>
>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.dotPow(2)
).toMatchTypeOf<MathJsChain<Matrix>>()
// exp
expectTypeOf(math.chain(1).exp()).toMatchTypeOf<MathJsChain<MathType>>()
// @ts-expect-error ... verify exp does not run on arrays.
assert.throws(() => math.chain([1, 2]).exp(), TypeError)
assert.throws(
() =>
// @ts-expect-error ... verify exp does not run on matrices.
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.exp(),
TypeError
)
// expm1
expectTypeOf(math.chain(1).expm1()).toMatchTypeOf<MathJsChain<MathType>>()
// @ts-expect-error ... verify expm1 does not run on arrays
assert.throws(() => math.chain([1, 2]).expm1(), TypeError)
assert.throws(
() =>
// @ts-expect-error ... verify expm1 does not run on arrays
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.expm1(),
TypeError
)
// gcd
expectTypeOf(math.chain([1, 2]).gcd(3)).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(math.chain([1, 2]).gcd(3, 4)).toMatchTypeOf<
MathJsChain<number>
>()
expectTypeOf(math.chain([1, 2]).gcd()).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(
math.chain([math.bignumber(1), math.bignumber(1)]).gcd()
).toMatchTypeOf<MathJsChain<BigNumber>>()
expectTypeOf(
math.chain([math.bignumber(1), math.bignumber(1)]).gcd()
).toMatchTypeOf<MathJsChain<BigNumber>>()
expectTypeOf(
math.gcd(math.bignumber(1), math.bignumber(1))
).toMatchTypeOf<BigNumber>()
expectTypeOf(
math.gcd([
math.matrix([
[1, 2],
[3, 4]
]),
math.matrix([
[1, 2],
[3, 4]
])
])
).toMatchTypeOf<Matrix>()
expectTypeOf(
math.gcd(
[
[1, 2],
[3, 4]
],
[
[1, 2],
[3, 4]
]
)
).toMatchTypeOf<MathArray>()
assert.throws(
() =>
// @ts-expect-error ... gcd() supports only 1d matrices!
math.gcd([
[
[1, 5],
[10, 49]
],
[
[1, 5],
[5, 7]
]
]),
Error
)
// hypot
expectTypeOf(math.chain([1, 2]).hypot()).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(
math.chain([math.bignumber(1), math.bignumber(1)]).hypot()
).toMatchTypeOf<MathJsChain<BigNumber>>()
// lcm
expectTypeOf(math.chain(1).lcm(2)).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(
math.chain(math.bignumber(1)).lcm(math.bignumber(2))
).toMatchTypeOf<MathJsChain<BigNumber>>()
expectTypeOf(math.chain([1, 2]).lcm([3, 4])).toMatchTypeOf<
MathJsChain<MathArray>
>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.lcm(
math.matrix([
[1, 2],
[3, 4]
])
)
).toMatchTypeOf<MathJsChain<Matrix>>()
// log
expectTypeOf(math.chain(1).log(2)).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(
math.chain(math.bignumber(1)).log(math.bignumber(2))
).toMatchTypeOf<MathJsChain<BigNumber>>()
// log10
expectTypeOf(math.chain(1).log10()).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(math.chain(math.bignumber(1)).log10()).toMatchTypeOf<
MathJsChain<BigNumber>
>()
expectTypeOf(math.chain([1, 2]).log10()).toMatchTypeOf<
MathJsChain<MathArray>
>()
expectTypeOf(
math
.chain(
math.matrix([
[1, 2],
[3, 4]
])
)
.log10()
).toMatchTypeOf<MathJsChain<Matrix>>()
expectTypeOf(math.chain([1, 2]).count()).toMatchTypeOf<MathJsChain<number>>()
expectTypeOf(math.chain('mathjs').count()).toMatchTypeOf<
MathJsChain<number>
>()
expectTypeOf(math.chain([1, 2]).sum()).toMatchTypeOf<MathJsChain<number>>()
// TODO complete the rest of these...
}
/*
Simplify examples
*/
{
const math = create(all)
math.simplify('2 * 1 * x ^ (2 - 1)')
math.simplifyConstant('2 * 1 * x ^ (2 - 1)')
math.simplifyCore('2 * 1 * x ^ (2 - 1)')
math.simplify('2 * 3 * x', { x: 4 })
expectTypeOf(math.simplify.rules).toMatchTypeOf<Array<SimplifyRule>>()
const f = math.parse('2 * 1 * x ^ (2 - 1)')
math.simplify(f)
math.simplify('0.4 * x', {}, { exactFractions: true })
math.simplifyConstant('0.4 * x', { exactFractions: true })
math.simplify('0.4 * x', {}, { exactFractions: false })
math.simplify('0.4 * x', {}, { fractionsLimit: 2 })
math.simplify('0.4 * x', {}, { consoleDebug: false })
math.simplify(
'0.4 * x',
{},
{
context: {
xor: {
trivial: true,
total: true,
commutative: true,
associative: true
}
}
}
)
math.simplify('0.4 * x', [])
math.simplify('0.4 * x', [
'n * n -> 2n',
{
s: 'n * n -> 2n',
repeat: true,
assuming: {
multiply: {
trivial: true,
total: true,
commutative: true,
associative: true
}
},
imposeContext: {
multiply: {
trivial: true,
total: true,
commutative: true,
associative: true
}
}
},
{
l: 'n * n',
r: '2n',
repeat: true,
assuming: {
multiply: {
trivial: true,
total: true,
commutative: true,
associative: true
}
},
imposeContext: {
multiply: {
trivial: true,
total: true,
commutative: true,
associative: true
}
}
},
(node: MathNode) => node
])
math.simplifyCore('0.4 * x + 0', { exactFractions: false })
math
.chain('0.4 * x + 0')
.parse()
.simplifyCore({ exactFractions: false })
.simplifyConstant()
}
/*
Complex numbers examples
*/
{
const math = create(all, {})
const a = math.complex(2, 3)
// create a complex number by providing a string with real and complex parts
const b = math.complex('3 - 7i')
// read the real and complex parts of the complex number
{
const _x: number = a.re
const _y: number = a.im
// adjust the complex value
a.re = 5
}
// clone a complex value
{
const _clone = a.clone()
}
// perform operations with complex numbers
{
math.add(a, b)
math.multiply(a, b)
math.sin(a)
}
// create a complex number from polar coordinates
{
const p: PolarCoordinates = {
r: math.sqrt(2) as number, // must be real but a sqrt could be Complex
phi: math.pi / 4
}
const c: Complex = math.complex(p)
assert.strictEqual(c.im, 1)
assert.ok(Math.abs(c.re - 1) < 1e-12)
}
// get polar coordinates of a complex number
{
const _p: PolarCoordinates = math.complex(3, 4).toPolar()
}
}
/*
Parenthesis examples
*/
{
const math = create(all, {})
expectTypeOf(
new math.ParenthesisNode(new math.ConstantNode(3))
).toMatchTypeOf<ParenthesisNode<ConstantNode>>()
}
/*
Expressions examples
*/
{
const math = create(all, {})
// evaluate expressions
{
math.evaluate('sqrt(3^2 + 4^2)')
}
// evaluate multiple expressions at once
{
math.evaluate(['f = 3', 'g = 4', 'f * g'])
}
// get content of a parenthesis node
{
const node = math.parse('(1)')
if (node.type !== 'ParenthesisNode') {
throw Error(`expected ParenthesisNode, got ${node.type}`)
}
}
// scope can contain both variables and functions
{
const scope = { hello: (name: string) => `hello, ${name}!` }
assert.strictEqual(math.evaluate('hello("hero")', scope), 'hello, hero!')
}
// define a function as an expression
{
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const scope: any = {
a: 3,
b: 4
}
const f = math.evaluate('f(x) = x ^ a', scope)
f(2)
scope.f(2)
}
{
const node2 = math.parse('x^a')
const _code2: EvalFunction = node2.compile()
node2.toString()
}
// 3. using function math.compile
// parse an expression
{
// provide a scope for the variable assignment
const code2 = math.compile('a = a + 3')
const scope = { a: 7 }
code2.evaluate(scope)
}
// 4. using a parser
const parser = math.parser()
// get and set variables and functions
{
assert.strictEqual(parser.evaluate('x = 7 / 2'), 3.5)
assert.strictEqual(parser.evaluate('x + 3'), 6.5)
parser.evaluate('f(x, y) = x^y') // f(x, y)
assert.strictEqual(parser.evaluate('f(2, 3)'), 8)
const _x = parser.get('x')
const f = parser.get('f')
const _y = parser.getAll()
const _z = parser.getAllAsMap()
const _g = f(3, 3)
parser.set('h', 500)
assert.strictEqual(parser.get('h'), 500)
assert.strictEqual(parser.evaluate('h'), 500)
parser.set('hello', (name: string) => `hello, ${name}!`)
parser.remove('h')
assert.strictEqual(parser.get('h'), undefined)
}
// clear defined functions and variables
parser.clear()
}
/*
Fractions examples
*/
{
// configure the default type of numbers as Fractions
const math = create(all, {
number: 'Fraction'
})
const x = math.fraction(0.125)
const y = math.fraction('1/3')
math.fraction(2, 3)
math.add(x, y)
math.divide(x, y)
// output formatting
const _a = math.fraction('2/3')
}
/*
Transform examples
*/
{
const math = create(all, {})
{
const myTransform1 = (node: MathNode): OperatorNode<'+', 'add'> =>
new OperatorNode('+', 'add', [node, new ConstantNode(1)])
const myTransform2 = (
node: OperatorNode<'+', 'add'>
): OperatorNode<'-', 'subtract'> =>
new OperatorNode('-', 'subtract', [node, new ConstantNode(5)])
expectTypeOf(
math.parse('sqrt(3^2 + 4^2)').transform(myTransform1)
).toMatchTypeOf<OperatorNode<'+', 'add', MathNode[]>>()
assert.deepStrictEqual(
math.parse('sqrt(3^2 + 4^2)').transform(myTransform1).toString(),
'sqrt(3 ^ 2 + 4 ^ 2) + 1'
)
expectTypeOf(
math
.parse('sqrt(3^2 + 4^2)')
.transform(myTransform1)
.transform(myTransform2)
).toMatchTypeOf<OperatorNode<'-', 'subtract', MathNode[]>>()
assert.deepStrictEqual(
math
.parse('sqrt(3^2 + 4^2)')
.transform(myTransform1)
.transform(myTransform2)
.toString(),
'sqrt(3 ^ 2 + 4 ^ 2) + 1 - 5'
)
}
}
/*
Matrices examples
*/
{
const math = create(all, {})
// create matrices and arrays. a matrix is just a wrapper around an Array,
// providing some handy utilities.
const a: Matrix = math.matrix([1, 4, 9, 16, 25])
const b: Matrix = math.matrix(math.ones([2, 3]))
b.size()
// @ts-expect-error ... ones() in a chain cannot take more dimensions
assert.throws(() => math.chain(3).ones(2, 'dense').done(), /Error:.*ones/)
// @ts-expect-error ... and neither can zeros()
assert.throws(() => math.chain(3).zeros(2, 'sparse').done(), /Error:.*zeros/)
// the Array data of a Matrix can be retrieved using valueOf()
const _array = a.valueOf()
// Matrices can be cloned
const _clone: Matrix = a.clone()
// perform operations with matrices
math.map(a, math.sqrt)
math.factorial(a)
// create and manipulate matrices. Arrays and Matrices can be used mixed.
{
const a = [
[1, 2],
[3, 4]
]
const b: Matrix = math.matrix([
[5, 6],
[1, 1]
])
b.subset(math.index(1, [0, 1]), [[7, 8]])
const _c = math.multiply(a, b)
const f: Matrix = math.matrix([1, 0])
const _d: Matrix = f.subset(math.index(1))
}
// get a sub matrix
{
const a: Matrix = math.diag(math.range(1, 4))
a.subset(math.index([1, 2], [1, 2]))
const b: Matrix = math.range(1, 6)
b.subset(math.index(math.range(1, 4)))
}
// resize a multi dimensional matrix
{
const a = math.matrix()
a.resize([2, 2, 2], 0)
a.size()
a.resize([2, 2])
a.size()
}
// can set a subset of a matrix to uninitialized
{
const m = math.matrix()
m.subset(math.index(2), 6, math.uninitialized)
}
// create ranges
{
math.range(1, 6)
math.range(0, 18, 3)
math.range('2:-1:-3')
math.factorial(math.range('1:6'))
}
// map matrix
{
assert.deepStrictEqual(
math.map([1, 2, 3], function (value) {
return value * value
}),
[1, 4, 9]
)
}
// filter matrix
{
assert.deepStrictEqual(
math.filter([6, -2, -1, 4, 3], function (x) {
return x > 0
}),
[6, 4, 3]
)
assert.deepStrictEqual(
math.filter(['23', 'foo', '100', '55', 'bar'], /\d+/),
['23', '100', '55']
)
}
// concat matrix
{
assert.deepStrictEqual(math.concat([[0, 1, 2]], [[1, 2, 3]]), [
[0, 1, 2, 1, 2, 3]
])
assert.deepStrictEqual(math.concat([[0, 1, 2]], [[1, 2, 3]], 0), [
[0, 1, 2],
[1, 2, 3]
])
}
// Matrix is available as a constructor for instanceof checks
{
assert.strictEqual(math.matrix([1, 2, 3]) instanceof math.Matrix, true)
}
// Eigenvalues and eigenvectors
{
const D = [
[1, 1],
[0, 1]
]
const eig = math.eigs(D)
assert.ok(math.deepEqual(eig.values, [1, 1]))
assert.deepStrictEqual(eig.eigenvectors, [{ value: 1, vector: [1, 0] }])
const eigvv = math.eigs(D, { precision: 1e-6 })
assert.ok(math.deepEqual(eigvv.values, [1, 1]))
assert.deepStrictEqual(eigvv.eigenvectors, [{ value: 1, vector: [1, 0] }])
const eigv = math.eigs(D, { eigenvectors: false })
assert.ok(math.deepEqual(eigv.values, [1, 1]))
//@ts-expect-error ...verify that eigenvectors not expected to be there
eigv.eigenvectors
}
// Fourier transform and inverse
{
assert.ok(
math.deepEqual(
math.fft([
[1, 0],
[1, 0]
]),
[
[math.complex(2, 0), math.complex(2, 0)],
[math.complex(0, 0), math.complex(0, 0)]
]
)
)
assert.ok(
math.deepEqual(
math.fft(
math.matrix([
[1, 0],
[1, 0]
])
),
math.matrix([
[math.complex(2, 0), math.complex(2, 0)],
[math.complex(0, 0), math.complex(0, 0)]
])
)
)
assert.ok(
math.deepEqual(
math.ifft([
[2, 2],
[0, 0]
]),
[
[math.complex(1, 0), math.complex(0, 0)],
[math.complex(1, 0), math.complex(0, 0)]
]
)
)
assert.ok(
math.deepEqual(
math.ifft(
math.matrix([
[2, 2],
[0, 0]
])
),
math.matrix([
[math.complex(1, 0), math.complex(0, 0)],
[math.complex(1, 0), math.complex(0, 0)]
])
)
)
}
// MoorePenrose inverse
{
assert.ok(
math.deepEqual(
math.pinv([
[1, 2],
[3, 4]
]),
[
[-2, 1],
[1.5, -0.5]
]
)
)
assert.ok(
math.deepEqual(
math.pinv(
math.matrix([
[1, 2],
[3, 4]
])
),
math.matrix([
[-2, 1],
[1.5, -0.5]
])
)
)
assert.ok(math.deepEqual(math.pinv(4), 0.25))
}
}
/*
Math types examples: Type results after multiplying 'MathTypes' with matrices
*/
{
const math = create(all, {})
const abc: MathArray = [1, 2, 3, 4]
const bcd: MathArray = [
[1, 2, 3, 4],
[2, 3, 4, 5],
[4, 5, 6, 7],
[5, 6, 7, 8]
]
const Mbcd = math.matrix(bcd)
const Mabc = math.matrix(abc)
// Number
const _r1 = math.multiply(1, 2)
// Unit
const a = math.unit(45, 'cm') // 450 mm
const b = math.unit(math.fraction(90, 2), 'cm') // 450 mm
const _r2 = math.multiply(a, b)
// 1D JS Array
const r3 = math.multiply(abc, bcd)
const _r31 = r3[1] // By default least promised valid syntax
// 2D JS Array
const r12 = math.multiply(bcd, bcd)
// Example to sort ambiguity between multidimensional & singledimensional arrays
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const multiDimensional = (x: any): x is any[][] => x.length && x[0].length
if (multiDimensional(r12)) {
const _r1211 = r12[1][1]
}
const _r121 = r12[1] // Valid syntax
// Matrix: matrix * vector
const r7 = math.multiply(Mabc, bcd)
r7.toArray() // Matrix-es have toArray function
// Matrix
const _r8 = math.multiply(Mabc, 4)
// Matrix
const _r11 = math.multiply(4, Mabc)
// Matrix of units
const _r9 = math.multiply(Mabc, a)
const _r10 = math.multiply(a, Mabc)
// Matrix
const _r6 = math.multiply(abc, Mbcd)
// 2D JS Array
const _r5 = math.multiply(bcd, abc)
// Number
const _r4 = math.multiply(abc, math.transpose(abc))
}
/*
Sparse matrices examples
*/
{
const math = create(all, {})
// create a sparse matrix
const a = math.identity(1000, 1000, 'sparse')
// do operations with a sparse matrix
const b = math.multiply(a, a)
const _c = math.multiply(b, math.complex(2, 2))
const d = math.matrix([0, 1])
const e = math.transpose(d)
const _f = math.multiply(e, d)
}
/*
Rotation matrices examples
*/
{
const math = create(all, {})
// create a rotation matrix
const a = math.rotationMatrix()
const b = math.rotationMatrix(math.pi, [1, 1, 0], 'sparse')
expectTypeOf(a).toMatchTypeOf<MathCollection>()
expectTypeOf(b).toMatchTypeOf<MathCollection>()
assert.throws(
// @ts-expect-error ... verify format parameter is either null, 'sparse' or 'dense'
() => math.rotationMatrix(math.pi, [1, 1, 0], 'format'),
TypeError
)
assert.throws(
// @ts-expect-error ... verify theta is number
() => math.rotationMatrix('pi'),
TypeError
)
assert.throws(
// @ts-expect-error ... verify axis is of MathColletion Type
() => math.rotationMatrix(math.pi, 1),
TypeError
)
}
/*
Units examples
*/
{
const math = create(all, {})
// units can be created by providing a value and unit name, or by providing
// a string with a valued unit.
const a = math.unit(45, 'cm') // 450 mm
const b = math.unit('0.1m') // 100 mm
const _c = math.unit(b)
// creating units
math.createUnit('foo')
math.createUnit('furlong', '220 yards')
math.createUnit('furlong', '220 yards', { override: true })
math.createUnit('testunit', { definition: '0.555556 kelvin', offset: 459.67 })
math.createUnit(
'testunit',
{ definition: '0.555556 kelvin', offset: 459.67 },
{ override: true }
)
math.createUnit('knot', {
definition: '0.514444 m/s',
aliases: ['knots', 'kt', 'kts']
})
math.createUnit(
'knot',
{ definition: '0.514444 m/s', aliases: ['knots', 'kt', 'kts'] },
{ override: true }
)
math.createUnit(
'knot',
{
definition: '0.514444 m/s',
aliases: ['knots', 'kt', 'kts'],
prefixes: 'long'
},
{ override: true }
)
math.createUnit(
{
foo2: {
prefixes: 'long'
},
bar: '40 foo',
baz: {
definition: '1 bar/hour',
prefixes: 'long'
}
},
{
override: true
}
)
// use Unit as definition
math.createUnit('c', { definition: b })
math.createUnit('c', { definition: b }, { override: true })
math.createUnit('customUnit', math.unit(0.5, 'm'))
// units can be added, subtracted, and multiplied or divided by numbers and by other units
math.add(a, b)
math.multiply(b, 2)
math.divide(math.unit('1 m'), math.unit('1 s'))
math.pow(math.unit('12 in'), 3)
// units can be converted to a specific type, or to a number
b.to('cm')
math.to(b, 'inch')
b.toNumber('cm')
math.number(b, 'cm')
// the expression parser supports units too
math.evaluate('2 inch to cm')
// units can be converted to SI
math.unit('1 inch').toSI()
// units can be split into other units
math.unit('1 m').splitUnit(['ft', 'in'])
}
/**
* Example of custom fallback for onUndefinedSymbol & onUndefinedFunction
*/
{
const math = create(all, {})
math.SymbolNode.onUndefinedSymbol = () => null
assert.strictEqual(math.evaluate('nonExistingSymbol'), null)
math.FunctionNode.onUndefinedFunction = () => () => 42
}
/*
Expression tree examples
*/
{
const math = create(all, {})
// Filter an expression tree
const node = math.parse('x^2 + x/4 + 3*y')
const filtered = node.filter(
(node) => isSymbolNode(node) && node.name === 'x'
)
const _arr: string[] = filtered.map((node: MathNode) => node.toString())
// Traverse an expression tree
const node1: MathNode = math.parse('3 * x + 2')
node1.traverse((node: MathNode, _path: string, _parent: MathNode) => {
switch (node.type) {
case 'OperatorNode':
return node.type === 'OperatorNode'
case 'ConstantNode':
return node.type === 'ConstantNode'
case 'SymbolNode':
return node.type === 'SymbolNode'
default:
return
}
})
}
/*
Function ceil examples
*/
{
const math = create(all, {})
// number input
assert.strictEqual(math.ceil(3.2), 4)
assert.strictEqual(math.ceil(-4.2), -4)
// number input
// roundoff result to 2 decimals
assert.strictEqual(math.ceil(3.212, 2), 3.22)
assert.deepStrictEqual(
math.ceil(3.212, math.bignumber(2)),
math.bignumber(3.22)
)
assert.strictEqual(math.ceil(-4.212, 2), -4.21)
// bignumber input
assert.deepStrictEqual(math.ceil(math.bignumber(3.212)), math.bignumber(4))
assert.deepStrictEqual(
math.ceil(math.bignumber(3.212), 2),
math.bignumber(3.22)
)
assert.deepStrictEqual(
math.ceil(math.bignumber(3.212), math.bignumber(2)),
math.bignumber(3.22)
)
// fraction input
assert.deepStrictEqual(math.ceil(math.fraction(44, 7)), math.fraction(7))
assert.deepStrictEqual(math.ceil(math.fraction(-44, 7)), math.fraction(-6))
assert.deepStrictEqual(
math.ceil(math.fraction(44, 7), 2),
math.fraction(629, 100)
)
assert.deepStrictEqual(
math.ceil(math.fraction(44, 7), math.bignumber(2)),
math.fraction(629, 100)
)
// Complex input
const c = math.complex(3.24, -2.71)
assert.deepStrictEqual(math.ceil(c), math.complex(4, -2))
assert.deepStrictEqual(math.ceil(c, 1), math.complex(3.3, -2.7))
assert.deepStrictEqual(
math.ceil(c, math.bignumber(1)),
math.complex(3.3, -2.7)
)
// array input
assert.deepStrictEqual(math.ceil([3.2, 3.8, -4.7]), [4, 4, -4])
assert.deepStrictEqual(math.ceil([3.21, 3.82, -4.71], 1), [3.3, 3.9, -4.7])
assert.deepStrictEqual(
math.ceil([3.21, 3.82, -4.71], math.bignumber(1)),
math.bignumber([3.3, 3.9, -4.7])
)
// numeric input, array or matrix of decimals
const numCeiled: MathArray = math.ceil(math.tau, [2, 3])
assert.deepStrictEqual(numCeiled, [6.29, 6.284])
const bigCeiled: Matrix = math.ceil(
math.bignumber(6.28318),
math.matrix([2, 3])
)
assert.deepStrictEqual(bigCeiled, math.matrix(math.bignumber([6.29, 6.284])))
assert.deepStrictEqual(math.ceil(math.fraction(44, 7), [2, 3]), [
math.fraction(629, 100),
math.fraction(6286, 1000)
])
// @ts-expect-error ... verify ceil(array, array) throws an error (for now)
assert.throws(() => math.ceil([3.21, 3.82], [1, 2]), TypeError)
}
/*
Function fix examples
*/
{
const math = create(all, {})
// number input
assert.strictEqual(math.fix(3.2), 3)
assert.strictEqual(math.fix(-4.2), -4)
// number input
// roundoff result to 2 decimals
assert.strictEqual(math.fix(3.212, 2), 3.21)
assert.deepStrictEqual(
math.fix(3.212, math.bignumber(2)),
math.bignumber(3.21)
)
assert.strictEqual(math.fix(-4.212, 2), -4.21)
// bignumber input
assert.deepStrictEqual(math.fix(math.bignumber(3.212)), math.bignumber(3))
assert.deepStrictEqual(
math.fix(math.bignumber(3.212), 2),
math.bignumber(3.21)
)
assert.deepStrictEqual(
math.fix(math.bignumber(3.212), math.bignumber(2)),
math.bignumber(3.21)
)
// fraction input
assert.deepStrictEqual(math.fix(math.fraction(44, 7)), math.fraction(6))
assert.deepStrictEqual(math.fix(math.fraction(-44, 7)), math.fraction(-6))
assert.deepStrictEqual(
math.fix(math.fraction(44, 7), 2),
math.fraction(628, 100)
)
assert.deepStrictEqual(
math.fix(math.fraction(44, 7), math.bignumber(2)),
math.fraction(628, 100)
)
// Complex input
const c = math.complex(3.24, -2.71)
assert.deepStrictEqual(math.fix(c), math.complex(3, -2))
assert.deepStrictEqual(math.fix(c, 1), math.complex(3.2, -2.7))
assert.deepStrictEqual(
math.fix(c, math.bignumber(1)),
math.complex(3.2, -2.7)
)
// array input
assert.deepStrictEqual(math.fix([3.2, 3.8, -4.7]), [3, 3, -4])
assert.deepStrictEqual(math.fix([3.21, 3.82, -4.71], 1), [3.2, 3.8, -4.7])
assert.deepStrictEqual(
math.fix([3.21, 3.82, -4.71], math.bignumber(1)),
math.bignumber([3.2, 3.8, -4.7])
)
// numeric input, array or matrix of decimals
const numFixed: MathArray = math.fix(math.tau, [2, 3])
assert.deepStrictEqual(numFixed, [6.28, 6.283])
const bigFixed: Matrix = math.fix(
math.bignumber(6.28318),
math.matrix([2, 3])
)
assert.deepStrictEqual(bigFixed, math.matrix(math.bignumber([6.28, 6.283])))
assert.deepStrictEqual(math.fix(math.fraction(44, 7), [2, 3]), [
math.fraction(628, 100),
math.fraction(6285, 1000)
])
// @ts-expect-error ... verify fix(array, array) throws an error (for now)
assert.throws(() => math.fix([3.21, 3.82], [1, 2]), TypeError)
}
/*
Function floor examples
*/
{
const math = create(all, {})
// number input
assert.strictEqual(math.floor(3.2), 3)
assert.strictEqual(math.floor(-4.2), -5)
// number input
// roundoff result to 2 decimals
assert.strictEqual(math.floor(3.212, 2), 3.21)
assert.deepStrictEqual(
math.floor(3.212, math.bignumber(2)),
math.bignumber(3.21)
)
assert.strictEqual(math.floor(-4.212, 2), -4.22)
// bignumber input
assert.deepStrictEqual(math.floor(math.bignumber(3.212)), math.bignumber(3))
assert.deepStrictEqual(
math.floor(math.bignumber(3.212), 2),
math.bignumber(3.21)
)
assert.deepStrictEqual(
math.floor(math.bignumber(3.212), math.bignumber(2)),
math.bignumber(3.21)
)
// fraction input
assert.deepStrictEqual(math.floor(math.fraction(44, 7)), math.fraction(6))
assert.deepStrictEqual(math.floor(math.fraction(-44, 7)), math.fraction(-7))
assert.deepStrictEqual(
math.floor(math.fraction(44, 7), 2),
math.fraction(628, 100)
)
assert.deepStrictEqual(
math.floor(math.fraction(44, 7), math.bignumber(2)),
math.fraction(628, 100)
)
// Complex input
const c = math.complex(3.24, -2.71)
assert.deepStrictEqual(math.floor(c), math.complex(3, -3))
assert.deepStrictEqual(math.floor(c, 1), math.complex(3.2, -2.8))
assert.deepStrictEqual(
math.floor(c, math.bignumber(1)),
math.complex(3.2, -2.8)
)
// array input
assert.deepStrictEqual(math.floor([3.2, 3.8, -4.7]), [3, 3, -5])
assert.deepStrictEqual(math.floor([3.21, 3.82, -4.71], 1), [3.2, 3.8, -4.8])
assert.deepStrictEqual(
math.floor([3.21, 3.82, -4.71], math.bignumber(1)),
math.bignumber([3.2, 3.8, -4.8])
)
// numeric input, array or matrix of decimals
const numFloored: MathArray = math.floor(math.tau, [2, 3])
assert.deepStrictEqual(numFloored, [6.28, 6.283])
const bigFloored: Matrix = math.floor(
math.bignumber(6.28318),
math.matrix([2, 3])
)
assert.deepStrictEqual(bigFloored, math.matrix(math.bignumber([6.28, 6.283])))
assert.deepStrictEqual(math.floor(math.fraction(44, 7), [2, 3]), [
math.fraction(628, 100),
math.fraction(6285, 1000)
])
// @ts-expect-error ... verify floor(array, array) throws an error (for now)
assert.throws(() => math.floor([3.21, 3.82], [1, 2]), TypeError)
}
/*
Function round examples
*/
{
const math = create(all, {})
// number input
assert.strictEqual(math.round(3.2), 3)
assert.strictEqual(math.round(-4.2), -4)
// number input
// roundoff result to 2 decimals
assert.strictEqual(math.round(3.212, 2), 3.21)
assert.deepStrictEqual(
math.round(3.212, math.bignumber(2)),
math.bignumber(3.21)
)
assert.strictEqual(math.round(-4.212, 2), -4.21)
// bignumber input
assert.deepStrictEqual(math.round(math.bignumber(3.212)), math.bignumber(3))
assert.deepStrictEqual(
math.round(math.bignumber(3.212), 2),
math.bignumber(3.21)
)
assert.deepStrictEqual(
math.round(math.bignumber(3.212), math.bignumber(2)),
math.bignumber(3.21)
)
// fraction input
assert.deepStrictEqual(math.round(math.fraction(44, 7)), math.fraction(6))
assert.deepStrictEqual(math.round(math.fraction(-44, 7)), math.fraction(-6))
assert.deepStrictEqual(
math.round(math.fraction(44, 7), 2),
math.fraction(629, 100)
)
assert.deepStrictEqual(
math.round(math.fraction(44, 7), math.bignumber(2)),
math.fraction(629, 100)
)
// Complex input
const c = math.complex(3.24, -2.71)
assert.deepStrictEqual(math.round(c), math.complex(3, -3))
assert.deepStrictEqual(math.round(c, 1), math.complex(3.2, -2.7))
assert.deepStrictEqual(
math.round(c, math.bignumber(1)),
math.complex(3.2, -2.7)
)
// unit input
assert.deepStrictEqual(
math.round(math.unit('5.21 cm'), math.unit('cm')),
math.unit('5 cm')
)
assert.deepStrictEqual(
math.round(math.unit('5.21 cm'), 1, math.unit('cm')),
math.unit('5.2 cm')
)
// array input
assert.deepStrictEqual(math.round([3.2, 3.8, -4.7]), [3, 4, -5])
assert.deepStrictEqual(math.round([3.21, 3.82, -4.71], 1), [3.2, 3.8, -4.7])
assert.deepStrictEqual(
math.round([3.21, 3.82, -4.71], math.bignumber(1)),
math.bignumber([3.2, 3.8, -4.7])
)
// numeric input, array or matrix of decimals
const numRounded: MathArray = math.round(math.tau, [2, 3])
assert.deepStrictEqual(numRounded, [6.28, 6.283])
const bigRounded: Matrix = math.round(
math.bignumber(6.28318),
math.matrix([2, 3])
)
assert.deepStrictEqual(bigRounded, math.matrix(math.bignumber([6.28, 6.283])))
assert.deepStrictEqual(math.round(math.fraction(44, 7), [2, 3]), [
math.fraction(629, 100),
math.fraction(6286, 1000)
])
// @ts-expect-error ... verify round(array, array) throws an error (for now)
assert.throws(() => math.round([3.21, 3.82], [1, 2]), TypeError)
}
/*
Clone examples
*/
{
const math = create(all, {})
expectTypeOf(
new math.OperatorNode('/', 'divide', [
new math.ConstantNode(3),
new math.SymbolNode('x')
])
).toMatchTypeOf<OperatorNode<'/', 'divide', (ConstantNode | SymbolNode)[]>>()
expectTypeOf(new math.ConstantNode(1).clone()).toMatchTypeOf<ConstantNode>()
expectTypeOf(
new math.OperatorNode('*', 'multiply', [
new math.ConstantNode(3),
new math.SymbolNode('x')
]).clone()
).toMatchTypeOf<
OperatorNode<'*', 'multiply', (ConstantNode | SymbolNode)[]>
>()
expectTypeOf(
new math.ConstantNode(1).cloneDeep()
).toMatchTypeOf<ConstantNode>()
expectTypeOf(
new math.OperatorNode('+', 'unaryPlus', [
new math.ConstantNode(3),
new math.SymbolNode('x')
]).cloneDeep()
).toMatchTypeOf<
OperatorNode<'+', 'unaryPlus', (ConstantNode | SymbolNode)[]>
>()
expectTypeOf(
math.clone(new math.ConstantNode(1))
).toMatchTypeOf<ConstantNode>()
}
/*
JSON serialization/deserialization
*/
{
const math = create(all, {})
const data = {
bigNumber: math.bignumber('1.5')
}
const stringified = JSON.stringify(data)
const parsed = JSON.parse(stringified, math.reviver)
assert.deepStrictEqual(parsed.bigNumber, math.bignumber('1.5'))
}
/*
Extend functionality with import
*/
declare module 'mathjs' {
interface MathJsInstance {
testFun(): number
value: number
}
}
{
const math = create(all, {})
const testFun = () => 5
math.import(
{
testFun,
value: 10
},
{}
)
math.testFun()
expectTypeOf(math.testFun()).toMatchTypeOf<number>()
expectTypeOf(
math.import({
myvalue: 42,
myFunc: (name: string) => `myFunc ${name}`
})
).toMatchTypeOf<void>()
expectTypeOf(
math.import(
{
myvalue: 42,
myFunc: (name: string) => `myFunc ${name}`
},
{
override: true
}
)
).toMatchTypeOf<void>()
expectTypeOf(
math.import(
{
myvalue2: 42
},
{
silent: true
}
)
).toMatchTypeOf<void>()
expectTypeOf(
math.import(
{
myvalue3: 42
},
{
wrap: true
}
)
).toMatchTypeOf<void>()
expectTypeOf(
math.import({
myvalue4: 42
})
).toMatchTypeOf<void>()
expectTypeOf(
math.import([
{
myvalue5: 42
},
{
myFunc2: (name: string) => `myFunc2 ${name}`
}
])
).toMatchTypeOf<void>()
}
/*
Renamed functions from v5 => v6
*/
{
const math = create(all, {})
math.typeOf(1)
math.variance([1, 2, 3, 4])
math.evaluate('1 + 2')
// chained operations
math.chain(3).typeOf().done()
math.chain([1, 2, 3]).variance().done()
math.chain('1 + 2').evaluate().done()
}
/*
Factory Test
*/
{
// create a factory function
const name = 'negativeSquare'
const dependencies: MathJsFunctionName[] = ['multiply', 'unaryMinus']
const createNegativeSquare = factory(name, dependencies, (injected) => {
const { multiply, unaryMinus } = injected
return function negativeSquare(x: number): number {
return unaryMinus(multiply(x, x))
}
})
// create an instance of the function yourself:
const multiply = (a: number, b: number) => a * b
const unaryMinus = (a: number) => -a
const negativeSquare = createNegativeSquare({ multiply, unaryMinus })
negativeSquare(3)
}
/**
* Dependency map typing test from mathjs official document:
* https://mathjs.org/docs/custom_bundling.html#using-just-a-few-functions
*/
{
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)
assert.strictEqual(format(c), '16/21')
assert.strictEqual(format(d), '7/9')
assert.strictEqual(format(255, { notation: 'bin' }), '0b11111111')
assert.strictEqual(format(255, { notation: 'hex' }), '0xff')
assert.strictEqual(format(255, { notation: 'oct' }), '0o377')
}
/**
* Custom parsing functions
* https://mathjs.org/docs/expressions/customization.html#customize-supported-characters
*/
{
const math = create(all, {})
const isAlphaOriginal = math.parse.isAlpha
math.parse.isAlpha = (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 })
assert.strictEqual(result, 42)
}
/**
* Util functions
* https://mathjs.org/docs/reference/functions.html#utils-functions
*/
{
const math = create(all, {})
// hasNumericValue function
assert.strictEqual(math.hasNumericValue(2), true)
assert.strictEqual(math.hasNumericValue('2'), true)
assert.strictEqual(math.isNumeric('2'), false)
assert.strictEqual(math.hasNumericValue(0), true)
assert.strictEqual(math.hasNumericValue(math.bignumber(500)), true)
assert.deepStrictEqual(math.hasNumericValue([2.3, 'foo', false]), [
true,
false,
true
])
assert.strictEqual(math.hasNumericValue(math.fraction(4)), true)
assert.strictEqual(math.hasNumericValue(math.complex('2-4i')), false)
}
/**
* src/util/is functions
*/
{
const math = create(all, {})
type IsFunc = (x: unknown) => boolean
const isFuncs: IsFunc[] = [
math.isNumber,
math.isBigNumber,
math.isComplex,
math.isFraction,
math.isUnit,
math.isString,
math.isArray,
math.isMatrix,
math.isCollection,
math.isDenseMatrix,
math.isSparseMatrix,
math.isRange,
math.isIndex,
math.isBoolean,
math.isResultSet,
math.isHelp,
math.isFunction,
math.isDate,
math.isRegExp,
math.isObject,
math.isNull,
math.isUndefined,
math.isAccessorNode,
math.isArrayNode,
math.isAssignmentNode,
math.isBlockNode,
math.isConditionalNode,
math.isConstantNode,
math.isFunctionAssignmentNode,
math.isFunctionNode,
math.isIndexNode,
math.isNode,
math.isObjectNode,
math.isOperatorNode,
math.isParenthesisNode,
math.isRangeNode,
math.isRelationalNode,
math.isSymbolNode,
math.isChain
]
isFuncs.forEach((f) => {
const result = f(1)
const isResultBoolean = result === true || result === false
assert.ok(isResultBoolean)
})
// Check guards do type refinement
const x: unknown = undefined
if (math.isNumber(x)) {
expectTypeOf(x).toMatchTypeOf<number>()
}
if (math.isBigNumber(x)) {
expectTypeOf(x).toMatchTypeOf<BigNumber>()
}
if (math.isComplex(x)) {
expectTypeOf(x).toMatchTypeOf<Complex>()
}
if (math.isFraction(x)) {
expectTypeOf(x).toMatchTypeOf<Fraction>()
}
if (math.isUnit(x)) {
expectTypeOf(x).toMatchTypeOf<Unit>()
}
if (math.isString(x)) {
expectTypeOf(x).toMatchTypeOf<string>()
}
if (math.isArray(x)) {
expectTypeOf(x).toMatchTypeOf<unknown[]>()
}
if (math.isMatrix(x)) {
expectTypeOf(x).toMatchTypeOf<Matrix>()
}
if (math.isDenseMatrix(x)) {
expectTypeOf(x).toMatchTypeOf<Matrix>()
}
if (math.isSparseMatrix(x)) {
expectTypeOf(x).toMatchTypeOf<Matrix>()
}
if (math.isIndex(x)) {
expectTypeOf(x).toMatchTypeOf<Index>()
}
if (math.isBoolean(x)) {
expectTypeOf(x).toMatchTypeOf<boolean>()
}
if (math.isHelp(x)) {
expectTypeOf(x).toMatchTypeOf<Help>()
}
if (math.isDate(x)) {
expectTypeOf(x).toMatchTypeOf<Date>()
}
if (math.isRegExp(x)) {
expectTypeOf(x).toMatchTypeOf<RegExp>()
}
if (math.isNull(x)) {
expectTypeOf(x).toMatchTypeOf<null>()
}
if (math.isUndefined(x)) {
expectTypeOf(x).toMatchTypeOf<undefined>()
}
if (math.isAccessorNode(x)) {
expectTypeOf(x).toMatchTypeOf<AccessorNode>()
}
if (math.isArrayNode(x)) {
expectTypeOf(x).toMatchTypeOf<ArrayNode>()
}
if (math.isAssignmentNode(x)) {
expectTypeOf(x).toMatchTypeOf<AssignmentNode>()
}
if (math.isBlockNode(x)) {
expectTypeOf(x).toMatchTypeOf<BlockNode>()
}
if (math.isConditionalNode(x)) {
expectTypeOf(x).toMatchTypeOf<ConditionalNode>()
}
if (math.isConstantNode(x)) {
expectTypeOf(x).toMatchTypeOf<ConstantNode>()
}
if (math.isFunctionAssignmentNode(x)) {
expectTypeOf(x).toMatchTypeOf<FunctionAssignmentNode>()
}
if (math.isFunctionNode(x)) {
expectTypeOf(x).toMatchTypeOf<FunctionNode>()
}
if (math.isIndexNode(x)) {
expectTypeOf(x).toMatchTypeOf<IndexNode>()
}
if (math.isNode(x)) {
expectTypeOf(x).toMatchTypeOf<MathNode>()
}
if (math.isNode(x)) {
expectTypeOf(x).toMatchTypeOf<MathNode>()
}
if (math.isObjectNode(x)) {
expectTypeOf(x).toMatchTypeOf<ObjectNode>()
}
if (math.isOperatorNode(x)) {
expectTypeOf(x).toMatchTypeOf<
OperatorNode<OperatorNodeOp, OperatorNodeFn, MathNode[]>
>()
}
if (math.isParenthesisNode(x)) {
expectTypeOf(x).toMatchTypeOf<ParenthesisNode>()
}
if (math.isRangeNode(x)) {
expectTypeOf(x).toMatchTypeOf<RangeNode>()
}
if (math.isRelationalNode(x)) {
expectTypeOf(x).toMatchTypeOf<math.RelationalNode>()
}
if (math.isSymbolNode(x)) {
expectTypeOf(x).toMatchTypeOf<SymbolNode>()
}
if (math.isChain(x)) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
expectTypeOf(x).toMatchTypeOf<MathJsChain<any>>()
}
}
/*
Probability function examples
*/
{
const math = create(all, {})
expectTypeOf(math.lgamma(1.5)).toMatchTypeOf<number>()
expectTypeOf(math.lgamma(math.complex(1.5, -1.5))).toMatchTypeOf<Complex>()
}
/*
toTex examples
*/
{
const math = create(all, {})
expectTypeOf(math.parse('a/b').toTex()).toMatchTypeOf<string>()
// TODO add proper types for toTex options
expectTypeOf(
math.parse('a/b').toTex({
a: '123'
})
).toMatchTypeOf<string>()
}
/*
Resolve examples
*/
{
const math = create(all, {})
expectTypeOf(math.resolve('x + y')).toMatchTypeOf<MathNode>()
expectTypeOf(math.resolve(math.parse('x + y'))).toMatchTypeOf<MathNode>()
expectTypeOf(
math.resolve(math.parse('x + y'), { x: 0 })
).toMatchTypeOf<MathNode>()
expectTypeOf(math.resolve('x + y', { x: 0 })).toMatchTypeOf<MathNode>()
expectTypeOf(
math.resolve([math.parse('x + y'), 'x*x'], { x: 0 })
).toMatchTypeOf<MathNode[]>()
expectTypeOf(math.resolve(math.matrix(['x', 'y']))).toMatchTypeOf<Matrix>()
}
/*
Random examples
*/
{
const math = create(all, {})
expectTypeOf(math.pickRandom([1, 2, 3])).toMatchTypeOf<number>()
expectTypeOf(math.pickRandom(['a', { b: 10 }, 42])).toMatchTypeOf<
string | number | { b: number }
>()
expectTypeOf(math.pickRandom([1, 2, 3])).toMatchTypeOf<number>()
expectTypeOf(math.pickRandom([1, 2, 3], 2)).toMatchTypeOf<number[]>()
expectTypeOf(math.chain([1, 2, 3]).pickRandom(2)).toMatchTypeOf<
MathJsChain<number[]>
>()
}
/*
MathNode examples
*/
{
class CustomNode extends Node {
a: MathNode
constructor(a: MathNode) {
super()
this.a = a
}
}
// Basic node
const instance1 = new Node()
// Built-in subclass of Node
const instance2 = new ConstantNode(2)
// Custom subclass of node
const instance3 = new CustomNode(new ConstantNode(2))
expectTypeOf(instance1).toMatchTypeOf<MathNode>()
expectTypeOf(instance1).toMatchTypeOf<MathNodeCommon>()
expectTypeOf(instance2).toMatchTypeOf<MathNode>()
expectTypeOf(instance2).toMatchTypeOf<MathNodeCommon>()
expectTypeOf(instance2).toMatchTypeOf<ConstantNode>()
expectTypeOf(instance3).toMatchTypeOf<MathNode>()
expectTypeOf(instance3).toMatchTypeOf<MathNodeCommon>()
expectTypeOf(instance3).toMatchTypeOf<CustomNode>()
}
/*
Statistics functions' return types
*/
{
const math = create(all, {})
expectTypeOf(math.min(1, 2, 3)).toMatchTypeOf<number>()
expectTypeOf(math.min([1, 2, 3])).toMatchTypeOf<number>()
expectTypeOf(
math.min(math.bignumber('123'), math.bignumber('456'))
).toMatchTypeOf<BigNumber>()
expectTypeOf(
math.min(math.unit('5cm'), math.unit('10cm'))
).toMatchTypeOf<Unit>()
expectTypeOf(
math.min([math.unit('5cm'), math.unit('10cm')])
).toMatchTypeOf<Unit>()
expectTypeOf(math.min(123, math.bignumber('456'))).toMatchTypeOf<
number | BigNumber | bigint | Fraction | Complex | Unit
>()
expectTypeOf(
math.min(
[
[1, 2],
[3, 4]
],
1
)
).toMatchTypeOf<MathScalarType>()
expectTypeOf(math.max(1, 2, 3)).toMatchTypeOf<number>()
expectTypeOf(math.max([1, 2, 3])).toMatchTypeOf<number>()
expectTypeOf(
math.max(math.bignumber('123'), math.bignumber('456'))
).toMatchTypeOf<BigNumber>()
expectTypeOf(
math.max(math.unit('5cm'), math.unit('10cm'))
).toMatchTypeOf<Unit>()
expectTypeOf(
math.max([math.unit('5cm'), math.unit('10cm')])
).toMatchTypeOf<Unit>()
expectTypeOf(
math.max(123, math.bignumber('456'))
).toMatchTypeOf<MathScalarType>()
expectTypeOf(math.mean(1, 2, 3)).toMatchTypeOf<number>()
expectTypeOf(math.mean([1, 2, 3])).toMatchTypeOf<number>()
expectTypeOf(
math.mean(math.bignumber('123'), math.bignumber('456'))
).toMatchTypeOf<BigNumber>()
expectTypeOf(
math.mean(math.unit('5cm'), math.unit('10cm'))
).toMatchTypeOf<Unit>()
expectTypeOf(
math.mean([math.unit('5cm'), math.unit('10cm')])
).toMatchTypeOf<Unit>()
expectTypeOf(math.mean(123, math.bignumber('456'))).toMatchTypeOf<
number | BigNumber | bigint | Fraction | Complex | Unit
>()
expectTypeOf(math.median(1, 2, 3)).toMatchTypeOf<number>()
expectTypeOf(math.median([1, 2, 3])).toMatchTypeOf<number>()
expectTypeOf(
math.median(math.bignumber('123'), math.bignumber('456'))
).toMatchTypeOf<BigNumber>()
expectTypeOf(
math.median(math.unit('5cm'), math.unit('10cm'))
).toMatchTypeOf<Unit>()
expectTypeOf(
math.median([math.unit('5cm'), math.unit('10cm')])
).toMatchTypeOf<Unit>()
expectTypeOf(math.median(123, math.bignumber('456'))).toMatchTypeOf<
number | BigNumber | bigint | Fraction | Complex | Unit
>()
expectTypeOf(math.quantileSeq([1, 2, 3], 0.75)).toMatchTypeOf<number>()
expectTypeOf(math.quantileSeq([1, 2, 3, 4, 5], [0.25, 0.75])).toMatchTypeOf<
MathArray | MathScalarType
>()
expectTypeOf(
math.quantileSeq([1, 2, 3, 4, 5], [0.25, 0.75]) as number[]
).toMatchTypeOf<number[]>()
expectTypeOf(math.quantileSeq([[1, 2, 3]], 0.75)).toMatchTypeOf<number>()
expectTypeOf(
math.quantileSeq([math.bignumber('123')], 0.75)
).toMatchTypeOf<BigNumber>()
expectTypeOf(math.quantileSeq(math.matrix([1, 2, 3]), 0.75)).toMatchTypeOf<
MathScalarType | MathArray
>()
expectTypeOf(
math.quantileSeq([math.unit('5cm'), math.unit('10cm')], 0.75)
).toMatchTypeOf<Unit>()
}
/*
Match types of exact positional arguments.
*/
{
const node1 = new ConstantNode(2)
const node2 = new SymbolNode('x')
const node3 = new FunctionNode('sqrt', [node2])
const node4 = new OperatorNode('+', 'add', [node1, node3])
expectTypeOf(node4.args[0]).toMatchTypeOf<ConstantNode>()
expectTypeOf(node4.args[1].args[0]).toMatchTypeOf<SymbolNode>()
}
{
const node1 = new ConstantNode(2)
const node2 = new SymbolNode('x')
const node3 = new ArrayNode([node1, node2])
expectTypeOf(node3.items[0]).toMatchTypeOf<ConstantNode>()
expectTypeOf(node3.items[1]).toMatchTypeOf<SymbolNode>()
}
/**
* mode Return Types
*/
{
const math = create(all, {})
const a = math.mode<number>([1, 2, 3])
expectTypeOf(a).toMatchTypeOf<number[]>()
assert.deepStrictEqual(a, [1, 2, 3])
const b = math.mode<number>([
[1, 2],
[2, 2],
[3, 5]
])
expectTypeOf(b).toMatchTypeOf<number[]>()
assert.deepStrictEqual(b, [2])
const c = math.mode<number>(1, 2, 2, 2, 3, 5)
expectTypeOf(c).toMatchTypeOf<number[]>()
assert.deepStrictEqual(c, [2])
const d = math.mode(1, 2, 2, 2, 3, 5)
expectTypeOf(d).toMatchTypeOf<number[]>()
assert.deepStrictEqual(d, [2])
const mathCollection = math.concat([1, 2, 3], [1], [4, 5])
const e = math.mode(mathCollection)
expectTypeOf(e).toMatchTypeOf<MathScalarType[]>()
assert.deepStrictEqual(e, [1])
}