Skip to content

Commit c7b8eb9

Browse files
fredrikekreKristofferC
authored andcommitted
deprecate cholfact[!](A, uplo) (#22188)
restructure the cholesky test
1 parent 8e4202a commit c7b8eb9

File tree

4 files changed

+57
-70
lines changed

4 files changed

+57
-70
lines changed

NEWS.md

+3
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ Deprecated or removed
7070

7171
* The method `srand(rng, filename, n=4)` has been deprecated ([#21359]).
7272

73+
* The `cholfact`/`cholfact!` methods that accepted an `uplo` symbol have been deprecated
74+
in favor of using `Hermitian` (or `Symmetric`) views ([#22187], [#22188]).
75+
7376

7477
Julia v0.6.0 Release Notes
7578
==========================

base/deprecated.jl

+8
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,14 @@ end
13541354
@deprecate versioninfo(verbose::Bool) versioninfo(verbose=verbose)
13551355
@deprecate versioninfo(io::IO, verbose::Bool) versioninfo(io, verbose=verbose)
13561356

1357+
# PR #22188
1358+
@deprecate cholfact!(A::StridedMatrix, uplo::Symbol, ::Type{Val{false}}) cholfact!(Hermitian(A, uplo), Val{false})
1359+
@deprecate cholfact!(A::StridedMatrix, uplo::Symbol) cholfact!(Hermitian(A, uplo))
1360+
@deprecate cholfact(A::StridedMatrix, uplo::Symbol, ::Type{Val{false}}) cholfact(Hermitian(A, uplo), Val{false})
1361+
@deprecate cholfact(A::StridedMatrix, uplo::Symbol) cholfact(Hermitian(A, uplo))
1362+
@deprecate cholfact!(A::StridedMatrix, uplo::Symbol, ::Type{Val{true}}; tol = 0.0) cholfact!(Hermitian(A, uplo), Val{true}, tol = tol)
1363+
@deprecate cholfact(A::StridedMatrix, uplo::Symbol, ::Type{Val{true}}; tol = 0.0) cholfact(Hermitian(A, uplo), Val{true}, tol = tol)
1364+
13571365
# END 0.7 deprecations
13581366

13591367
# BEGIN 1.0 deprecations

base/linalg/cholesky.jl

+19-42
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
# The internal structure is as follows
2222
# - _chol! returns the factor and info without checking positive definiteness
2323
# - chol/chol! returns the factor and checks for positive definiteness
24-
# - cholfact/cholfact! returns Cholesky with checking positive definiteness
24+
# - cholfact/cholfact! returns Cholesky without checking positive definiteness
2525

2626
# FixMe? The dispatch below seems overly complicated. One simplification could be to
2727
# merge the two Cholesky types into one. It would remove the need for Val completely but
@@ -207,8 +207,8 @@ chol(x::Number, args...) = ((C, info) = _chol!(x, nothing); @assertposdef C info
207207

208208
# cholfact!. Destructive methods for computing Cholesky factorization of real symmetric
209209
# or Hermitian matrix
210-
## No pivoting
211-
function cholfact!(A::RealHermSymComplexHerm, ::Type{Val{false}})
210+
## No pivoting (default)
211+
function cholfact!(A::RealHermSymComplexHerm, ::Type{Val{false}}=Val{false})
212212
if A.uplo == 'U'
213213
CU, info = _chol!(A.data, UpperTriangular)
214214
Cholesky(CU.data, 'U', info)
@@ -220,7 +220,7 @@ end
220220

221221
### for StridedMatrices, check that matrix is symmetric/Hermitian
222222
"""
223-
cholfact!(A, [uplo::Symbol,] Val{false}) -> Cholesky
223+
cholfact!(A, Val{false}) -> Cholesky
224224
225225
The same as [`cholfact`](@ref), but saves space by overwriting the input `A`,
226226
instead of creating a copy. An [`InexactError`](@ref) exception is thrown if
@@ -239,18 +239,9 @@ julia> cholfact!(A)
239239
ERROR: InexactError()
240240
```
241241
"""
242-
function cholfact!(A::StridedMatrix, uplo::Symbol, ::Type{Val{false}})
242+
function cholfact!(A::StridedMatrix, ::Type{Val{false}}=Val{false})
243243
ishermitian(A) || non_hermitian_error("cholfact!")
244-
return cholfact!(Hermitian(A, uplo), Val{false})
245-
end
246-
247-
### Default to no pivoting (and storing of upper factor) when not explicit
248-
cholfact!(A::RealHermSymComplexHerm) = cholfact!(A, Val{false})
249-
250-
#### for StridedMatrices, check that matrix is symmetric/Hermitian
251-
function cholfact!(A::StridedMatrix, uplo::Symbol = :U)
252-
ishermitian(A) || non_hermitian_error("cholfact!")
253-
return cholfact!(Hermitian(A, uplo))
244+
return cholfact!(Hermitian(A), Val{false})
254245
end
255246

256247

@@ -270,37 +261,34 @@ cholfact!(A::RealHermSymComplexHerm{<:Real}, ::Type{Val{true}};
270261

271262
### for StridedMatrices, check that matrix is symmetric/Hermitian
272263
"""
273-
cholfact!(A, [uplo::Symbol,] Val{true}; tol = 0.0) -> CholeskyPivoted
264+
cholfact!(A, Val{true}; tol = 0.0) -> CholeskyPivoted
274265
275266
The same as [`cholfact`](@ref), but saves space by overwriting the input `A`,
276267
instead of creating a copy. An [`InexactError`](@ref) exception is thrown if the
277268
factorization produces a number not representable by the element type of `A`,
278269
e.g. for integer types.
279270
"""
280-
function cholfact!(A::StridedMatrix, uplo::Symbol, ::Type{Val{true}}; tol = 0.0)
271+
function cholfact!(A::StridedMatrix, ::Type{Val{true}}; tol = 0.0)
281272
ishermitian(A) || non_hermitian_error("cholfact!")
282-
return cholfact!(Hermitian(A, uplo), Val{true}; tol = tol)
273+
return cholfact!(Hermitian(A), Val{true}; tol = tol)
283274
end
284275

285276
# cholfact. Non-destructive methods for computing Cholesky factorization of real symmetric
286277
# or Hermitian matrix
287-
## No pivoting
288-
cholfact(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}, ::Type{Val{false}}) =
289-
cholfact!(copy_oftype(A, promote_type(typeof(chol(one(eltype(A)))),Float32)), Val{false})
278+
## No pivoting (default)
279+
cholfact(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}, ::Type{Val{false}}=Val{false}) =
280+
cholfact!(copy_oftype(A, promote_type(typeof(chol(one(eltype(A)))),Float32)))
290281

291282
### for StridedMatrices, check that matrix is symmetric/Hermitian
292283
"""
293-
cholfact(A, [uplo::Symbol,] Val{false}) -> Cholesky
284+
cholfact(A, Val{false}) -> Cholesky
294285
295286
Compute the Cholesky factorization of a dense symmetric positive definite matrix `A`
296287
and return a `Cholesky` factorization. The matrix `A` can either be a [`Symmetric`](@ref) or [`Hermitian`](@ref)
297-
`StridedMatrix` or a *perfectly* symmetric or Hermitian `StridedMatrix`. In the latter case,
298-
the optional argument `uplo` may be `:L` for using the lower part or `:U` for the upper part of `A`.
299-
The default is to use `:U`.
288+
`StridedMatrix` or a *perfectly* symmetric or Hermitian `StridedMatrix`.
300289
The triangular Cholesky factor can be obtained from the factorization `F` with: `F[:L]` and `F[:U]`.
301290
The following functions are available for `Cholesky` objects: [`size`](@ref), [`\\`](@ref),
302291
[`inv`](@ref), and [`det`](@ref).
303-
A `PosDefException` exception is thrown in case the matrix is not positive definite.
304292
305293
# Example
306294
@@ -331,18 +319,9 @@ julia> C[:L] * C[:U] == A
331319
true
332320
```
333321
"""
334-
function cholfact(A::StridedMatrix, uplo::Symbol, ::Type{Val{false}})
335-
ishermitian(A) || non_hermitian_error("cholfact")
336-
return cholfact(Hermitian(A, uplo), Val{false})
337-
end
338-
339-
### Default to no pivoting (and storing of upper factor) when not explicit
340-
cholfact(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}) = cholfact(A, Val{false})
341-
342-
#### for StridedMatrices, check that matrix is symmetric/Hermitian
343-
function cholfact(A::StridedMatrix, uplo::Symbol = :U)
322+
function cholfact(A::StridedMatrix, ::Type{Val{false}}=Val{false})
344323
ishermitian(A) || non_hermitian_error("cholfact")
345-
return cholfact(Hermitian(A, uplo))
324+
return cholfact(Hermitian(A))
346325
end
347326

348327

@@ -353,22 +332,20 @@ cholfact(A::RealHermSymComplexHerm{<:Real,<:StridedMatrix}, ::Type{Val{true}}; t
353332

354333
### for StridedMatrices, check that matrix is symmetric/Hermitian
355334
"""
356-
cholfact(A, [uplo::Symbol,] Val{true}; tol = 0.0) -> CholeskyPivoted
335+
cholfact(A, Val{true}; tol = 0.0) -> CholeskyPivoted
357336
358337
Compute the pivoted Cholesky factorization of a dense symmetric positive semi-definite matrix `A`
359338
and return a `CholeskyPivoted` factorization. The matrix `A` can either be a [`Symmetric`](@ref)
360339
or [`Hermitian`](@ref) `StridedMatrix` or a *perfectly* symmetric or Hermitian `StridedMatrix`.
361-
In the latter case, the optional argument `uplo` may be `:L` for using the lower part or `:U`
362-
for the upper part of `A`. The default is to use `:U`.
363340
The triangular Cholesky factor can be obtained from the factorization `F` with: `F[:L]` and `F[:U]`.
364341
The following functions are available for `PivotedCholesky` objects:
365342
[`size`](@ref), [`\\`](@ref), [`inv`](@ref), [`det`](@ref), and [`rank`](@ref).
366343
The argument `tol` determines the tolerance for determining the rank.
367344
For negative values, the tolerance is the machine precision.
368345
"""
369-
function cholfact(A::StridedMatrix, uplo::Symbol, ::Type{Val{true}}; tol = 0.0)
346+
function cholfact(A::StridedMatrix, ::Type{Val{true}}; tol = 0.0)
370347
ishermitian(A) || non_hermitian_error("cholfact")
371-
return cholfact(Hermitian(A, uplo), Val{true}; tol = tol)
348+
return cholfact(Hermitian(A), Val{true}; tol = tol)
372349
end
373350

374351
## Number

test/linalg/cholesky.jl

+27-28
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,11 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
2323
for eltya in (Float32, Float64, Complex64, Complex128, BigFloat, Int)
2424
a = eltya == Int ? rand(1:7, n, n) : convert(Matrix{eltya}, eltya <: Complex ? complex.(areal, aimg) : areal)
2525
a2 = eltya == Int ? rand(1:7, n, n) : convert(Matrix{eltya}, eltya <: Complex ? complex.(a2real, a2img) : a2real)
26-
apd = a'*a # symmetric positive-definite
2726

28-
apds = Symmetric(apd)
29-
apdsL = Symmetric(apd, :L)
30-
apdh = Hermitian(apd)
31-
apdhL = Hermitian(apd, :L)
3227
ε = εa = eps(abs(float(one(eltya))))
3328

29+
# Test of symmetric pos. def. strided matrix
30+
apd = a'*a
3431
@inferred cholfact(apd)
3532
@inferred chol(apd)
3633
capd = factorize(apd)
@@ -61,6 +58,11 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
6158
@test all(x -> x apos, cholfact(apos).factors)
6259
@test_throws PosDefException chol(-one(eltya))
6360

61+
# Test cholfact with Symmetric/Hermitian upper/lower
62+
apds = Symmetric(apd)
63+
apdsL = Symmetric(apd, :L)
64+
apdh = Hermitian(apd)
65+
apdhL = Hermitian(apd, :L)
6466
if eltya <: Real
6567
capds = cholfact(apds)
6668
@test inv(capds)*apds eye(n)
@@ -82,9 +84,6 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
8284
capdh = cholfact!(copy(apd))
8385
@test inv(capdh)*apdh eye(n)
8486
@test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n
85-
capdh = cholfact!(copy(apd), :L)
86-
@test inv(capdh)*apdh eye(n)
87-
@test abs((det(capdh) - det(apd))/det(capdh)) <= ε*κ*n
8887
ulstring = sprint(show,capdh[:UL])
8988
@test sprint(show,capdh) == "$(typeof(capdh)) with factor:\n$ulstring"
9089
end
@@ -94,18 +93,13 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
9493
U = Bidiagonal([2,sqrt(eltya(3))],[-1],true) / sqrt(eltya(2))
9594
@test full(chol(S)) full(U)
9695

97-
#lower Cholesky factor
98-
lapd = cholfact(apd, :L)
99-
@test full(lapd) apd
100-
l = lapd[:L]
101-
@test l*l' apd
102-
@test triu(capd.factors) lapd[:U]
103-
@test tril(lapd.factors) capd[:L]
96+
# test extraction of factor and re-creating original matrix
10497
if eltya <: Real
10598
capds = cholfact(apds)
10699
lapds = cholfact(apdsL)
107100
cl = chol(apdsL)
108101
ls = lapds[:L]
102+
@test full(capds) full(lapds) apd
109103
@test ls*ls' apd
110104
@test triu(capds.factors) lapds[:U]
111105
@test tril(lapds.factors) capds[:L]
@@ -117,6 +111,7 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
117111
lapdh = cholfact(apdhL)
118112
cl = chol(apdhL)
119113
ls = lapdh[:L]
114+
@test full(capdh) full(lapdh) apd
120115
@test ls*ls' apd
121116
@test triu(capdh.factors) lapdh[:U]
122117
@test tril(lapdh.factors) capdh[:L]
@@ -127,9 +122,9 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
127122

128123
#pivoted upper Cholesky
129124
if eltya != BigFloat
130-
cz = cholfact(zeros(eltya,n,n), :U, Val{true})
125+
cz = cholfact(Hermitian(zeros(eltya,n,n)), Val{true})
131126
@test_throws Base.LinAlg.RankDeficientException Base.LinAlg.chkfullrank(cz)
132-
cpapd = cholfact(apd, :U, Val{true})
127+
cpapd = cholfact(apdh, Val{true})
133128
@test rank(cpapd) == n
134129
@test all(diff(diag(real(cpapd.factors))).<=0.) # diagonal should be non-increasing
135130
if isreal(apd)
@@ -162,17 +157,19 @@ using Base.LinAlg: BlasComplex, BlasFloat, BlasReal, QRPivoted, PosDefException
162157
@test norm(a*(capd\(a'*b)) - b,1)/norm(b,1) <= ε*κ*n # Ad hoc, revisit
163158

164159
if eltya != BigFloat && eltyb != BigFloat
160+
lapd = cholfact(apdhL)
165161
@test norm(apd * (lapd\b) - b)/norm(b) <= ε*κ*n
166162
@test norm(apd * (lapd\b[1:n]) - b[1:n])/norm(b[1:n]) <= ε*κ*n
167163
end
168-
@test_throws DimensionMismatch lapd\RowVector(ones(n))
164+
@test_throws DimensionMismatch cholfact(apdhL)\RowVector(ones(n))
169165

170166
if eltya != BigFloat && eltyb != BigFloat # Note! Need to implement pivoted Cholesky decomposition in julia
171167

168+
cpapd = cholfact(apdh, Val{true})
172169
@test norm(apd * (cpapd\b) - b)/norm(b) <= ε*κ*n # Ad hoc, revisit
173170
@test norm(apd * (cpapd\b[1:n]) - b[1:n])/norm(b[1:n]) <= ε*κ*n
174171

175-
lpapd = cholfact(apd, :L, Val{true})
172+
lpapd = cholfact(apdhL, Val{true})
176173
@test norm(apd * (lpapd\b) - b)/norm(b) <= ε*κ*n # Ad hoc, revisit
177174
@test norm(apd * (lpapd\b[1:n]) - b[1:n])/norm(b[1:n]) <= ε*κ*n
178175

@@ -214,8 +211,8 @@ end
214211
AcA = A'A
215212
BcB = AcA + v*v'
216213
BcB = (BcB + BcB')/2
217-
F = cholfact(AcA, uplo)
218-
G = cholfact(BcB, uplo)
214+
F = cholfact(Hermitian(AcA, uplo))
215+
G = cholfact(Hermitian(BcB, uplo))
219216
@test LinAlg.lowrankupdate(F, v)[uplo] G[uplo]
220217
@test_throws DimensionMismatch LinAlg.lowrankupdate(F, ones(eltype(v), length(v)+1))
221218
@test LinAlg.lowrankdowndate(G, v)[uplo] F[uplo]
@@ -244,7 +241,7 @@ end
244241
0.25336108035924787 + 0.975317836492159im 0.0628393808469436 - 0.1253397353973715im
245242
0.11192755545114 - 0.1603741874112385im 0.8439562576196216 + 1.0850814110398734im
246243
-1.0568488936791578 - 0.06025820467086475im 0.12696236014017806 - 0.09853584666755086im]
247-
cholfact(apd, :L, Val{true}) \ b
244+
cholfact(Hermitian(apd, :L), Val{true}) \ b
248245
r = factorize(apd)[:U]
249246
E = abs.(apd - r'*r)
250247
ε = eps(abs(float(one(Complex64))))
@@ -255,12 +252,14 @@ end
255252
end
256253

257254
@testset "throw if non-Hermitian" begin
258-
@test_throws ArgumentError cholfact(randn(5,5))
259-
@test_throws ArgumentError cholfact(complex.(randn(5,5), randn(5,5)))
260-
@test_throws ArgumentError Base.LinAlg.chol!(randn(5,5))
261-
@test_throws ArgumentError Base.LinAlg.cholfact!(randn(5,5),:U,Val{false})
262-
@test_throws ArgumentError Base.LinAlg.cholfact!(randn(5,5),:U,Val{true})
263-
@test_throws ArgumentError cholfact(randn(5,5),:U,Val{false})
255+
R = randn(5, 5)
256+
C = complex.(R, R)
257+
for A in (R, C)
258+
@test_throws ArgumentError cholfact(A)
259+
@test_throws ArgumentError cholfact!(copy(A))
260+
@test_throws ArgumentError chol(A)
261+
@test_throws ArgumentError Base.LinAlg.chol!(copy(A))
262+
end
264263
end
265264

266265
@testset "fail for non-BLAS element types" begin

0 commit comments

Comments
 (0)