Hi Jos,
Thanks for providing such a useful math library for JS. I'm considering MathJS for a current project, and would like some guidance retrieving rows and columns from a Matrix object. Let's say I have a matrix:
var my_matrix = math.matrix(
[
[ 0.50, 0.25, 0.00],
[ 0.25, 0.50, 1.00]
]
);
And, now I want to retrieve the last column as a 1-D array. After trying various approaches, I came up with this:
var super_special_column = math.flatten(
my_matrix.subset(
math.index([0, 2], 2)
)
).toArray();
Admittedly, I may be spoiled from Python's NumPy syntax, but this seems like a lot of work. Is this the easiest/best way to access members of a Matrix in MathJS?
Thanks again,
Scott
Yes, the syntax for getting/setting subsets is terribly verbose. JavaScript doesn't have a colon operator like python :(. Using the (one-based) expression parser it's great, there you just do my_matrix[1:2, 2], similar to Python and Matlab.
If you know a less verbose solution please let me know, I'm very interested in that!
A few thoughts:
Index accept special values like '*' and end, to denote a whole row/column and the end of a column (Similar to doing A[:] and A[2:end] in the expression parser). That way you don't have to figure out the size of the dimensions to write your Index.``` js
/**
/**
Whether you want to flatten the output and convert to an Array is application specific I think.
I will close this issue. The (JavaScript) API is still verbose, but I don't know of a better solution.
Hi guys, I think this issue should be reopened - if nothing else, it seems like this sort of functionality should be included in the API for matrices.
The actual helper functions can be very short, something like
getRow = (M, i) => math.flatten(M.subset(math.index(i, math.range(0, M._size[0])))).toArray();
getColumn = (M, i) => math.flatten(M.subset(math.index(math.range(0, M._size[0]),i))).toArray();
Ideally, though, these would be functions attached to any matrix, so you could call something like
let row = M.getRow(2);
This code is perhaps not the best solution, but isolating a single row/column from a matrix is such a common numerical procedure that it really should have some first-class support. If it's possible for something like this to be added in a PR, just point me towards the appropriate files!
Agree @dzackgarza , ok let's add these two functions.
I like the shorter names row() and col() or column() more than the getters. When the input is a Matrix, output should be a Matrix, and when input is an Array, output should be an Array.
I think we should at least create these two as standalone functions row(matrix, index) and column(matrix, index), so you can handle both Arrays and Matrices and not just matrices. We could add them as methods on a Matrix too. Does that make sense?
The functions are zero-based, and need a transform so they work with one-based indices in the expression parser. The Matrix methods are just zero-based.
Would be great if you could contribute these functions @dzackgarza ! Docs and unit tests is probably the most work here, not the actual implementation. You could look at how concat.js and concat.transform.js is implemented, it has a last index argument too which is transformed in the expression parser.
@dzackgarza in getRow it should be M._size[1], shouldn't it?
```
getRow = (M, i) => math.flatten(M.subset(math.index(i, math.range(0, M._size[1])))).toArray();
This is already implemented as math.row and math.column, no?
Did you try it out? :smile:
good point though, this issue should be closed long time ago (the functions column and row are indeed implemented)
But they do indeed work differently than documented 😅️
The documentation says:
// get a row
const d = [[1, 2], [3, 4]]
math.row(d, 1) // returns [3, 4]
// get a column
const d = [[1, 2], [3, 4]]
math.column(d, 1) // returns [2, 4]
But in reality they return [[3,4]] and [[2],[4]] respectively. What's up with math.js returning vectors inconsistently either as 1D or 2D?
EDIT: For example lsolve, usolve, lusolve all return 2D column vectors (both in documentation and in reality), kron returns 2D row vectors. If I were to chose, I'd definitely go with 1D vectors everywhere.
hm have to double check that.
The row and column implementations indeed returns 2d result so the comments are wrong.
What's up with math.js returning vectors inconsistently either as 1D or 2D?
I have a vague idea but can you give an example so I understand what you mean?
I found out that I remembered the inconsistencies much worse than they actually were. Ah, those fake memories 😅️. If we fix the documentation of column and row to reflect the reality, there's a clear precedence for 2D vectors.
The only thing that really bugs me now is that kron converts 1D vectors to 2D _row vectors_. I think it shouldn't change the size of matrices.
It is important that the functions are consistent with each other. It makes sense to me to have 1d in -> 2d out. I've opened an issue for that: #1753.
Turns out these weren't fake memories in the end. The dot function only works for 1-dim vectors, not column vectors. I'm working on a PR already.
math.dot( math.matrix([[1],[2]]), math.matrix([[1],[2]]) )
// RangeError: Vector expected
Most helpful comment
Hi guys, I think this issue should be reopened - if nothing else, it seems like this sort of functionality should be included in the API for matrices.
The actual helper functions can be very short, something like
Ideally, though, these would be functions attached to any matrix, so you could call something like
This code is perhaps not the best solution, but isolating a single row/column from a matrix is such a common numerical procedure that it really should have some first-class support. If it's possible for something like this to be added in a PR, just point me towards the appropriate files!