math.size and Matrix.size are inconsistent #3059
Replies: 11 comments
-
In the documentation for math.size(2.3) // returns []
math.size('hello world') // returns [11]
const A = [[1, 2, 3], [4, 5, 6]]
math.size(A) // returns [2, 3]
math.size(math.range(1,6)) // returns [5] This is not true in the current version. Size actually returns |
Beta Was this translation helpful? Give feedback.
-
I was surprised how many tests dependend on The only real-life consequence of let m = math.matrix([ [0, 1], [1, 0] ])
let e = math.ones( size(m) )
// used to return: matrix([ [1, 1], [1, 1] ])
// now returns: [ [1, 1], [1, 1] ] This inconvenience can be easily fixed by using spread: let e = math.ones( ...size(m) ) // matrix(...) However, it is a breaking change. |
Beta Was this translation helpful? Give feedback.
-
Thanks for your suggestions Michal. It's interesting to think about how we can make this "most" consistent. So far, all functions of mathjs try to follow this behavior:
So functions like So I'm not sure if it's a good idea to change Just thinking aloud: would it make sense to have Or we could simply leave this as is, and accept it is just a coincidence that the function At least we should clarify the docs and examples so you can see when output is an Array or a Matrix. |
Beta Was this translation helpful? Give feedback.
-
I understand that the current status quo is array in – array out; matrix in – matrix out. But is there actually a good reason why anybody would want size as a matrix? I struggle to imagine such a scenario. Matrices are useful if you multiply, transpose or decompose them. I don't think anybody will ever need to do something like this with size. But then again, I might be wrong. If there are actual benfits to having size as a matrix, adding |
Beta Was this translation helpful? Give feedback.
-
That's a true point, I can't come up with a clear case where you want want the returned size to be a Matrix necessarily. The idea behind keeping types consistent What is the reason why you want to have |
Beta Was this translation helpful? Give feedback.
-
And what is the reason they shouldn't be the same?
While I don't agree that this is a good principle, I respect it. If it's really that important for you, let's make a |
Beta Was this translation helpful? Give feedback.
-
I've been giving this a bit more thought. I think having So let's go for it and change |
Beta Was this translation helpful? Give feedback.
-
I've created a PR: #1805 I have to say, I'm not entirely happy. Some of the changes required in the unit tests show the effect of the changed behavior: const a = math.matrix([[1, 2, 3], [4, 5, 6]])
const b = math.zeros(math.size(a))
assert.deepStrictEqual(b.size(), a.size()) // Error now, if you are working with matrices, like This really makes me doubt about it again if it's a good idea after all 😕 |
Beta Was this translation helpful? Give feedback.
-
I already mentioned this inconvenience in my previous comment. If one wants to create a const a = math.matrix([[1, 2, 3], [4, 5, 6]])
const b = math.zeros(...math.size(a)) // spread the size
assert.deepStrictEqual(b.size(), a.size()) // works But I agree that this isn't very straightforward and would probably be a bad design. The problem here is that Instead of trying to work around the legacy API, I propose a new call signature for // When given a matrix, it will return a new matrix with the same type and dimensions
function zeros(matrix: DenseMatrix): DenseMatrix
function zeros(matrix: SparseMatrix): SparseMatrix
function zeros(matrix: number[][]): number[][]
// When given a size, it will create a DenseMatrix (the default one)
function zeros(size: number[]): DenseMatrix
function zeros(m: number, n: number): DenseMatrix
// When given a size and a type, it will create the correct type of matrix
function zeros(size: number[], type: 'dense'): DenseMatrix
function zeros(size: number[], type: 'sparse'): SparseMatrix
function zeros(size: number[], type: 'array'): number[][] I'm willing to make a PR that implements this. With this new API, the code you've posted would have been: const a = math.matrix([[1, 2, 3], [4, 5, 6]])
const b = math.zeros(a)
assert.deepStrictEqual(b.size(), a.size()) // works |
Beta Was this translation helpful? Give feedback.
-
Ah, your're right. Yes I had seen it coming too, but using it for real helps me weight the impact (for me and all current users with certain expectations). I'm sorry for the back-and-forth in this regard, but it still doesn't feel "right" so I'm reluctant to make this change. I have the feeling that we're going to mix the current API with a different type of API.
It's an interesting idea to have
I think this touches the core of our different way of looking at the API. The API of mathjs is designed around the simple rule "data type in -> same data type out". Such a rule gives predictability and makes it easy to use the library. The intention also is to use functions and no class methods (functional API). If you're doing calculations with BigNumbers, the results are in BigNumbers and should not suddenly switch to numbers. When calculating with plain Array, you get plain Array out, and not a DenseMatrix. And when working with DenseMatrices, you get DenseMatrices out and not suddenly switch to low level Arrays. It may be good to take a step back and first get the bigger picture clear. You have some interesting ideas and a different view on things than me which is always good. Here an open question to you: if you could start from scratch, what API would you come up with for mathjs? Would you like to replace the "data type in -> same data type out" API with something totally different, and if so what? |
Beta Was this translation helpful? Give feedback.
-
There's a lot of back and forth here with no clear actionable outcome, so moving to Discussions. |
Beta Was this translation helpful? Give feedback.
-
The
.size()
method on matrices always returnsnumber[]
. Themath.size(x)
method, which should be more robust, can take not onlyMatrix
instances, but also array matrices and scalars. For arrays it returnsnumber[]
, but for matrices it returns an instance ofMatrix
.This is unexpected and useless. Size is usefull when one can read the dimensions rightaway, with matrix, you have to convert it to array first.
Beta Was this translation helpful? Give feedback.
All reactions