Skip to content

Commit

Permalink
Add older scipy version for testing
Browse files Browse the repository at this point in the history
  • Loading branch information
asistradition committed Oct 17, 2023
1 parent 794a870 commit 46d2c4d
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 101 deletions.
1 change: 1 addition & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10"]
scipy-version: ['1.0.0', '1.11.3']
os: [macos-latest, ubuntu-latest]

steps:
Expand Down
50 changes: 22 additions & 28 deletions sparse_dot_mkl/_sparse_sypr.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,16 @@
SPARSE_FILL_MODE_UPPER,
SPARSE_DIAG_NON_UNIT,
SPARSE_STAGE_FULL_MULT,
_get_numpy_layout,
_check_return_value,
LAYOUT_CODE_C,
_out_matrix,
SPARSE_OPERATION_NON_TRANSPOSE,
SPARSE_OPERATION_TRANSPOSE,

is_csr,
is_bsr
)
import ctypes as _ctypes
import numpy as np
import scipy.sparse as _spsparse
from scipy.sparse import (
isspmatrix_csr as is_csr,
isspmatrix_csc as is_csc,
isspmatrix_bsr as is_bsr,
isspmatrix as is_sparse,
)
from scipy.sparse import issparse


def _sypr_sparse_A_dense_B(
Expand Down Expand Up @@ -60,7 +53,10 @@ def _sypr_sparse_A_dense_B(
out_t=False,
)

output_layout, output_ld = _get_numpy_layout(output_arr, second_arr=matrix_b)
output_layout, output_ld = _get_numpy_layout(
output_arr,
second_arr=matrix_b
)

if transpose_a:
t_flag = SPARSE_OPERATION_TRANSPOSE
Expand Down Expand Up @@ -149,31 +145,29 @@ def _sparse_sypr(
# Check dtypes
matrix_a, matrix_b = _type_check(matrix_a, matrix_b, cast=cast)

default_output, output_type = sparse_output_type(matrix_a)

if is_csr(matrix_b):
default_output, output_type = _spsparse.csr_matrix, "csr"
elif is_bsr(matrix_b):
default_output, output_type = _spsparse.bsr_matrix, "bsr"
elif not is_sparse(matrix_b):
default_output, output_type = np.zeros, "dense"

if not (is_csr(matrix_a) or is_bsr(matrix_a)) or not (
is_csr(matrix_b) or is_bsr(matrix_b) or not is_sparse(matrix_b)
if (
not (is_csr(matrix_a) or is_bsr(matrix_a)) or
not (is_csr(matrix_b) or is_bsr(matrix_b) or not issparse(matrix_b))
):
raise ValueError(
"Input matrices to spyr must be CSR or BSR; CSC and COO is not supported"
"Input matrices to spyr must be CSR or BSR; "
"CSC and COO are not supported"
)

# Call sypr if B is sparse
if is_sparse(matrix_b):
if issparse(matrix_b):
if out is not None or out_scalar is not None or scalar is not None:
_msg = (
"out, out_scalar, and scalar have no effect if matrix B is not sparse"
warnings.warn(
"out, out_scalar, and scalar have no effect if matrix B "
"is not sparse",
RuntimeWarning
)
warnings.warn(_msg, RuntimeWarning)

return _sypr_sparse_A_sparse_B(matrix_a, matrix_b, transpose_a=transpose_a)
return _sypr_sparse_A_sparse_B(
matrix_a,
matrix_b,
transpose_a=transpose_a
)

# Call syprd if B is dense
else:
Expand Down
122 changes: 93 additions & 29 deletions sparse_dot_mkl/_sparse_vector.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
from sparse_dot_mkl._mkl_interface import (MKL, _sanity_check, _empty_output_check, _type_check, _create_mkl_sparse,
_destroy_mkl_handle, matrix_descr, _is_dense_vector, _out_matrix,
_check_return_value, _is_allowed_sparse_format, _output_dtypes, _mkl_scalar)
from sparse_dot_mkl._mkl_interface import (
MKL,
_sanity_check,
_empty_output_check,
_type_check,
_create_mkl_sparse,
_destroy_mkl_handle,
matrix_descr,
_is_dense_vector,
_out_matrix,
_check_return_value,
_is_allowed_sparse_format,
_output_dtypes,
_mkl_scalar,
)

import numpy as np
import ctypes as _ctypes

# Dict keyed by ('double_precision_bool', 'complex_bool')
_mkl_sp_mv_funcs = {(False, False): MKL._mkl_sparse_s_mv,
(True, False): MKL._mkl_sparse_d_mv,
(False, True): MKL._mkl_sparse_c_mv,
(True, True): MKL._mkl_sparse_z_mv}

def _sparse_dense_vector_mult(matrix_a, vector_b, scalar=1., transpose=False, out=None, out_scalar=None, out_t=None):
_mkl_sp_mv_funcs = {
(False, False): MKL._mkl_sparse_s_mv,
(True, False): MKL._mkl_sparse_d_mv,
(False, True): MKL._mkl_sparse_c_mv,
(True, True): MKL._mkl_sparse_z_mv,
}


def _sparse_dense_vector_mult(
matrix_a,
vector_b,
scalar=1.0,
transpose=False,
out=None,
out_scalar=None,
out_t=None,
):
"""
Multiply together a sparse matrix and a dense vector
Expand All @@ -35,7 +57,11 @@ def _sparse_dense_vector_mult(matrix_a, vector_b, scalar=1., transpose=False, ou
output_shape = (output_shape,) if vector_b.ndim == 1 else (output_shape, 1)

if _empty_output_check(matrix_a, vector_b):
final_dtype = np.float64 if matrix_a.dtype != vector_b.dtype or matrix_a.dtype != np.float32 else np.float32
final_dtype = (
np.float64
if matrix_a.dtype != vector_b.dtype or matrix_a.dtype != np.float32
else np.float32
)
return _out_matrix(output_shape, final_dtype, out_arr=out)

mkl_a, dbl, cplx = _create_mkl_sparse(matrix_a)
Expand All @@ -51,15 +77,22 @@ def _sparse_dense_vector_mult(matrix_a, vector_b, scalar=1., transpose=False, ou
scalar = _mkl_scalar(scalar, cplx, dbl)
out_scalar = _mkl_scalar(out_scalar, cplx, dbl)

output_arr = _out_matrix(output_shape, output_dtype, out_arr=out, out_t=out_t)

ret_val = func(11 if transpose else 10,
scalar,
mkl_a,
matrix_descr(),
vector_b,
out_scalar,
output_arr)
output_arr = _out_matrix(
output_shape,
output_dtype,
out_arr=out,
out_t=out_t
)

ret_val = func(
11 if transpose else 10,
scalar,
mkl_a,
matrix_descr(),
vector_b,
out_scalar,
output_arr,
)

# Check return
_check_return_value(ret_val, func.__name__)
Expand All @@ -69,7 +102,14 @@ def _sparse_dense_vector_mult(matrix_a, vector_b, scalar=1., transpose=False, ou
return output_arr


def _sparse_dot_vector(mv_a, mv_b, cast=False, scalar=1., out=None, out_scalar=None):
def _sparse_dot_vector(
mv_a,
mv_b,
cast=False,
scalar=1.0,
out=None,
out_scalar=None
):
"""
Multiply a sparse matrix by a dense vector.
The matrix must be CSR or CSC format.
Expand All @@ -82,8 +122,9 @@ def _sparse_dot_vector(mv_a, mv_b, cast=False, scalar=1., out=None, out_scalar=N
:type mv_b: np.ndarray, sp.spmatrix.csr, sp.spmatrix.csc
:param scalar: A value to multiply the result matrix by. Defaults to 1.
:type scalar: float
:param cast: Convert values to compatible floats if True. Raise an error if they are not compatible if False.
Defaults to False.
:param cast: Convert values to compatible floats if True.
Raise an error if they are not compatible if False.
Defaults to False.
:type cast: bool
:param out: Add the dot product to this array if provided.
:type out: np.ndarray, None
Expand All @@ -96,15 +137,38 @@ def _sparse_dot_vector(mv_a, mv_b, cast=False, scalar=1., out=None, out_scalar=N
_sanity_check(mv_a, mv_b, allow_vector=True)
mv_a, mv_b = _type_check(mv_a, mv_b, cast=cast)

if not _is_allowed_sparse_format(mv_a) or not _is_allowed_sparse_format(mv_b):
raise ValueError("Only CSR, CSC, and BSR-type sparse matrices are supported")
if (
not _is_allowed_sparse_format(mv_a) or
not _is_allowed_sparse_format(mv_b)
):
raise ValueError(
"Only CSR, CSC, and BSR-type sparse matrices are supported"
)
elif _is_dense_vector(mv_b):
return _sparse_dense_vector_mult(mv_a, mv_b, scalar=scalar, out=out, out_scalar=out_scalar)
return _sparse_dense_vector_mult(
mv_a,
mv_b,
scalar=scalar,
out=out,
out_scalar=out_scalar
)
elif _is_dense_vector(mv_a) and out is None:
return _sparse_dense_vector_mult(mv_b, mv_a.T, scalar=scalar, transpose=True).T
return _sparse_dense_vector_mult(
mv_b,
mv_a.T,
scalar=scalar,
transpose=True
).T
elif _is_dense_vector(mv_a) and out is not None:
_ = _sparse_dense_vector_mult(mv_b, mv_a.T, scalar=scalar, transpose=True,
out=out.T, out_scalar=out_scalar, out_t=True)
_ = _sparse_dense_vector_mult(
mv_b,
mv_a.T,
scalar=scalar,
transpose=True,
out=out.T,
out_scalar=out_scalar,
out_t=True,
)
return out
else:
raise ValueError("Neither mv_a or mv_b is a dense vector")
Loading

0 comments on commit 46d2c4d

Please sign in to comment.