uncomplicate / neanderthal

Fast Clojure Matrix Library
http://neanderthal.uncomplicate.org
Eclipse Public License 1.0
1.06k stars 56 forks source link

Make `entry!` accept indices in any order for symmetric matrices #98

Closed p-himik closed 3 years ago

p-himik commented 4 years ago

entry! seems to accept indices according to the :uplo of the matrix, even despite the fact that the matrix is symmetric:

=> (entry! (dsy 5 {}) 0 1 7)
Execution error (ExceptionInfo) at uncomplicate.neanderthal.core/entry! (core.clj:838).
The element you're trying to set is out of bounds of the matrix.

But at the same time entry accepts indices in any order:

=> (-> (dsy 5 {})
  (entry! 1 0 7)
  (entry 0 1))
7.0

I think it would be quite convenient and intuitive to let entry! accept indices in any order for symmetric matrices.

blueberry commented 3 years ago

This is intended behavior. entry! can edit only the fields that exist, while entry can return a value from an editable field, hardcoded value (such as 1), or value that can be computed from the context.

Do you have an use case where this is a problem for you, or you asked out of curiosity?

p-himik commented 3 years ago

I can't provide a full use case. But I'm in the process of porting some C++ code to Clojure, and the C++ code just takes a regular matrix and fills it in symmetrically:

mat.at(i, j) = val;
mat.at(j, i) = val;

Obviously, that's a waste of space so I used dsy. But with a neanderthal symmetrical matrix, I now must make sure that the indices correspond to the internal shape of the matrix:

(entry! mat (max i j) (min i j) val)

I understand why the above exception would show up with a triangular matrix. But with a symmetrical one? To me it seems like an implementation detail leaking into the user space. Of course I just started working with neanderthal, so my understanding may be completely misplaced.

blueberry commented 3 years ago

Your use case is covered by GE matrices. BTW the point of a matrix library is to NOT work with individual entries, but in bulk. You rarely (if ever) should call entry! on individual elements except when you're debugging or experimenting.

p-himik commented 3 years ago

Your use case is covered by GE matrices

Not really because that would take twice as much space, no? My matrices are always symmetrical.

You rarely (if ever) should call entry! on individual elements

I know. But I really doubt this particular algorithm can be vectorized as for each particular item it potentially references two other items indices of which depend on external data. It's more of a tree traversal algorithm than a linear algebra one.

blueberry commented 3 years ago

It's more of a tree traversal algorithm than a linear algebra one.

Then Neanderthal can't help you. BTW even if the entry! supported such indexing, you'd be setting each entry twice.

p-himik commented 3 years ago

Then Neanderthal can't help you

It can, in terms of space efficiency. Regular vectors of vectors will take much, much more space.

even if the entry! supported such indexing, you'd be setting each entry twice

How come? To me it seems that the internal representation of a symmetrical matrix is a triangular matrix. If so, where would the second entry come from?