scipy / scipy

SciPy library main repository
https://scipy.org
BSD 3-Clause "New" or "Revised" License
13.16k stars 5.21k forks source link

ENH: Easy transformation betwean `spmatrix` and `_sparray` #15849

Open mfeuerle opened 2 years ago

mfeuerle commented 2 years ago

Is your feature request related to a problem? Please describe.

All the constructor methods in scipy.sparse (e.g. kron, eye, etc) are not yet transferred to the new array interface. I really like the numpy compatible element-wise multiplication, but the usage of those new arrays is really cumbersome since you have to manually change every single format. I would suggest a simple switcher method to simply switch between both formats.

Describe the solution you'd like.

A straight forward solution would be something like

def tosparray(matrix):
    if matrix._is_array == True: 
        return matrix
    if matrix.format == 'coo':
        return coo_array(matrix)
    if matrix.format == 'csr':
        return csr_array(matrix)
    # and so forth

def tospmatrix(array):
    if array._is_array == False: 
        return array
    if array.format == 'coo':
        return coo_matrix(array)
    if array.format == 'csr':
        return csr_matrix(array)
    # and so forth

This would make the interplay between those two formats easier and especially the new arrays way more accessible.

Of course, this could (and probably) should be done in a more flexible way than simply if statements, so that it ideally works for all spmatrix e.g. with something like

def tosparray(matrix):
    class TMP(_sparray, type(matrix)):
        pass    
    return TMP(matrix)

Unfortunatly, the result would be a _sparray of type TMP and not e.g. of type coo_array which is a problem e.g. for isspmatrix_coo. But i think a quite easy solution is from this point not to far away.

Describe alternatives you've considered.

No response

Additional context (e.g. screenshots, GIFs)

No response

perimosocordiae commented 2 years ago

We could accomplish this with a dynamic attribute lookup hack:

def to_sparse_array(x):
  cls = getattr(x, f'_{x.format}_container')
  return cls(x)
mfeuerle commented 2 years ago

It nearly worked. If x is a matrix, the corresponding container is also a matrix, so the above function did in fact nothing, but

def tosparray(x):
    if isdense(x):
        return x
    cls = getattr(_arrays, f'{x.format}_array')
    return cls(x)

works. Unfortunalty, it only works for the default sparrays located in _arrays but not for other, e.g. a self implemented spmatrix.