|
""" Functions that operate on sparse matrices |
|
""" |
|
|
|
__all__ = ['count_blocks','estimate_blocksize'] |
|
|
|
from ._base import issparse |
|
from ._csr import csr_array |
|
from ._sparsetools import csr_count_blocks |
|
|
|
|
|
def estimate_blocksize(A,efficiency=0.7): |
|
"""Attempt to determine the blocksize of a sparse matrix |
|
|
|
Returns a blocksize=(r,c) such that |
|
- A.nnz / A.tobsr( (r,c) ).nnz > efficiency |
|
""" |
|
if not (issparse(A) and A.format in ("csc", "csr")): |
|
A = csr_array(A) |
|
|
|
if A.nnz == 0: |
|
return (1,1) |
|
|
|
if not 0 < efficiency < 1.0: |
|
raise ValueError('efficiency must satisfy 0.0 < efficiency < 1.0') |
|
|
|
high_efficiency = (1.0 + efficiency) / 2.0 |
|
nnz = float(A.nnz) |
|
M,N = A.shape |
|
|
|
if M % 2 == 0 and N % 2 == 0: |
|
e22 = nnz / (4 * count_blocks(A,(2,2))) |
|
else: |
|
e22 = 0.0 |
|
|
|
if M % 3 == 0 and N % 3 == 0: |
|
e33 = nnz / (9 * count_blocks(A,(3,3))) |
|
else: |
|
e33 = 0.0 |
|
|
|
if e22 > high_efficiency and e33 > high_efficiency: |
|
e66 = nnz / (36 * count_blocks(A,(6,6))) |
|
if e66 > efficiency: |
|
return (6,6) |
|
else: |
|
return (3,3) |
|
else: |
|
if M % 4 == 0 and N % 4 == 0: |
|
e44 = nnz / (16 * count_blocks(A,(4,4))) |
|
else: |
|
e44 = 0.0 |
|
|
|
if e44 > efficiency: |
|
return (4,4) |
|
elif e33 > efficiency: |
|
return (3,3) |
|
elif e22 > efficiency: |
|
return (2,2) |
|
else: |
|
return (1,1) |
|
|
|
|
|
def count_blocks(A,blocksize): |
|
"""For a given blocksize=(r,c) count the number of occupied |
|
blocks in a sparse matrix A |
|
""" |
|
r,c = blocksize |
|
if r < 1 or c < 1: |
|
raise ValueError('r and c must be positive') |
|
|
|
if issparse(A): |
|
if A.format == "csr": |
|
M,N = A.shape |
|
return csr_count_blocks(M,N,r,c,A.indptr,A.indices) |
|
elif A.format == "csc": |
|
return count_blocks(A.T,(c,r)) |
|
return count_blocks(csr_array(A),blocksize) |
|
|