diff --git a/README.md b/README.md index fe01d309..5b9f8188 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A Julia package for representing banded matrices [![Build Status](https://travis-ci.org/JuliaMatrices/BandedMatrices.jl.svg?branch=master)](https://travis-ci.org/JuliaMatrices/BandedMatrices.jl) -[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaMatrices.github.io/BandedMatrices.jl/stable) +[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaMatrices.github.io/BandedMatrices.jl/stable) [![](https://img.shields.io/badge/docs-latest-blue.svg)](https://JuliaMatrices.github.io/BandedMatrices.jl/latest) @@ -14,10 +14,10 @@ bands. One can create banded matrices of type `BandedMatrix` as follows: ```julia -bzeros(m,n,l,u) # creates a banded matrix of zeros, with l sub-diagonals and u super-diagonals +BandedMatrix(Zeros(m,n), l, u) # creates a banded matrix of zeros, with l sub-diagonals and u super-diagonals brand(m,n,l,u) # creates a random banded matrix, with l sub-diagonals and u super-diagonals -bones(m,n,l,u) # creates a banded matrix of ones, with l sub-diagonals and u super-diagonals -beye(n,l,u) # creates a banded n x n identity matrix, with l sub-diagonals and u super-diagonals +BandedMatrix(Ones(m,n), l, u) # creates a banded matrix of ones, with l sub-diagonals and u super-diagonals +BandedMatrix(Eye(n),l,u) # creates a banded n x n identity matrix, with l sub-diagonals and u super-diagonals ``` Specialized algebra routines are overriden, include `*` and `\`: diff --git a/REQUIRE b/REQUIRE index cdbbe78e..f7ae3d68 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1,2 +1,3 @@ julia 0.6 -Compat 0.32 +Compat 0.39 +FillArrays 0.0.1 diff --git a/docs/src/index.md b/docs/src/index.md index c8f725f4..0ef376eb 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -7,10 +7,6 @@ BandedMatrix ``` -```@docs -beye -``` - ```@docs bones ``` @@ -19,10 +15,6 @@ bones brand ``` -```@docs -bzeros -``` - ## Accessing banded matrices @@ -54,9 +46,6 @@ BandRange SymBandedMatrix ``` -```@docs -sbeye -``` ```@docs sbones @@ -66,10 +55,6 @@ sbones sbrand ``` -```@docs -sbzeros -``` - ## Banded matrix interface diff --git a/src/BandedMatrices.jl b/src/BandedMatrices.jl index 7eab202f..767b039b 100644 --- a/src/BandedMatrices.jl +++ b/src/BandedMatrices.jl @@ -1,12 +1,14 @@ __precompile__() module BandedMatrices -using Base, Compat +using Base, Compat, FillArrays import Base: getindex, setindex!, *, +, -, ==, <, <=, >, - >=, /, ^, \, transpose, showerror, reindex, checkbounds + >=, /, ^, \, transpose, showerror, reindex, checkbounds, @propagate_inbounds -import Base: convert, size, view +import Base: convert, size, view, indices, unsafe_indices, indices1, + first, last, size, length, unsafe_length, start, next, done, step, + to_indices, to_index, indices, show, fill!, copy! import Base.BLAS: libblas import Base.LAPACK: liblapack @@ -36,31 +38,38 @@ import Base.LinAlg: BlasInt, copy_oftype, checksquare -import Base: lufact, cholfact, cholfact! +import Base: lufact, cholfact, cholfact!, promote_op + +import FillArrays: AbstractFill export BandedMatrix, SymBandedMatrix, bandrange, - bzeros, - beye, brand, - bones, bandwidth, BandError, band, + Band, BandRange, bandwidths, colrange, - rowrange + rowrange, + isbanded, + Zeros, + Fill, + Ones, + Eye + include("blas.jl") include("lapack.jl") -include("AbstractBandedMatrix.jl") -include("Band.jl") -include("utils.jl") +include("generic/AbstractBandedMatrix.jl") +include("generic/Band.jl") +include("generic/utils.jl") +include("generic/interface.jl") include("banded/BandedMatrix.jl") include("banded/BandedLU.jl") @@ -72,7 +81,8 @@ include("symbanded/SymBandedMatrix.jl") include("symbanded/BandedCholesky.jl") include("symbanded/linalg.jl") -include("interface.jl") +include("interfaceimpl.jl") + include("deprecate.jl") diff --git a/src/banded/BandedMatrix.jl b/src/banded/BandedMatrix.jl index 1f6247c5..6ccacefe 100644 --- a/src/banded/BandedMatrix.jl +++ b/src/banded/BandedMatrix.jl @@ -4,18 +4,21 @@ # a_21 a_22 a_23 # a_31 a_32 a_33 a_34 # a_42 a_43 a_44 ] -# ordering the data like (columns first) +# ordering the data like (cobbndsmns first) # [ * a_12 a_23 a_34 # a_11 a_22 a_33 a_44 # a_21 a_32 a_43 * # a_31 a_42 * * ] ### + +function _BandedMatrix end + mutable struct BandedMatrix{T} <: AbstractBandedMatrix{T} data::Matrix{T} # l+u+1 x n (# of columns) m::Int #Number of rows l::Int # lower bandwidth ≥0 u::Int # upper bandwidth ≥0 - function BandedMatrix{T}(data::Matrix{T},m,l,u) where {T} + global function _BandedMatrix(data::Matrix{T},m,l,u) where {T} if size(data,1) ≠ l+u+1 && !(size(data,1) == 0 && -l > u) error("Data matrix must have number rows equal to number of bands") else @@ -24,75 +27,61 @@ mutable struct BandedMatrix{T} <: AbstractBandedMatrix{T} end end +MemoryLayout(::BandedMatrix{T}) where T = BandedLayout{T}() + # BandedMatrix with unit range indexes is also banded const BandedSubBandedMatrix{T} = SubArray{T,2,BandedMatrix{T},I} where I<:Tuple{Vararg{AbstractUnitRange}} - -# these are the banded matrices that are ameniable to BLAS routines -const BLASBandedMatrix{T} = Union{ - BandedMatrix{T}, - BandedSubBandedMatrix{T} - } - - -isbanded(::BandedSubBandedMatrix{T}) where {T} = true +@banded BandedSubBandedMatrix ## Constructors -BandedMatrix(data::Matrix,m::Integer,a::Integer,b::Integer) = BandedMatrix{eltype(data)}(data,m,a,b) - doc""" - BandedMatrix(T, n, m, l, u) + BandedMatrix{T}(n, m, l, u) returns an unitialized `n`×`m` banded matrix of type `T` with bandwidths `(l,u)`. """ -# Use zeros to avoid unallocated entries for bigfloat -BandedMatrix(::Type{T},n::Integer,m::Integer,a::Integer,b::Integer) where {T<:BlasFloat} = - BandedMatrix{T}(Matrix{T}(max(0,b+a+1),m),n,a,b) -BandedMatrix(::Type{T},n::Integer,m::Integer,a::Integer,b::Integer) where {T<:Number} = - BandedMatrix{T}(zeros(T,max(0,b+a+1),m),n,a,b) -BandedMatrix(::Type{T},n::Integer,m::Integer,a::Integer,b::Integer) where {T} = - BandedMatrix{T}(Matrix{T}(max(0,b+a+1),m),n,a,b) - -BandedMatrix(::Type{T},n::Integer,a::Integer,b::Integer) where {T} = BandedMatrix(T,n,n,a,b) -BandedMatrix(::Type{T},n::Integer,::Colon,a::Integer,b::Integer) where {T} = BandedMatrix(T,n,n+b,a,b) - - -BandedMatrix(data::Matrix,m::Integer,a) = BandedMatrix(data,m,-a[1],a[end]) -BandedMatrix(::Type{T},n::Integer,m::Integer,a) where {T} = BandedMatrix(T,n,m,-a[1],a[end]) -BandedMatrix(::Type{T},n::Integer,::Colon,a) where {T} = BandedMatrix(T,n,:,-a[1],a[end]) -BandedMatrix(::Type{T},n::Integer,a) where {T} = BandedMatrix(T,n,-a[1],a[end]) - +BandedMatrix{T}(::Uninitialized, n::Integer, m::Integer, a::Integer, b::Integer) where {T<:BlasFloat} = + _BandedMatrix(Matrix{T}(max(0,b+a+1),m), n, a, b) +BandedMatrix{T}(::Uninitialized, n::Integer, m::Integer, a::Integer, b::Integer) where {T<:Number} = + _BandedMatrix(zeros(T,max(0,b+a+1),m),n,a,b) +BandedMatrix{T}(::Uninitialized, n::Integer, m::Integer, a::Integer, b::Integer) where {T} = + _BandedMatrix(Matrix{T}(max(0,b+a+1),m),n,a,b) +BandedMatrix{T}(::Uninitialized, nm::NTuple{2,Integer}, ab::NTuple{2,Integer}) where T = + BandedMatrix{T}(uninitialized, nm..., ab...) +BandedMatrix{T}(::Uninitialized, n::Integer, ::Colon, a::Integer, b::Integer) where {T} = + BandedMatrix{T}(uninitialized,n,n+b,a,b) for MAT in (:BandedMatrix, :AbstractBandedMatrix, :AbstractMatrix, :AbstractArray) - @eval Base.convert(::Type{$MAT{V}},M::BandedMatrix) where {V} = - BandedMatrix{V}(convert(Matrix{V},M.data),M.m,M.l,M.u) + @eval Base.convert(::Type{$MAT{V}}, M::BandedMatrix) where {V} = + _BandedMatrix(convert(Matrix{V}, M.data), M.m, M.l, M.u) end -function Base.convert(::Type{BM},M::Matrix) where {BM<:BandedMatrix} - ret = BandedMatrix(eltype(BM)==Any ? eltype(M) : - promote_type(eltype(BM),eltype(M)),size(M,1),size(M,2),size(M,1)-1,size(M,2)-1) + +#TODO: Add test +function Base.convert(::Type{BM}, M::Matrix) where {BM<:BandedMatrix} + ret = BandedMatrix{eltype(BM) == Any ? eltype(M) : + promote_type(eltype(BM),eltype(M))}(uninitialized, size(M,1),size(M,2),size(M,1)-1,size(M,2)-1) for k=1:size(M,1),j=1:size(M,2) ret[k,j] = M[k,j] end ret end -Base.copy(B::BandedMatrix) = BandedMatrix(copy(B.data),B.m,B.l,B.u) +Base.copy(B::BandedMatrix) = _BandedMatrix(copy(B.data), B.m, B.l, B.u) -Base.promote_rule(::Type{BandedMatrix{T}},::Type{BandedMatrix{V}}) where {T,V} = BandedMatrix{promote_type(T,V)} +Base.promote_rule(::Type{BandedMatrix{T}}, ::Type{BandedMatrix{V}}) where {T,V} = BandedMatrix{promote_type(T,V)} -for (op,bop) in ((:(Base.rand),:brand),(:(Base.zeros),:bzeros),(:(Base.ones),:bones)) - name_str = "bzeros" +for (op,bop) in ((:(Base.rand),:brand),) @eval begin $bop(::Type{T},n::Integer,m::Integer,a::Integer,b::Integer) where {T} = - BandedMatrix($op(T,max(0,b+a+1),m),n,a,b) + _BandedMatrix($op(T,max(0,b+a+1),m),n,a,b) $bop(::Type{T},n::Integer,a::Integer,b::Integer) where {T} = $bop(T,n,n,a,b) $bop(::Type{T},n::Integer,::Colon,a::Integer,b::Integer) where {T} = $bop(T,n,n+b,a,b) $bop(::Type{T},::Colon,m::Integer,a::Integer,b::Integer) where {T} = $bop(T,m+a,m,a,b) @@ -111,19 +100,6 @@ for (op,bop) in ((:(Base.rand),:brand),(:(Base.zeros),:bzeros),(:(Base.ones),:bo end end -doc""" - bzeros(T,n,m,l,u) - -Creates an `n×m` banded matrix of all zeros of type `T` with bandwidths `(l,u)` -""" -bzeros - -doc""" - bones(T,n,m,l,u) - -Creates an `n×m` banded matrix with ones in the bandwidth of type `T` with bandwidths `(l,u)` -""" -bones doc""" brand(T,n,m,l,u) @@ -133,24 +109,39 @@ Creates an `n×m` banded matrix with random numbers in the bandwidth of type `T brand -""" - beye(T,n,l,u) -`n×n` banded identity matrix of type `T` with bandwidths `(l,u)` -""" -function beye(::Type{T},n::Integer,a...) where {T} - ret=bzeros(T,n,a...) - for k=1:n - ret[k,k]=one(T) +## Conversions from AbstractArrays, we include FillArrays in case `zeros` is ever faster +function BandedMatrix{T}(A::AbstractMatrix, bnds::NTuple{2,Int}) where T + (n,m) = size(A) + (l,u) = bnds + ret = BandedMatrix{T}(uninitialized, n, m, bnds...) + @inbounds for j = 1:m, k = max(1,j-u):min(n,j+l) + inbands_setindex!(ret, A[k,j], k, j) end ret end -beye(::Type{T},n::Integer) where {T} = beye(T,n,0,0) -beye(n::Integer) = beye(n,0,0) -beye(n::Integer,a...) = beye(Float64,n,a...) + +BandedMatrix(A::AbstractMatrix{T}, bnds::NTuple{2,Int}) where T = + BandedMatrix{T}(A, bnds) + +BandedMatrix{V}(Z::Zeros{T,2}, bnds::NTuple{2,Int}) where {T,V} = + _BandedMatrix(zeros(V,max(0,sum(bnds)+1),size(Z,2)),size(Z,1),bnds...) + +BandedMatrix(Z::Zeros{T,2}, bnds::NTuple{2,Int}) where T = BandedMatrix{T}(Z, bnds) + + +BandedMatrix(E::Eye{T}, bnds::NTuple{2,Int}) where T = BandedMatrix{T}(E, bnds) +function BandedMatrix{T}(E::Eye, bnds::NTuple{2,Int}) where T + ret=BandedMatrix(Zeros{T}(E), bnds) + ret[band(0)] = one(T) + ret +end + +BandedMatrix(A::AbstractMatrix) = + BandedMatrix(A, bandwidths(A)) Base.similar(B::BandedMatrix) = - BandedMatrix(eltype(B),size(B,1),size(B,2),bandwidth(B,1),bandwidth(B,2)) + BandedMatrix{eltype(B)}(size(B,1), size(B,2), bandwidth(B,1), bandwidth(B,2)) ## Abstract Array Interface @@ -207,30 +198,55 @@ end @inline getindex(A::BandedMatrix, kr::Colon, jr::Colon) = copy(A) # ~ indexing along a band +# we reduce it to converting a View # scalar - band - colon -@inline function getindex(A::BandedMatrix{T}, b::Band) where {T} - @boundscheck checkband(A, b) - if b.i > 0 - vec(A.data[A.u - b.i + 1, b.i+1:min(size(A,2),size(A,1)+b.i)]) - elseif b.i == 0 - vec(A.data[A.u - b.i + 1, 1:min(size(A,2),size(A,1))]) - else # b.i < 0 - vec(A.data[A.u - b.i + 1, 1:min(size(A,2),size(A,1)+b.i)]) +@inline getindex(A::BandedMatrix{T}, b::Band) where {T} = Vector{T}(view(A, b)) + +# type to represent a view of a band +const BandedMatrixBand{T} = SubArray{T, 1, Base.ReshapedArray{T,1,BandedMatrix{T}, + Tuple{Base.MultiplicativeInverses.SignedMultiplicativeInverse{Int}}}, Tuple{BandSlice}, false} + + +band(V::BandedMatrixBand) = first(parentindexes(V)).band.i + +# gives a view of the parent's data matrix +function dataview(V::BandedMatrixBand) + A = parent(parent(V)) + b = band(V) + m,n = size(A) + if b > 0 + view(A.data, A.u - b + 1, b+1:min(n,m+b)) + elseif b == 0 + view(A.data, A.u - b + 1, 1:min(n,m)) + else # b < 0 + view(A.data, A.u - b + 1, 1:min(n,m+b)) end end -@inline function view(A::BandedMatrix{T}, b::Band) where {T} - @boundscheck checkband(A, b) - if b.i > 0 - view(A.data,A.u - b.i + 1, b.i+1:min(size(A,2),size(A,1)+b.i)) - elseif b.i == 0 - view(A.data,A.u - b.i + 1, 1:min(size(A,2),size(A,1))) - else # b.i < 0 - view(A.data,A.u - b.i + 1, 1:min(size(A,2),size(A,1)+b.i)) +function convert(::Type{Vector{T}}, V::BandedMatrixBand) where T + A = parent(parent(V)) + if -A.l ≤ band(V) ≤ A.u + Vector{T}(dataview(V)) + else + zeros(T, length(V)) end end +convert(::Type{Array{T}}, A::BandedMatrixBand) where T = convert(Vector{T}, A) +convert(::Type{Array}, A::BandedMatrixBand) = convert(Vector{eltype(A)}, A) +convert(::Type{Vector}, A::BandedMatrixBand)= convert(Vector{eltype(A)}, A) + + +convert(::Type{AbstractArray{T}}, A::BandedMatrixBand{T}) where T = A +convert(::Type{AbstractVector{T}}, A::BandedMatrixBand{T}) where T = A +convert(::Type{AbstractArray}, A::BandedMatrixBand{T}) where T = A +convert(::Type{AbstractVector}, A::BandedMatrixBand{T}) where T = A + +convert(::Type{AbstractArray{T}}, A::BandedMatrixBand) where T = convert(Vector{T}, A) +convert(::Type{AbstractVector{T}}, A::BandedMatrixBand) where T = convert(Vector{T}, A) + + # scalar - BandRange - integer -- A[1, BandRange] @inline getindex(A::AbstractMatrix, ::Type{BandRange}, j::Integer) = A[colrange(A, j), j] @@ -238,6 +254,7 @@ end @inline getindex(A::AbstractMatrix, k::Integer, ::Type{BandRange}) = A[k, rowrange(A, k)] + # ~ indexing along a row @@ -582,6 +599,12 @@ Base.norm(B::BandedMatrix,opts...) = norm(Matrix(B),opts...) ## ALgebra and other functions +function fill!(A::BandedMatrix{T}, x) where T + x == zero(T) || throw(BandError(A)) + fill!(A.data, x) + A +end + function Base.scale!(α::Number, A::BandedMatrix) Base.scale!(α, A.data) A @@ -593,7 +616,7 @@ function Base.scale!(A::BandedMatrix, α::Number) end function Base.transpose(B::BandedMatrix) - Bt=bzeros(eltype(B),size(B,2),size(B,1),B.u,B.l) + Bt = BandedMatrix(Zeros{eltype(B)}(size(B,2),size(B,1)), (B.u,B.l)) for j = 1:size(B,2), k = colrange(B,j) Bt[j,k]=B[k,j] end @@ -601,7 +624,7 @@ function Base.transpose(B::BandedMatrix) end function Base.ctranspose(B::BandedMatrix) - Bt=bzeros(eltype(B),size(B,2),size(B,1),B.u,B.l) + Bt=BandedMatrix(Zeros{eltype(B)}(size(B,2),size(B,1)), (B.u,B.l)) for j = 1:size(B,2), k = colrange(B,j) Bt[j,k]=conj(B[k,j]) end @@ -639,16 +662,21 @@ end ## numbers for OP in (:*,:/) @eval begin - $OP(A::BandedMatrix, b::Number) = BandedMatrix($OP(A.data,b),A.m,A.l,A.u) + $OP(A::BandedMatrix, b::Number) = + _BandedMatrix($OP(A.data,b),A.m,A.l,A.u) broadcast(::typeof($OP), A::BandedMatrix, b::Number) = - BandedMatrix($OP.(A.data,b),A.m,A.l,A.u) + _BandedMatrix($OP.(A.data,b),A.m,A.l,A.u) end end - -*(a::Number,B::BandedMatrix) = BandedMatrix(a*B.data,B.m,B.l,B.u) -broadcast(::typeof(*), a::Number, B::BandedMatrix) = BandedMatrix(a.*B.data,B.m,B.l,B.u) - +for OP in (:*,:\) + @eval begin + $OP(a::Number, B::BandedMatrix) = + _BandedMatrix($OP(a,B.data),B.m,B.l,B.u) + broadcast(::typeof($OP), a::Number, B::BandedMatrix) = + _BandedMatrix($OP.(a,B.data),B.m,B.l,B.u) + end +end #implements fliplr(flipud(A)) @@ -691,23 +719,23 @@ end end -function Base.convert(::Type{BandedMatrix},S::BandedSubBandedMatrix{T}) where {T} +function Base.convert(::Type{BandedMatrix}, S::BandedSubBandedMatrix{T}) where {T} A=parent(S) kr,jr=parentindexes(S) shft=kr[1]-jr[1] l,u=bandwidths(A) if -u ≤ shft ≤ l - BandedMatrix(A.data[:,jr],length(kr),l-shft,u+shft) + _BandedMatrix(A.data[:,jr],length(kr),l-shft,u+shft) elseif shft > l # need to add extra zeros at top since negative bandwidths not supported # new bandwidths = (0,u+shft) dat = zeros(T,u+shft+1,length(jr)) dat[1:l+u+1,:] = A.data[:,jr] - BandedMatrix(dat,length(kr),0,u+shft) + _BandedMatrix(dat,length(kr),0,u+shft) else # shft < -u dat = zeros(T,l-shft+1,length(jr)) dat[-shft-u+1:end,:] = A.data[:,jr] # l-shft+1 - (-shft-u) == l+u+1 - BandedMatrix(dat,length(kr),l-shft,0) + _BandedMatrix(dat,length(kr),l-shft,0) end end diff --git a/src/banded/BandedQR.jl b/src/banded/BandedQR.jl index e02ca506..cd22f57d 100644 --- a/src/banded/BandedQR.jl +++ b/src/banded/BandedQR.jl @@ -147,7 +147,7 @@ function Base.qr(A::BandedMatrix) end function Base.qrfact(A::BandedMatrix) - R=bzeros(eltype(A),size(A,1),size(A,2),A.l,A.l+A.u) + R=BandedMatrix(Zeros{eltype(A)}(size(A)), (A.l,A.l+A.u)) R.data[A.l+1:end,:]=A.data banded_qrfact!(R) end @@ -156,8 +156,7 @@ flipsign(x,y) = Base.flipsign(x,y) flipsign(x::BigFloat,y::BigFloat) = sign(y)==1 ? x : (-x) flipsign(x,y::Complex) = y==0 ? x : x*sign(y) -function banded_qrfact!(R::BandedMatrix) - T=eltype(R) +function banded_qrfact!(R::BandedMatrix{T}) where T M=R.l+1 # number of diag+subdiagonal bands m,n=size(R) W=Matrix{T}(M,(n Yl - # test that all entries are zero in extra bands - for j=1:size(X,2),k=max(1,j+Yl+1):min(j+Xl,n) - if inbands_getindex(X,k,j) ≠ 0 - error("X has nonzero entries in bands outside bandrange of Y.") - end - end - end - if Xu > Yu - # test that all entries are zero in extra bands - for j=1:size(X,2),k=max(1,j-Xu):min(j-Yu-1,n) - if inbands_getindex(X,k,j) ≠ 0 - error("X has nonzero entries in bands outside bandrange of Y.") - end - end - end - - l = min(Xl,Yl) - u = min(Xu,Yu) - - @inbounds for j=1:m,k=max(1,j-u):min(n,j+l) - inbands_setindex!(Y,a*inbands_getindex(X,k,j)+inbands_getindex(Y,k,j),k,j) - end - Y -end - -function banded_dense_axpy!(a::Number, X::AbstractMatrix ,Y::AbstractMatrix) - if size(X) != size(Y) - throw(DimensionMismatch("+")) - end - @inbounds for j=1:size(X,2),k=colrange(X,j) - Y[k,j]+=a*inbands_getindex(X,k,j) - end - Y -end - -banded_axpy!(a::Number, X::BLASBandedMatrix ,Y::BLASBandedMatrix) = banded_generic_axpy!(a, X, Y) -banded_axpy!(a::Number, X::BLASBandedMatrix ,Y::AbstractMatrix) = banded_dense_axpy!(a, X, Y) - -axpy!(a::Number, X::BLASBandedMatrix, Y::BLASBandedMatrix) = banded_axpy!(a, X, Y) -axpy!(a::Number, X::BLASBandedMatrix, Y::AbstractMatrix) = banded_axpy!(a, X, Y) - - -function +(A::BLASBandedMatrix{T},B::BLASBandedMatrix{V}) where {T,V} - n, m=size(A) - ret = bzeros(promote_type(T,V),n,m,sumbandwidths(A, B)...) - axpy!(1.,A,ret) - axpy!(1.,B,ret) - ret -end - -function +(A::BLASBandedMatrix{T},B::AbstractMatrix{T}) where {T} - ret = deepcopy(B) - axpy!(one(T),A,ret) - ret -end - -function +(A::BLASBandedMatrix{T},B::AbstractMatrix{V}) where {T,V} - n, m=size(A) - ret = zeros(promote_type(T,V),n,m) - axpy!(one(T),A,ret) - axpy!(one(V),B,ret) - ret -end - -+(A::AbstractMatrix{T},B::BLASBandedMatrix{V}) where {T,V} = B+A - - -function -(A::BLASBandedMatrix{T}, B::BLASBandedMatrix{V}) where {T,V} - n, m=size(A) - ret = bzeros(promote_type(T,V),n,m,sumbandwidths(A, B)...) - axpy!(one(T),A,ret) - axpy!(-one(V),B,ret) - ret -end - -function -(A::BLASBandedMatrix{T},B::AbstractMatrix{T}) where {T} - ret = deepcopy(B) - Base.scale!(ret,-1) - axpy!(one(T),A,ret) - ret -end - - -function -(A::BLASBandedMatrix{T},B::AbstractMatrix{V}) where {T,V} - n, m=size(A) - ret = zeros(promote_type(T,V),n,m) - axpy!(one(T),A,ret) - axpy!(-one(V),B,ret) - ret -end - --(A::AbstractMatrix{T},B::BLASBandedMatrix{V}) where {T,V} = Base.scale!(B-A,-1) - - - -## UniformScaling - -function axpy!(a::Number,X::UniformScaling,Y::BLASBandedMatrix{T}) where {T} - checksquare(Y) - α = a * X.λ - @inbounds for k = 1:size(Y,1) - inbands_setindex!(Y, inbands_getindex(Y, k, k) + α, k, k) - end - Y -end - -function +(A::BLASBandedMatrix, B::UniformScaling) - ret = deepcopy(A) - axpy!(1,B,ret) -end - -+(A::UniformScaling, B::BLASBandedMatrix) = B+A - -function -(A::BLASBandedMatrix, B::UniformScaling) - ret = deepcopy(A) - axpy!(-1,B,ret) -end - -function -(A::UniformScaling, B::BLASBandedMatrix) - ret = deepcopy(B) - Base.scale!(ret,-1) - axpy!(1,A,ret) -end - - -# matrix * vector - -function _banded_generic_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{U}, b::AbstractVector{V}) where {T, U, V} - @inbounds c[:] = zero(T) - if tA == 'N' - @inbounds for j = 1:size(A,2), k = colrange(A,j) - c[k] += inbands_getindex(A,k,j)*b[j] - end - elseif tA == 'C' - @inbounds for j = 1:size(A,2), k = colrange(A,j) - c[j] += inbands_getindex(A,k,j)'*b[k] - end - elseif tA == 'T' - @inbounds for j = 1:size(A,2), k = colrange(A,j) - c[j] += inbands_getindex(A,k,j)*b[k] - end - end - c -end - -positively_banded_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{U}, b::AbstractVector{V}) where {T, U, V} = _banded_generic_matvecmul!(c, tA, A, b) -# use BLAS routine for positively banded BLASBandedMatrix -positively_banded_matvecmul!(c::StridedVector{T}, tA::Char, A::BLASBandedMatrix{T}, b::StridedVector{T}) where {T <: BlasFloat} = gbmv!(tA, one(T), A, b, zero(T), c) - -function generally_banded_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{U}, b::AbstractVector{V}) where {T, U, V} - m, n = _size(tA, A) - if length(c) ≠ m || length(b) ≠ n - throw(DimensionMismatch("*")) - end - - l, u = _bandwidths(tA, A) - if -l > u - # no bands - c[:] = zero(T) - elseif l < 0 - banded_matvecmul!(c, tA, _view(tA, A, :, 1-l:n), view(b, 1-l:n)) - elseif u < 0 - c[1:-u] = zero(T) - banded_matvecmul!(view(c, 1-u:m), tA, _view(tA, A, 1-u:m, :), b) - else - positively_banded_matvecmul!(c, tA, A, b) - end - c -end - -banded_matvecmul!(c::StridedVector{T}, tA::Char, A::BLASBandedMatrix{T}, b::AbstractVector{T}) where {T <: BlasFloat} = generally_banded_matvecmul!(c, tA, A, b) - -banded_generic_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{U}, b::AbstractVector{V}) where {T, U, V} = generally_banded_matvecmul!(c, tA, A, b) - -A_mul_B!(c::AbstractVector{T}, A::BLASBandedMatrix{U}, b::AbstractVector{V}) where {T, U, V} = banded_matvecmul!(c, 'N', A, b) -Ac_mul_B!(c::AbstractVector{T}, A::BLASBandedMatrix{U}, b::AbstractVector{V}) where {T, U, V} = banded_matvecmul!(c, 'C', A, b) -Ac_mul_B!(c::AbstractVector{T}, A::BLASBandedMatrix{U}, b::AbstractVector{V}) where {T, U<:Real, V} = banded_matvecmul!(c, 'T', A, b) -At_mul_B!(c::AbstractVector{T}, A::BLASBandedMatrix{U}, b::AbstractVector{V}) where {T, U, V} = banded_matvecmul!(c, 'T', A, b) - -*(A::BLASBandedMatrix{U}, b::StridedVector{V}) where {U, V} = - A_mul_B!(Vector{promote_type(U, V)}(size(A, 1)), A, b) - - -# matrix * matrix -function _banded_generic_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{U}, B::AbstractMatrix{V}) where {T, U, V} - Am, An = _size(tA, A) - Bm, Bn = _size(tB, B) - Al,Au = _bandwidths(tA, A) - Bl,Bu = _bandwidths(tB, B) - Cl,Cu = prodbandwidths(tA, tB, A, B) - - if tA == 'N' && tB == 'N' - @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) - νmin = max(1,k-Al,j-Bu) - νmax = min(An,k+Au,j+Bl) - - tmp = zero(T) - for ν=νmin:νmax - tmp = tmp + inbands_getindex(A,k,ν) * inbands_getindex(B,ν,j) - end - inbands_setindex!(C,tmp,k,j) - end - elseif tA == 'C' && tB == 'N' - @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) - νmin = max(1,k-Al,j-Bu) - νmax = min(An,k+Au,j+Bl) - - tmp = zero(T) - for ν=νmin:νmax - tmp = tmp + inbands_getindex(A,ν,k)' * inbands_getindex(B,ν,j) - end - inbands_setindex!(C,tmp,k,j) - end - elseif tA == 'N' && tB == 'C' - @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) - νmin = max(1,k-Al,j-Bu) - νmax = min(An,k+Au,j+Bl) - - tmp = zero(T) - for ν=νmin:νmax - tmp = tmp + inbands_getindex(A,k,ν) * inbands_getindex(B,j,ν)' - end - inbands_setindex!(C,tmp,k,j) - end - elseif tA == 'C' && tB == 'C' - @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) - νmin = max(1,k-Al,j-Bu) - νmax = min(An,k+Au,j+Bl) - - tmp = zero(T) - for ν=νmin:νmax - tmp = tmp + inbands_getindex(A,ν,k)' * inbands_getindex(B,j,ν)' - end - inbands_setindex!(C,tmp,k,j) - end - elseif tA == 'T' && tB == 'N' - @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) - νmin = max(1,k-Al,j-Bu) - νmax = min(An,k+Au,j+Bl) - - tmp = zero(T) - for ν=νmin:νmax - tmp = tmp + inbands_getindex(A,ν,k) * inbands_getindex(B,ν,j) - end - inbands_setindex!(C,tmp,k,j) - end - - elseif tA == 'N' && tB == 'T' - @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) - νmin = max(1,k-Al,j-Bu) - νmax = min(An,k+Au,j+Bl) - - tmp = zero(T) - for ν=νmin:νmax - tmp = tmp + inbands_getindex(A,k,ν) * inbands_getindex(B,j,ν) - end - inbands_setindex!(C,tmp,k,j) - end - elseif tA == 'T' && tB == 'T' - @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) - νmin = max(1,k-Al,j-Bu) - νmax = min(An,k+Au,j+Bl) - - tmp = zero(T) - for ν=νmin:νmax - tmp = tmp + inbands_getindex(A,ν,k) * inbands_getindex(B,j,ν) - end - inbands_setindex!(C,tmp,k,j) - end - end - C -end - -# use BLAS routine for positively banded BLASBandedMatrices -function _positively_banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{T}, B::AbstractMatrix{T}) where {T <: BlasFloat} - Al,Au = _bandwidths(tA, A) - Bl,Bu = _bandwidths(tB, B) - # _banded_generic_matmatmul! is faster for sparse matrix - if tA != 'N' || tB != 'N' || (Al + Au < 100 && Bl + Bu < 100) - _banded_generic_matmatmul!(C, tA, tB, A, B) - else - # TODO: implement gbmm! routines for other flags - gbmm!('N', 'N', one(T), A, B, zero(T), C) - end -end - -positively_banded_matmatmul!(C::BLASBandedMatrix{T}, tA::Char, tB::Char, A::BLASBandedMatrix{T}, B::BLASBandedMatrix{T}) where {T <: BlasFloat} = _positively_banded_matmatmul!(C, tA, tB, A, B) -positively_banded_matmatmul!(C::StridedMatrix{T}, tA::Char, tB::Char, A::BLASBandedMatrix{T}, B::StridedMatrix{T}) where {T <: BlasFloat} = _positively_banded_matmatmul!(C, tA, tB, A, B) -positively_banded_matmatmul!(C::StridedMatrix{T}, tA::Char, tB::Char, A::StridedMatrix{T}, B::BLASBandedMatrix{T}) where {T <: BlasFloat} = _positively_banded_matmatmul!(C, tA, tB, A, B) -positively_banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{U}, B::AbstractMatrix{V}) where {T, U, V} = _banded_generic_matmatmul!(C, tA, tB, A, B) - - -function generally_banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{U}, B::AbstractMatrix{V}) where {T, U, V} - Am, An = _size(tA, A) - Bm, Bn = _size(tB, B) - if An != Bm || size(C, 1) != Am || size(C, 2) != Bn - throw(DimensionMismatch("*")) - end - # TODO: checkbandmatch - - Al, Au = _bandwidths(tA, A) - Bl, Bu = _bandwidths(tB, B) - - if (-Al > Au) || (-Bl > Bu) # A or B has empty bands - C[:,:] = zero(T) - elseif Al < 0 - C[max(1,Bn+Al-1):Am, :] = zero(T) - banded_matmatmul!(C, tA, tB, _view(tA, A, :, 1-Al:An), _view(tB, B, 1-Al:An, :)) - elseif Au < 0 - C[1:-Au,:] = zero(T) - banded_matmatmul!(view(C, 1-Au:Am,:), tA, tB, _view(tA, A, 1-Au:Am,:), B) - elseif Bl < 0 - C[:, 1:-Bl] = zero(T) - banded_matmatmul!(view(C, :, 1-Bl:Bn), tA, tB, A, _view(tB, B, :, 1-Bl:Bn)) - elseif Bu < 0 - C[:, max(1,Am+Bu-1):Bn] = zero(T) - banded_matmatmul!(C, tA, tB, _view(tA, A, :, 1-Bu:Bm), _view(tB, B, 1-Bu:Bm, :)) - else - positively_banded_matmatmul!(C, tA::Char, tB::Char, A, B) - end - C -end - - -banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::BLASBandedMatrix{T}, B::BLASBandedMatrix{T}) where {T <: BlasFloat} = generally_banded_matmatmul!(C, tA, tB, A, B) -banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::BLASBandedMatrix{T}, B::StridedMatrix{T}) where {T <: BlasFloat} = generally_banded_matmatmul!(C, tA, tB, A, B) -banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::StridedMatrix{T}, B::BLASBandedMatrix{T}) where {T <: BlasFloat} = generally_banded_matmatmul!(C, tA, tB, A, B) - -banded_generic_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{U}, B::AbstractMatrix{V}) where {T, U, V} = generally_banded_matmatmul!(C, tA, tB, A, B) - -A_mul_B!(C::AbstractMatrix ,A::BLASBandedMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'N', 'N', A, B) -A_mul_B!(C::AbstractMatrix ,A::BLASBandedMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'N', A, B) -A_mul_B!(C::AbstractMatrix ,A::AbstractMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'N', 'N', A, B) - -Ac_mul_B!(C::AbstractMatrix ,A::BLASBandedMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'C', 'N', A, B) -Ac_mul_B!(C::AbstractMatrix ,A::BLASBandedMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'C', 'N', A, B) -Ac_mul_B!(C::AbstractMatrix ,A::AbstractMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'C', 'N', A, B) -A_mul_Bc!(C::AbstractMatrix ,A::BLASBandedMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'N', 'C', A, B) -A_mul_Bc!(C::AbstractMatrix ,A::BLASBandedMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'C', A, B) -A_mul_Bc!(C::AbstractMatrix ,A::AbstractMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'N', 'C', A, B) -Ac_mul_Bc!(C::AbstractMatrix ,A::BLASBandedMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'C', 'C', A, B) -Ac_mul_Bc!(C::AbstractMatrix ,A::BLASBandedMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'C', 'C', A, B) -Ac_mul_Bc!(C::AbstractMatrix ,A::AbstractMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'C', 'C', A, B) - -At_mul_B!(C::AbstractMatrix ,A::BLASBandedMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'T', 'N', A, B) -At_mul_B!(C::AbstractMatrix ,A::BLASBandedMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'T', 'N', A, B) -At_mul_B!(C::AbstractMatrix ,A::AbstractMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'T', 'N', A, B) -A_mul_Bt!(C::AbstractMatrix ,A::BLASBandedMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'N', 'T', A, B) -A_mul_Bt!(C::AbstractMatrix ,A::BLASBandedMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'T', A, B) -A_mul_Bt!(C::AbstractMatrix ,A::AbstractMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'N', 'T', A, B) -At_mul_Bt!(C::AbstractMatrix ,A::BLASBandedMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'T', 'T', A, B) -At_mul_Bt!(C::AbstractMatrix ,A::BLASBandedMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'T', 'T', A, B) -At_mul_Bt!(C::AbstractMatrix ,A::AbstractMatrix, B::BLASBandedMatrix) = banded_matmatmul!(C, 'T', 'T', A, B) - -# override the Ac_mul_B, A_mul_Bc and Ac_mul_c for real values -Ac_mul_B!(C::AbstractMatrix{T} ,A::BLASBandedMatrix{U}, B::BLASBandedMatrix{V}) where {T, U<:Real, V} = banded_matmatmul!(C, 'T', 'N', A, B) -Ac_mul_B!(C::AbstractMatrix{T} ,A::BLASBandedMatrix{U}, B::AbstractMatrix{V}) where {T, U<:Real, V} = banded_matmatmul!(C, 'T', 'N', A, B) -Ac_mul_B!(C::AbstractMatrix{T} ,A::AbstractMatrix{U}, B::BLASBandedMatrix{V}) where {T, U<:Real, V} = banded_matmatmul!(C, 'T', 'N', A, B) -A_mul_Bc!(C::AbstractMatrix{T} ,A::BLASBandedMatrix{U}, B::BLASBandedMatrix{V}) where {T, U, V<:Real} = banded_matmatmul!(C, 'N', 'T', A, B) -A_mul_Bc!(C::AbstractMatrix{T} ,A::BLASBandedMatrix{U}, B::AbstractMatrix{V}) where {T, U, V<:Real} = banded_matmatmul!(C, 'N', 'T', A, B) -A_mul_Bc!(C::AbstractMatrix{T} ,A::AbstractMatrix{U}, B::BLASBandedMatrix{V}) where {T, U, V<:Real} = banded_matmatmul!(C, 'N', 'T', A, B) -Ac_mul_Bc!(C::AbstractMatrix{T} ,A::BLASBandedMatrix{U}, B::BLASBandedMatrix{V}) where {T, U<:Real, V<:Real} = banded_matmatmul!(C, 'T', 'T', A, B) -Ac_mul_Bc!(C::AbstractMatrix{T} ,A::BLASBandedMatrix{U}, B::AbstractMatrix{V}) where {T, U<:Real, V<:Real} = banded_matmatmul!(C, 'T', 'T', A, B) -Ac_mul_Bc!(C::AbstractMatrix{T} ,A::AbstractMatrix{U}, B::BLASBandedMatrix{V}) where {T, U<:Real, V<:Real} = banded_matmatmul!(C, 'T', 'T', A, B) - - - -function *(A::BLASBandedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} - n, m = size(A,1), size(B,2) - Y = BandedMatrix(promote_type(T,V), n, m, prodbandwidths(A, B)...) - A_mul_B!(Y,A,B) -end - -function *(A::BLASBandedMatrix{T},B::StridedMatrix{V}) where {T, V} - n, m = size(A,1), size(B,2) - A_mul_B!(Matrix{promote_type(T,V)}(n, m), A, B) -end - -function *(A::StridedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} - n, m = size(A,1), size(B,2) - A_mul_B!(Matrix{promote_type(T,V)}(n, m), A, B) -end - - -Ac_mul_B(A::BLASBandedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = Ac_mul_B!(banded_similar('C', 'N', A, B, promote_type(T, V)), A, B) -Ac_mul_B(A::BLASBandedMatrix{T},B::StridedMatrix{V}) where {T, V} = Ac_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 2)), A, B) -Ac_mul_B(A::StridedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = Ac_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 2)), A, B) -A_mul_Bc(A::BLASBandedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = A_mul_Bc!(banded_similar('N', 'C', A, B, promote_type(T, V)), A, B) -A_mul_Bc(A::BLASBandedMatrix{T},B::StridedMatrix{V}) where {T, V} = A_mul_Bc!(Matrix{promote_type(T,V)}(size(A, 1), size(B, 1)), A, B) -A_mul_Bc(A::StridedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = A_mul_Bc!(Matrix{promote_type(T,V)}(size(A, 1), size(B, 1)), A, B) -Ac_mul_Bc(A::BLASBandedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = Ac_mul_Bc!(banded_similar('C', 'C', A, B, promote_type(T, V)), A, B) -Ac_mul_Bc(A::BLASBandedMatrix{T},B::StridedMatrix{V}) where {T, V} = Ac_mul_Bc!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 1)), A, B) -Ac_mul_Bc(A::StridedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = Ac_mul_Bc!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 1)), A, B) - -At_mul_B(A::BLASBandedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = At_mul_B!(banded_similar('T', 'N', A, B, promote_type(T, V)), A, B) -At_mul_B(A::BLASBandedMatrix{T},B::StridedMatrix{V}) where {T, V} = At_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 2)), A, B) -At_mul_B(A::StridedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = At_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 2)), A, B) -A_mul_Bt(A::BLASBandedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = A_mul_Bt!(banded_similar('N', 'T', A, B, promote_type(T, V)), A, B) -A_mul_Bt(A::BLASBandedMatrix{T},B::StridedMatrix{V}) where {T, V} = A_mul_Bt!(Matrix{promote_type(T,V)}(size(A, 1), size(B, 1)), A, B) -A_mul_Bt(A::StridedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = A_mul_Bt!(Matrix{promote_type(T,V)}(size(A, 1), size(B, 1)), A, B) -At_mul_Bt(A::BLASBandedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = At_mul_B!(banded_similar('T', 'T', A, B, promote_type(T, V)), A, B) -At_mul_Bt(A::BLASBandedMatrix{T},B::StridedMatrix{V}) where {T, V} = At_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 1)), A, B) -At_mul_Bt(A::StridedMatrix{T},B::BLASBandedMatrix{V}) where {T, V} = At_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 1)), A, B) +@_banded_linalg AbstractBandedMatrix ## Method definitions for generic eltypes - will make copies @@ -426,11 +13,11 @@ for typ in [BandedMatrix, BandedLU] end end # \ is different because it needs a copy, but we have to avoid ambiguity - @eval function (\)(A::$typ{T}, B::VecOrMat{Complex{T}}) where {T<:BlasReal} + @eval function \(A::$typ{T}, B::VecOrMat{Complex{T}}) where {T<:BlasReal} checksquare(A) A_ldiv_B!(convert($typ{Complex{T}}, A), copy(B)) # goes to BlasFloat call end - @eval function (\)(A::$typ{T}, B::StridedVecOrMat{S}) where {T<:Number, S<:Number} + @eval function \(A::$typ{T}, B::StridedVecOrMat{S}) where {T<:Number, S<:Number} checksquare(A) TS = _promote_to_blas_type(T, S) A_ldiv_B!(convert($typ{TS}, A), copy_oftype(B, TS)) # goes to BlasFloat call diff --git a/src/deprecate.jl b/src/deprecate.jl index 11f79242..44d99a80 100644 --- a/src/deprecate.jl +++ b/src/deprecate.jl @@ -1 +1,93 @@ @deprecate gbmm!(α::T, A::AbstractMatrix{T}, B::AbstractMatrix{T}, β::T, C::AbstractMatrix{T}) where {T<:BlasFloat} gbmm!('N', 'N', α, A, B, β, C) + + +@deprecate BandedMatrix{T}(n::Integer,::Colon,a::Integer,b::Integer) where {T} BandedMatrix{T}(uninitialized,n,:,a,b) +@deprecate BandedMatrix{T}(n::Integer,m::Integer,a::Integer,b::Integer) where {T} BandedMatrix{T}(uninitialized, n, m, a, b) +@deprecate BandedMatrix{T}(n::Integer,a::Integer,b::Integer) where {T} BandedMatrix{T}(uninitialized, n, n, a, b) + + +@deprecate BandedMatrix(data::Matrix,m::Integer,a) BandedMatrices._BandedMatrix(data,m,-a[1],a[end]) +@deprecate BandedMatrix(::Type{T},n::Integer,m::Integer,a) where {T} BandedMatrix{T}(uninitialized, n,m,-a[1],a[end]) +@deprecate BandedMatrix(::Type{T},n::Integer,::Colon,a) where {T} BandedMatrix{T}(uninitialized, n,:,-a[1],a[end]) +@deprecate BandedMatrix(::Type{T},n::Integer,a) where {T} BandedMatrix{T}(uninitialized, n,-a[1],a[end]) + +@deprecate BandedMatrix(::Type{T},n::Integer,m::Integer,a::Integer,b::Integer) where {T} BandedMatrix{T}(uninitialized, n,m,a,b) + + +@deprecate BandedMatrix(::Type{T},n::Integer,a::Integer,b::Integer) where {T} BandedMatrix{T}(uninitialized, n,a,b) +@deprecate BandedMatrix(::Type{T},n::Integer,::Colon,a::Integer,b::Integer) where {T} BandedMatrix{T}(uninitialized, n,:,a,b) + +@deprecate BandedMatrix{T}(n::Integer,m::Integer,a) where {T} BandedMatrix{T}(uninitialized, n,m,-a[1],a[end]) +@deprecate BandedMatrix{T}(n::Integer,::Colon,a) where {T} BandedMatrix{T}(uninitialized, n,:,-a[1],a[end]) +@deprecate BandedMatrix{T}(n::Integer,a) where {T} BandedMatrix{T}(uninitialized, n,-a[1],a[end]) + +@deprecate bzeros(::Type{T},n::Integer,m::Integer,a::Integer,b::Integer) where {T} BandedMatrix(Zeros{T}(n,m), (a,b)) +@deprecate bzeros(::Type{T},n::Integer,a::Integer,b::Integer) where {T} BandedMatrix(Zeros{T}(n,n), (a,b)) +@deprecate bzeros(::Type{T},n::Integer,::Colon,a::Integer,b::Integer) where {T} BandedMatrix(Zeros{T}(n,n+b), (a,b)) +@deprecate bzeros(::Type{T},::Colon,m::Integer,a::Integer,b::Integer) where {T} BandedMatrix(Zeros{T}(m+a,m), (a,b)) +@deprecate bzeros(n::Integer,m::Integer,a::Integer,b::Integer) BandedMatrix(Zeros(n,m), (a,b)) +@deprecate bzeros(n::Integer,a::Integer,b::Integer) BandedMatrix(Zeros(n,n), (a,b)) + +@deprecate bzeros(::Type{T},n::Integer,m::Integer,a) where {T} BandedMatrix(Zeros(n,m),(-a[1],a[2])) +@deprecate bzeros(::Type{T},n::Number,::Colon,a) where {T} BandedMatrix(Zeros(n,n+a[2]),(-a[1],a[end])) +@deprecate bzeros(::Type{T},::Colon,m::Integer,a) where {T} BandedMatrix(Zeros(m-a[1],m),(-a[1],a[end])) +@deprecate bzeros(::Type{T},n::Integer,a) where {T} BandedMatrix(Zeros{T}(n,n),(-a[1],a[end])) +@deprecate bzeros(n::Integer,m::Integer,a) BandedMatrix(Zeros(n,m),(-a[1],a[end])) +@deprecate bzeros(n::Integer,a) BandedMatrix(Zeros(n,n),(-a[1],a[end])) + +@deprecate bzeros(B::AbstractMatrix) BandedMatrix(Zeros(B),bandwidths(B)) + + +@deprecate bones(::Type{T},n::Integer,m::Integer,a::Integer,b::Integer) where {T} BandedMatrix(Ones{T}(n,m), (a,b)) +@deprecate bones(::Type{T},n::Integer,a::Integer,b::Integer) where {T} BandedMatrix(Ones{T}(n,n), (a,b)) +@deprecate bones(::Type{T},n::Integer,::Colon,a::Integer,b::Integer) where {T} BandedMatrix(Ones{T}(n,n+b), (a,b)) +@deprecate bones(::Type{T},::Colon,m::Integer,a::Integer,b::Integer) where {T} BandedMatrix(Ones{T}(m+a,m), (a,b)) +@deprecate bones(n::Integer,m::Integer,a::Integer,b::Integer) BandedMatrix(Ones(n,m), (a,b)) +@deprecate bones(n::Integer,a::Integer,b::Integer) BandedMatrix(Ones(n,n), (a,b)) + +@deprecate bones(::Type{T},n::Integer,m::Integer,a) where {T} BandedMatrix(Ones(n,m),(-a[1],a[2])) +@deprecate bones(::Type{T},n::Number,::Colon,a) where {T} BandedMatrix(Ones(n,n+a[2]),(-a[1],a[end])) +@deprecate bones(::Type{T},::Colon,m::Integer,a) where {T} BandedMatrix(Ones(m-a[1],m),(-a[1],a[end])) +@deprecate bones(::Type{T},n::Integer,a) where {T} BandedMatrix(Ones{T}(n,n),(-a[1],a[end])) +@deprecate bones(n::Integer,m::Integer,a) BandedMatrix(Ones(n,m),(-a[1],a[end])) +@deprecate bones(n::Integer,a) BandedMatrix(Ones(n,n),(-a[1],a[end])) + +@deprecate bones(B::AbstractMatrix) BandedMatrix(Ones(B),bandwidths(B)) + + + +@deprecate beye(::Type{T},n::Integer,a) where {T} BandedMatrix(Eye{T}(n), (-a[1],a[2])) +@deprecate beye(::Type{T},n::Integer) where {T} BandedMatrix(Eye{T}(n)) +@deprecate beye(n::Integer,m::Integer,a::Integer,b::Integer) BandedMatrix(Eye(n,m),(a,b)) +@deprecate beye(n::Integer) BandedMatrix(Eye(n)) +@deprecate beye(n::Integer,a) BandedMatrix(Eye(n),(-a[1],a[2])) + + + +@deprecate BandedMatrix{T}(data::Matrix{T},m::Integer,l::Int,u::Int) where T BandedMatrices._BandedMatrix(data,m,l,u) +@deprecate BandedMatrix(data::Matrix,m::Integer,l::Int,u::Int) BandedMatrices._BandedMatrix(data,m,l,u) + +@deprecate SymBandedMatrix{T}(n::Integer,k::Integer) where {T} SymBandedMatrix{T}(uninitialized,n::Integer,k::Integer) + +@deprecate SymBandedMatrix{T}(data::Matrix{T},k::Integer) where T BandedMatrices._SymBandedMatrix(data,k) +@deprecate SymBandedMatrix(data::Matrix,k::Integer) BandedMatrices._SymBandedMatrix(data,k) + +@deprecate SymBandedMatrix(::Type{T},n::Integer,k::Integer) where {T} SymBandedMatrix{T}(uninitialized,n,k) + + +@deprecate sbzeros(::Type{T},n::Integer,a::Integer) where {T} SymBandedMatrix(Zeros{T}(n,n),a) +@deprecate sbzeros(n::Integer,a::Integer) SymBandedMatrix(Zeros(n,n),a) + +@deprecate sbzeros(B::AbstractMatrix) SymBandedMatrix(Zeros(B), bandwidths(B)) + + +@deprecate sbones(::Type{T},n::Integer,a::Integer) where {T} SymBandedMatrix(Ones{T}(n,n),a) +@deprecate sbones(n::Integer,a::Integer) SymBandedMatrix(Ones(n,n),a) + +@deprecate sbones(B::AbstractMatrix) SymBandedMatrix(Ones(B), bandwidths(B)) + + + + +@deprecate sbeye(::Type{T},n::Integer,a) where {T} SymBandedMatrix(Eye(n),a) +@deprecate sbeye(n::Integer) SymBandedMatrix(Eye(n)) diff --git a/src/AbstractBandedMatrix.jl b/src/generic/AbstractBandedMatrix.jl similarity index 100% rename from src/AbstractBandedMatrix.jl rename to src/generic/AbstractBandedMatrix.jl diff --git a/src/Band.jl b/src/generic/Band.jl similarity index 71% rename from src/Band.jl rename to src/generic/Band.jl index 595017eb..7cab3a71 100644 --- a/src/Band.jl +++ b/src/generic/Band.jl @@ -3,6 +3,8 @@ struct Band i::Int end +show(io::IO, r::Band) = print(io, "Band(", r.i, ")") + doc""" band(i) @@ -64,6 +66,10 @@ struct BandError <: Exception i::Int end +# shorthand to specify k and j without calculating band +BandError(A::AbstractMatrix, kj::Tuple{Int,Int}) = BandError(A, kj[2]-kj[1]) +BandError(A::AbstractMatrix) = BandError(A, max(size(A)...)-1) + function showerror(io::IO, e::BandError) A, i = e.A, e.i print(io, "attempt to access $(typeof(A)) with bandwidths " * @@ -100,12 +106,12 @@ checkband(A::AbstractMatrix, kr::AbstractRange, jr::AbstractRange) = function checkbandmatch(A::AbstractMatrix{T}, V::AbstractVector, ::Colon, j::Integer) where {T} for k = 1:colstart(A,j)-1 if V[k] ≠ zero(T) - throw(BandError(A, j-k)) + throw(BandError(A, (k,j))) end end for k = colstop(A,j)+1:size(A,1) if V[k] ≠ zero(T) - throw(BandError(A, j-k)) + throw(BandError(A, (k,j))) end end end @@ -117,7 +123,7 @@ function checkbandmatch(A::AbstractMatrix{T}, V::AbstractVector, kr::AbstractRan for v in V k = kr[i+=1] if (k < a || k > b) && v ≠ zero(T) - throw(BandError(A, j-k)) + throw(BandError(A, (k,j))) end end end @@ -125,12 +131,12 @@ end function checkbandmatch(A::AbstractMatrix{T}, V::AbstractVector, k::Integer, ::Colon) where {T} for j = 1:rowstart(A,k)-1 if V[j] ≠ zero(T) - throw(BandError(A, j-k)) + throw(BandError(A, (k,j))) end end for j = rowstop(A,j)+1:size(A,2) if V[j] ≠ zero(T) - throw(BandError(A, j-k)) + throw(BandError(A, (k,j))) end end end @@ -142,7 +148,7 @@ function checkbandmatch(A::AbstractMatrix{T}, V::AbstractVector, k::Integer, jr: for v in V j = jr[i+=1] if (j < a || j > b) && v ≠ zero(T) - throw(BandError(A, j-k)) + throw(BandError(A, (k,j))) end end end @@ -155,7 +161,7 @@ function checkbandmatch(A::AbstractMatrix{T}, V::AbstractMatrix, kr::AbstractRan for k in kr if !(-l ≤ j - k ≤ u) && V[kk, jj] ≠ zero(T) # we index V manually in column-major order - throw(BandError(A, j-k)) + throw(BandError(A, (k,j))) end kk += 1 end @@ -165,3 +171,34 @@ end checkbandmatch(A::AbstractMatrix, V::AbstractMatrix, ::Colon, ::Colon) = checkbandmatch(A, V, 1:size(A,1), 1:size(A,2)) + +""" + BandSlice(band, indices) + +Represent an AbstractUnitRange of indices corresponding to a band. + +Upon calling `to_indices()`, Bands are converted to BandSlice objects to represent +the indices over which the Band spans. + +This mimics the relationship between `Colon` and `Base.Slice`. +""" + + +struct BandSlice <: OrdinalRange{Int,Int} + band::Band + indices::StepRange{Int,Int} +end + +for f in (:indices, :unsafe_indices, :indices1, :first, :last, :size, :length, + :unsafe_length, :start, :step) + @eval $f(S::BandSlice) = $f(S.indices) +end + +getindex(S::BandSlice, i::Int) = getindex(S.indices, i) +show(io::IO, r::BandSlice) = print(io, "BandSlice(", r.band, ",", r.indices, ")") +next(S::BandSlice, s) = next(S.indices, s) +done(S::BandSlice, s) = done(S.indices, s) + +to_index(::Band) = throw(ArgumentError("Block must be converted by to_indices(...)")) + +@inline to_indices(A, I::Tuple{Band}) = (BandSlice(I[1], diagind(A, I[1].i)),) diff --git a/src/generic/interface.jl b/src/generic/interface.jl new file mode 100644 index 00000000..3be19540 --- /dev/null +++ b/src/generic/interface.jl @@ -0,0 +1,614 @@ + +#### +# Matrix memory layout traits +# +# if MemoryLayout(A) returns BandedLayout, you must override +# pointer and leadingdimension +# in addition to the banded matrix interface +#### + +abstract type MemoryLayout{T} end +struct UnknownLayout{T} <: MemoryLayout{T} end +abstract type AbstractStridedLayout{T} <: MemoryLayout{T} end +abstract type AbstractColumnMajor{T} <: AbstractStridedLayout{T} end +struct DenseColumnMajor{T} <: AbstractColumnMajor{T} end +struct ColumnMajor{T} <: AbstractColumnMajor{T} end +abstract type AbstractRowMajor{T} <: AbstractStridedLayout{T} end +struct DenseRowMajor{T} <: AbstractRowMajor{T} end +struct RowMajor{T} <: AbstractRowMajor{T} end +struct StridedLayout{T} <: AbstractStridedLayout{T} end + + +struct BandedLayout{T} <: MemoryLayout{T} end +struct SymBandedLayout{T} <: MemoryLayout{T} end + +MemoryLayout(A::AbstractArray{T}) where T = UnknownLayout{T}() +MemoryLayout(A::Vector{T}) where T = DenseColumnMajor{T}() +MemoryLayout(A::Matrix{T}) where T = DenseColumnMajor{T}() + +import Base: AbstractCartesianIndex, Slice + +MemoryLayout(A::SubArray) = submemorylayout(MemoryLayout(parent(A)), parentindexes(A)) +submemorylayout(::MemoryLayout{T}, _) where T = UnknownLayout{T}() +submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I}) where {T,I<:Union{RangeIndex,AbstractCartesianIndex}} = + StridedLayout{T}() +submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I,Int}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I,Int}) where {T,I<:Slice} = + DenseColumnMajor{T}() +submemorylayout(::AbstractRowMajor{T}, ::Tuple{Int,I}) where {T,I<:Union{AbstractUnitRange{Int},Int,AbstractCartesianIndex}} = + DenseColumnMajor{T}() +submemorylayout(::AbstractRowMajor{T}, ::Tuple{Int,I}) where {T,I<:Slice} = + DenseColumnMajor{T}() +submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:Slice,I2<:AbstractUnitRange{Int}} = + DenseColumnMajor{T}() +submemorylayout(::DenseColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + ColumnMajor{T}() +submemorylayout(::AbstractColumnMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + ColumnMajor{T}() +submemorylayout(::AbstractRowMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:Slice} = + DenseRowMajor{T}() +submemorylayout(::AbstractRowMajor{T}, ::Tuple{I1,I2}) where {T,I1<:AbstractUnitRange{Int},I2<:AbstractUnitRange{Int}} = + RowMajor{T}() +submemorylayout(::AbstractStridedLayout{T}, ::Tuple{I1,I2}) where {T,I1<:Union{RangeIndex,AbstractCartesianIndex},I2<:Union{RangeIndex,AbstractCartesianIndex}} = + StridedLayout{T}() + + + +# copy! + +function banded_copy!(dest::AbstractMatrix{T}, src::AbstractMatrix) where T + m,n = size(dest) + (m,n) == size(src) || throw(DimensionMismatch()) + + d_l, d_u = bandwidths(dest) + s_l, s_u = bandwidths(src) + (d_l ≥ s_l && d_u ≥ s_u) || throw(BandError(dest)) + for j=1:n + for k = max(1,j-d_u):min(j-s_u-1,m) + inbands_setindex!(dest, zero(T), k, j) + end + for k = max(1,j-s_u):min(j+s_l,m) + inbands_setindex!(dest, inbands_getindex(src, k, j), k, j) + end + for k = max(1,j+s_l+1):min(j+d_l,m) + inbands_setindex!(dest, zero(T), k, j) + end + end + dest +end + +# these are the routines of the banded interface of other AbstractMatrices +banded_axpy!(a::Number, X::AbstractMatrix, Y::AbstractMatrix) = _banded_axpy!(a, X, Y, MemoryLayout(X), MemoryLayout(Y)) +_banded_axpy!(a::Number, X::AbstractMatrix, Y::AbstractMatrix, ::BandedLayout, ::BandedLayout) = + banded_generic_axpy!(a, X, Y) +_banded_axpy!(a::Number, X::AbstractMatrix, Y::AbstractMatrix, notbandedX, notbandedY) = + banded_dense_axpy!(a, X, Y) + + +# matrix * vector +banded_matvecmul!(c::AbstractVector, tA::Char, A::AbstractMatrix, b::AbstractVector) = + _banded_matvecmul!(c, tA, A, b, MemoryLayout(c), MemoryLayout(A), MemoryLayout(b)) +_banded_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{T}, b::AbstractVector{T}, + ::StridedLayout{T}, ::BandedLayout{T}, ::StridedLayout{T}) where {T <: BlasFloat} = + generally_banded_matvecmul!(c, tA, A, b) +_banded_matvecmul!(c::AbstractVector, tA::Char, A::AbstractMatrix, b::AbstractVector, + notblasc, notblasA, notblasb) = + banded_generic_matvecmul!(c, tA, A, b) + + +banded_A_mul_B!(c::AbstractVector, A::AbstractMatrix, b::AbstractVector) = banded_matvecmul!(c, 'N', A, b) +banded_Ac_mul_B!(c::AbstractVector, A::AbstractMatrix, b::AbstractVector) = banded_matvecmul!(c, 'C', A, b) +banded_At_mul_B!(c::AbstractVector, A::AbstractMatrix, b::AbstractVector) = banded_matvecmul!(c, 'T', A, b) + + +# matrix * matrix +banded_matmatmul!(C::AbstractMatrix, tA::Char, tB::Char, A::AbstractMatrix, B::AbstractMatrix) = + banded_matmatmul!(C, tA, tB, A, B, MemoryLayout(A), MemoryLayout(B)) +banded_matmatmul!(C::AbstractMatrix, tA::Char, tB::Char, A::AbstractMatrix, B::AbstractMatrix, + notblasA, notblasB) = + banded_generic_matmatmul!(C, tA, tB, A, B) +banded_matmatmul!(C::AbstractMatrix, tA::Char, tB::Char, A::AbstractMatrix, B::AbstractMatrix, + ::BandedLayout, ::BandedLayout) = + generally_banded_matmatmul!(C, tA, tB, A, B) + + + +banded_A_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'N', A, B) +banded_Ac_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'C', 'N', A, B) +banded_At_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'T', 'N', A, B) +banded_A_mul_Bc!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'C', A, B) +banded_A_mul_Bt!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'T', A, B) +banded_Ac_mul_Bc!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'C', 'C', A, B) +banded_At_mul_Bt!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'T', 'T', A, B) + + + +# some default functions + + + +# additions and subtractions + + +@propagate_inbounds function banded_generic_axpy!(a::Number, X::AbstractMatrix, Y::AbstractMatrix) + n,m = size(X) + if (n,m) ≠ size(Y) + throw(BoundsError()) + end + Xl, Xu = bandwidths(X) + Yl, Yu = bandwidths(Y) + + @boundscheck if Xl > Yl + # test that all entries are zero in extra bands + for j=1:size(X,2),k=max(1,j+Yl+1):min(j+Xl,n) + if inbands_getindex(X, k, j) ≠ 0 + throw(BandError(X, (k,j))) + end + end + end + @boundscheck if Xu > Yu + # test that all entries are zero in extra bands + for j=1:size(X,2),k=max(1,j-Xu):min(j-Yu-1,n) + if inbands_getindex(X, k, j) ≠ 0 + throw(BandError(X, (k,j))) + end + end + end + + l = min(Xl,Yl) + u = min(Xu,Yu) + + @inbounds for j=1:m,k=max(1,j-u):min(n,j+l) + inbands_setindex!(Y, a*inbands_getindex(X,k,j) + inbands_getindex(Y,k,j) ,k, j) + end + Y +end + +function banded_dense_axpy!(a::Number, X::AbstractMatrix, Y::AbstractMatrix) + if size(X) != size(Y) + throw(DimensionMismatch("+")) + end + @inbounds for j=1:size(X,2),k=colrange(X,j) + Y[k,j] += a*inbands_getindex(X,k,j) + end + Y +end + + +# matrix * vector + +function _banded_generic_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{U}, b::AbstractVector{V}) where {T, U, V} + @inbounds c[:] = zero(T) + if tA == 'N' + @inbounds for j = 1:size(A,2), k = colrange(A,j) + c[k] += inbands_getindex(A,k,j)*b[j] + end + elseif tA == 'C' + @inbounds for j = 1:size(A,2), k = colrange(A,j) + c[j] += inbands_getindex(A,k,j)'*b[k] + end + elseif tA == 'T' + @inbounds for j = 1:size(A,2), k = colrange(A,j) + c[j] += inbands_getindex(A,k,j)*b[k] + end + end + c +end + + +positively_banded_matvecmul!(c::AbstractVector, tA::Char, A::AbstractMatrix, b::AbstractVector) = + _positively_banded_matvecmul!(c, tA, A, b, MemoryLayout(c), MemoryLayout(A), MemoryLayout(b)) +_positively_banded_matvecmul!(c::AbstractVector, tA::Char, A::AbstractMatrix, b::AbstractVector, + notblasc, notblasA, notblasb) = + _banded_generic_matvecmul!(c, tA, A, b) + +# use BLAS routine for positively banded BlasBanded +_positively_banded_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{T}, b::AbstractVector{T}, + ::StridedLayout{T}, ::BandedLayout{T}, ::StridedLayout{T}) where {T <: BlasFloat} = + gbmv!(tA, one(T), A, b, zero(T), c) + +positively_banded_matmatmul!(C::AbstractMatrix, tA::Char, tB::Char, A::AbstractMatrix, B::AbstractMatrix) = + _positively_banded_matmatmul!(C, tA, tB, A, B, MemoryLayout(C), MemoryLayout(A), MemoryLayout(B)) +_positively_banded_matmatmul!(C::AbstractMatrix, tA::Char, tB::Char, A::AbstractMatrix, B::AbstractMatrix, + notblasC, notblasA, notblasb) = + _banded_generic_matmatmul!(C, tA, tB, A, B) + +function generally_banded_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{U}, b::AbstractVector{V}) where {T, U, V} + m, n = _size(tA, A) + if length(c) ≠ m || length(b) ≠ n + throw(DimensionMismatch("*")) + end + + l, u = _bandwidths(tA, A) + if -l > u + # no bands + c[:] = zero(T) + elseif l < 0 + banded_matvecmul!(c, tA, _view(tA, A, :, 1-l:n), view(b, 1-l:n)) + elseif u < 0 + c[1:-u] = zero(T) + banded_matvecmul!(view(c, 1-u:m), tA, _view(tA, A, 1-u:m, :), b) + else + positively_banded_matvecmul!(c, tA, A, b) + end + c +end + +banded_generic_matvecmul!(c::AbstractVector, tA::Char, A::AbstractMatrix, b::AbstractVector) = + generally_banded_matvecmul!(c, tA, A, b) + + + +# matrix * matrix +function _banded_generic_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{U}, B::AbstractMatrix{V}) where {T, U, V} + Am, An = _size(tA, A) + Bm, Bn = _size(tB, B) + Al, Au = _bandwidths(tA, A) + Bl, Bu = _bandwidths(tB, B) + Cl,Cu = prodbandwidths(tA, tB, A, B) + + if tA == 'N' && tB == 'N' + @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) + νmin = max(1,k-Al,j-Bu) + νmax = min(An,k+Au,j+Bl) + + tmp = zero(T) + for ν=νmin:νmax + tmp = tmp + inbands_getindex(A,k,ν) * inbands_getindex(B,ν,j) + end + inbands_setindex!(C,tmp,k,j) + end + elseif tA == 'C' && tB == 'N' + @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) + νmin = max(1,k-Al,j-Bu) + νmax = min(An,k+Au,j+Bl) + + tmp = zero(T) + for ν=νmin:νmax + tmp = tmp + inbands_getindex(A,ν,k)' * inbands_getindex(B,ν,j) + end + inbands_setindex!(C,tmp,k,j) + end + elseif tA == 'N' && tB == 'C' + @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) + νmin = max(1,k-Al,j-Bu) + νmax = min(An,k+Au,j+Bl) + + tmp = zero(T) + for ν=νmin:νmax + tmp = tmp + inbands_getindex(A,k,ν) * inbands_getindex(B,j,ν)' + end + inbands_setindex!(C,tmp,k,j) + end + elseif tA == 'C' && tB == 'C' + @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) + νmin = max(1,k-Al,j-Bu) + νmax = min(An,k+Au,j+Bl) + + tmp = zero(T) + for ν=νmin:νmax + tmp = tmp + inbands_getindex(A,ν,k)' * inbands_getindex(B,j,ν)' + end + inbands_setindex!(C,tmp,k,j) + end + elseif tA == 'T' && tB == 'N' + @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) + νmin = max(1,k-Al,j-Bu) + νmax = min(An,k+Au,j+Bl) + + tmp = zero(T) + for ν=νmin:νmax + tmp = tmp + inbands_getindex(A,ν,k) * inbands_getindex(B,ν,j) + end + inbands_setindex!(C,tmp,k,j) + end + + elseif tA == 'N' && tB == 'T' + @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) + νmin = max(1,k-Al,j-Bu) + νmax = min(An,k+Au,j+Bl) + + tmp = zero(T) + for ν=νmin:νmax + tmp = tmp + inbands_getindex(A,k,ν) * inbands_getindex(B,j,ν) + end + inbands_setindex!(C,tmp,k,j) + end + elseif tA == 'T' && tB == 'T' + @inbounds for j = 1:Bn, k = max(j-Cu, 1):max(min(j+Cl, Am), 0) + νmin = max(1,k-Al,j-Bu) + νmax = min(An,k+Au,j+Bl) + + tmp = zero(T) + for ν=νmin:νmax + tmp = tmp + inbands_getindex(A,ν,k) * inbands_getindex(B,j,ν) + end + inbands_setindex!(C,tmp,k,j) + end + end + C +end + +# use BLAS routine for positively banded BlasBandedMatrices +function _positively_banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{T}, B::AbstractMatrix{T}, + ::BandedLayout{T}, ::BandedLayout{T}, ::BandedLayout{T}) where {T} + Al, Au = _bandwidths(tA, A) + Bl, Bu = _bandwidths(tB, B) + # _banded_generic_matmatmul! is faster for sparse matrix + if tA != 'N' || tB != 'N' || (Al + Au < 100 && Bl + Bu < 100) + _banded_generic_matmatmul!(C, tA, tB, A, B) + else + # TODO: implement gbmm! routines for other flags + gbmm!('N', 'N', one(T), A, B, zero(T), C) + end +end + + +function generally_banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{U}, B::AbstractMatrix{V}) where {T, U, V} + Am, An = _size(tA, A) + Bm, Bn = _size(tB, B) + if An != Bm || size(C, 1) != Am || size(C, 2) != Bn + throw(DimensionMismatch("*")) + end + # TODO: checkbandmatch + + Al, Au = _bandwidths(tA, A) + Bl, Bu = _bandwidths(tB, B) + + if (-Al > Au) || (-Bl > Bu) # A or B has empty bands + C[:,:] = zero(T) + elseif Al < 0 + C[max(1,Bn+Al-1):Am, :] = zero(T) + banded_matmatmul!(C, tA, tB, _view(tA, A, :, 1-Al:An), _view(tB, B, 1-Al:An, :)) + elseif Au < 0 + C[1:-Au,:] = zero(T) + banded_matmatmul!(view(C, 1-Au:Am,:), tA, tB, _view(tA, A, 1-Au:Am,:), B) + elseif Bl < 0 + C[:, 1:-Bl] = zero(T) + banded_matmatmul!(view(C, :, 1-Bl:Bn), tA, tB, A, _view(tB, B, :, 1-Bl:Bn)) + elseif Bu < 0 + C[:, max(1,Am+Bu-1):Bn] = zero(T) + banded_matmatmul!(C, tA, tB, _view(tA, A, :, 1-Bu:Bm), _view(tB, B, 1-Bu:Bm, :)) + else + positively_banded_matmatmul!(C, tA::Char, tB::Char, A, B) + end + C +end + + +banded_generic_matmatmul!(C::AbstractMatrix, tA::Char, tB::Char, A::AbstractMatrix, B::AbstractMatrix) = + generally_banded_matmatmul!(C, tA, tB, A, B) + + + +# add banded linear algebra routines between Typ1 and Typ2 both implementing +# the BandedMatrix interface +macro _banded_banded_linalg(Typ1, Typ2) + ret = quote + Base.copy!(dest::$Typ1, src::$Typ2) = BandedMatrices.banded_copy!(dest,src) + Base.BLAS.axpy!(a::Number, X::$Typ1, Y::$Typ2) = BandedMatrices.banded_axpy!(a, X, Y) + + function Base.:+(A::$Typ1{T}, B::$Typ2{V}) where {T,V} + n, m = size(A) + ret = BandedMatrices.BandedMatrix(BandedMatrices.Zeros{promote_type(T,V)}(n, m), BandedMatrices.sumbandwidths(A, B)) + axpy!(one(T), A, ret) + axpy!(one(V), B, ret) + ret + end + + function Base.:-(A::$Typ1{T}, B::$Typ2{V}) where {T,V} + n, m=size(A) + ret = BandedMatrices.BandedMatrix(BandedMatrices.Zeros{promote_type(T,V)}(n, m), BandedMatrices.sumbandwidths(A, B)) + axpy!(one(T), A, ret) + axpy!(-one(V), B, ret) + ret + end + + + Base.LinAlg.A_mul_B!(C::AbstractMatrix, A::$Typ1, B::$Typ2) = banded_matmatmul!(C, 'N', 'N', A, B) + + Base.LinAlg.Ac_mul_B!(C::AbstractMatrix, A::$Typ1, B::$Typ2) = BandedMatrices.banded_matmatmul!(C, 'C', 'N', A, B) + Base.LinAlg.A_mul_Bc!(C::AbstractMatrix, A::$Typ1, B::$Typ2) = BandedMatrices.banded_matmatmul!(C, 'N', 'C', A, B) + Base.LinAlg.Ac_mul_Bc!(C::AbstractMatrix, A::$Typ1, B::$Typ2) = BandedMatrices.banded_matmatmul!(C, 'C', 'C', A, B) + + Base.LinAlg.At_mul_B!(C::AbstractMatrix, A::$Typ1, B::$Typ2) = BandedMatrices.banded_matmatmul!(C, 'T', 'N', A, B) + Base.LinAlg.A_mul_Bt!(C::AbstractMatrix, A::$Typ1, B::$Typ2) = BandedMatrices.banded_matmatmul!(C, 'N', 'T', A, B) + Base.LinAlg.At_mul_Bt!(C::AbstractMatrix, A::$Typ1, B::$Typ2) = BandedMatrices.banded_matmatmul!(C, 'T', 'T', A, B) + + # override the Ac_mul_B, A_mul_Bc and Ac_mul_c for real values + Base.LinAlg.Ac_mul_B!(C::AbstractMatrix{T}, A::$Typ1{U}, B::$Typ2{V}) where {T, U<:Real, V} = BandedMatrices.banded_matmatmul!(C, 'T', 'N', A, B) + Base.LinAlg.A_mul_Bc!(C::AbstractMatrix{T}, A::$Typ1{U}, B::$Typ2{V}) where {T, U, V<:Real} = BandedMatrices.banded_matmatmul!(C, 'N', 'T', A, B) + Base.LinAlg.Ac_mul_Bc!(C::AbstractMatrix{T}, A::$Typ1{U}, B::$Typ2{V}) where {T, U<:Real, V<:Real} = BandedMatrices.banded_matmatmul!(C, 'T', 'T', A, B) + + function Base.:*(A::$Typ1{T}, B::$Typ2{V}) where {T, V} + n, m = size(A,1), size(B,2) + Y = BandedMatrix{promote_type(T,V)}(uninitialized, n, m, prodbandwidths(A, B)...) + A_mul_B!(Y, A, B) + end + + Base.LinAlg.Ac_mul_B(A::$Typ1{T}, B::$Typ2{V}) where {T, V} = Ac_mul_B!(BandedMatrices.banded_similar('C', 'N', A, B, promote_type(T, V)), A, B) + Base.LinAlg.A_mul_Bc(A::$Typ1{T}, B::$Typ2{V}) where {T, V} = A_mul_Bc!(BandedMatrices.banded_similar('N', 'C', A, B, promote_type(T, V)), A, B) + Base.LinAlg.Ac_mul_Bc(A::$Typ1{T}, B::$Typ2{V}) where {T, V} = Ac_mul_Bc!(BandedMatrices.banded_similar('C', 'C', A, B, promote_type(T, V)), A, B) + + Base.LinAlg.At_mul_B(A::$Typ1{T}, B::$Typ2{V}) where {T, V} = At_mul_B!(BandedMatrices.banded_similar('T', 'N', A, B, promote_type(T, V)), A, B) + Base.LinAlg.A_mul_Bt(A::$Typ1{T}, B::$Typ2{V}) where {T, V} = A_mul_Bt!(BandedMatrices.banded_similar('N', 'T', A, B, promote_type(T, V)), A, B) + Base.LinAlg.At_mul_Bt(A::$Typ1{T}, B::$Typ2{V}) where {T, V} = At_mul_B!(BandedMatrices.banded_similar('T', 'T', A, B, promote_type(T, V)), A, B) + end + esc(ret) +end + +macro banded_banded_linalg(Typ1, Typ2) + ret = quote + BandedMatrices.@_banded_banded_linalg($Typ1, $Typ2) + end + if Typ1 ≠ Typ2 + ret = quote + $ret + BandedMatrices.@_banded_banded_linalg($Typ2, $Typ1) + end + end + esc(ret) +end + +# add banded linear algebra routines for Typ implementing the BandedMatrix interface +macro _banded_linalg(Typ) + ret = quote + BandedMatrices.@banded_banded_linalg($Typ, $Typ) + + Base.BLAS.axpy!(a::Number, X::$Typ, Y::AbstractMatrix) = + BandedMatrices.banded_axpy!(a, X, Y) + function Base.:+(A::$Typ{T}, B::AbstractMatrix{T}) where {T} + ret = deepcopy(B) + axpy!(one(T), A, ret) + ret + end + function Base.:+(A::$Typ{T}, B::AbstractMatrix{V}) where {T,V} + n, m=size(A) + ret = zeros(promote_type(T,V),n,m) + axpy!(one(T), A,ret) + axpy!(one(V), B,ret) + ret + end + Base.:+(A::AbstractMatrix{T}, B::$Typ{V}) where {T,V} = B + A + + function Base.:-(A::$Typ{T}, B::AbstractMatrix{T}) where {T} + ret = deepcopy(B) + Base.scale!(ret, -one(T)) + Base.BLAS.axpy!(one(T), A, ret) + ret + end + function Base.:-(A::$Typ{T}, B::AbstractMatrix{V}) where {T,V} + n, m= size(A) + ret = zeros(promote_type(T,V),n,m) + Base.BLAS.axpy!( one(T), A, ret) + Base.BLAS.axpy!(-one(V), B, ret) + ret + end + Base.:-(A::AbstractMatrix{T}, B::$Typ{V}) where {T,V} = Base.scale!(B - A, -1) + + + + ## UniformScaling + + function Base.BLAS.axpy!(a::Number, X::UniformScaling, Y::$Typ{T}) where {T} + BandedMatrices.checksquare(Y) + α = a * X.λ + @inbounds for k = 1:size(Y,1) + BandedMatrices.inbands_setindex!(Y, BandedMatrices.inbands_getindex(Y, k, k) + α, k, k) + end + Y + end + + function Base.:+(A::$Typ, B::UniformScaling) + ret = deepcopy(A) + Base.BLAS.axpy!(1, B,ret) + end + + Base.:+(A::UniformScaling, B::$Typ) = B + A + + function Base.:-(A::$Typ, B::UniformScaling) + ret = deepcopy(A) + axpy!(-1, B, ret) + end + + function Base.:-(A::UniformScaling, B::$Typ) + ret = deepcopy(B) + Base.scale!(ret, -1) + axpy!(1, A, ret) + end + + Base.LinAlg.A_mul_B!(c::AbstractVector, A::$Typ, b::AbstractVector) = + BandedMatrices.banded_matvecmul!(c, 'N', A, b) + Base.LinAlg.Ac_mul_B!(c::AbstractVector, A::$Typ, b::AbstractVector) = + BandedMatrices.banded_matvecmul!(c, 'C', A, b) + Base.LinAlg.Ac_mul_B!(c::AbstractVector, A::$Typ{<:Real}, b::AbstractVector) = + BandedMatrices.banded_matvecmul!(c, 'T', A, b) + Base.LinAlg.At_mul_B!(c::AbstractVector, A::$Typ, b::AbstractVector) = + BandedMatrices.banded_matvecmul!(c, 'T', A, b) + + Base.:*(A::$Typ{U}, b::StridedVector{V}) where {U, V} = + Base.LinAlg.A_mul_B!(Vector{promote_type(U, V)}(size(A, 1)), A, b) + + + Base.LinAlg.A_mul_B!(C::AbstractMatrix, A::$Typ, B::AbstractMatrix) = BandedMatrices.banded_matmatmul!(C, 'N', 'N', A, B) + Base.LinAlg.A_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::$Typ) = BandedMatrices.banded_matmatmul!(C, 'N', 'N', A, B) + + + + Base.LinAlg.Ac_mul_B!(C::AbstractMatrix, A::$Typ, B::AbstractMatrix) = BandedMatrices.banded_matmatmul!(C, 'C', 'N', A, B) + Base.LinAlg.Ac_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::$Typ) = BandedMatrices.banded_matmatmul!(C, 'C', 'N', A, B) + Base.LinAlg.A_mul_Bc!(C::AbstractMatrix, A::$Typ, B::AbstractMatrix) = BandedMatrices.banded_matmatmul!(C, 'N', 'C', A, B) + Base.LinAlg.A_mul_Bc!(C::AbstractMatrix, A::AbstractMatrix, B::$Typ) = BandedMatrices.banded_matmatmul!(C, 'N', 'C', A, B) + Base.LinAlg.Ac_mul_Bc!(C::AbstractMatrix, A::$Typ, B::AbstractMatrix) = BandedMatrices.banded_matmatmul!(C, 'C', 'C', A, B) + Base.LinAlg.Ac_mul_Bc!(C::AbstractMatrix, A::AbstractMatrix, B::$Typ) = BandedMatrices.banded_matmatmul!(C, 'C', 'C', A, B) + + Base.LinAlg.At_mul_B!(C::AbstractMatrix, A::$Typ, B::AbstractMatrix) = BandedMatrices.banded_matmatmul!(C, 'T', 'N', A, B) + Base.LinAlg.At_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::$Typ) = BandedMatrices.banded_matmatmul!(C, 'T', 'N', A, B) + Base.LinAlg.A_mul_Bt!(C::AbstractMatrix, A::$Typ, B::AbstractMatrix) = BandedMatrices.banded_matmatmul!(C, 'N', 'T', A, B) + Base.LinAlg.A_mul_Bt!(C::AbstractMatrix, A::AbstractMatrix, B::$Typ) = BandedMatrices.banded_matmatmul!(C, 'N', 'T', A, B) + Base.LinAlg.At_mul_Bt!(C::AbstractMatrix, A::$Typ, B::AbstractMatrix) = BandedMatrices.banded_matmatmul!(C, 'T', 'T', A, B) + Base.LinAlg.At_mul_Bt!(C::AbstractMatrix, A::AbstractMatrix, B::$Typ) = BandedMatrices.banded_matmatmul!(C, 'T', 'T', A, B) + + # override the Ac_mul_B, A_mul_Bc and Ac_mul_c for real values + Base.LinAlg.Ac_mul_B!(C::AbstractMatrix{T}, A::$Typ{U}, B::AbstractMatrix{V}) where {T, U<:Real, V} = BandedMatrices.banded_matmatmul!(C, 'T', 'N', A, B) + Base.LinAlg.Ac_mul_B!(C::AbstractMatrix{T}, A::AbstractMatrix{U}, B::$Typ{V}) where {T, U<:Real, V} = BandedMatrices.banded_matmatmul!(C, 'T', 'N', A, B) + Base.LinAlg.A_mul_Bc!(C::AbstractMatrix{T}, A::$Typ{U}, B::AbstractMatrix{V}) where {T, U, V<:Real} = BandedMatrices.banded_matmatmul!(C, 'N', 'T', A, B) + Base.LinAlg.A_mul_Bc!(C::AbstractMatrix{T}, A::AbstractMatrix{U}, B::$Typ{V}) where {T, U, V<:Real} = BandedMatrices.banded_matmatmul!(C, 'N', 'T', A, B) + Base.LinAlg.Ac_mul_Bc!(C::AbstractMatrix{T}, A::$Typ{U}, B::AbstractMatrix{V}) where {T, U<:Real, V<:Real} = BandedMatrices.banded_matmatmul!(C, 'T', 'T', A, B) + Base.LinAlg.Ac_mul_Bc!(C::AbstractMatrix{T}, A::AbstractMatrix{U}, B::$Typ{V}) where {T, U<:Real, V<:Real} = BandedMatrices.banded_matmatmul!(C, 'T', 'T', A, B) + + + function Base.:*(A::$Typ{T}, B::StridedMatrix{V}) where {T, V} + n, m = size(A,1), size(B,2) + A_mul_B!(Matrix{promote_type(T,V)}(n, m), A, B) + end + + function Base.:*(A::StridedMatrix{T}, B::$Typ{V}) where {T, V} + n, m = size(A,1), size(B,2) + A_mul_B!(Matrix{promote_type(T,V)}(n, m), A, B) + end + + Base.LinAlg.Ac_mul_B(A::$Typ{T}, B::StridedMatrix{V}) where {T, V} = Ac_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 2)), A, B) + Base.LinAlg.Ac_mul_B(A::StridedMatrix{T}, B::$Typ{V}) where {T, V} = Ac_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 2)), A, B) + Base.LinAlg.A_mul_Bc(A::$Typ{T}, B::StridedMatrix{V}) where {T, V} = A_mul_Bc!(Matrix{promote_type(T,V)}(size(A, 1), size(B, 1)), A, B) + Base.LinAlg.A_mul_Bc(A::StridedMatrix{T}, B::$Typ{V}) where {T, V} = A_mul_Bc!(Matrix{promote_type(T,V)}(size(A, 1), size(B, 1)), A, B) + Base.LinAlg.Ac_mul_Bc(A::$Typ{T}, B::StridedMatrix{V}) where {T, V} = Ac_mul_Bc!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 1)), A, B) + Base.LinAlg.Ac_mul_Bc(A::StridedMatrix{T}, B::$Typ{V}) where {T, V} = Ac_mul_Bc!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 1)), A, B) + + Base.LinAlg.At_mul_B(A::$Typ{T}, B::StridedMatrix{V}) where {T, V} = At_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 2)), A, B) + Base.LinAlg.At_mul_B(A::StridedMatrix{T}, B::$Typ{V}) where {T, V} = At_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 2)), A, B) + Base.LinAlg.A_mul_Bt(A::$Typ{T}, B::StridedMatrix{V}) where {T, V} = A_mul_Bt!(Matrix{promote_type(T,V)}(size(A, 1), size(B, 1)), A, B) + Base.LinAlg.A_mul_Bt(A::StridedMatrix{T}, B::$Typ{V}) where {T, V} = A_mul_Bt!(Matrix{promote_type(T,V)}(size(A, 1), size(B, 1)), A, B) + Base.LinAlg.At_mul_Bt(A::$Typ{T}, B::StridedMatrix{V}) where {T, V} = At_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 1)), A, B) + Base.LinAlg.At_mul_Bt(A::StridedMatrix{T}, B::$Typ{V}) where {T, V} = At_mul_B!(Matrix{promote_type(T,V)}(size(A, 2), size(B, 1)), A, B) + end + esc(ret) +end + +macro banded_linalg(Typ) + ret = quote + BandedMatrices.@_banded_linalg($Typ) + BandedMatrices.@banded_banded_linalg($Typ, BandedMatrices.AbstractBandedMatrix) + end + esc(ret) +end + +# add routines for banded interface +macro banded_interface(Typ) + ret = quote + BandedMatrices.MemoryLayout(A::$Typ) = BandedMatrices.BandedLayout{eltype(A)}() + BandedMatrices.isbanded(::$Typ) = true + end + esc(ret) +end + +macro banded(Typ) + ret = quote + BandedMatrices.@banded_interface($Typ) + BandedMatrices.@banded_linalg($Typ) + end + esc(ret) +end diff --git a/src/utils.jl b/src/generic/utils.jl similarity index 96% rename from src/utils.jl rename to src/generic/utils.jl index 370e15b1..b266d26e 100644 --- a/src/utils.jl +++ b/src/generic/utils.jl @@ -52,7 +52,7 @@ end prodbandwidths(A::AbstractMatrix, B::AbstractMatrix) = prodbandwidths('N', 'N', A, B) function banded_similar(tA::Char, tB::Char, A::AbstractMatrix, B::AbstractMatrix, T::DataType) - BandedMatrix(T, _size(tA, A, 1), _size(tB, B, 2), prodbandwidths(tA, tB, A, B)...) + BandedMatrix{T}(uninitialized, _size(tA, A, 1), _size(tB, B, 2), prodbandwidths(tA, tB, A, B)...) end # helper functions in matrix addition routines diff --git a/src/interface.jl b/src/interface.jl deleted file mode 100644 index f1aec62f..00000000 --- a/src/interface.jl +++ /dev/null @@ -1,23 +0,0 @@ -# these are the routines of the banded interface of other AbstractMatrices - -banded_axpy!(a::Number, X::AbstractMatrix{U}, Y::AbstractMatrix{V}) where {U, V} = banded_generic_axpy!(a, X, Y) - -# matrix * vector - -# for AbstractMatrix, uses the generic version of multiplication -banded_matvecmul!(c::AbstractVector{T}, tA::Char, A::AbstractMatrix{U}, b::AbstractVector{V}) where {T, U, V} = banded_generic_matvecmul!(c, tA, A, b) -banded_A_mul_B!(c::AbstractVector, A::AbstractMatrix, b::AbstractVector) = banded_matvecmul!(c, 'N', A, b) -banded_Ac_mul_B!(c::AbstractVector, A::AbstractMatrix, b::AbstractVector) = banded_matvecmul!(c, 'C', A, b) -banded_At_mul_B!(c::AbstractVector, A::AbstractMatrix, b::AbstractVector) = banded_matvecmul!(c, 'T', A, b) - - -# matrix * matrix - -banded_matmatmul!(C::AbstractMatrix{T}, tA::Char, tB::Char, A::AbstractMatrix{U}, B::AbstractMatrix{V}) where {T, U, V} = banded_generic_matmatmul!(C, tA, tB, A, B) -banded_A_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'N', A, B) -banded_Ac_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'C', 'N', A, B) -banded_At_mul_B!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'T', 'N', A, B) -banded_A_mul_Bc!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'C', A, B) -banded_A_mul_Bt!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'N', 'T', A, B) -banded_Ac_mul_Bc!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'C', 'C', A, B) -banded_At_mul_Bt!(C::AbstractMatrix, A::AbstractMatrix, B::AbstractMatrix) = banded_matmatmul!(C, 'T', 'T', A, B) diff --git a/src/interfaceimpl.jl b/src/interfaceimpl.jl new file mode 100644 index 00000000..88aaf823 --- /dev/null +++ b/src/interfaceimpl.jl @@ -0,0 +1,22 @@ + + +# Here we implement the banded matrix interface for some key examples +isbanded(::Zeros) = true +bandwidth(::Zeros, k::Integer) = 0 +inbands_getindex(::Zeros{T}, k::Integer, j::Integer) where T = zero(T) + +isbanded(::Eye) = true +bandwidth(::Eye, k::Integer) = 0 +inbands_getindex(::Eye{T}, k::Integer, j::Integer) where T = one(T) + +isbanded(::Diagonal) = true +bandwidth(::Diagonal, k::Integer) = 0 +inbands_getindex(D::Diagonal, k::Integer, j::Integer) = D.diag[k] +inbands_setindex!(D::Diagonal, v, k::Integer, j::Integer) = (D.diag[k] = v) + +isbanded(::SymTridiagonal) = true +bandwidth(::SymTridiagonal, k::Integer) = 1 +inbands_getindex(J::SymTridiagonal, k::Integer, j::Integer) = + k == j ? J.dv[k] : J.ev[k] +inbands_setindex!(J::SymTridiagonal, v, k::Integer, j::Integer) = + k == j ? (J.dv[k] = v) : (J.ev[k] = v) diff --git a/src/symbanded/SymBandedMatrix.jl b/src/symbanded/SymBandedMatrix.jl index 0e44ec4d..9906c5f7 100644 --- a/src/symbanded/SymBandedMatrix.jl +++ b/src/symbanded/SymBandedMatrix.jl @@ -11,10 +11,12 @@ export sbrand, sbeye, sbzeros # * a_12 a_23 a_34 # a_11 a_22 a_33 a_44 ] ### +function _SymBandedMatrix end + mutable struct SymBandedMatrix{T} <: AbstractBandedMatrix{T} data::Matrix{T} # k+1 x n (# of columns) k::Int # bandwidth ≥ 0 - function SymBandedMatrix{T}(data::Matrix{T},k) where {T} + global function _SymBandedMatrix(data::Matrix{T}, k) where {T} if size(data,1) != k+1 error("Data matrix must have number rows equal to number of superdiagonals") else @@ -24,7 +26,8 @@ mutable struct SymBandedMatrix{T} <: AbstractBandedMatrix{T} end -SymBandedMatrix(data::Matrix,k::Integer) = SymBandedMatrix{eltype(data)}(data,k) +MemoryLayout(::SymBandedMatrix{T}) where T = BlasSymBanded{T}() + doc""" SymBandedMatrix(T, n, k) @@ -33,48 +36,75 @@ returns an unitialized `n`×`n` symmetric banded matrix of type `T` with bandwid """ # Use zeros to avoid unallocated entries for bigfloat -SymBandedMatrix(::Type{T},n::Integer,k::Integer) where {T<:BlasFloat} = - SymBandedMatrix{T}(Matrix{T}(k+1,n),k) -SymBandedMatrix(::Type{T},n::Integer,k::Integer) where {T<:Number} = - SymBandedMatrix{T}(zeros(T,k+1,n),k) -SymBandedMatrix(::Type{T},n::Integer,k::Integer) where {T} = - SymBandedMatrix{T}(Matrix{T}(k+1,n),k) - - -for MAT in (:SymBandedMatrix, :AbstractBandedMatrix, :AbstractMatrix, :AbstractArray) - @eval Base.convert(::Type{$MAT{V}},M::SymBandedMatrix) where {V} = - SymBandedMatrix{V}(convert(Matrix{V},M.data),M.k) +SymBandedMatrix{T}(::Uninitialized, n::Integer, k::Integer) where {T<:BlasFloat} = + _SymBandedMatrix(Matrix{T}(uninitialized, k+1, n), k) +SymBandedMatrix{T}(::Uninitialized, n::Integer, k::Integer) where {T<:Number} = + _SymBandedMatrix(zeros(T, k+1, n), k) +SymBandedMatrix{T}(::Uninitialized, n::Integer, k::Integer) where {T} = + _SymBandedMatrix(Matrix{T}(uninitialized, k+1, n), k) + +for MAT in (:SymBandedMatrix, :AbstractBandedMatrix, :AbstractMatrix, :AbstractArray) + @eval Base.convert(::Type{$MAT{V}}, M::SymBandedMatrix) where {V} = + SymBandedMatrix{V}(uninitialized, convert(Matrix{V}, M.data), M.k) end -Base.copy(B::SymBandedMatrix) = SymBandedMatrix(copy(B.data),B.k) +Base.copy(B::SymBandedMatrix{T}) where T = _SymBandedMatrix(copy(B.data),B.k) Base.promote_rule(::Type{SymBandedMatrix{T}},::Type{SymBandedMatrix{V}}) where {T,V} = SymBandedMatrix{promote_type(T,V)} -for (op,bop) in ((:(Base.rand),:sbrand),(:(Base.zeros),:sbzeros),(:(Base.ones),:sbones)) +for (op,bop) in ((:(Base.rand),:sbrand),) @eval begin - $bop(::Type{T},n::Integer,a::Integer) where {T} = SymBandedMatrix($op(T,a+1,n),a) - $bop(n::Integer,a::Integer) = $bop(Float64,n,a) + $bop(::Type{T}, n::Integer, a::Integer) where {T} = _SymBandedMatrix($op(T,a+1,n),a) + $bop(n::Integer, a::Integer) = $bop(Float64,n,a) - $bop(B::AbstractMatrix) = $bop(eltype(B),size(B,1),bandwidth(B,2)) + $bop(B::AbstractMatrix) = $bop(eltype(B), size(B,1), bandwidth(B,2)) end end -doc""" - sbzeros(T,n,k) +##### +# Convert abstract matrix +##### +# TODO: uncomment: this is commented out because of + +# function BandedMatrix{T}(A::AbstractMatrix, a::Int) where T +# (n,m) = size(A) +# @boundscheck n == m || throw(BoundsError()) +# ret = SymBandedMatrix{T}(uninitialized, n, a) +# @inbounds for j = 1:m, k = max(1,j-u):min(n,j+l) +# syminbands_setindex!(ret, A[k,j], k, j) +# end +# ret +# end + +function SymBandedMatrix{V}(Z::Ones{T,2}, a::Int) where {T,V} + n,m = size(Z) + @boundscheck n == m || throw(BoundsError()) + _SymBandedMatrix(ones(V, a+1, n),a) +end -Creates an `n×n` symmetric banded matrix of all zeros of type `T` with bandwidths `(k,k)` -""" -sbzeros +function SymBandedMatrix{V}(Z::Zeros{T,2}, a::Int) where {T,V} + n,m = size(Z) + @boundscheck n == m || throw(BoundsError()) + _SymBandedMatrix(zeros(V,a+1,n),a) +end -doc""" - sbones(T,n,k) +SymBandedMatrix(Z::AbstractFill{T,2}, a::Int) where T = SymBandedMatrix{T}(Z, a) + + +function SymBandedMatrix{T}(E::Eye, a::Int) where T + n,m = size(E) + @boundscheck n == m || throw(BoundsError()) + ret = SymBandedMatrix(Zeros{T}(E), a) + ret[band(0)] = one(T) + ret +end + +SymBandedMatrix(Z::Eye{T}, a::Int) where T = SymBandedMatrix{T}(Z, a) +SymBandedMatrix(Z::Eye) = SymBandedMatrix(Z, 0) -Creates an `n×n` symmetric banded matrix with ones in the bandwidth of type `T` with bandwidths `(k,k)` -""" -sbones doc""" sbrand(T,n,k) @@ -84,18 +114,6 @@ Creates an `n×n` symmetric banded matrix with random numbers in the bandwidth sbrand -""" - sbeye(T,n,l,u) - -`n×n` banded identity matrix of type `T` with bandwidths `(l,u)` -""" -function sbeye(::Type{T},n::Integer,a=0) where {T} - ret=sbzeros(T,n,a) - ret[band(0)] = one(T) - ret -end -sbeye(n::Integer,a...) = sbeye(Float64,n,a...) - Base.similar(B::SymBandedMatrix) = SymBandedMatrix(eltype(B),size(B,1),bandwidth(B,1)) @@ -191,7 +209,7 @@ function setindex!(A::SymBandedMatrix{T}, v, ::Colon, ::Colon) where {T} end end -function Base.convert(::Type{Matrix},A::SymBandedMatrix) +function Base.convert(::Type{Matrix}, A::SymBandedMatrix) ret=zeros(eltype(A),size(A,1),size(A,2)) for j = 1:size(ret,2), k = colrange(ret,j) @inbounds ret[k,j] = A[k,j] @@ -204,7 +222,7 @@ Base.full(A::SymBandedMatrix) = convert(Matrix, A) # algebra -function +(A::SymBandedMatrix{T},B::SymBandedMatrix{V}) where {T,V} +function +(A::SymBandedMatrix{T}, B::SymBandedMatrix{V}) where {T,V} if size(A) != size(B) throw(DimensionMismatch("+")) end diff --git a/test/runtests.jl b/test/runtests.jl index 88b5727a..a359824c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,10 +1,6 @@ using BandedMatrices, Compat +using Compat.Test -if VERSION < v"0.7-" - using Base.Test -else - using Test -end println("Banded matrix tests") include("test_banded.jl") @@ -18,7 +14,7 @@ println("LU tests") include("test_bandedlu.jl") println("QR tests") include("test_bandedqr.jl") -println("Symetrix banded matrix tests") +println("Symmetric banded matrix tests") include("test_symbanded.jl") println("Banded matrix interface tests") include("test_interface.jl") diff --git a/test/test_banded.jl b/test/test_banded.jl index 7b06337d..17952494 100644 --- a/test/test_banded.jl +++ b/test/test_banded.jl @@ -1,5 +1,15 @@ +using BandedMatrices +import BandedMatrices: _BandedMatrix + # some basic operations +@test BandedMatrix(Zeros(5,5), (1,1)) == _BandedMatrix(zeros(3,5), 5, 1, 1) +@test BandedMatrix(Zeros{Int}(5,5), (1,1)) == _BandedMatrix(zeros(Int,3,5), 5, 1, 1) +@test BandedMatrix{Int}(Zeros(5,5), (1,1)) == _BandedMatrix(zeros(Int,3,5), 5, 1, 1) + +@test_throws UndefRefError BandedMatrix{Vector{Float64}}(uninitialized, (5,5), (1,1))[1,1] + + let A = brand(10,12,2,3),B = brand(10,12,3,4) @test Matrix(sparse(A)) ≈ Matrix(A) @@ -94,7 +104,7 @@ end ## BigFloat -let A = brand(5, 5, 1, 2), B = bzeros(BigFloat,5,5,2,3), D = rand(5, 5) +let A = brand(5, 5, 1, 2), B = BandedMatrix(Zeros{BigFloat}(5,5),(2,3)), D = rand(5, 5) for j = 1:size(B,2), k = colrange(B,j) B[k,j]=randn() end @@ -176,6 +186,15 @@ end # Test for errors in collect -let B=brand(10,10,0,4) +let B = brand(10,10,0,4) @test B*[collect(1.0:10) collect(1.0:10)] ≈ Matrix(B)*[collect(1.0:10) collect(1.0:10)] end + +# Test fill! + +let B = brand(10,10,1,4) + @test_throws BandError fill!(B, 1.0) + @test_throws BandError fill!(B, 1) + fill!(B, 0) + @test Matrix(B) == zeros(10,10) +end diff --git a/test/test_bandedlu.jl b/test/test_bandedlu.jl index ae418013..589196c9 100644 --- a/test/test_bandedlu.jl +++ b/test/test_bandedlu.jl @@ -1,3 +1,5 @@ +import BandedMatrices: _BandedMatrix + # set prng to some value that avoids test failure srand(0) @@ -30,9 +32,9 @@ end # conversion of inputs to appropriate blas type let - As = Any[BandedMatrix(rand(1:10, 3, 5), 5, 1, 1), - BandedMatrix(rand(3, 5)*im, 5, 1, 1), - BandedMatrix(rand(3, 5), 5, 1, 1) + As = Any[_BandedMatrix(rand(1:10, 3, 5), 5, 1, 1), + _BandedMatrix(rand(3, 5)*im, 5, 1, 1), + _BandedMatrix(rand(3, 5), 5, 1, 1) ] bs = Any[rand(1:10, 5), rand(1:10, 5), @@ -92,15 +94,15 @@ end # conversion of inputs if needed let # factorisation performs conversion - Ai = BandedMatrix(rand(1:10, 3, 5), 5, 1, 1) + Ai = _BandedMatrix(rand(1:10, 3, 5), 5, 1, 1) @test eltype(lufact(Ai)) == Float64 # no op - Af = BandedMatrix(rand(Float32, 3, 5), 5, 1, 1) + Af = _BandedMatrix(rand(Float32, 3, 5), 5, 1, 1) @test eltype(lufact(Af)) == Float32 # linear systems of integer data imply promotion - Ai = BandedMatrix(rand(1:10, 3, 5), 5, 1, 1) + Ai = _BandedMatrix(rand(1:10, 3, 5), 5, 1, 1) bi = collect(1:5) @test eltype(Ai\bi) == Float64 # this code ≈ julia base @@ -110,7 +112,7 @@ let @test A_ldiv_B!(lufact(Ai), bi) ≈ Matrix(Ai)\copy(bi) # check A\b makes a copy of b - Ai = BandedMatrix(rand(1:10, 3, 5), 5, 1, 1) + Ai = _BandedMatrix(rand(1:10, 3, 5), 5, 1, 1) bi = collect(1:5) Ai\bi @test bi == [1, 2, 3, 4, 5] diff --git a/test/test_indexing.jl b/test/test_indexing.jl index d7496701..354c061d 100644 --- a/test/test_indexing.jl +++ b/test/test_indexing.jl @@ -1,4 +1,10 @@ -using Base.Test, BandedMatrices +using BandedMatrices +if VERSION < v"0.7-" + using Base.Test +else + using Test +end + import BandedMatrices: rowstart, rowstop, colstart, @@ -18,7 +24,7 @@ end # rowstart/rowstop business let - A = bones(7, 5, 1, 2) + A = BandedMatrix(Ones(7, 5), (1, 2)) # 1.0 1.0 1.0 0.0 0.0 # 1.0 1.0 1.0 1.0 0.0 # 0.0 1.0 1.0 1.0 1.0 @@ -39,7 +45,7 @@ let @test (colstart(A, 4), colstop(A, 4), collength(A, 4)) == (2, 5, 4) @test (colstart(A, 5), colstop(A, 5), collength(A, 5)) == (3, 6, 4) - A = bones(3, 6, 1, 2) + A = BandedMatrix(Ones(3, 6), (1, 2)) # 1.0 1.0 1.0 0.0 0.0 0.0 # 1.0 1.0 1.0 1.0 0.0 0.0 # 0.0 1.0 1.0 1.0 1.0 0.0 @@ -53,7 +59,7 @@ let @test (colstart(A, 5), colstop(A, 5), collength(A, 5)) == (3, 3, 1) @test (colstart(A, 6), colstop(A, 6), collength(A, 6)) == (4, 3, 0) # zero length - A = bones(3, 4, -1, 2) + A = BandedMatrix(Ones(3, 4), (-1, 2)) # 0.0 1.0 1.0 0.0 # 0.0 0.0 1.0 1.0 # 0.0 0.0 0.0 1.0 @@ -68,7 +74,7 @@ end # test length of diagonal let - A = bones(4, 6, 2, 3) + A = BandedMatrix(Ones(4, 6), (2, 3)) # 4x6 BandedMatrices.BandedMatrix{Float64}: # 1.0 1.0 1.0 1.0 # 1.0 1.0 1.0 1.0 1.0 @@ -81,7 +87,7 @@ let @test diaglength(A, 2) == 4 @test diaglength(A, 3) == 3 - A = bones(6, 5, 2, 1) + A = BandedMatrix(Ones(6, 5), (2, 1)) # 6x5 BandedMatrices.BandedMatrix{Float64}: # 1.0 1.0 # 1.0 1.0 1.0 @@ -94,7 +100,7 @@ let @test diaglength(A, 0) == 5 @test diaglength(A, 1) == 4 - A = bones(4, 4, 1, 1) + A = BandedMatrix(Ones(4, 4), (1, 1)) # 4x4 BandedMatrices.BandedMatrix{Float64}: # 1.0 1.0 # 1.0 1.0 1.0 @@ -110,7 +116,7 @@ end # _firstdiagrow/_firstdiagcol let - A = bones(6, 5, 2, 1) + A = BandedMatrix(Ones(6, 5), (2, 1)) # 6x5 BandedMatrices.BandedMatrix{Float64}: # 1.0 1.0 # 1.0 1.0 1.0 @@ -135,7 +141,7 @@ end # scalar - integer - integer let - a = bones(5, 5, 1, 1) + a = BandedMatrix(Ones(5, 5), (1, 1)) # 1.0 1.0 0.0 0.0 0.0 # 1.0 1.0 1.0 0.0 0.0 # 0.0 1.0 1.0 1.0 0.0 @@ -157,7 +163,7 @@ let @test_throws BoundsError a[6, 5] = 1 @test_throws BoundsError a[6, 6] = 1 - a = bones(5, 5, -1, 1) + a = BandedMatrix(Ones(5, 5), (-1, 1)) a[1, 2] = 2 @test a[1, 2] == 2 @test_throws BandError a[1, 1] = 1 @@ -168,7 +174,7 @@ end # scalar - BandRange/Colon - integer let - a = bones(5, 5, 1, 1) + a = BandedMatrix(Ones(5, 5), (1, 1)) # 1.0 1.0 0.0 0.0 0.0 # 1.0 1.0 1.0 0.0 0.0 # 0.0 1.0 1.0 1.0 0.0 @@ -198,7 +204,7 @@ let @test_throws BoundsError a[BandRange, 0] = 1 @test_throws BoundsError a[BandRange, 6] = 1 - a = bones(3, 5, -1, 2) + a = BandedMatrix(Ones(3, 5), (-1, 2)) @test isempty(a[BandRange,1]) a[BandRange,2] = [1] a[BandRange,3] = [2, 2] @@ -213,7 +219,7 @@ end # vector - BandRange/Colon - integer let - a = bones(Int, 5, 7, 2, 1) + a = BandedMatrix(Ones{Int}(5, 7), (2, 1)) # 5x7 BandedMatrices.BandedMatrix{Float64}: # 1.0 1.0 0 0 0 0 0 0 # 1.0 1.0 1.0 0 0 0 0 0 @@ -252,7 +258,7 @@ end # scalar - range - integer let - a = bones(3, 4, 2, 1) + a = BandedMatrix(Ones(3, 4), (2, 1)) # 1.0 1.0 0.0 0.0 # 1.0 1.0 1.0 0.0 # 1.0 1.0 1.0 1.0 @@ -292,7 +298,7 @@ end # vector - range - integer let - a = bones(5, 4, 1, 2) + a = BandedMatrix(Ones(5, 4), (1, 2)) # 1.0 1.0 1.0 0.0 # 1.0 1.0 1.0 1.0 # 0.0 1.0 1.0 1.0 @@ -345,7 +351,7 @@ end # scalar - integer - BandRange/colon let - a = bones(5, 5, 1, 1) + a = BandedMatrix(Ones(5, 5), (1, 1)) # 1.0 1.0 0.0 0.0 0.0 # 1.0 1.0 1.0 0.0 0.0 # 0.0 1.0 1.0 1.0 0.0 @@ -379,7 +385,7 @@ end # vector - integer - BandRange/colon let - a = bones(7, 5, 1, 2) + a = BandedMatrix(Ones(7, 5), (1, 2)) # 7x5 BandedMatrices.BandedMatrix{Float64}: # 1.0 1.0 1.0 0.0 0.0 # 1.0 1.0 1.0 1.0 0.0 @@ -417,7 +423,7 @@ end # scalar - integer - range let - a = bones(7, 5, 1, 2) + a = BandedMatrix(Ones(7, 5), (1, 2)) # 7x5 BandedMatrices.BandedMatrix{Float64}: # 1.0 1.0 1.0 0.0 0.0 # 1.0 1.0 1.0 1.0 0.0 @@ -463,7 +469,7 @@ end # vector - integer - range let - a = bones(7, 5, 1, 2) + a = BandedMatrix(Ones(7, 5), (1, 2)) # 7x5 BandedMatrices.BandedMatrix{Float64}: # 1.0 1.0 1.0 0.0 0.0 # 1.0 1.0 1.0 1.0 0.0 @@ -501,7 +507,7 @@ end # indexing along a band let - a = bzeros(5, 4, 2, 1) + a = BandedMatrix(Zeros(5, 4), (2, 1)) # 5x4 BandedMatrices.BandedMatrix{Float64}: # 0.0 0.0 # 0.0 0.0 0.0 @@ -543,7 +549,7 @@ end let - a = bzeros(5, 4, 2, 2) + a = BandedMatrix(Zeros(5, 4), (2, 2)) # 5x4 BandedMatrices.BandedMatrix{Float64}: # 0.0 0.0 0.0 # 0.0 0.0 0.0 0.0 @@ -592,7 +598,7 @@ end # other special methods let # all elements - a = bones(3, 3, 1, 1) + a = BandedMatrix(Ones(3, 3), (1, 1)) a[:] = 0 @test a == [0 0 0; 0 0 0; @@ -620,7 +626,7 @@ end # replace a block in the band let - a = bzeros(5, 4, 2, 1) + a = BandedMatrix(Zeros(5, 4), (2, 1)) # 5x4 BandedMatrices.BandedMatrix{Float64}: # 0.0 0.0 # 0.0 0.0 0.0 @@ -658,7 +664,26 @@ end let # tests bug - a = bzeros(1,1,3,-1) - a[band(-2)] .+= 2 - @test isempty(a[band(-2)]) + a = BandedMatrix(Zeros(1,1), (3,-1)) + @test_throws ArgumentError a[band(-2)] +end + + +# test band views +let + for A in (rand(11,10), brand(11,10,2,3), brand(Float32, 11,10,2,3), + brand(Complex128, 11,10,2,3)) + for k = -5:5 + V = view(A, band(k)) + bs = parentindexes(V)[1] # a bandslice + @test bs.indices == diagind(A, k) + @test bs.band == Band(k) + @test collect(bs) == collect(diagind(A, k)) + @test Vector{eltype(A)}(V) == collect(V) == A[diagind(A,k)] == A[band(k)] + @test Vector{Complex128}(V) == Vector{Complex128}(A[diagind(A,k)]) == + convert(AbstractVector{Complex128}, V) == convert(AbstractArray{Complex128}, V) + @test V ≡ convert(AbstractArray, V) ≡ convert(AbstractArray{eltype(A)}, V) ≡ + convert(AbstractArray, V) ≡ convert(AbstractVector, V) + end + end end diff --git a/test/test_interface.jl b/test/test_interface.jl index e03ef8aa..76e30869 100644 --- a/test/test_interface.jl +++ b/test/test_interface.jl @@ -1,4 +1,34 @@ -import BandedMatrices: banded_axpy!, banded_A_mul_B! +using BandedMatrices, Compat.Test + +import BandedMatrices: banded_axpy!, banded_A_mul_B!, isbanded + + + +## test intervface +@test isbanded(Zeros(5,6)) +@test bandwidths(Zeros(5,6)) == (0,0) +@test BandedMatrices.inbands_getindex(Zeros(5,6), 1,2) == 0 + +@test isbanded(Eye(5)) +@test bandwidths(Eye(5)) == (0,0) +@test BandedMatrices.inbands_getindex(Eye(5), 1,1) == 1 + +A = Diagonal(ones(5,5)) +@test isbanded(A) +@test bandwidths(A) == (0,0) +@test BandedMatrices.inbands_getindex(A, 1,1) == 1 +BandedMatrices.inbands_setindex!(A, 2, 1,1) +@test A[1,1] == 2 + +A = SymTridiagonal([1,2,3],[4,5]) +@test isbanded(A) +@test bandwidths(A) == (1,1) +@test BandedMatrices.inbands_getindex(A, 1,1) == 1 +BandedMatrices.inbands_setindex!(A, 2, 1,1) +@test A[1,1] == 2 + + + struct SimpleBandedMatrix{T} <: AbstractMatrix{T} data::Array{T} diff --git a/test/test_miscs.jl b/test/test_miscs.jl index 3e679ff6..ada647f7 100644 --- a/test/test_miscs.jl +++ b/test/test_miscs.jl @@ -4,14 +4,14 @@ BandedMatrixWithZero = Union{BandedMatrix{Float64}, UniformScaling} # need to define the concept of zero Base.zero(::Type{BandedMatrixWithZero}) = 0*I -A=BandedMatrix(BandedMatrixWithZero,1,2,0,1) -A[1,1]=beye(1,1,0,1) -A[1,2]=bzeros(1,2,0,1) +A=BandedMatrix{BandedMatrixWithZero}(uninitialized, 1, 2, 0, 1) +A[1,1]=BandedMatrix(Eye(1),(0,1)) +A[1,2]=BandedMatrix(Zeros(1,2),(0,1)) A[1,2][1,1]=-1/3 A[1,2][1,2]=1/3 -B=BandedMatrix(BandedMatrixWithZero,2,1,1,1) -B[1,1]=0.2beye(1,1,0,1) -B[2,1]=bzeros(2,1,1,0) +B=BandedMatrix{BandedMatrixWithZero}(uninitialized, 2, 1, 1, 1) +B[1,1]=0.2BandedMatrix(Eye(1),(0,1)) +B[2,1]=BandedMatrix(Zeros(2,1), (1,0)) B[2,1][1,1]=-2/30 B[2,1][2,1]=1/3 @@ -48,7 +48,7 @@ A = brand(3,4,1,2) end, "10×10 BandedMatrices.BandedMatrix{Float64}") @test contains(sprint() do io - show(io, beye(3, 1, 1)) + show(io, BandedMatrix(Eye(3),(1,1))) end, "1.0 0.0 \n 0.0 1.0 0.0\n 0.0 1.0") diff --git a/test/test_symbanded.jl b/test/test_symbanded.jl index 804afc24..6c7df512 100644 --- a/test/test_symbanded.jl +++ b/test/test_symbanded.jl @@ -1,4 +1,7 @@ -using BandedMatrices, Base.Test +using Compat +using BandedMatrices, Compat.Test + +@test_throws UndefRefError SymBandedMatrix{Vector{Float64}}(uninitialized, 5, 1)[1,1] A = sbrand(10,2) @@ -19,7 +22,7 @@ A = sbrand(Float64, 100, 4) # generalized eigvals function An(::Type{T}, N::Int) where {T} - A = sbzeros(T, N, 2) + A = SymBandedMatrix(Zeros{T}(N,N), 2) for n = 0:N-1 A.data[3,n+1] = T((n+1)*(n+2)) end @@ -27,7 +30,7 @@ function An(::Type{T}, N::Int) where {T} end function Bn(::Type{T}, N::Int) where {T} - B = sbzeros(T, N, 2) + B = SymBandedMatrix(Zeros{T}(N,N), 2) for n = 0:N-1 B.data[3,n+1] = T(2*(n+1)*(n+2))/T((2n+1)*(2n+5)) end