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

Multiplying two arrays can return a scalar #529

Closed
Crazometer opened this Issue Jan 1, 2016 · 6 comments

Comments

Projects
None yet
4 participants
@Crazometer

Crazometer commented Jan 1, 2016

Hey, thanks for the great library!

When a 1 x N array and N x 1 array are multiplied using math.multiply a scalar is returned. For example the value '3'. If my two inputs are arrays (matrices) I would expected the result to also be in array form, in this case ['3'].

I believe it would lead to more intuitive use of the library if all matrix multiplication operations returned a matrix. If it is difficult to change the current implementation of math.multiply perhaps a small wrapper function matrix.multiply could be created that simply packages the result in the case of a 1x1 matrix. Users who wish for a matrix (or array) to always be returned could use that function.

@Crazometer Crazometer changed the title from Multiplying two matrices returns can return a scalar to Multiplying two arrays can return a scalar Jan 1, 2016

@ericman314 ericman314 added the bug label Jan 1, 2016

@ericman314

This comment has been minimized.

Collaborator

ericman314 commented Jan 1, 2016

Looks like the single-element matrix is being converted to a scalar.

Many users prefer to have predictable outputs. The config.predictable option usually forces the output to have the same type as the input(s), but apparently this case was overlooked.

@josdejong

This comment has been minimized.

Owner

josdejong commented Jan 1, 2016

This behavior has always been there, but thinking about this again, it may make sense to just always return a 2d array, not just in some specific cases. We could indeed use config.predictable here to make the behavior configurable, but shouldn't we just get rid of this?

@josdejong

This comment has been minimized.

Owner

josdejong commented Jan 8, 2016

Ok then I will simply remove this behavior in the next breaking release.

@EthanRBrown

This comment has been minimized.

EthanRBrown commented Feb 28, 2016

I agree that consistency is a good thing...however, there is some precedent for this behavior. For example, Matheatica and Maxima both return a scalar when you multiply a 1 x N matrix by a N x 1 matrix.

That's not to say if Mathematica and Maxima both jumped off a cliff that mathjs should as well. They're just big enough to set precedent (I don't have access to Mathcad or Maple, and I don't know R well enough to test it).

I also checked another popular numerics library, for the .NET world, Math.NET Numerics, and they quite sensibly return a 1x1 matrix (not a scalar). So there's some precedent in the other direction.

See also this interesting answer on math.stackexchange.com. The accepted answer makes an excellent point: if a 1x1 matrix was really equivalent to a scalar, then you should be able to multiply it by a 2x2 (or any dimensionality matrix for that matter), but you can only multiply it by a nx1 matrix.

The other thing to take into account, of course, is people that are using this and expecting the behavior...I imagine a lot of applications commonly do row & column vector multiplications, and I could see how it would be useful to accept a scalar. Perhaps provide a switch in the other direction (i.e., if you are doing a million row/column vector multiplications and all you care about is the scalar result, you could set the switch and skip the step of extracting the single entry in the 1x1 matrix).

My suggestion would be to proceed, and make the result a matrix, but to provide a switch for those who rely on the behavior (probably reasonably so).

@josdejong

This comment has been minimized.

Owner

josdejong commented Feb 29, 2016

Thanks for your input Ethan.

When choosing behavior we look at applications like Mathematica, Matlab, and also Python and JavaScript, and lastly consistency within the mathjs library itself. It's sometimes hard to make a choice, for example we ended up having zero-based indexes in the JavaScript functions (typically used by programmers) but offer one-based indexes in the expression parser (typically used by mathematicians). In most cases mathjs has the same behavior as well know math applications, in some cases it differs, like using geometric dimensions for matrices (i.e. a vector actually has 1 dimension and a scalar has zero 0 dimensions).

When people need the "old" behavior of returning a value instead of a 1x1 matrix, they can do so by overriding the function multiply:

var math = require('./index');

// by default, mathjs always returns a 2d matrix when input is 2d.
console.log(math.multiply([[1,2,3]], [[4],[5],[6]]));  // outputs matrix [[32]]

// change multiply such that it returns a value instead of 1x1 matrix:
var originalMultiply = math.multiply;
math.import({
  multiply: function () {
    var res = originalMultiply.apply(null, arguments);

    if (math.deepEqual(math.size(res), [1, 1])) {
      return math.squeeze(res);
    }
    else {
      return res;
    }
  }
}, {override: true});

// now mathjs will return a scalar when a multiplication results in a single value
console.log(math.multiply([[1,2,3]], [[4],[5],[6]]));  // outputs number 32
@EthanRBrown

This comment has been minimized.

EthanRBrown commented Mar 1, 2016

This all looks good! I appreciate you taking such a considered approach to these issues.

@josdejong josdejong closed this in 3aa38ee Mar 4, 2016

paulobuchsbaum added a commit to paulobuchsbaum/mathjs that referenced this issue Nov 7, 2017

Update rationalize.js
Remove stri() call in Line josdejong#529, leftovers from debug code.

paulobuchsbaum added a commit to paulobuchsbaum/mathjs that referenced this issue Nov 17, 2017

Update rationalize.js
Remove stri() call in Line josdejong#529, leftovers from debug code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment