diff --git a/src/deprecated.jl b/src/deprecated.jl index 9f64c45..56ac25c 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -9,56 +9,56 @@ matdescra(A::SparseMatrixCSC) = "GFNF" matdescra(A::Transpose) = matdescra(A.parent) matdescra(A::Adjoint) = matdescra(A.parent) -function cscmv!(transa::Char, α::T, matdescra::String, +function cscmv!(transA::Char, α::T, matdescrA::String, A::AbstractSparseMatrix{T}, x::StridedVector{T}, β::T, y::StridedVector{T}) where {T <: BlasFloat} - check_transa(transa) - check_mat_op_sizes(y, A, transa, x, 'N') + check_trans(transA) + check_mat_op_sizes(y, A, transA, x, 'N') mkl_call(Val{:mkl_TSmvI}(), typeof(A), - transa, A.m, A.n, α, matdescra, + transA, A.m, A.n, α, matdescrA, A.nzval, A.rowval, A.colptr, pointer(A.colptr, 2), x, β, y) return y end -function cscmm!(transa::Char, α::T, matdescra::String, +function cscmm!(transA::Char, α::T, matdescrA::String, A::SparseMatrixCSC{T}, B::StridedMatrix{T}, β::T, C::StridedMatrix{T}) where {T <: BlasFloat} - check_transa(transa) - check_mat_op_sizes(C, A, transa, B, 'N') + check_trans(transA) + check_mat_op_sizes(C, A, transA, B, 'N') mB, nB = size(B) mC, nC = size(C) mkl_call(Val{:mkl_TSmmI}(), typeof(A), - transa, A.m, nC, A.n, α, matdescra, + transA, A.m, nC, A.n, α, matdescrA, A.nzval, A.rowval, A.colptr, pointer(A.colptr, 2), B, mB, β, C, mC) return C end -function cscsv!(transa::Char, α::T, matdescra::String, +function cscsv!(transA::Char, α::T, matdescrA::String, A::SparseMatrixCSC{T}, x::StridedVector{T}, y::StridedVector{T}) where {T <: BlasFloat} n = checksquare(A) - check_transa(transa) - check_mat_op_sizes(y, A, transa, x, 'N') + check_trans(transA) + check_mat_op_sizes(y, A, transA, x, 'N') mkl_call(Val{:mkl_TSsvI}(), typeof(A), - transa, A.m, α, matdescra, + transA, A.m, α, matdescrA, A.nzval, A.rowval, A.colptr, pointer(A.colptr, 2), x, y) return y end -function cscsm!(transa::Char, α::T, matdescra::String, +function cscsm!(transA::Char, α::T, matdescrA::String, A::SparseMatrixCSC{T}, B::StridedMatrix{T}, C::StridedMatrix{T}) where {T <: BlasFloat} mB, nB = size(B) mC, nC = size(C) n = checksquare(A) - check_transa(transa) - check_mat_op_sizes(C, A, transa, B, 'N') + check_trans(transA) + check_mat_op_sizes(C, A, transA, B, 'N') mkl_call(Val{:mkl_TSsmI}(), typeof(A), - transa, A.n, nC, α, matdescra, + transA, A.n, nC, α, matdescrA, A.nzval, A.rowval, A.colptr, pointer(A.colptr, 2), B, mB, C, mC) return C end diff --git a/src/generic.jl b/src/generic.jl index 9eeea9b..0b55408 100644 --- a/src/generic.jl +++ b/src/generic.jl @@ -1,3 +1,9 @@ +# Intermediate wrappers for the Sparse BLAS routines +# that check the parameters validity (including matrix dimensions checks) +# and convert Julia's matrix types to the MKL's matrix types. +# See https://www.intel.com/content/www/us/en/docs/onemkl/developer-reference-c/2024-2/inspector-executor-sparse-blas-execution-routines.html +# for the detailed description of the wrapped functions. + # generates the reference to the MKL function from the template @inline @generated function mkl_function( ::Val{F}, ::Type{S} @@ -18,56 +24,68 @@ end return body end -function mv!(transa::Char, alpha::T, A::AbstractSparseMatrix{T}, descr::matrix_descr, +# y := alpha * op(A) * x + beta * y +function mv!(transA::Char, alpha::T, A::AbstractSparseMatrix{T}, descr::matrix_descr, x::StridedVector{T}, beta::T, y::StridedVector{T} ) where T - check_transa(transa) - check_mat_op_sizes(y, A, transa, x, 'N') + check_trans(transA) + check_mat_op_sizes(y, A, transA, x, 'N') + hA = MKLSparseMatrix(A) res = mkl_call(Val{:mkl_sparse_T_mvI}(), typeof(A), - transa, alpha, MKLSparseMatrix(A), descr, x, beta, y) + transA, alpha, hA, descr, x, beta, y) + destroy(hA) check_status(res) return y end -function mm!(transa::Char, alpha::T, A::AbstractSparseMatrix{T}, descr::matrix_descr, - x::StridedMatrix{T}, beta::T, y::StridedMatrix{T}; +# C := alpha * op(A) * B + beta * C +function mm!(transA::Char, alpha::T, A::AbstractSparseMatrix{T}, descr::matrix_descr, + B::StridedMatrix{T}, beta::T, C::StridedMatrix{T}; dense_layout::sparse_layout_t = SPARSE_LAYOUT_COLUMN_MAJOR ) where T - check_transa(transa) - check_mat_op_sizes(y, A, transa, x, 'N'; dense_layout) - columns = size(y, dense_layout == SPARSE_LAYOUT_COLUMN_MAJOR ? 2 : 1) - ldx = stride(x, 2) - ldy = stride(y, 2) + check_trans(transA) + check_mat_op_sizes(C, A, transA, B, 'N'; dense_layout) + columns = size(C, dense_layout == SPARSE_LAYOUT_COLUMN_MAJOR ? 2 : 1) + ldB = stride(B, 2) + ldC = stride(C, 2) + hA = MKLSparseMatrix(A) res = mkl_call(Val{:mkl_sparse_T_mmI}(), typeof(A), - transa, alpha, MKLSparseMatrix(A), descr, dense_layout, x, columns, ldx, beta, y, ldy) + transA, alpha, hA, descr, dense_layout, B, columns, ldB, beta, C, ldC) + destroy(hA) check_status(res) - return y + return C end -function trsv!(transa::Char, alpha::T, A::AbstractSparseMatrix{T}, descr::matrix_descr, +# find y: op(A) * y = alpha * x +function trsv!(transA::Char, alpha::T, A::AbstractSparseMatrix{T}, descr::matrix_descr, x::StridedVector{T}, y::StridedVector{T} ) where T checksquare(A) - check_transa(transa) - check_mat_op_sizes(y, A, transa, x, 'N') + check_trans(transA) + check_mat_op_sizes(y, A, transA, x, 'N') + hA = MKLSparseMatrix(A) res = mkl_call(Val{:mkl_sparse_T_trsvI}(), typeof(A), - transa, alpha, MKLSparseMatrix(A), descr, x, y) + transA, alpha, hA, descr, x, y) + destroy(hA) check_status(res) return y end -function trsm!(transa::Char, alpha::T, A::AbstractSparseMatrix{T}, descr::matrix_descr, - x::StridedMatrix{T}, y::StridedMatrix{T}; +# Y := alpha * inv(op(A)) * X +function trsm!(transA::Char, alpha::T, A::AbstractSparseMatrix{T}, descr::matrix_descr, + X::StridedMatrix{T}, Y::StridedMatrix{T}; dense_layout::sparse_layout_t = SPARSE_LAYOUT_COLUMN_MAJOR ) where T checksquare(A) - check_transa(transa) - check_mat_op_sizes(y, A, transa, x, 'N'; dense_layout) - columns = size(y, dense_layout == SPARSE_LAYOUT_COLUMN_MAJOR ? 2 : 1) - ldx = stride(x, 2) - ldy = stride(y, 2) + check_trans(transA) + check_mat_op_sizes(Y, A, transA, X, 'N'; dense_layout) + columns = size(Y, dense_layout == SPARSE_LAYOUT_COLUMN_MAJOR ? 2 : 1) + ldX = stride(X, 2) + ldY = stride(Y, 2) + hA = MKLSparseMatrix(A) res = mkl_call(Val{:mkl_sparse_T_trsmI}(), typeof(A), - transa, alpha, MKLSparseMatrix(A), descr, dense_layout, x, columns, ldx, y, ldy) + transA, alpha, hA, descr, dense_layout, X, columns, ldX, Y, ldY) + destroy(hA) check_status(res) - return y + return Y end diff --git a/src/interface.jl b/src/interface.jl index fb9daf4..b11f16e 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -12,26 +12,27 @@ SimpleOrSpecialMat{T, M} = Union{M, SpecialMat{T, <:M}} SimpleOrSpecialOrAdjMat{T, M} = Union{SimpleOrAdjMat{T, <:SimpleOrSpecialMat{T, <:M}}, SimpleOrSpecialMat{T, <:SimpleOrAdjMat{T, <:M}}} -unwrapa(A::AbstractMatrix) = A -unwrapa(A::Union{Adjoint, Transpose}) = unwrapa(parent(A)) -unwrapa(A::SpecialMat) = unwrapa(parent(A)) - -# returns a tuple of transa, matdescra and unwrapped A -describe_and_unwrap(A::AbstractMatrix) = ('N', matrix_descr(A), unwrapa(A)) -describe_and_unwrap(A::Adjoint) = ('C', matrix_descr(A), unwrapa(parent(A))) -describe_and_unwrap(A::Transpose) = ('T', matrix_descr(A), unwrapa(parent(A))) +# unwraps matrix A from Adjoint/Transpose transform +unwrap_trans(A::AbstractMatrix) = A +unwrap_trans(A::Union{Adjoint, Transpose}) = unwrap_trans(parent(A)) +unwrap_trans(A::SpecialMat) = unwrap_trans(parent(A)) + +# returns a tuple of trans, matrix_descr and unwrapped A +describe_and_unwrap(A::AbstractMatrix) = ('N', matrix_descr(A), unwrap_trans(A)) +describe_and_unwrap(A::Adjoint) = ('C', matrix_descr(A), unwrap_trans(parent(A))) +describe_and_unwrap(A::Transpose) = ('T', matrix_descr(A), unwrap_trans(parent(A))) describe_and_unwrap(A::LowerTriangular{<:Any, T}) where T <: Union{Adjoint, Transpose} = - (T <: Adjoint ? 'C' : 'T', matrix_descr('T', 'U', 'N'), unwrapa(A)) + (T <: Adjoint ? 'C' : 'T', matrix_descr('T', 'U', 'N'), unwrap_trans(A)) describe_and_unwrap(A::UpperTriangular{<:Any, T}) where T <: Union{Adjoint, Transpose} = - (T <: Adjoint ? 'C' : 'T', matrix_descr('T', 'L', 'N'), unwrapa(A)) + (T <: Adjoint ? 'C' : 'T', matrix_descr('T', 'L', 'N'), unwrap_trans(A)) describe_and_unwrap(A::UnitLowerTriangular{<:Any, T}) where T <: Union{Adjoint, Transpose} = - (T <: Adjoint ? 'C' : 'T', matrix_descr('T', 'U', 'U'), unwrapa(A)) + (T <: Adjoint ? 'C' : 'T', matrix_descr('T', 'U', 'U'), unwrap_trans(A)) describe_and_unwrap(A::UnitUpperTriangular{<:Any, T}) where T <: Union{Adjoint, Transpose} = - (T <: Adjoint ? 'C' : 'T', matrix_descr('T', 'L', 'U'), unwrapa(A)) + (T <: Adjoint ? 'C' : 'T', matrix_descr('T', 'L', 'U'), unwrap_trans(A)) describe_and_unwrap(A::Symmetric{<:Any, T}) where T <: Union{Adjoint, Transpose} = - (T <: Transpose || (eltype(A) <: Real) ? 'N' : 'C', matrix_descr('S', A.uplo, 'N'), unwrapa(A)) + (T <: Transpose || (eltype(A) <: Real) ? 'N' : 'C', matrix_descr('S', A.uplo, 'N'), unwrap_trans(A)) describe_and_unwrap(A::Hermitian{<:Any, T}) where T <: Union{Adjoint, Transpose} = - (T <: Adjoint || (eltype(A) <: Real) ? 'N' : 'T', matrix_descr('H', A.uplo, 'N'), unwrapa(A)) + (T <: Adjoint || (eltype(A) <: Real) ? 'N' : 'T', matrix_descr('H', A.uplo, 'N'), unwrap_trans(A)) # 5-arg mul!() function mul!(y::StridedVector{T}, A::SimpleOrSpecialOrAdjMat{T, S}, diff --git a/src/mklsparsematrix.jl b/src/mklsparsematrix.jl index 7ff38a9..a03f5b7 100644 --- a/src/mklsparsematrix.jl +++ b/src/mklsparsematrix.jl @@ -90,110 +90,120 @@ lazypermutedims(descr::matrix_descr) = matrix_descr( descr.diag) """ - MKLSparseMatrix + MKLSparseMatrix{S} -A wrapper around a MKLSparse matrix handle. +A wrapper around the handle of a MKLSparse matrix +created from the Julia sparse matrix of type `S`. """ -mutable struct MKLSparseMatrix +struct MKLSparseMatrix{S <: AbstractSparseMatrix} handle::sparse_matrix_t end -Base.unsafe_convert(::Type{sparse_matrix_t}, desc::MKLSparseMatrix) = desc.handle +Base.unsafe_convert(::Type{sparse_matrix_t}, A::MKLSparseMatrix) = A.handle +# create sparse_matrix_t handle for the SparseMKL representation of a given sparse matrix +# the created SparseMKL matrix handle has to be disposed by calling destroy_handle() function MKLSparseMatrix(A::SparseMatrixCOO; index_base = SPARSE_INDEX_BASE_ONE) - matrix_ref = Ref{sparse_matrix_t}() + ref = Ref{sparse_matrix_t}() res = mkl_call(Val{:mkl_sparse_T_create_SI}(), typeof(A), - matrix_ref, index_base, A.m, A.n, nnz(A), A.rows, A.cols, A.vals, + ref, index_base, A.m, A.n, nnz(A), A.rows, A.cols, A.vals, log=Val{false}()) check_status(res) - obj = MKLSparseMatrix(matrix_ref[]) - finalizer(mkl_function(Val{:mkl_sparse_destroyI}(), typeof(A)), obj) - return obj + return MKLSparseMatrix{typeof(A)}(ref[]) end function MKLSparseMatrix(A::SparseMatrixCSR; index_base = SPARSE_INDEX_BASE_ONE) - matrix_ref = Ref{sparse_matrix_t}() + ref = Ref{sparse_matrix_t}() res = mkl_call(Val{:mkl_sparse_T_create_SI}(), typeof(A), - matrix_ref, index_base, A.m, A.n, A.rowptr, pointer(A.rowptr, 2), A.colval, A.nzval, + ref, index_base, A.m, A.n, A.rowptr, pointer(A.rowptr, 2), A.colval, A.nzval, log=Val{false}()) check_status(res) - obj = MKLSparseMatrix(matrix_ref[]) - finalizer(mkl_function(Val{:mkl_sparse_destroyI}(), typeof(A)), obj) - return obj + return MKLSparseMatrix{typeof(A)}(ref[]) end function MKLSparseMatrix(A::SparseMatrixCSC; index_base = SPARSE_INDEX_BASE_ONE) + ref = Ref{sparse_matrix_t}() # SparseMatrixCSC is fixed to 1-based indexing, passing SPARSE_INDEX_BASE_ZERO is most likely an error - matrix_ref = Ref{sparse_matrix_t}() res = mkl_call(Val{:mkl_sparse_T_create_SI}(), typeof(A), - matrix_ref, index_base, A.m, A.n, A.colptr, pointer(A.colptr, 2), A.rowval, A.nzval, + ref, index_base, A.m, A.n, A.colptr, pointer(A.colptr, 2), A.rowval, A.nzval, log=Val{false}()) check_status(res) - obj = MKLSparseMatrix(matrix_ref[]) - finalizer(mkl_function(Val{:mkl_sparse_destroyI}(), typeof(A)), obj) - return obj + return MKLSparseMatrix{typeof(A)}(ref[]) end -function Base.convert(::Type{S}, A::MKLSparseMatrix) where {S <: SparseMatrixCSC{Tv, Ti}} where {Tv, Ti} +function destroy(A::MKLSparseMatrix{S}) where S + if A.handle != C_NULL + res = mkl_call(Val{:mkl_sparse_destroyI}(), S, A.handle, log=Val{false}()) + check_status(res) + return res + else + return SPARSE_STATUS_NOT_INITIALIZED + end +end + +# extract the Intel MKL's sparse matrix A information assuming its storage type is S +# the returned arrays are internal to MKL representation of A, their lifetime is limited by A +# "major_" refers to the major axis (rows for CSR, columns for CSC) +# "minor_" refers to the minor axis (columns for CSR, rows for CSC) +function extract_data(ref::MKLSparseMatrix{S}) where {S <: AbstractSparseMatrix{Tv, Ti}} where {Tv, Ti} IT = ifelse(BlasInt === Int64 && Ti === Int32, BlasInt, Ti) index_base = Ref{sparse_index_base_t}() nrows = Ref{IT}(0) ncols = Ref{IT}(0) - colstartsptr = Ref{Ptr{IT}}() - colendsptr = Ref{Ptr{IT}}() - rowvalptr = Ref{Ptr{IT}}() + major_startsptr = Ref{Ptr{IT}}() + major_endsptr = Ref{Ptr{IT}}() + minor_valptr = Ref{Ptr{IT}}() nzvalptr = Ref{Ptr{Tv}}() res = mkl_call(Val{:mkl_sparse_T_export_SI}(), S, - A.handle, index_base, nrows, ncols, colstartsptr, colendsptr, rowvalptr, nzvalptr, + ref, index_base, nrows, ncols, major_startsptr, major_endsptr, minor_valptr, nzvalptr, log=Val{false}()) check_status(res) - colstarts = unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, colstartsptr[]), ncols[], own=false) - colends = unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, colendsptr[]), ncols[], own=false) - @assert colends[end] >= colstarts[1] - rowval = unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, rowvalptr[]), colends[end] - colstarts[1], own=false) - nzval = unsafe_wrap(Vector{Tv}, nzvalptr[], colends[end] - colstarts[1], own=false) - rowval = if index_base[] == SPARSE_INDEX_BASE_ZERO - rowval .+ one(Ti) # convert to 1-based (rowval is copied) - else - copy(rowval) - end - # check if row and nz values occupy continuous memory segment - if pointer(colends) == pointer(colstarts, 2) # all(colstarts[i + 1] == colends[i] for i in 1:length(colstarts)-1) - colstarts = unsafe_wrap(Vector{Ti}, pointer(colstarts), ncols[] + 1, own=false) - return S(nrows[], ncols[], copy(colstarts), rowval, copy(nzval)) + nmajor = S <: SparseMatrixCSC ? ncols[] : S <: SparseMatrixCSR ? nrows[] : error("Unsupported storage type $S") + if major_startsptr[] != C_NULL && major_endsptr[] != C_NULL + major_starts = unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, major_startsptr[]), nmajor, own=false) + major_ends = unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, major_endsptr[]), nmajor, own=false) + @assert major_ends[end] >= major_starts[1] + # check if minor_val and nzvl values occupy continuous memory segment + if pointer(major_ends) == pointer(major_starts, 2) # all(major_starts[i + 1] == major_ends[i] for i in 1:length(major_starts)-1) + major_starts = unsafe_wrap(Vector{Ti}, pointer(major_starts), nmajor + 1, own=false) + else + error("Support for non-continuous minor axis indices and non-zero values is not implemented") + end else - error("Support for non-continuous row and values is not implemented") + major_starts = nothing + major_ends = nothing end + return ( + size = (nrows[], ncols[]), + index_base = index_base[], + major_starts = major_starts, + #major_ends = major_ends, + minor_val = minor_valptr[] != C_NULL ? unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, minor_valptr[]), + major_ends[end] - major_starts[1], own=false) : nothing, + nzval = nzvalptr[] != C_NULL ? unsafe_wrap(Vector{Tv}, nzvalptr[], + major_ends[end] - major_starts[1], own=false) : nothing, + ) +end + +function Base.convert(::Type{S}, A::MKLSparseMatrix{S}) where {S <: SparseMatrixCSC} + _A = extract_data(A) + Ti = eltype(_A.minor_val) + rowval = _A.index_base == SPARSE_INDEX_BASE_ZERO ? + _A.minor_val .+ one(Ti) : # convert to 1-based (rowval is copied) + copy(_A.minor_val) + return S(_A.size..., copy(_A.major_starts), rowval, copy(_A.nzval)) end # converter for the default SparseMatrixCSC storage type -Base.convert(::Type{SparseMatrixCSC}, A::MKLSparseMatrix) = - convert(SparseMatrixCSC{Float64, BlasInt}, A) +Base.convert(::Type{SparseMatrixCSC}, A::MKLSparseMatrix{SparseMatrixCSC{Tv, Ti}}) where {Tv, Ti} = + convert(SparseMatrixCSC{Tv, Ti}, A) -function Base.convert(::Type{S}, A::MKLSparseMatrix) where {S <: SparseMatrixCSR{Tv, Ti}} where {Tv, Ti} - IT = ifelse(BlasInt === Int64 && Ti === Int32, BlasInt, Ti) - index_base = Ref{sparse_index_base_t}() - nrows = Ref{IT}(0) - ncols = Ref{IT}(0) - rowstartsptr = Ref{Ptr{IT}}() - rowendsptr = Ref{Ptr{IT}}() - colvalptr = Ref{Ptr{IT}}() - nzvalptr = Ref{Ptr{Tv}}() - res = mkl_call(Val{:mkl_sparse_T_export_SI}(), S, - A.handle, index_base, nrows, ncols, rowstartsptr, rowendsptr, colvalptr, nzvalptr, - log=Val{false}()) - check_status(res) - rowstarts = unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, rowstartsptr[]), nrows[], own=false) - rowends = unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, rowendsptr[]), nrows[], own=false) - @assert rowends[end] >= rowstarts[1] - colval = unsafe_wrap(Vector{Ti}, reinterpret(Ptr{Ti}, colvalptr[]), rowends[end] - rowstarts[1], own=false) - nzval = unsafe_wrap(Vector{Tv}, nzvalptr[], rowends[end] - rowstarts[1], own=false) +function Base.convert(::Type{S}, A::MKLSparseMatrix{S}) where {S <: SparseMatrixCSR} + _A = extract_data(A) # not converting the col indices depending on index_base - # check if row and nz values occupy continuous memory segment - if pointer(rowends) == pointer(rowstarts, 2) # all(rowstarts[i + 1] == rowends[i] for i in 1:length(rowstarts)-1) - rowstarts = unsafe_wrap(Vector{Ti}, pointer(rowstarts), nrows[] + 1, own=false) - return S(nrows[], ncols[], copy(rowstarts), copy(colval), copy(nzval)) - else - error("Support for non-continuous row and values is not implemented") - end + @show length(_A.nzval) + return S(_A.size..., copy(_A.major_starts), copy(_A.minor_val), copy(_A.nzval)) end + +Base.convert(::Type{SparseMatrixCSR}, A::MKLSparseMatrix{SparseMatrixCSR{Tv, Ti}}) where {Tv, Ti} = + convert(SparseMatrixCSR{Tv, Ti}, A) diff --git a/src/types.jl b/src/types.jl index 6aa2ae6..465ee7d 100644 --- a/src/types.jl +++ b/src/types.jl @@ -167,10 +167,10 @@ end convert(sparse_fill_mode_t, matdescr[2]), convert(sparse_diag_type_t, matdescr[3])) -# check the correctness of transa argument of MKLSparse calls -check_transa(t::Char) = +# check the correctness of transA (transB etc) argument of MKLSparse calls +check_trans(t::Char) = (t in ('C', 'N', 'T')) || - throw(ArgumentError("transa: is '$t', must be 'N', 'T', or 'C'")) + throw(ArgumentError("trans: is '$t', must be 'N', 'T', or 'C'")) # check matrix sizes for the multiplication-like operation C <- tA[A] * tB[B] function check_mat_op_sizes(C, A, tA, B, tB; diff --git a/test/test_BLAS.jl b/test/test_BLAS.jl index 613b2e2..a232c0f 100644 --- a/test/test_BLAS.jl +++ b/test/test_BLAS.jl @@ -130,7 +130,7 @@ end # test conversion to incompatible Julia types SPMT2 = SPMT === SparseMatrixCSC ? MKLSparse.SparseMatrixCSR : SparseMatrixCSC - @test_throws MKLSparseError convert(SPMT2{T, IT}, mklA) + @test_throws MethodError convert(SPMT2{T, IT}, mklA) # MKL Sparse does not check for matrix index type and function name compatibility #if Base.USE_BLAS64 @@ -143,6 +143,7 @@ end # MKL does not support export of COO matrices @test convert(SPMT{T, IT}, mklA) == spA skip=isCOO + MKLSparse.destroy(mklA) end @testset "$SPMT{$T,$IT} * Vector{$T}" begin