1 | # Extension
|
2 |
|
3 | The library can easily be extended with functions and variables using the
|
4 | [`import`](../reference/functions/import.md) function. The function `import`
|
5 | accepts an object with functions and variables.
|
6 |
|
7 | Function `import` has the following syntax:
|
8 |
|
9 | ```js
|
10 | math.import(object: Object [, options: Object])
|
11 | ```
|
12 |
|
13 | Where:
|
14 |
|
15 | - `object` is an object or array containing the functions and/or values to be
|
16 | imported. `import` support regular values and functions, typed functions
|
17 | (see section [Typed functions](#typed-functions)), and factory functions
|
18 | (see section [Factory functions](#factory-functions)).
|
19 | An array is only applicable when it contains factory functions.
|
20 |
|
21 | - `options` is an optional second argument with options.
|
22 | The following options are available:
|
23 |
|
24 | - `{boolean} override`
|
25 | If `true`, existing functions will be overwritten. The default value is `false`.
|
26 | - `{boolean} silent`
|
27 | If `true`, the function will not throw errors on duplicates or invalid
|
28 | types. Default value is `false`.
|
29 | - `{boolean} wrap`
|
30 | If `true`, the functions will be wrapped in a wrapper function which
|
31 | converts data types like Matrix to primitive data types like Array.
|
32 | The wrapper is needed when extending math.js with libraries which do not
|
33 | support the math.js data types. The default value is `false`.
|
34 |
|
35 | The following code example shows how to import a function and a value into math.js:
|
36 |
|
37 | ```js
|
38 | // define new functions and variables
|
39 | math.import({
|
40 | myvalue: 42,
|
41 | hello: function (name) {
|
42 | return 'hello, ' + name + '!'
|
43 | }
|
44 | })
|
45 |
|
46 | // defined functions can be used in both JavaScript as well as the parser
|
47 | math.myvalue * 2 // 84
|
48 | math.hello('user') // 'hello, user!'
|
49 |
|
50 | const parser = math.parser()
|
51 | parser.eval('myvalue + 10') // 52
|
52 | parser.eval('hello("user")') // 'hello, user!'
|
53 | ```
|
54 |
|
55 | ## Import external libraries
|
56 |
|
57 | External libraries like
|
58 | [numbers.js](https://github.com/sjkaliski/numbers.js) and
|
59 | [numeric.js](https://github.com/sloisel/numeric) can be imported as follows.
|
60 | The libraries must be installed using npm:
|
61 |
|
62 | $ npm install numbers
|
63 | $ npm install numeric
|
64 |
|
65 | The libraries can be easily imported into math.js using `import`.
|
66 | In order to convert math.js specific data types like `Matrix` to primitive types
|
67 | like `Array`, the imported functions can be wrapped by enabling `{wrap: true}`.
|
68 |
|
69 | ```js
|
70 | // import the numbers.js and numeric.js libraries into math.js
|
71 | math.import(require('numbers'), {wrap: true, silent: true})
|
72 | math.import(require('numeric'), {wrap: true, silent: true})
|
73 |
|
74 | // use functions from numbers.js
|
75 | math.fibonacci(7) // 13
|
76 | math.eval('fibonacci(7)') // 13
|
77 |
|
78 | // use functions from numeric.js
|
79 | math.eval('eig([1, 2; 4, 3])').lambda.x // [5, -1]
|
80 | ```
|
81 |
|
82 |
|
83 | ## Typed functions
|
84 |
|
85 | Typed functions can be created using `math.typed`. A typed function is a function
|
86 | which does type checking on the input arguments. It can have multiple signatures.
|
87 | And can automatically convert input types where needed.
|
88 |
|
89 | A typed function can be created like:
|
90 |
|
91 | ```js
|
92 | const max = typed('max', {
|
93 | 'number, number': function (a, b) {
|
94 | return Math.max(a, b)
|
95 | },
|
96 |
|
97 | 'BigNumber, BigNumber': function (a, b) {
|
98 | return a.greaterThan(b) ? a : b
|
99 | }
|
100 | })
|
101 | ```
|
102 |
|
103 | Typed functions can be merged as long as there are no conflicts in the signatures.
|
104 | This allows for extending existing functions in math.js with support for new
|
105 | data types.
|
106 |
|
107 | ```js
|
108 | // create a new data type
|
109 | function MyType (value) {
|
110 | this.value = value
|
111 | }
|
112 | MyType.prototype.isMyType = true
|
113 | MyType.prototype.toString = function () {
|
114 | return 'MyType:' + this.value
|
115 | }
|
116 |
|
117 | // define a new datatype
|
118 | math.typed.addType({
|
119 | name: 'MyType',
|
120 | test: function (x) {
|
121 | // test whether x is of type MyType
|
122 | return x && x.isMyType
|
123 | }
|
124 | })
|
125 |
|
126 | // use the type in a new typed function
|
127 | const add = typed('add', {
|
128 | 'MyType, MyType': function (a, b) {
|
129 | return new MyType(a.value + b.value)
|
130 | }
|
131 | })
|
132 |
|
133 | // import in math.js, extend the existing function `add` with support for MyType
|
134 | math.import({add: add})
|
135 |
|
136 | // use the new type
|
137 | const ans = math.add(new MyType(2), new MyType(3)) // returns MyType(5)
|
138 | console.log(ans) // outputs 'MyType:5'
|
139 | ```
|
140 |
|
141 | Detailed information on typed functions is available here:
|
142 | [https://github.com/josdejong/typed-function](https://github.com/josdejong/typed-function)
|
143 |
|
144 |
|
145 |
|
146 |
|
147 | ## Factory functions
|
148 |
|
149 | Regular JavaScript functions can be imported in math.js using `math.import`:
|
150 |
|
151 | ```js
|
152 | math.import({
|
153 | myFunction: function (a, b) {
|
154 | // ...
|
155 | }
|
156 | })
|
157 | ```
|
158 |
|
159 | The function can be stored in a separate file:
|
160 |
|
161 | ```js
|
162 | exports.myFunction = function (a, b) {
|
163 | // ...
|
164 | }
|
165 | ```
|
166 |
|
167 | Which can be imported like:
|
168 |
|
169 | ```js
|
170 | math.import(require('./myFunction.js'))
|
171 | ```
|
172 |
|
173 | An issue arises when `myFunction` needs functionality from math.js:
|
174 | it doesn't have access to the current instance of math.js when in a separate file.
|
175 | Factory functions can be used to solve this issue. A file exporting a factory function
|
176 | looks like:
|
177 |
|
178 | ```js
|
179 | exports.name = 'myFunction'
|
180 | exports.factory = function (type, config, load, typed) {
|
181 | return function myFunction (a, b) {
|
182 | // ...
|
183 | }
|
184 | }
|
185 | ```
|
186 |
|
187 | The file exports a name and a factory function. When running `math.import`, the factory
|
188 | function is invoked by math.js with four arguments:
|
189 |
|
190 | - `type: Object`: Object containing the data types of math.js,
|
191 | like `type.BigNumber` and `type.Unit`.
|
192 | - `config: Object`: object with the configuration of math.js.
|
193 | - `load: function`: loader function to access functions from math.js. For example to
|
194 | load the function `add`:
|
195 |
|
196 | ```js
|
197 | exports.factory = function (type, config, load, typed) {
|
198 | const add = load(require('mathjs/lib/function/arithmetic/add'))
|
199 |
|
200 | return myFunction (a, b) {
|
201 | // ...
|
202 | }
|
203 | }
|
204 | ```
|
205 |
|
206 | - `typed: function`: function to create typed-functions.
|
207 |
|
208 | The result returned by a factory function will be imported into the `math`
|
209 | namespace under the given `name`, `math.myFunction` in the above example.
|
210 |
|
211 | A factory can contain the following properties:
|
212 |
|
213 | - `name: string`. The name of the exported function or value. Required.
|
214 | - `factory: function (type, config, load, typed) `. The factory function,
|
215 | must return the function or value to be imported in math.js. Required.
|
216 | - `path: string`. An optional path to where the function or value will be
|
217 | imported. By default, imported functions have no path and are imported in
|
218 | the 'flat' namespace `math`. Data types have `type` as path, and will be
|
219 | located under `math.type.*`. Optional.
|
220 | - `lazy: boolean`. If true (default), the factory function will be lazy loaded:
|
221 | it is executed as soon as the function is about to be used.
|
222 | - `math: boolean`. False by default. If true, the `math` namespace is passed
|
223 | to the factory function as fifth argument. Should not be used unless there
|
224 | is a very good reason for it.
|
225 |
|
226 | To import a set of factory functions, the function `math.import` accepts an
|
227 | array containing factory functions:
|
228 |
|
229 | ```js
|
230 | math.import([
|
231 | require('./myFactoryFunction1.js'),
|
232 | require('./myFactoryFunction2.js'),
|
233 | require('./myFactoryFunction3.js'),
|
234 | // ...
|
235 | ])
|
236 | ```
|