Skip to content

Commit 9efd5d4

Browse files
authored
Merge branch 'master' into julia1.6
2 parents 10d9d66 + 63c9ae4 commit 9efd5d4

File tree

9 files changed

+195
-81
lines changed

9 files changed

+195
-81
lines changed

.github/workflows/CI.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,18 @@ on:
77
pull_request:
88

99
jobs:
10+
pre_job:
11+
# continue-on-error: true # Uncomment once integration is finished
12+
runs-on: ubuntu-latest
13+
# Map a step output to a job output
14+
outputs:
15+
should_skip: ${{ steps.skip_check.outputs.should_skip }}
16+
steps:
17+
- id: skip_check
18+
uses: fkirc/skip-duplicate-actions@v5
1019
test:
20+
needs: pre_job
21+
if: needs.pre_job.outputs.should_skip != 'true'
1122
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
1223
runs-on: ${{ matrix.os }}
1324
strategy:

Project.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "ToeplitzMatrices"
22
uuid = "c751599d-da0a-543b-9d20-d0a503d91d24"
3-
version = "0.9.0"
3+
version = "0.8.2"
44

55
[deps]
66
AbstractFFTs = "621f4979-c628-5d54-868e-fcf4e3e8185c"
@@ -10,8 +10,11 @@ StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1010

1111
[compat]
1212
AbstractFFTs = "0.4, 0.5, 1"
13+
Aqua = "0.6"
1314
DSP = "0.7.7"
1415
StatsBase = "0.32, 0.33"
16+
FFTW = "1"
17+
StatsBase = "0.32, 0.33, 0.34"
1518
julia = "1.6"
1619

1720
[extras]

src/ToeplitzMatrices.jl

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,28 @@ module ToeplitzMatrices
33
import DSP: conv
44

55
import Base: adjoint, convert, transpose, size, getindex, similar, copy, getproperty, inv, sqrt, copyto!, reverse, conj, zero, fill!, checkbounds, real, imag, isfinite, DimsInteger, iszero
6+
import Base: parent
67
import Base: ==, +, -, *, \
8+
import Base: AbstractMatrix
79
import LinearAlgebra: Cholesky, Factorization
8-
import LinearAlgebra: ldiv!, factorize, lmul!, pinv, eigvals, cholesky!, cholesky, tril!, triu!, checksquare, rmul!, dot, mul!, tril, triu
10+
import LinearAlgebra: ldiv!, factorize, lmul!, pinv, eigvals, eigvecs, eigen, Eigen, det
11+
import LinearAlgebra: cholesky!, cholesky, tril!, triu!, checksquare, rmul!, dot, mul!, tril, triu
12+
import LinearAlgebra: istriu, istril, isdiag
913
import LinearAlgebra: UpperTriangular, LowerTriangular, Symmetric, Adjoint
1014
import AbstractFFTs: Plan, plan_fft!
1115
import StatsBase
1216

1317
export AbstractToeplitz, Toeplitz, SymmetricToeplitz, Circulant, LowerTriangularToeplitz, UpperTriangularToeplitz, TriangularToeplitz, Hankel
1418
export durbin, trench, levinson
1519

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+
1628
include("iterativeLinearSolvers.jl")
1729

1830
# Abstract
@@ -30,6 +42,21 @@ convert(::Type{AbstractToeplitz{T}}, A::AbstractToeplitz) where T = AbstractToep
3042
isconcrete(A::AbstractToeplitz) = isconcretetype(typeof(A.vc)) && isconcretetype(typeof(A.vr))
3143
iszero(A::AbstractToeplitz) = iszero(A.vc) && iszero(A.vr)
3244

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+
3360
"""
3461
ToeplitzFactorization
3562

src/hankel.jl

Lines changed: 2 additions & 2 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
@@ -68,8 +69,7 @@ Base.@propagate_inbounds function getindex(A::Hankel, i::Integer, j::Integer)
6869
@boundscheck checkbounds(A, i, j)
6970
return A.v[i+j-1]
7071
end
71-
similar(A::Hankel, T::Type, dims::DimsInteger{2}) = Hankel{T}(similar(A.v, T, dims[1]+dims[2]-true), dims)
72-
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
72+
AbstractMatrix{T}(A::Hankel) where {T} = Hankel{T}(AbstractVector{T}(A.v), A.size)
7373
for fun in (:zero, :conj, :copy, :-, :similar, :real, :imag)
7474
@eval $fun(A::Hankel) = Hankel($fun(A.v), size(A))
7575
end

src/linearalgebra.jl

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ end
122122
function factorize(A::Toeplitz)
123123
T = eltype(A)
124124
m, n = size(A)
125-
S = promote_type(T, Complex{Float32})
125+
S = promote_type(float(T), Complex{Float32})
126126
tmp = Vector{S}(undef, m + n - 1)
127127
copyto!(tmp, A.vc)
128128
copyto!(tmp, m + 1, Iterators.reverse(A.vr), 1, n - 1)
@@ -142,7 +142,7 @@ StatsBase.levinson(A::AbstractToeplitz, B::AbstractVecOrMat) = StatsBase.levinso
142142
function factorize(A::SymmetricToeplitz{T}) where {T<:Number}
143143
vc = A.vc
144144
m = length(vc)
145-
S = promote_type(T, Complex{Float32})
145+
S = promote_type(float(T), Complex{Float32})
146146
tmp = Vector{S}(undef, 2 * m)
147147
copyto!(tmp, vc)
148148
@inbounds tmp[m + 1] = zero(T)
@@ -199,7 +199,7 @@ const CirculantFactorization{T, V<:AbstractVector{T}} = ToeplitzFactorization{T,
199199
function factorize(C::Circulant)
200200
T = eltype(C)
201201
vc = C.vc
202-
S = promote_type(T, Complex{Float32})
202+
S = promote_type(float(T), Complex{Float32})
203203
tmp = Vector{S}(undef, length(vc))
204204
copyto!(tmp, vc)
205205
dft = plan_fft!(tmp)
@@ -247,14 +247,12 @@ function ldiv!(C::CirculantFactorization, b::AbstractVector)
247247
))
248248
end
249249
dft = C.dft
250-
@inbounds begin
251-
copyto!(tmp, b)
252-
dft * tmp
253-
tmp ./= vcvr_dft
254-
dft \ tmp
255-
T = eltype(C)
256-
b .= maybereal.(T, tmp)
257-
end
250+
copyto!(tmp, b)
251+
dft * tmp
252+
tmp ./= vcvr_dft
253+
dft \ tmp
254+
T = eltype(C)
255+
b .= maybereal.(T, tmp)
258256
return b
259257
end
260258

@@ -302,6 +300,28 @@ end
302300

303301
eigvals(C::Circulant) = eigvals(factorize(C))
304302
eigvals(C::CirculantFactorization) = copy(C.vcvr_dft)
303+
_det(C) = prod(eigvals(C))
304+
det(C::Circulant) = _det(C)
305+
det(C::Circulant{<:Real}) = real(_det(C))
306+
@static if VERSION <= v"1.6"
307+
_cispi(x) = cis(pi*x)
308+
else
309+
_cispi(x) = cispi(x)
310+
end
311+
function eigvecs(C::Circulant)
312+
n = size(C,1)
313+
M = Array{complex(float(eltype(C)))}(undef, size(C))
314+
x = 2/n
315+
invnorm = 1/√n
316+
for CI in CartesianIndices(M)
317+
k, j = Tuple(CI)
318+
M[CI] = _cispi((k-1) * (j-1) * x) * invnorm
319+
end
320+
return M
321+
end
322+
function eigen(C::Circulant)
323+
Eigen(eigvals(C), eigvecs(C))
324+
end
305325

306326
sqrt(C::Circulant) = sqrt(factorize(C))
307327
function sqrt(C::CirculantFactorization)
@@ -394,7 +414,7 @@ function factorize(A::LowerTriangularToeplitz)
394414
T = eltype(A)
395415
v = A.v
396416
n = length(v)
397-
S = promote_type(T, Complex{Float32})
417+
S = promote_type(float(T), Complex{Float32})
398418
tmp = zeros(S, 2 * n - 1)
399419
copyto!(tmp, v)
400420
dft = plan_fft!(tmp)
@@ -404,7 +424,7 @@ function factorize(A::UpperTriangularToeplitz)
404424
T = eltype(A)
405425
v = A.v
406426
n = length(v)
407-
S = promote_type(T, Complex{Float32})
427+
S = promote_type(float(T), Complex{Float32})
408428
tmp = zeros(S, 2 * n - 1)
409429
tmp[1] = v[1]
410430
copyto!(tmp, n + 1, Iterators.reverse(v), 1, n - 1)

src/special.jl

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,71 @@
11
# special Toeplitz types that can be represented by a single vector
22
# Symmetric, Circulant, LowerTriangular, UpperTriangular
3+
4+
abstract type AbstractToeplitzSingleVector{T} <: AbstractToeplitz{T} end
5+
6+
parent(A::AbstractToeplitzSingleVector) = A.v
7+
basetype(x) = basetype(typeof(x))
8+
9+
function size(A::AbstractToeplitzSingleVector)
10+
n = length(parent(A))
11+
(n,n)
12+
end
13+
14+
adjoint(A::AbstractToeplitzSingleVector) = transpose(conj(A))
15+
function zero!(A::AbstractToeplitzSingleVector)
16+
fill!(parent(A), zero(eltype(A)))
17+
return A
18+
end
19+
20+
function lmul!(x::Number, A::AbstractToeplitzSingleVector)
21+
lmul!(x,parent(A))
22+
A
23+
end
24+
function rmul!(A::AbstractToeplitzSingleVector, x::Number)
25+
rmul!(parent(A),x)
26+
A
27+
end
28+
29+
for fun in (:iszero,)
30+
@eval $fun(A::AbstractToeplitzSingleVector) = $fun(parent(A))
31+
end
32+
33+
AbstractToeplitz{T}(A::AbstractToeplitzSingleVector) where T = basetype(A){T}(A)
34+
35+
(*)(scalar::Number, C::AbstractToeplitzSingleVector) = basetype(C)(scalar * parent(C))
36+
(*)(C::AbstractToeplitzSingleVector, scalar::Number) = basetype(C)(parent(C) * scalar)
37+
38+
AbstractMatrix{T}(A::AbstractToeplitzSingleVector) where {T} = basetype(A){T}(AbstractVector{T}(A.v))
39+
40+
for fun in (:zero, :conj, :copy, :-, :real, :imag)
41+
@eval $fun(A::AbstractToeplitzSingleVector) = basetype(A)($fun(parent(A)))
42+
end
43+
344
for TYPE in (:SymmetricToeplitz, :Circulant, :LowerTriangularToeplitz, :UpperTriangularToeplitz)
445
@eval begin
5-
struct $TYPE{T, V<:AbstractVector{T}} <: AbstractToeplitz{T}
46+
struct $TYPE{T, V<:AbstractVector{T}} <: AbstractToeplitzSingleVector{T}
647
v::V
7-
end
8-
$TYPE{T}(v::V) where {T,V<:AbstractVector{T}} = $TYPE{T,V}(v)
9-
$TYPE{T}(v::AbstractVector) where T = $TYPE{T}(convert(AbstractVector{T},v))
10-
11-
AbstractToeplitz{T}(A::$TYPE) where T = $TYPE{T}(A)
12-
$TYPE{T}(A::$TYPE) where T = $TYPE{T}(convert(AbstractVector{T},A.v))
13-
convert(::Type{$TYPE{T}}, A::$TYPE) where {T} = $TYPE{T}(A)
14-
15-
size(A::$TYPE) = (length(A.v),length(A.v))
16-
17-
adjoint(A::$TYPE) = transpose(conj(A))
18-
(*)(scalar::Number, C::$TYPE) = $TYPE(scalar * C.v)
19-
(*)(C::$TYPE, scalar::Number) = $TYPE(C.v * scalar)
20-
(==)(A::$TYPE,B::$TYPE) = A.v==B.v
21-
function zero!(A::$TYPE)
22-
if isconcrete(A)
23-
fill!(A.v,zero(eltype(A)))
24-
else
25-
A.v=zero(A.v)
48+
function $TYPE{T,V}(v::V) where {T,V<:AbstractVector{T}}
49+
require_one_based_indexing(v)
50+
new{T,V}(v)
2651
end
2752
end
53+
function $TYPE{T}(v::AbstractVector) where T
54+
vT = convert(AbstractVector{T},v)
55+
$TYPE{T, typeof(vT)}(vT)
56+
end
57+
$TYPE(v::V) where {T,V<:AbstractVector{T}} = $TYPE{T,V}(v)
58+
59+
basetype(::Type{T}) where {T<:$TYPE} = $TYPE
60+
61+
(==)(A::$TYPE, B::$TYPE) = A.v == B.v
62+
63+
convert(::Type{$TYPE{T}}, A::$TYPE) where {T} = A isa $TYPE{T} ? A : $TYPE{T}(A)::$TYPE{T}
2864

2965
function copyto!(A::$TYPE,B::$TYPE)
3066
copyto!(A.v,B.v)
3167
A
3268
end
33-
similar(A::$TYPE, T::Type) = $TYPE{T}(similar(A.v, T))
34-
function lmul!(x::Number, A::$TYPE)
35-
lmul!(x,A.v)
36-
A
37-
end
38-
function rmul!(A::$TYPE, x::Number)
39-
rmul!(A.v,x)
40-
A
41-
end
42-
end
43-
for fun in (:zero, :conj, :copy, :-, :real, :imag)
44-
@eval $fun(A::$TYPE) = $TYPE($fun(A.v))
45-
end
46-
for fun in (:iszero,)
47-
@eval $fun(A::$TYPE) = $fun(A.v)
4869
end
4970
for op in (:+, :-)
5071
@eval $op(A::$TYPE,B::$TYPE) = $TYPE($op(A.v,B.v))
@@ -95,8 +116,12 @@ function getproperty(A::UpperTriangularToeplitz, s::Symbol)
95116
end
96117
end
97118

98-
_circulate(v::AbstractVector) = vcat(v[1],v[end:-1:2])
99-
_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
100125

101126
# transpose
102127
transpose(A::SymmetricToeplitz) = A
@@ -226,3 +251,6 @@ function _trisame!(A::TriangularToeplitz, k::Integer)
226251
end
227252
tril!(A::LowerTriangularToeplitz, k::Integer) = _trisame!(A,k)
228253
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: 4 additions & 4 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
@@ -104,10 +105,9 @@ end
104105

105106
adjoint(A::AbstractToeplitz) = transpose(conj(A))
106107
transpose(A::AbstractToeplitz) = Toeplitz(A.vr, A.vc)
107-
function similar(A::AbstractToeplitz, T::Type, dims::Dims{2})
108-
vc=similar(A.vc, T, dims[1])
109-
vr=similar(A.vr, T, dims[2])
110-
vr[1]=vc[1]
108+
function AbstractMatrix{T}(A::AbstractToeplitz) where {T}
109+
vc = AbstractVector{T}(_vc(A))
110+
vr = AbstractVector{T}(_vr(A))
111111
Toeplitz{T}(vc,vr)
112112
end
113113
for fun in (:zero, :conj, :copy, :-, :real, :imag)

test/Project.toml

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)