Skip to content

Commit 63c9ae4

Browse files
authored
Faster istriu/istril/isdiag for AbstractToeplitz (#88)
* Faster istriu/istril/isdiag for AbstractToeplitz * rectangular tests
1 parent 49bde1d commit 63c9ae4

File tree

5 files changed

+65
-2
lines changed

5 files changed

+65
-2
lines changed

src/ToeplitzMatrices.jl

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,22 @@ import Base: AbstractMatrix
99
import LinearAlgebra: Cholesky, Factorization
1010
import LinearAlgebra: ldiv!, factorize, lmul!, pinv, eigvals, eigvecs, eigen, Eigen, det
1111
import LinearAlgebra: cholesky!, cholesky, tril!, triu!, checksquare, rmul!, dot, mul!, tril, triu
12+
import LinearAlgebra: istriu, istril, isdiag
1213
import LinearAlgebra: UpperTriangular, LowerTriangular, Symmetric, Adjoint
1314
import AbstractFFTs: Plan, plan_fft!
1415
import StatsBase
1516

1617
export AbstractToeplitz, Toeplitz, SymmetricToeplitz, Circulant, LowerTriangularToeplitz, UpperTriangularToeplitz, TriangularToeplitz, Hankel
1718
export durbin, trench, levinson
1819

20+
@static if isdefined(Base, :require_one_based_indexing)
21+
const require_one_based_indexing = Base.require_one_based_indexing
22+
else
23+
function require_one_based_indexing(A...)
24+
!Base.has_offset_axes(A...) || throw(ArgumentError("offset arrays are not supported but got an array with index other than 1"))
25+
end
26+
end
27+
1928
include("iterativeLinearSolvers.jl")
2029

2130
# Abstract
@@ -33,6 +42,21 @@ convert(::Type{AbstractToeplitz{T}}, A::AbstractToeplitz) where T = AbstractToep
3342
isconcrete(A::AbstractToeplitz) = isconcretetype(typeof(A.vc)) && isconcretetype(typeof(A.vr))
3443
iszero(A::AbstractToeplitz) = iszero(A.vc) && iszero(A.vr)
3544

45+
function istril(A::AbstractToeplitz, k::Integer=0)
46+
vr, vc = _vr(A), _vc(A)
47+
all(iszero, @view vr[max(1, k+2):end]) && all(iszero, @view vc[2:min(-k,end)])
48+
end
49+
50+
function istriu(A::AbstractToeplitz, k::Integer=0)
51+
vr, vc = _vr(A), _vc(A)
52+
all(iszero, @view vc[max(1, -k+2):end]) && all(iszero, @view vr[2:min(k,end)])
53+
end
54+
55+
function isdiag(A::AbstractToeplitz)
56+
vr, vc = _vr(A), _vc(A)
57+
all(iszero, @view vr[2:end]) && all(iszero, @view vc[2:end])
58+
end
59+
3660
"""
3761
ToeplitzFactorization
3862

src/hankel.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ struct Hankel{T, V<:AbstractVector{T}, S<:DimsInteger} <: AbstractMatrix{T}
55

66
function Hankel{T,V,S}(v::V, (m,n)::DimsInteger) where {T, V<:AbstractVector{T}, S<:DimsInteger}
77
(m < 0 || n < 0) && throw(ArgumentError("negative size: $s"))
8+
require_one_based_indexing(v)
89
length(v) m+n-1 || throw(ArgumentError("inconsistency between size and number of anti-diagonals"))
910
new{T,V,S}(v, (m,n))
1011
end

src/special.jl

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,16 @@ for TYPE in (:SymmetricToeplitz, :Circulant, :LowerTriangularToeplitz, :UpperTri
4545
@eval begin
4646
struct $TYPE{T, V<:AbstractVector{T}} <: AbstractToeplitzSingleVector{T}
4747
v::V
48+
function $TYPE{T,V}(v::V) where {T,V<:AbstractVector{T}}
49+
require_one_based_indexing(v)
50+
new{T,V}(v)
51+
end
4852
end
4953
function $TYPE{T}(v::AbstractVector) where T
5054
vT = convert(AbstractVector{T},v)
5155
$TYPE{T, typeof(vT)}(vT)
5256
end
57+
$TYPE(v::V) where {T,V<:AbstractVector{T}} = $TYPE{T,V}(v)
5358

5459
basetype(::Type{T}) where {T<:$TYPE} = $TYPE
5560

@@ -111,8 +116,12 @@ function getproperty(A::UpperTriangularToeplitz, s::Symbol)
111116
end
112117
end
113118

114-
_circulate(v::AbstractVector) = vcat(v[1],v[end:-1:2])
115-
_firstnonzero(v::AbstractVector) = vcat(v[1],zero(view(v,2:lastindex(v))))
119+
_circulate(v::AbstractVector) = reverse(v, 2)
120+
function _firstnonzero(v::AbstractVector)
121+
w = zero(v)
122+
w[1] = v[1]
123+
w
124+
end
116125

117126
# transpose
118127
transpose(A::SymmetricToeplitz) = A
@@ -242,3 +251,6 @@ function _trisame!(A::TriangularToeplitz, k::Integer)
242251
end
243252
tril!(A::LowerTriangularToeplitz, k::Integer) = _trisame!(A,k)
244253
triu!(A::UpperTriangularToeplitz, k::Integer) = _trisame!(A,-k)
254+
255+
isdiag(A::Union{Circulant, LowerTriangularToeplitz, SymmetricToeplitz}) = all(iszero, @view _vc(A)[2:end])
256+
isdiag(A::UpperTriangularToeplitz) = all(iszero, @view _vr(A)[2:end])

src/toeplitz.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct Toeplitz{T, VC<:AbstractVector{T}, VR<:AbstractVector{T}} <: AbstractToep
99
vr::VR
1010

1111
function Toeplitz{T, VC, VR}(vc::VC, vr::VR) where {T, VC<:AbstractVector{T}, VR<:AbstractVector{T}}
12+
require_one_based_indexing(vr, vc)
1213
if first(vc) != first(vr)
1314
error("First element of the vectors must be the same")
1415
end

test/runtests.jl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,9 @@ end
347347
@test TA+TB == A+B
348348
@test TA-TB == A-B
349349

350+
@test all(k -> istril(TA, k) == istril(A, k), -5:5)
351+
@test all(k -> istriu(TA, k) == istriu(A, k), -5:5)
352+
350353
@test_throws ArgumentError reverse(TA,dims=3)
351354
if isa(TA,AbstractToeplitz)
352355
@test isa(reverse(TA),Hankel)
@@ -372,6 +375,28 @@ end
372375
end
373376
@test fill!(Toeplitz(zeros(2,2)),1) == ones(2,2)
374377

378+
@testset "istril/istriu/isdiag" begin
379+
for (vc,vr) in (([1,2,0,0], [1,4,5,0]), ([0,0,0], [0,5,0]), ([3,0,0], [3,0,0]), ([0], [0]))
380+
for T in (Toeplitz(vc, vr), Circulant(vr),
381+
SymmetricToeplitz(vc), LowerTriangularToeplitz(vc),
382+
UpperTriangularToeplitz(vr))
383+
M = Matrix(T)
384+
for k in -5:5, f in [istriu, istril]
385+
@test f(T, k) == f(M, k)
386+
end
387+
@test isdiag(T) == isdiag(M)
388+
end
389+
end
390+
391+
for (vr, vc) in (([1,2], [1,2,3,4]), ([1,2,3,4], [1,2]))
392+
T = Toeplitz(vr, vc)
393+
M = Matrix(T)
394+
@testset for f in (istril, istriu)
395+
@test all(k -> f(T,k) == f(M,k), -5:5)
396+
end
397+
end
398+
end
399+
375400
@testset "aliasing" begin
376401
v = [1,2,3]
377402
T = Toeplitz(v, v)

0 commit comments

Comments
 (0)