Calculate subset of matrix multiplication

心不动则不痛 提交于 2019-12-22 08:59:06

问题


When I have two non-sparse matrices A and B, is there a way to efficiently calculate C=A.T.dot(B) when I only want a subset of the elements of C? I have the desired indices of C stored in CSC format which is specified here.


回答1:


If you know in advance which parts of C you want and some of these parts are contiguous and rectangular regions*, then you can use the matrix algebra rules associated with the Multiplication of Partitioned Matrices (1) or Block matrix multiplication (2) to speed up some of these calculations. So for example, you can use the same basic logic of @GaryBishop, but instead of having a list of 'i' and 'j' elements you have a list (or array) of four-tuples of i_start, i_end and j_start, j_end that define sub-matrices of C then you can use those indices (though rules established in those links) to figure out the the sub-matrices of A and B you need to solve for the desired blocks of C.

For a simple example, Say you only wanted the middle block of C, so we partition C into C1, C2, and C3 by row and all we care about is C2. If A^{T} is likewise partitioned into three sets of rows A1, A2, A3 then C2 = A2 * B. The idea generalizes to rectangles of any shape, it just requires different partitions of A and B to calculate. The idea is the same.

  • -This is trivially true but you'd only get time savings if the regions are larger than single elements.



回答2:


Instead of iterating on the coordinates using Python (GaryBishop's answer), you can have numpy do the looping, which constitutes a substantial speed-up (timings below):

def sparse_mult(a, b, coords) :
    rows, cols = zip(*coords)
    rows, r_idx = np.unique(rows, return_inverse=True)
    cols, c_idx = np.unique(cols, return_inverse=True)
    C = np.dot(a[rows, :], b[:, cols])
    return C[r_idx, c_idx]

>>> A = np.arange(12).reshape(3, 4)
>>> B = np.arange(15).reshape(3, 5)
>>> np.dot(A.T, B)
array([[100, 112, 124, 136, 148],
       [115, 130, 145, 160, 175],
       [130, 148, 166, 184, 202],
       [145, 166, 187, 208, 229]])
>>> sparse_mult(A.T, B, [(0, 0), (1, 2), (2, 4), (3, 3)])
array([100, 145, 202, 208])

sparse_mult returns a flattened array of the values at the coordinates you provide as a list of tuples. I am not very familiar with sparse matrix formats, so I don't know how to define CSC from the above data, but the following works:

>>> coords = [(0, 0), (1, 2), (2, 4), (3, 3)]
>>> sparse.coo_matrix((sparse_mult(A.T, B, coords), zip(*coords))).tocsc()
<4x5 sparse matrix of type '<type 'numpy.int32'>'
    with 4 stored elements in Compressed Sparse Column format>

This is a timing of various alternatives:

>>> import timeit
>>> a = np.random.rand(2000, 3000)
>>> b = np.random.rand(3000, 5000)
>>> timeit.timeit('np.dot(a,b)[[0, 0, 1999, 1999], [0, 4999, 0, 4999]]', 'from __main__ import np, a, b', number=1)
5.848562187263569
>>> timeit.timeit('sparse_mult(a, b, [(0, 0), (0, 4999), (1999, 0), (1999, 4999)])', 'from __main__ import np, a, b, sparse_mult', number=1)
0.0018596387374678613
>>> np.dot(a,b)[[0, 0, 1999, 1999], [0, 4999, 0, 4999]]
array([ 758.76351111,  750.32613815,  751.4614542 ,  758.8989648 ])
>>> sparse_mult(a, b, [(0, 0), (0, 4999), (1999, 0), (1999, 4999)])
array([ 758.76351111,  750.32613815,  751.4614542 ,  758.8989648 ])



回答3:


Ignoring the CSC business, and perhaps answering a simpler question than you are asking. Here is how I would compute a subset of the elements of C given a list of tuples of C index values.

Since you are evaluating C=A.T.dot(B) you are multiplying columns of A by columns of B. So,

for i, j in indexList:
    C[i, j] = np.dot(A[:,i], B[:,j])

I'm guessing that isn't what you're looking for but I find the simple answer sometimes helps clarify the question.



来源:https://stackoverflow.com/questions/13731405/calculate-subset-of-matrix-multiplication

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!