mathjs
mathjs copied to clipboard
Added type inferencing for Vector & Matrix operations in multiply.js (+performance boost!)
The Issue
mathjs has had an "issue" with performance (some of the first search results for "mathjs is slow":
- https://stackoverflow.com/questions/54328275/math-js-is-slow-to-multiply-2-big-matrices
- https://www.reddit.com/r/javascript/comments/275fi9/comment/iyj6t2n/?utm_source=share&utm_medium=web2x&context=3
Except it doesn't.
Why the slow performance and all the complaints then?
mathjs is quite powerful, but the idea that you should explicitly set the numeric type of your tensors is something that people simply don't come across when reading the documentation (here are some pages from the documentation):
- https://mathjs.org/docs/reference/functions/multiply.html
- https://mathjs.org/docs/datatypes/matrices.html
In fact, mathjs's documentation makes it look like explicitly defining the numeric type is completely unnecessary because of the default type assignment in the config of mathjs:
- https://mathjs.org/docs/datatypes/numbers.html "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"
This leads to extremely poor performance when people try to use mathjs:
- Rendering 1000 hyper-cubes rotated around 2 axis using vanilla mathjs, no explicit numeric types (slow & avgs ~40ms/frame on my machine): https://editor.p5js.org/PotatoBoy/sketches/uPZZwvhgC
Which wouldn't exist had these explicit numeric types been used:
- Rendering 1000 hyper-cubes rotated around 2 axis using vanilla mathjs with explicit numeric types (fast & avgs ~1-2ms/frame on my machine): https://editor.p5js.org/PotatoBoy/sketches/DsDHNojgz
Why this wasn't done before now and how this PR fixes the issue that caused it
It seems like adding type inferencing was previously considered, but then ignored because of an issue with changing element types:
- Issue: https://github.com/josdejong/mathjs/issues/1709
- Issue's issue: https://github.com/josdejong/mathjs/issues/1709#issuecomment-590008781
This PR fixes this by getting the type during the tensor operation itself
-
<tensor>.getDataType()
is called to infer the datatype if it wasn't explicitly defined - While getting inferring the type every operation may seem slow, compared to the alternative of using the generic function, it's much much faster as seen by the previous examples and the solution's example and is well worth it for the performance.
- The datatype of the generated tensor using the inferred datatype is changed right before returning it, but not for the instantiation parameter in order to future-proof it in case future optimized methods of loading tensor data are used so that they can be used for the operation.
The Solution this PR provides
Type inferencing boosts the performance to speeds nearly indistinguishable from the speeds of explicit types
- Rendering 1000 hyper-cubes rotated around 2 axis using type inferencing mathjs, no explicit numeric types (fast & avgs ~1-2ms/frame on my machine): https://editor.p5js.org/PotatoBoy/sketches/01IsuOlTR
Lastly, I'd still recommend that the documentation more readily states and promotes the existence of these explicit types, but I'm not sure whether or not that would fit in with what mathjs is trying to go for in its documentation, and it mostly likely won't be necessary with type inferencing added so I won't be adding documentation doing that in this PR.