Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

In-place operations #1134

Closed
torfsen opened this issue Jun 15, 2018 · 10 comments
Closed

In-place operations #1134

torfsen opened this issue Jun 15, 2018 · 10 comments

Comments

@torfsen
Copy link

torfsen commented Jun 15, 2018

Currently, if I want to add a vector y to an existing vector x and store the result in x I need to do

x = math.add(x, y);

This means that new storage has to be allocated to hold the result of the addition. I'd like to avoid that.

I suggest in-place variants of those operations where it makes sense, e.g. math.iadd:

math.iadd(x, y); // Add y to x in-place, no return value

From an implementation point of view, add(x, y) could easily be implemented via iadd by something like

function add(x, y) {
  let result = math.clone(x);
  result.iadd(y);
  return result;
}

Almost all arithmetic, bitwise, complex, logical, trigonometry and some of the matrix and set functions could benefit from an in-place variant.

@josdejong
Copy link
Owner

In general, I strongly prefer immutable objects and pure functions. Your proposal is exactly the opposite of that, so there must be a really good reason for it.

For matrices, reuse may seriously improve performance, which can be a valid reason. We should validate whether this is indeed the case though, and get to know how much we could gain.

From a practical point of view: it would require a huge amount of refactoring, we should keep that in mind.

@torfsen
Copy link
Author

torfsen commented Jun 18, 2018

You're spot on regarding the trade-off between the benefits of immutability and improved performance. I'm from a scientific computing background, so I'll happily throw out the former for the latter. But of course you might come to a different conclusion (which is perfectly fine!).

It probably boils down to deciding whether mathjs wants to be a platform for resource-intensive computations like, e.g., NumPy for Python (with all the drawbacks that improved performance and memory usage usually has regarding usability and code readability) or if it has different goals.

AFAIK, there is currently no de-facto standard JS library for scientific computing. Besides mathjs there are some other candidates, but none of those (including mathjs) are built from the ground up for resource-intensive computations.

@josdejong
Copy link
Owner

josdejong commented Jun 23, 2018

Yeah, first we should do a benchmark to see how many impact it would have.

@torfsen how does numpy do this? Does numpy have such functions?

Just thinking aloud: maybe we could consider iadd like functions only for specific operations instead of for "all "functions. I'm thinking about the operators +=, -=, *=, and /=. These are operations I regularly use in loops to do cumulatives and things like that. We could implement these operators in the expression parser, and have them powered by iadd, isubtract, imultiply, and idivide.

An other direction is that we could have such functions as methods on the Matrix class but not as pure functions, i.e. methods can be mutable but functions not. There are already immutable methods on Matrix like .set(...) and .resize(...).

@harrysarson
Copy link
Collaborator

I believe a much greater improvement to performance would come from using something like numpy's ndarray to store vectors and matrices rather than javscript arrays and therefore that should be a priority.

Additionally, I would argue for more meaningful method names such as matrix.inplaceAdd or matrix.modifyAdd or even matrix.withMutation.add

@harrysarson
Copy link
Collaborator

See #760

@harrysarson harrysarson mentioned this issue Jun 23, 2018
@Nekomajin42
Copy link
Contributor

Please don't forget the %=!

And what do you think about the ++ and -- operators?

@josdejong
Copy link
Owner

@harrysarson good point. we should really first put these ideas for improvement in perspective. See also the benchmark folder, where for example the performance of the JavaScript library ndarray (using Float64Array) against other libraries like numericjs which is amazingly fast but uses nested JavaScript arrays.

@torfsen
Copy link
Author

torfsen commented Jun 25, 2018

@josdejong NumPy has a complex array architecture and supports in-place updates for example via the standard operators.

To be honest I didn't even know about the ndarray JS library -- it already supports in-place operations (for example using ndarray-ops), so there might be no reason to reinvent the wheel.

@josdejong
Copy link
Owner

I was thinking a bit more about these operators +=, -=, *=, /=, etc. We can see these operators simply as eye-candy / compact notation: a += b is the same as a = a + b. It should not necessarily have a different implementation under the hood. So maybe we should not mix them in this discussion and keep this discussion focused on matrix operations that mutate matrices vs pure functions and immutable matrices.

Most important arguments I think are:

  1. pro: mutating the matrix itself is much faster (need to validate how much performance increase we're talking about)
  2. con: keeping data immutable and functions pure is much less sensitive to bugs in general.

@gwhitney
Copy link
Collaborator

gwhitney commented Oct 6, 2023

Going to reference this in the "future of matrices" discussion #2702 so closing it.

@gwhitney gwhitney closed this as completed Oct 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants