예제 #1
0
def _dense_dot_dense(matrix_a,
                     matrix_b,
                     cast=False,
                     dprint=print,
                     scalar=1.,
                     out=None,
                     out_scalar=None):

    _sanity_check(matrix_a, matrix_b, allow_vector=True)

    # Check for edge condition inputs which result in empty outputs
    if _empty_output_check(matrix_a, matrix_b):
        dprint(
            "Skipping multiplication because A (dot) B must yield an empty matrix"
        )
        final_dtype = np.float64 if matrix_a.dtype != matrix_b.dtype or matrix_a.dtype != np.float32 else np.float32
        return _out_matrix((matrix_a.shape[0], matrix_b.shape[1]),
                           final_dtype,
                           out_arr=out)

    matrix_a, matrix_b = _type_check(matrix_a,
                                     matrix_b,
                                     cast=cast,
                                     dprint=dprint)

    a_dbl, b_dbl = matrix_a.dtype == np.float64, matrix_b.dtype == np.float64

    return _dense_matmul(matrix_a,
                         matrix_b,
                         a_dbl or b_dbl,
                         scalar=scalar,
                         out=out,
                         out_scalar=out_scalar)
예제 #2
0
def _sparse_dot_vector(mv_a, mv_b, cast=False, dprint=print, scalar=1.):
    """
    Multiply a sparse matrix by a dense vector.
    The matrix must be CSR or CSC format.
    The vector must be (N,) or (N, 1) shape.
    Returns a dense vector of (N,) or (N, 1) shape (depending on vector)

    :param mv_a: Left (A) matrix or vector
    :type mv_a: np.ndarray, sp.spmatrix.csr, sp.spmatrix.csc
    :param mv_b: Right (B) matrix or vector
    :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.
    :type cast: bool
    :param dprint: A function that will handle debug strings. Defaults to print.
    :type dprint: function

    :return: A (dot) B as a dense matrix
    :rtype: np.ndarray
    """

    _sanity_check(mv_a, mv_b, allow_vector=True)
    mv_a, mv_b = _type_check(mv_a, mv_b, cast=cast, dprint=dprint)

    if _is_dense_vector(mv_b):
        return _sparse_dense_vector_mult(mv_a, mv_b, scalar=scalar)
    elif _is_dense_vector(mv_a):
        return _sparse_dense_vector_mult(mv_b, mv_a.T, scalar=scalar, transpose=True).T
예제 #3
0
def sparse_qr_solver(matrix_a, matrix_b, cast=False, dprint=print):
    """

    :param matrix_a:
    :param matrix_b:
    :param cast:
    :param dprint:
    :return:
    """

    if _spsparse.isspmatrix_csc(matrix_a) and not cast:
        raise ValueError(
            "sparse_qr_solver only accepts CSR matrices if cast=False")
    elif not _spsparse.isspmatrix_csr(
            matrix_a) and not _spsparse.isspmatrix_csc(matrix_a):
        raise ValueError(
            "sparse_qr_solver requires matrix A to be CSR or CSC sparse matrix"
        )
    elif matrix_a.shape[0] != matrix_b.shape[0]:
        err_msg = "Bad matrix shapes for AX=B solver: A {sha} & B {shb}".format(
            sha=matrix_a.shape, shb=matrix_b.shape)
        raise ValueError(err_msg)
    else:
        matrix_a, matrix_b = _type_check(matrix_a,
                                         matrix_b,
                                         cast=cast,
                                         dprint=dprint)
        x_arr = _sparse_qr(
            matrix_a,
            matrix_b if matrix_b.ndim == 2 else matrix_b.reshape(-1, 1))
        return x_arr if matrix_b.ndim == 2 else x_arr.ravel()
예제 #4
0
def _sparse_dot_vector(mv_a,
                       mv_b,
                       cast=False,
                       dprint=print,
                       scalar=1.,
                       out=None,
                       out_scalar=None):
    """
    Multiply a sparse matrix by a dense vector.
    The matrix must be CSR or CSC format.
    The vector must be (N,) or (N, 1) shape.
    Returns a dense vector of (N,) or (N, 1) shape (depending on vector)

    :param mv_a: Left (A) matrix or vector
    :type mv_a: np.ndarray, sp.spmatrix.csr, sp.spmatrix.csc
    :param mv_b: Right (B) matrix or vector
    :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.
    :type cast: bool
    :param dprint: A function that will handle debug strings. Defaults to print.
    :type dprint: function
    :param out: Add the dot product to this array if provided.
    :type out: np.ndarray, None
    :param out_scalar: Multiply the out array by this scalar if provided.
    :type out_scalar: float, None
    :return: A (dot) B as a dense matrix
    :rtype: np.ndarray
    """

    _sanity_check(mv_a, mv_b, allow_vector=True)
    mv_a, mv_b = _type_check(mv_a, mv_b, cast=cast, dprint=dprint)

    if _is_dense_vector(mv_b):
        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
    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)
        return out
    else:
        raise ValueError("Neither mv_a or mv_b is a dense vector")
예제 #5
0
def _sparse_dot_dense(matrix_a, matrix_b, cast=False, dprint=print, scalar=1.):
    """
    Multiply together a dense and a sparse matrix.
    If the sparse matrix is not CSR, it may need to be reordered, depending on the order of the dense array.

    :param matrix_a: Left (A) matrix
    :type matrix_a: np.ndarray, sp.spmatrix.csr, sp.spmatrix.csc
    :param matrix_b: Right (B) matrix
    :type matrix_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.
    :type cast: bool
    :param dprint: A function that will handle debug strings. Defaults to print.
    :type dprint: function

    :return: A (dot) B as a dense matrix
    :rtype: np.ndarray
    """
    _sanity_check(matrix_a, matrix_b)

    # Check for edge condition inputs which result in empty outputs
    if _empty_output_check(matrix_a, matrix_b):
        dprint(
            "Skipping multiplication because A (dot) B must yield an empty matrix"
        )
        final_dtype = np.float64 if matrix_a.dtype != matrix_b.dtype or matrix_a.dtype != np.float32 else np.float32
        return np.zeros((matrix_a.shape[0], matrix_b.shape[1]),
                        dtype=final_dtype)

    matrix_a, matrix_b = _type_check(matrix_a,
                                     matrix_b,
                                     cast=cast,
                                     dprint=dprint)

    if sum([_spsparse.isspmatrix(matrix_a),
            _spsparse.isspmatrix(matrix_b)]) != 1:
        raise ValueError(
            "_sparse_dot_dense takes one sparse and one dense array")
    elif _spsparse.isspmatrix(matrix_a):
        return _sparse_dense_matmul(matrix_a, matrix_b, scalar=scalar)
    elif _spsparse.isspmatrix(matrix_b):
        return _dense_sparse_matmul(matrix_a, matrix_b, scalar=scalar)
예제 #6
0
def _sparse_dot_sparse(matrix_a,
                       matrix_b,
                       cast=False,
                       reorder_output=False,
                       dense=False,
                       dprint=print):
    """
    Multiply together two scipy sparse matrixes using the intel Math Kernel Library.
    This currently only supports float32 and float64 data

    :param matrix_a: Sparse matrix A in CSC/CSR format
    :type matrix_a: scipy.sparse.spmatrix
    :param matrix_b: Sparse matrix B in CSC/CSR format
    :type matrix_b: scipy.sparse.spmatrix
    :param cast: Should the data be coerced into float64 if it isn't float32 or float64
    If set to True and any other dtype is passed, the matrix data will be modified in-place
    If set to False and any dtype that isn't float32 or float64 is passed, a ValueError will be raised
    Defaults to False
    :param reorder_output: Should the array indices be reordered using MKL
    If set to True, the object in C will be ordered and then exported into python
    If set to False, the array column indices will not be ordered.
    The scipy sparse dot product does not yield ordered column indices so this defaults to False
    :type reorder_output: bool
    :param dense: Should the matrix multiplication yield a dense numpy array
    This does not require any copy and is memory efficient if the output array density is > 50%
    :type dense: bool
    :param dprint: Should debug and timing messages be printed. Defaults to false.
    :type dprint: function
    :return: Sparse matrix that is the result of A * B in CSR format
    :rtype: scipy.sparse.csr_matrix
    """

    # Check for allowed sparse matrix types

    if is_csr(matrix_a) and (is_csc(matrix_b) or is_csr(matrix_b)):
        default_output = _spsparse.csr_matrix
        output_type = "csr"
    elif is_csc(matrix_a) and (is_csc(matrix_b) or is_csr(matrix_b)):
        default_output = _spsparse.csc_matrix
        output_type = "csc"
    else:
        raise ValueError(
            "Both input matrices to dot_product_mkl must be CSR or CSC; COO and BSR are not supported"
        )

    # Override output if dense flag is set
    default_output = default_output if not dense else np.zeros

    # Check to make sure that this multiplication can work and check dtypes
    _sanity_check(matrix_a, matrix_b)

    # Check for edge condition inputs which result in empty outputs
    if _empty_output_check(matrix_a, matrix_b):
        dprint(
            "Skipping multiplication because A (dot) B must yield an empty matrix"
        )
        final_dtype = np.float64 if matrix_a.dtype != matrix_b.dtype or matrix_a.dtype != np.float32 else np.float32
        return default_output((matrix_a.shape[0], matrix_b.shape[1]),
                              dtype=final_dtype)

    # Check dtypes
    matrix_a, matrix_b = _type_check(matrix_a,
                                     matrix_b,
                                     cast=cast,
                                     dprint=dprint)

    t0 = time.time()

    # Create intel MKL objects
    mkl_a, a_dbl = _create_mkl_sparse(matrix_a)
    mkl_b, b_dbl = _create_mkl_sparse(matrix_b)

    t1 = time.time()
    dprint("Created MKL sparse handles: {0:.6f} seconds".format(t1 - t0))

    # Call spmmd for dense output directly if the dense flag is set
    if dense:
        dense_arr = _matmul_mkl_dense(mkl_a, mkl_b,
                                      (matrix_a.shape[0], matrix_b.shape[1]),
                                      a_dbl or b_dbl)

        t2 = time.time()
        dprint("Multiplied matrices: {0:.6f} seconds".format(t2 - t1))

        _destroy_mkl_handle(mkl_a)
        _destroy_mkl_handle(mkl_b)

        return dense_arr

    # Call spmm for sparse output if the dense flag is not set and then export the sparse matrix to python
    else:
        # Dot product
        mkl_c = _matmul_mkl(mkl_a, mkl_b)

        _destroy_mkl_handle(mkl_a)
        _destroy_mkl_handle(mkl_b)

        t2 = time.time()
        dprint("Multiplied matrices: {0:.6f} seconds".format(t2 - t1))

        # Reorder
        if reorder_output:
            _order_mkl_handle(mkl_c)

            dprint("Reordered indicies: {0:.6f} seconds".format(time.time() -
                                                                t2))
            t2 = time.time()

        # Extract
        python_c = _export_mkl(mkl_c, a_dbl or b_dbl, output_type=output_type)
        _destroy_mkl_handle(mkl_c)

        dprint("Created python handle: {0:.6f} seconds".format(time.time() -
                                                               t2))

        return python_c
예제 #7
0
def _gram_matrix(matrix,
                 transpose=False,
                 cast=False,
                 dense=False,
                 reorder_output=False,
                 dprint=print,
                 out=None,
                 out_scalar=None):
    """
    Calculate a gram matrix (AT (dot) A) from a sparse matrix.

    :param matrix: Sparse matrix (CSR format is required but will convert if cast is True)
    :type matrix: scipy.sparse.csr_matrix
    :param transpose: Calculate A (dot) AT instead
    :type transpose: bool
    :param cast: Make internal copies to convert matrix to a float matrix or convert to a CSR matrix if necessary
    :type cast: bool
    :param dense: Produce a dense matrix output instead of a sparse matrix
    :type dense: bool
    :param out: Add the dot product to this array if provided.
    :type out: np.ndarray, None
    :param out_scalar: Multiply the out array by this scalar if provided.
    :type out_scalar: float, None
    :return: Gram matrix
    :rtype: scipy.sparse.csr_matrix, np.ndarray
    """

    # Check for edge condition inputs which result in empty outputs
    if _empty_output_check(matrix, matrix):
        dprint(
            "Skipping multiplication because AT (dot) A must yield an empty matrix"
        )
        output_shape = (matrix.shape[1],
                        matrix.shape[1]) if transpose else (matrix.shape[0],
                                                            matrix.shape[0])
        output_func = _sps.csr_matrix if _sps.isspmatrix(matrix) else np.zeros
        return output_func(output_shape, dtype=matrix.dtype)

    matrix = _type_check(matrix, cast=cast, dprint=dprint)

    if _sps.isspmatrix(matrix) and not (_sps.isspmatrix_csr(matrix)
                                        or _sps.isspmatrix_csc(matrix)):
        raise ValueError(
            "gram_matrix requires sparse matrix to be CSR or CSC format")
    if _sps.isspmatrix_csc(matrix) and not cast:
        raise ValueError(
            "gram_matrix cannot use a CSC matrix unless cast=True")
    elif not _sps.isspmatrix(matrix):
        return _gram_matrix_dense_to_dense(matrix,
                                           aat=transpose,
                                           out=out,
                                           out_scalar=out_scalar)
    elif dense:
        return _gram_matrix_sparse_to_dense(matrix,
                                            aat=transpose,
                                            out=out,
                                            out_scalar=out_scalar)
    elif out is not None:
        raise ValueError(
            "out argument cannot be used with sparse (dot) sparse matrix multiplication"
        )
    else:
        return _gram_matrix_sparse(matrix,
                                   aat=transpose,
                                   reorder_output=reorder_output)