Skip to content
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,7 @@ The `reverse` can transform between Hankel and Toeplitz. It is used to achieve f
|copy|✓|✓|✓|✓|✓|✓|
|similar|✓|✓|✓|✓|✓|✓|
|zero|✓|✓|✓|✓|✓|✓|
|real|✓|✓|✓|✓|✓|✓|
|imag|✓|✓|✓|✓|✓|✓|
|fill!|✓|✗|✗|✗|✗|✓|
|conj|✓|✓|✓|✓|✓|✓|
|transpose|✓|✓|✓|✓|✓|✓|
|adjoint|✓|✓|✓|✓|✓|✓|
|tril!|✓|✗|✗|✓|✓|✗|
Expand All @@ -90,19 +87,19 @@ The `reverse` can transform between Hankel and Toeplitz. It is used to achieve f
|triu|✓|✓|✓|✓|✓|✗|
|+|✓|✓|✓|✓|✓|✓|
|-|✓|✓|✓|✓|✓|✓|
|scalar<br>mult|✓|✓|✓|✓|✓|✓|
|==|✓|✓|✓|✓|✓|✓|
|issymmetric|||||||
|istriu|||||||
|istril|||||||
|iszero|✓|✓|✓|✓|✓||
|isone|||||||
|copyto!|✓|✓|✓|✓|✓|✓|
|reverse|✓|✓|✓|✓|✓|✓|
|broadcast|||||||
|\_all|✓|✓|✓|✓|✓|✓|
|unary broadcast|✓|✓|✓|✓|✓|✓|
|number broadcast|✓|✓|✓|✓|✓|✓|
|broadcast!|||||||

Note that scalar multiplication, `conj`, `+` and `-` could be removed once `broadcast` is implemented.
Note that `+` and `-` could be removed once binary `broadcast` is implemented.

`reverse(Hankel)` returns a `Toeplitz`, while `reverse(AbstractToeplitz)` returns a `Hankel`.

Expand Down
7 changes: 4 additions & 3 deletions src/ToeplitzMatrices.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ module ToeplitzMatrices
# import StatsBase: levinson!, levinson
import DSP: conv

import Base: adjoint, convert, transpose, size, getindex, similar, copy, getproperty, inv, sqrt, copyto!, reverse, conj, zero, fill!, checkbounds, real, imag, isfinite, DimsInteger, iszero
import Base: adjoint, convert, transpose, size, getindex, similar, copy, getproperty, inv, sqrt, copyto!, reverse, conj, zero, fill!, checkbounds, real, isfinite, DimsInteger, _all
import Base: ==, +, -, *, \
import Base.Broadcast: broadcasted, DefaultMatrixStyle
import LinearAlgebra: Cholesky, Factorization
import LinearAlgebra: ldiv!, factorize, lmul!, pinv, eigvals, cholesky!, cholesky, tril!, triu!, checksquare, rmul!, dot, mul!, tril, triu
import LinearAlgebra: UpperTriangular, LowerTriangular, Symmetric, Adjoint
Expand All @@ -16,7 +17,7 @@ export durbin, trench, levinson
include("iterativeLinearSolvers.jl")

# Abstract
abstract type AbstractToeplitz{T<:Number} <: AbstractMatrix{T} end
abstract type AbstractToeplitz{T} <: AbstractMatrix{T} end

size(A::AbstractToeplitz) = (length(A.vc),length(A.vr))
@inline _vr(A::AbstractToeplitz) = A.vr
Expand All @@ -28,7 +29,7 @@ AbstractArray{T}(A::AbstractToeplitz) where T = AbstractToeplitz{T}(A)
convert(::Type{AbstractToeplitz{T}}, A::AbstractToeplitz) where T = AbstractToeplitz{T}(A)

isconcrete(A::AbstractToeplitz) = isconcretetype(typeof(A.vc)) && isconcretetype(typeof(A.vr))
iszero(A::AbstractToeplitz) = iszero(A.vc) && iszero(A.vr)
_all(f, A::AbstractToeplitz, ::Colon) = _all(f, A.vc, :) && _all(f, A.vr, :)

"""
ToeplitzFactorization
Expand Down
12 changes: 7 additions & 5 deletions src/hankel.jl
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ end
convert(::Type{AbstractArray{T}}, A::Hankel) where {T<:Number} = convert(Hankel{T}, A)
convert(::Type{AbstractMatrix{T}}, A::Hankel) where {T<:Number} = convert(Hankel{T}, A)
convert(::Type{Hankel{T}}, A::Hankel) where {T<:Number} = Hankel{T}(convert(AbstractVector{T}, A.v), size(A))
broadcasted(::DefaultMatrixStyle, f, A::Hankel) = Hankel(f.(A.v), A.size)
broadcasted(::DefaultMatrixStyle, f, x::Number, A::Hankel) = Hankel(f.(x, A.v), A.size)
broadcasted(::DefaultMatrixStyle, f, A::Hankel, x::Number) = Hankel(f.(A.v, x), A.size)
_all(f, A::Hankel, ::Colon) = _all(f, A.v, :)

# Size
size(H::Hankel) = H.size
Expand All @@ -68,9 +72,9 @@ Base.@propagate_inbounds function getindex(A::Hankel, i::Integer, j::Integer)
@boundscheck checkbounds(A, i, j)
return A.v[i+j-1]
end
similar(A::Hankel, T::Type, dims::DimsInteger{2}) = Hankel{T}(similar(A.v, T, dims[1]+dims[2]-true), dims)
similar(A::Hankel, T::Type, dims::Tuple{Int64,Int64}) = Hankel{T}(similar(A.v, T, dims[1]+dims[2]-true), dims) # for ambiguity with `similar(a::AbstractArray, ::Type{T}, dims::Tuple{Vararg{Int64, N}}) where {T, N}` in Base
for fun in (:zero, :conj, :copy, :-, :similar, :real, :imag)
similar(A::Hankel, T::Type = eltype(A), dims::DimsInteger{2} = size(A)) = Hankel{T}(similar(A.v, T, dims[1]+dims[2]-true), dims)
similar(A::Hankel, T::Type = eltype(A), dims::Tuple{Int64,Int64} = size(A)) = Hankel{T}(similar(A.v, T, dims[1]+dims[2]-true), dims) # for ambiguity with `similar(a::AbstractArray, ::Type{T}, dims::Tuple{Vararg{Int64, N}}) where {T, N}` in Base
for fun in (:zero, :copy)
@eval $fun(A::Hankel) = Hankel($fun(A.v), size(A))
end
for op in (:+, :-)
Expand Down Expand Up @@ -100,8 +104,6 @@ end
transpose(A::Hankel) = Hankel(A.v, reverse(size(A)))
adjoint(A::Hankel) = transpose(conj(A))
(==)(A::Hankel, B::Hankel) = A.v == B.v && size(A) == size(B)
(*)(scalar::Number, C::Hankel) = Hankel(scalar * C.v, size(C))
(*)(C::Hankel,scalar::Number) = Hankel(C.v * scalar, size(C))

isconcrete(A::Hankel) = isconcretetype(A.v)

Expand Down
26 changes: 19 additions & 7 deletions src/special.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ for TYPE in (:SymmetricToeplitz, :Circulant, :LowerTriangularToeplitz, :UpperTri
size(A::$TYPE) = (length(A.v),length(A.v))

adjoint(A::$TYPE) = transpose(conj(A))
(*)(scalar::Number, C::$TYPE) = $TYPE(scalar * C.v)
(*)(C::$TYPE, scalar::Number) = $TYPE(C.v * scalar)
(==)(A::$TYPE,B::$TYPE) = A.v==B.v
function zero!(A::$TYPE)
if isconcrete(A)
Expand All @@ -40,20 +38,18 @@ for TYPE in (:SymmetricToeplitz, :Circulant, :LowerTriangularToeplitz, :UpperTri
A
end
end
for fun in (:zero, :conj, :copy, :-, :real, :imag)
for fun in (:zero, :copy)
@eval $fun(A::$TYPE) = $TYPE($fun(A.v))
end
for fun in (:iszero,)
@eval $fun(A::$TYPE) = $fun(A.v)
end
for op in (:+, :-)
@eval $op(A::$TYPE,B::$TYPE) = $TYPE($op(A.v,B.v))
end
for TY in (:AbstractMatrix, :AbstractToeplitz)
@eval $TYPE(v::$TY) = $TYPE{eltype(v)}(v)
end
end
TriangularToeplitz{T}=Union{UpperTriangularToeplitz{T},LowerTriangularToeplitz{T}}
SymToeplitzOrCirc{T} = Union{SymmetricToeplitz{T}, Circulant{T}}
TriangularToeplitz{T} = Union{UpperTriangularToeplitz{T}, LowerTriangularToeplitz{T}}

# vc and vr
function getproperty(A::SymmetricToeplitz, s::Symbol)
Expand Down Expand Up @@ -104,6 +100,22 @@ transpose(A::Circulant) = Circulant(A.vr)
transpose(A::LowerTriangularToeplitz) = UpperTriangularToeplitz(A.v)
transpose(A::UpperTriangularToeplitz) = LowerTriangularToeplitz(A.v)

# _all
_all(f, A::SymToeplitzOrCirc, ::Colon) = _all(f, A.v, :)
_all(f, A::TriangularToeplitz, ::Colon) = f(zero(eltype(A))) && _all(f, A.v, :)

# broadcast
for TYPE in (:SymmetricToeplitz, :Circulant)
@eval broadcasted(::DefaultMatrixStyle, f, A::$TYPE) = $TYPE(f.(A.v))
@eval broadcasted(::DefaultMatrixStyle, f, x::Number, A::$TYPE) = $TYPE(f.(x, A.v))
@eval broadcasted(::DefaultMatrixStyle, f, A::$TYPE, x::Number) = $TYPE(f.(A.v, x))
end
for TYPE in (:UpperTriangularToeplitz, :LowerTriangularToeplitz)
@eval broadcasted(::DefaultMatrixStyle, f, A::$TYPE) = iszero(f(zero(eltype(A)))) ? $TYPE(f.(A.v)) : _toep_broadcast(f, A)
@eval broadcasted(::DefaultMatrixStyle, f, x::Number, A::$TYPE) = iszero(f(x, zero(eltype(A)))) ? $TYPE(f.(x, A.v)) : _toep_broadcast(f, x, A)
@eval broadcasted(::DefaultMatrixStyle, f, A::$TYPE, x::Number) = iszero(f(zero(eltype(A)), x)) ? $TYPE(f.(A.v, x)) : _toep_broadcast(f, A, x)
end

# getindex
Base.@propagate_inbounds function getindex(A::SymmetricToeplitz, i::Integer, j::Integer)
@boundscheck checkbounds(A,i,j)
Expand Down
35 changes: 25 additions & 10 deletions src/toeplitz.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ struct Toeplitz{T, VC<:AbstractVector{T}, VR<:AbstractVector{T}} <: AbstractToep
vr::VR

function Toeplitz{T, VC, VR}(vc::VC, vr::VR) where {T, VC<:AbstractVector{T}, VR<:AbstractVector{T}}
if first(vc) != first(vr)
if !isequal(first(vc), first(vr))
error("First element of the vectors must be the same")
end
return new{T,VC,VR}(vc, vr)
Expand Down Expand Up @@ -42,6 +42,22 @@ AbstractToeplitz{T}(A::Toeplitz) where T = Toeplitz{T}(A)
convert(::Type{Toeplitz{T}}, A::AbstractToeplitz) where {T} = Toeplitz{T}(A)
convert(::Type{Toeplitz}, A::AbstractToeplitz) = Toeplitz(A)

# Dims for disambiguity
for DIM in (:DimsInteger, :Dims)
@eval function similar(::Type{Toeplitz{T, VC, VR}}, dims::$DIM{2}) where {T, VC, VR}
vc = similar(VC, dims[1])
vr = similar(VR, dims[2])
vr[1] = vc[1]
Toeplitz(vc, vr)
end
@eval function similar(A::AbstractToeplitz, T::Type = eltype(A), dims::$DIM{2} = size(A))
vc = similar(A.vc, T, dims[1])
vr = similar(A.vr, T, dims[2])
vr[1] = vc[1]
Toeplitz{T}(vc, vr)
end
end

# Retrieve an entry
Base.@propagate_inbounds function getindex(A::AbstractToeplitz, i::Integer, j::Integer)
@boundscheck checkbounds(A,i,j)
Expand All @@ -53,6 +69,13 @@ Base.@propagate_inbounds function getindex(A::AbstractToeplitz, i::Integer, j::I
end
end

broadcasted(::DefaultMatrixStyle, f, A::AbstractToeplitz) = _toep_broadcast(f, A)
broadcasted(::DefaultMatrixStyle, f, x::Number, A::AbstractToeplitz) = _toep_broadcast(f, x, A)
broadcasted(::DefaultMatrixStyle, f, A::AbstractToeplitz, x::Number) = _toep_broadcast(f, A, x)
_toep_broadcast(f, A::AbstractToeplitz) = Toeplitz(f.(A.vc), f.(A.vr))
_toep_broadcast(f, x::Number, A::AbstractToeplitz) = Toeplitz(f.(x, A.vc), f.(x, A.vr))
_toep_broadcast(f, A::AbstractToeplitz, x::Number) = Toeplitz(f.(A.vc, x), f.(A.vr, x))

checknonaliased(A::Toeplitz) = Base.mightalias(A.vc, A.vr) && throw(ArgumentError("Cannot modify Toeplitz matrices in place with aliased data"))

function tril!(A::Toeplitz, k::Integer=0)
Expand Down Expand Up @@ -104,13 +127,7 @@ end

adjoint(A::AbstractToeplitz) = transpose(conj(A))
transpose(A::AbstractToeplitz) = Toeplitz(A.vr, A.vc)
function similar(A::AbstractToeplitz, T::Type, dims::Dims{2})
vc=similar(A.vc, T, dims[1])
vr=similar(A.vr, T, dims[2])
vr[1]=vc[1]
Toeplitz{T}(vc,vr)
end
for fun in (:zero, :conj, :copy, :-, :real, :imag)
for fun in (:zero, :copy)
@eval $fun(A::AbstractToeplitz)=Toeplitz($fun(A.vc),$fun(A.vr))
end
for op in (:+, :-)
Expand All @@ -129,8 +146,6 @@ function fill!(A::Toeplitz, x::Number)
fill!(A.vr,x)
A
end
(*)(scalar::Number, C::AbstractToeplitz) = Toeplitz(scalar * C.vc, scalar * C.vr)
(*)(C::AbstractToeplitz,scalar::Number) = Toeplitz(C.vc * scalar, C.vr * scalar)

function lmul!(x::Number, A::Toeplitz)
checknonaliased(A)
Expand Down
18 changes: 18 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ end
T=copy(TA)
end
@test fill!(Toeplitz(zeros(2,2)),1) == ones(2,2)
@test isa(similar(Toeplitz{Int, Vector{Int}, Vector{Int}}, 5, 3), Toeplitz)

@testset "aliasing" begin
v = [1,2,3]
Expand All @@ -377,6 +378,23 @@ end
end
end

@testset "Broadcast" begin
A = rand(ComplexF64, 3, 3)
T = Toeplitz(A)
S = Symmetric(T)
C = Circulant(T)
U = UpperTriangular(T)
L = LowerTriangular(T)

for M in (T, S, C, U, L)
@testset "$(typeof(M))" begin
@test M .+ 1 == Matrix(M) .+ 1
@test exp.(M) == exp.(Matrix(M))
@test isa(M .* 2, typeof(M))
end
end
end

@testset "Circulant mathematics" begin
C1 = Circulant(rand(5))
C2 = Circulant(rand(5))
Expand Down