Пример #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 _gram_matrix_dense_to_dense(matrix_a,
                                aat=False,
                                scalar=1.,
                                out=None,
                                out_scalar=None):
    """
    Calculate the gram matrix aTa for dense matrix and return a dense matrix

    :param matrix_a: Dense matrix
    :type matrix_a: numpy.ndarray
    :param aat: Return A (dot) AT instead of AT (dot) A
    :type aat: bool
    :param scalar: Multiply output by a scalar value
    :type scalar: float
    :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: Dense matrix
    :rtype: numpy.ndarray
    """

    # Get dimensions
    n, k = matrix_a.shape if aat else matrix_a.shape[::-1]

    # Get the memory order for arrays
    layout_a, ld_a = _get_numpy_layout(matrix_a)
    double_precision = matrix_a.dtype == np.float64

    # Set the MKL function for precision
    func = MKL._cblas_dsyrk if double_precision else MKL._cblas_ssyrk
    output_ctype = _ctypes.c_double if double_precision else _ctypes.c_float

    # Allocate an array for outputs and set functions and types for float or doubles
    output_arr = _out_matrix((n, n),
                             matrix_a.dtype,
                             order="C" if layout_a == LAYOUT_CODE_C else "F",
                             out_arr=out)

    func(layout_a, 121, 111 if aat else 112, n, k, scalar, matrix_a, ld_a,
         float(out_scalar) if out_scalar is not None else 1.,
         output_arr.ctypes.data_as(_ctypes.POINTER(output_ctype)), n)

    return output_arr
Пример #3
0
def _dense_matmul(matrix_a,
                  matrix_b,
                  double_precision,
                  scalar=1.,
                  out=None,
                  out_scalar=None):

    # Reshape matrix_b to a column instead of a vector if it's 1d
    flatten_output = matrix_b.ndim == 1
    matrix_b = matrix_b.reshape(-1, 1) if flatten_output else matrix_b

    # Get dimensions
    m, n, k = matrix_a.shape[0], matrix_b.shape[1], matrix_a.shape[1]
    output_shape = (m, n)

    # Set the MKL function for precision
    func = MKL._cblas_dgemm if double_precision else MKL._cblas_sgemm

    # Get the memory order for arrays
    layout_a, ld_a = _get_numpy_layout(matrix_a)
    layout_b, ld_b = _get_numpy_layout(matrix_b)

    # If they aren't the same, use the order for matrix a and have matrix b transposed
    op_b = 112 if layout_b != layout_a else 111

    # Set output array; use the memory order from matrix_a
    out_order, ld_out = ("C",
                         output_shape[1]) if layout_a == LAYOUT_CODE_C else (
                             "F", output_shape[0])

    # Allocate an array for outputs and set functions and types for float or doubles
    output_arr = _out_matrix(output_shape,
                             np.float64 if double_precision else np.float32,
                             order=out_order,
                             out_arr=out)
    output_ctype = _ctypes.c_double if double_precision else _ctypes.c_float

    func(layout_a, 111, op_b, m, n, k, scalar, matrix_a, ld_a, matrix_b, ld_b,
         float(out_scalar) if out_scalar is not None else 1.,
         output_arr.ctypes.data_as(_ctypes.POINTER(output_ctype)), ld_out)

    return output_arr.ravel() if flatten_output else output_arr
Пример #4
0
def _sparse_dense_matmul(matrix_a,
                         matrix_b,
                         scalar=1.,
                         transpose=False,
                         out=None,
                         out_scalar=None,
                         out_t=None):
    """
    Multiply together a sparse and a dense matrix
    mkl_sparse_?_mm requires the left (A) matrix to be sparse and the right (B) matrix to be dense
    This requires conversion of the sparse matrix to CSR format for some dense arrays.
    A must be CSR if B is column-major. Otherwise CSR or CSC are acceptable.

    :param matrix_a: Left (A) matrix
    :type matrix_a: sp.spmatrix.csr, sp.spmatrix.csc
    :param matrix_b: Right (B) matrix
    :type matrix_b: np.ndarray
    :param scalar: A value to multiply the result matrix by. Defaults to 1.
    :type scalar: float
    :param transpose: Return AT (dot) B instead of A (dot) B.
    :type transpose: 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: A (dot) B as a dense array in either column-major or row-major format
    :rtype: np.ndarray
    """

    output_shape = (matrix_a.shape[1] if transpose else matrix_a.shape[0],
                    matrix_b.shape[1])
    layout_b, ld_b = _get_numpy_layout(matrix_b, second_arr=out)

    # Prep MKL handles and check that matrixes are compatible types
    # MKL requires CSR format if the dense array is column-major
    if layout_b == LAYOUT_CODE_F and not _spsparse.isspmatrix_csr(matrix_a):
        mkl_non_csr, dbl = _create_mkl_sparse(matrix_a)
        mkl_a = _convert_to_csr(mkl_non_csr)
    else:
        mkl_a, dbl = _create_mkl_sparse(matrix_a)

    # Set functions and types for float or doubles
    output_ctype = _ctypes.c_double if dbl else _ctypes.c_float
    output_dtype = np.float64 if dbl else np.float32
    func = MKL._mkl_sparse_d_mm if dbl else MKL._mkl_sparse_s_mm

    # Allocate an output array
    output_arr = _out_matrix(output_shape,
                             output_dtype,
                             order="C" if layout_b == LAYOUT_CODE_C else "F",
                             out_arr=out,
                             out_t=out_t)

    _, output_ld = _get_numpy_layout(output_arr)

    ret_val = func(11 if transpose else 10, scalar, mkl_a, matrix_descr(),
                   layout_b, matrix_b, output_shape[1], ld_b,
                   float(out_scalar) if out_scalar is not None else 1.,
                   output_arr.ctypes.data_as(_ctypes.POINTER(output_ctype)),
                   output_ld)

    # Check return
    if ret_val != 0:
        err_msg = "{fn} returned {v} ({e})".format(fn=func.__name__,
                                                   v=ret_val,
                                                   e=RETURN_CODES[ret_val])
        raise ValueError(err_msg)

    _destroy_mkl_handle(mkl_a)

    return output_arr
Пример #5
0
def _sparse_dot_dense(matrix_a,
                      matrix_b,
                      cast=False,
                      dprint=print,
                      scalar=1.,
                      out=None,
                      out_scalar=None):
    """
    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
    :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(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 _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)

    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,
                                    out=out,
                                    out_scalar=out_scalar)
    elif _spsparse.isspmatrix(matrix_b) and out is not None:
        _ = _sparse_dense_matmul(matrix_b,
                                 matrix_a.T,
                                 scalar=scalar,
                                 transpose=True,
                                 out=out.T,
                                 out_scalar=out_scalar,
                                 out_t=True)
        return out
    elif _spsparse.isspmatrix(matrix_b) and out is None:
        return _sparse_dense_matmul(matrix_b,
                                    matrix_a.T,
                                    scalar=scalar,
                                    transpose=True).T
Пример #6
0
def _sparse_dense_vector_mult(matrix_a,
                              vector_b,
                              scalar=1.,
                              transpose=False,
                              out=None,
                              out_scalar=None,
                              out_t=None):
    """
    Multiply together a sparse matrix and a dense vector

    :param matrix_a: Left (A) matrix
    :type matrix_a: sp.spmatrix.csr, sp.spmatrix.csc
    :param vector_b: Right (B) vector with shape (N, ) or (N, 1)
    :type vector_b: np.ndarray
    :param scalar: A value to multiply the result matrix by. Defaults to 1.
    :type scalar: float
    :param transpose: Return AT (dot) B instead of A (dot) B.
    :type transpose: 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: A (dot) B as a dense array
    :rtype: np.ndarray
    """

    output_shape = matrix_a.shape[1] if transpose else matrix_a.shape[0]
    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
        return _out_matrix(output_shape, final_dtype, out_arr=out)

    mkl_a, dbl = _create_mkl_sparse(matrix_a)
    vector_b = vector_b.ravel()

    # Set functions and types for float or doubles
    output_ctype = _ctypes.c_double if dbl else _ctypes.c_float
    output_dtype = np.float64 if dbl else np.float32
    func = MKL._mkl_sparse_d_mv if dbl else MKL._mkl_sparse_s_mv

    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,
                   float(out_scalar) if out_scalar is not None else 1.,
                   output_arr.ctypes.data_as(_ctypes.POINTER(output_ctype)))

    # Check return
    if ret_val != 0:
        err_msg = "{fn} returned {v} ({e})".format(fn=func.__name__,
                                                   v=ret_val,
                                                   e=RETURN_CODES[ret_val])
        raise ValueError(err_msg)

    _destroy_mkl_handle(mkl_a)

    return output_arr
Пример #7
0
def _gram_matrix_sparse_to_dense(matrix_a,
                                 aat=False,
                                 scalar=1.,
                                 out=None,
                                 out_scalar=None):
    """
    Calculate the gram matrix aTa for sparse matrix and return a dense matrix

    :param matrix_a: Sparse matrix
    :type matrix_a: scipy.sparse.csr_matrix, scipy.sparse.csc_matrix
    :param aat: Return A (dot) AT instead of AT (dot) A
    :type aat: bool
    :param scalar: Multiply output by a scalar value
    :type scalar: float
    :return: Dense matrix
    :rtype: numpy.ndarray
    """

    sp_ref_a, double_prec = _create_mkl_sparse(matrix_a)

    if _sps.isspmatrix_csc(matrix_a):
        sp_ref_a = _convert_to_csr(sp_ref_a, destroy_original=True)

    _order_mkl_handle(sp_ref_a)

    out_dtype = np.float64 if double_prec else np.float32
    output_ctype = _ctypes.c_double if double_prec else _ctypes.c_float
    out_dim = matrix_a.shape[0] if aat else matrix_a.shape[1]

    output_arr = _out_matrix((out_dim, out_dim),
                             out_dtype,
                             order="C",
                             out_arr=out)
    _, output_ld = _get_numpy_layout(output_arr)

    if _empty_output_check(matrix_a, matrix_a):
        return output_arr

    func = MKL._mkl_sparse_d_syrkd if double_prec else MKL._mkl_sparse_s_syrkd

    ret_val = func(10 if aat else 11, sp_ref_a, scalar,
                   float(out_scalar) if out_scalar is not None else 1.,
                   output_arr.ctypes.data_as(_ctypes.POINTER(output_ctype)),
                   LAYOUT_CODE_C, output_ld)

    # Check return
    if ret_val != 0:
        _err_msg = "{fn} returned {v} ({e})".format(fn=func.__name__,
                                                    v=ret_val,
                                                    e=RETURN_CODES[ret_val])
        raise ValueError(_err_msg)

    _destroy_mkl_handle(sp_ref_a)

    # This fixes a specific bug in mkl_sparse_d_syrkd which returns a full matrix
    # This stupid thing only happens with specific flags
    # I could probably leave it but it's pretty annoying
    if not aat and out is None:
        output_arr[np.tril_indices(output_arr.shape[0], k=-1)] = 0.

    return output_arr