Skip to content

Commit b97cfd7

Browse files
committed
Add documentation to durbin!() and restore tests
1 parent 84045b1 commit b97cfd7

File tree

3 files changed

+79
-41
lines changed

3 files changed

+79
-41
lines changed

src/signalcorr.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ default_autolags(lx::Int) = 0 : default_laglen(lx)
4545

4646
_autodot(x::AbstractVector, lx::Int, l::Int) = dot(view(x, 1:(lx-l)), view(x, (1+l):lx))
4747

48-
4948
## autocov
5049
"""
5150
autocov!(r, x, lags; demean=true)
@@ -64,15 +63,15 @@ function autocov!(
6463
r::AbstractVector,
6564
x::AbstractVector,
6665
lags::AbstractVector{<:Integer},
67-
z=zeros(typeof(zero(eltype(x)) / 1), length(x));
66+
z=Vector{typeof(zero(eltype(x)) / 1)}(undef, size(x, 1));
6867
demean::Bool=true
6968
)
7069
lx = length(x)
7170
m = length(lags)
7271
length(r) == m || throw(DimensionMismatch())
7372
check_lags(lx, lags)
74-
T = typeof(zero(eltype(x)) / 1)
75-
demean ? z = x : z .= x .- mean(x)
73+
z .= x
74+
demean && z .= z .- mean(z)
7675
for k = 1 : m # foreach lag value
7776
r[k] = _autodot(z, lx, lags[k]) / lx
7877
end
@@ -82,7 +81,8 @@ end
8281
function autocov!(
8382
r::AbstractMatrix, x::AbstractMatrix, lags::AbstractVector{<:Integer}; demean::Bool=true
8483
)
85-
z = zeros(typeof(zero(eltype(x))/1), size(x, 1))
84+
T = typeof(zero(eltype(x)) / 1)
85+
z = Vector{T}(undef, size(x, 1))
8686
for n in 1:size(x, 2)
8787
autocov!(view(r, :, n), view(x, :, n), lags, z; demean)
8888
end
@@ -145,7 +145,7 @@ function autocor!(
145145
autocov!(view(r, 1:1), x, 0:0, z; demean)
146146
zz = r[1]
147147
autocov!(r, x, lags, z; demean)
148-
r ./= zz
148+
ldiv!(zz, r)
149149
return r
150150
end
151151

@@ -552,7 +552,7 @@ function pacf_yulewalker!(r::AbstractMatrix, X::AbstractMatrix, lags::IntegerVec
552552
y = Vector{eltype(X)}(undef, mk)
553553
for j = 1 : size(X,2)
554554
acfs = autocor(X[:,j], 1:mk)
555-
durbin!(acfs, p, y)
555+
durbin!(acfs, y, p)
556556
for i = 1 : length(lags)
557557
l = lags[i]
558558
r[i,j] = l == 0 ? 1 : -p[l]

src/toeplitzsolvers.jl

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
1-
# Symmetric Toeplitz solver
2-
function durbin!(r::AbstractVector{T}, p::AbstractVector{T}, y::AbstractVector{T}) where T
1+
"""
2+
durbin!(r::AbstractVector, y::AbstractVector, p::AbstractVector) -> Vector
3+
4+
Solve Yule-Walker equations using Durbin algorithm.
5+
6+
Solution of NxN system is obtained iteratively, by solving 1x1, 2x2, ...
7+
in succession. For use in computing partial autocorrelation matrix,
8+
return the last elements of the successive solutions in vector p[].
9+
10+
The section 4.7 of Golub,VanLoan "Matrix Computations," 4th ed.,
11+
discusses the algorithm in detail.
12+
13+
# Arguments
14+
- `r::AbstractVector`: first column of a herimitian positive definite
15+
Toeplitz matrix, excluding the diagonal element (equal to one).
16+
- `y::AbstractVector`: work vector for solution, should have the same length
17+
as r[]
18+
- `p::AbstractVector`: last elements of the successive solutions, should
19+
have the same length as r[]
20+
21+
# Returns
22+
- `y::AbstractVector`: same as the second argument
23+
"""
24+
function durbin!(r::AbstractVector{T}, y::AbstractVector{T}, p::AbstractVector{T}) where T
325
n = length(r)
426
n <= length(p) || n <= length(y) || throw(DimensionMismatch("Auxiliary vectors cannot be shorter than data vector"))
527
y[1] = -r[1]
@@ -24,7 +46,7 @@ function durbin!(r::AbstractVector{T}, p::AbstractVector{T}, y::AbstractVector{T
2446
y[k+1] = α
2547
p[k+1] = α
2648
end
27-
return p
49+
return y
2850
end
2951
durbin(r::AbstractVector{T}) where T = durbin!(r, zeros(T, length(r)), zeros(T, length(r)))
3052

test/signalcorr.jl

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,46 @@ x = [0.5316732188954801 + 0.015032026010878084im -0.8051436916816284 - 0.7302380
2222

2323
x1 = view(x, :, 1)
2424
x2 = view(x, :, 2)
25-
25+
cmplx_x = convert(AbstractMatrix{Complex}, x)
26+
cmplx_x1 = convert(AbstractVector{Complex}, x1)
27+
cmplx_x2 = convert(AbstractVector{Complex}, x2)
2628
# autocov & autocorr
2729

2830
@test autocov([1:5;]) [2.0, 0.8, -0.2, -0.8, -0.8]
2931
@test autocor([1, 2, 3, 4, 5]) [1.0, 0.4, -0.1, -0.4, -0.4]
3032

31-
racovx1 = [0.755284179631112 + 0.0im,
32-
-0.005333112170365584 - 0.18633291805458002im,
33-
-0.28638133506011604 + 0.1397225175604478im,
34-
-0.05476759020476188 + 0.12991227531087618im,
35-
-0.00499902418309206 + 0.023463421186162473im,
36-
0.11854989361702409 - 0.0028772373657594066im,
37-
-0.005123812003979093 - 0.08041878599400383im,
38-
-0.14090692583679154 + 0.035230042290069444im,
39-
0.039899180711674635 + 0.004918236900383659im,
40-
-0.03857936468514856 - 0.04063999068714769im]
41-
42-
@test autocov(x1) racovx1
33+
acovx1 = [0.755284179631112 + 0.0im,
34+
-0.005333112170365584 - 0.18633291805458002im,
35+
-0.28638133506011604 + 0.1397225175604478im,
36+
-0.05476759020476188 + 0.12991227531087618im,
37+
-0.00499902418309206 + 0.023463421186162473im,
38+
0.11854989361702409 - 0.0028772373657594066im,
39+
-0.005123812003979093 - 0.08041878599400383im,
40+
-0.14090692583679154 + 0.035230042290069444im,
41+
0.039899180711674635 + 0.004918236900383659im,
42+
-0.03857936468514856 - 0.04063999068714769im]
43+
44+
@test autocov(x1) acovx1
45+
@test autocov(cmplx_x1) acovx1
4346
@test autocov(x) [autocov(x1) autocov(x2)]
44-
45-
racorx1 = [1.0 + 0.0im,
46-
-0.007061066965510023 - 0.24670570770539213im,
47-
-0.3791703080554228 + 0.18499330626611243im,
48-
-0.07251256107537019 + 0.17200449686941222im,
49-
-0.006618732813301651 + 0.031065686027770673im,
50-
0.1569606471499575 - 0.0038094765432061303im,
51-
-0.00678395250709688 - 0.106474871528861im,
52-
-0.18656146869859214 + 0.04664475073114351im,
53-
0.05282671316002114 + 0.0065117700502952056im,
54-
-0.051079270194684986 - 0.0538075492419246im]
55-
56-
@test autocor(x1) racorx1
47+
@test autocov(cmplx_x) [autocov(cmplx_x1) autocov(cmplx_x2)]
48+
49+
acorx1 = [1.0 + 0.0im,
50+
-0.007061066965510023 - 0.24670570770539213im,
51+
-0.3791703080554228 + 0.18499330626611243im,
52+
-0.07251256107537019 + 0.17200449686941222im,
53+
-0.006618732813301651 + 0.031065686027770673im,
54+
0.1569606471499575 - 0.0038094765432061303im,
55+
-0.00678395250709688 - 0.106474871528861im,
56+
-0.18656146869859214 + 0.04664475073114351im,
57+
0.05282671316002114 + 0.0065117700502952056im,
58+
-0.051079270194684986 - 0.0538075492419246im]
59+
60+
@test autocor(x1) acorx1
61+
@test autocor(cmplx_x1) acorx1
5762
@test autocor(x) [autocor(x1) autocor(x2)]
63+
@test autocor(cmplx_x) [autocor(cmplx_x1) autocor(cmplx_x2)]
64+
5865

5966
# crosscov & crosscor
6067

@@ -75,10 +82,14 @@ c11 = crosscov(x1, x1)
7582
c12 = crosscov(x1, x2)
7683
c21 = crosscov(x2, x1)
7784
c22 = crosscov(x2, x2)
85+
@test crosscov(cmplx_x1, cmplx_x2) c12
7886

7987
@test crosscov(x, x1) [c11 c21]
88+
@test crosscov(cmplx_x, cmplx_x1) [c11 c21]
8089
@test crosscov(x1, x) [c11 c12]
90+
@test crosscov(cmplx_x1, cmplx_x) [c11 c12]
8191
@test crosscov(x, x) cat([c11 c21], [c12 c22], dims=3)
92+
@test crosscov(cmplx_x, cmplx_x) cat([c11 c21], [c12 c22], dims=3)
8293

8394
# issue #805: avoid converting one input to the other's eltype
8495
@test crosscov([34566.5345, 3466.4566], Float16[1, 10])
@@ -102,10 +113,14 @@ c11 = crosscor(x1, x1)
102113
c12 = crosscor(x1, x2)
103114
c21 = crosscor(x2, x1)
104115
c22 = crosscor(x2, x2)
116+
@test crosscor(cmplx_x1, cmplx_x2) c12
105117

106118
@test crosscor(x, x1) [c11 c21]
119+
@test crosscor(cmplx_x, cmplx_x1) [c11 c21]
107120
@test crosscor(x1, x) [c11 c12]
121+
@test crosscor(cmplx_x1, cmplx_x) [c11 c12]
108122
@test crosscor(x, x) cat([c11 c21], [c12 c22], dims=3)
123+
@test crosscor(cmplx_x, cmplx_x) cat([c11 c21], [c12 c22], dims=3)
109124

110125
# issue #805: avoid converting one input to the other's eltype
111126
@test crosscor([34566.5345, 3466.4566], Float16[1, 10])
@@ -139,9 +154,10 @@ function toeplitz(v::AbstractVector{T}) where T
139154
end
140155
# durbin solver
141156
acf = autocor(x1)
142-
p = [yulewalker_qr(acf[1:n])[n-1] for n in 2:length(acf)]
143-
@test p StatsBase.durbin(acf[2:end])
144-
145-
pacfy = [];
157+
p_qr = [yulewalker_qr(acf[1:n])[n-1] for n in 2:length(acf)]
158+
y = similar(acf[2:end])
159+
pd = similar(acf[2:end])
160+
StatsBase.durbin!(acf[2:end], y, pd)
161+
@test p_qr pd
146162

147-
@test pacf(x1, 1:4, method=:yulewalker) -p[1:4]
163+
@test pacf(x1, 1:4, method=:yulewalker) -p_qr[1:4]

0 commit comments

Comments
 (0)