Skip to content

Commit 826c42f

Browse files
committed
Eliminate l,u,p = lu(A) and friends in favor of using factorizations
The compatibility function "factors" is introduced
1 parent cbaad36 commit 826c42f

7 files changed

+149
-147
lines changed

base/export.jl

+10-7
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,12 @@ export
9090
Zip,
9191
Stat,
9292
Factorization,
93-
Cholesky,
94-
LU,
93+
CholeskyDense,
94+
LUDense,
9595
LUTridiagonal,
96-
LDLT,
9796
LDLTTridiagonal,
98-
QR,
99-
QRP,
97+
QRDense,
98+
QRPDense,
10099

101100
# Exceptions
102101
ArgumentError,
@@ -623,22 +622,26 @@ export
623622
eig,
624623
expm,
625624
eye,
625+
factors,
626626
ishermitian,
627627
issym,
628628
issym_rnd,
629629
istril,
630630
istriu,
631631
kron,
632+
ldlt,
632633
linreg,
633634
lu,
634635
lu!,
635636
matmul2x2,
636637
matmul3x3,
637638
norm,
638639
qr,
640+
qrp,
639641
randsym,
640642
rank,
641643
rref,
644+
sdd,
642645
solve,
643646
svd,
644647
svdvals,
@@ -647,8 +650,8 @@ export
647650
trideig,
648651
tril,
649652
triu,
650-
qrp,
651-
sdd,
653+
tril!,
654+
triu!,
652655

653656
# dequeues
654657
append!,

base/factorizations.jl

+102-64
Original file line numberDiff line numberDiff line change
@@ -112,50 +112,95 @@ end
112112

113113
abstract Factorization{T}
114114

115-
type Cholesky{T} <: Factorization{T}
115+
type CholeskyDense{T} <: Factorization{T}
116116
LR::Matrix{T}
117117
uplo::LapackChar
118-
function Cholesky(A::Matrix{T}, ul::LapackChar)
119-
if ul != 'U' && ul != 'L' error("Cholesky: uplo must be 'U' or 'L'") end
120-
Acopy = copy(A)
121-
_jl_lapack_potrf(ul, Acopy) == 0 ? new(ul == 'U' ? triu(Acopy) : tril(Acopy), ul) : error("Cholesky: Matrix is not positive-definite")
118+
end
119+
120+
# chol() does not check that input matrix is symmetric/hermitian
121+
# It simply uses upper triangular half
122+
function chol{T<:LapackScalar}(A::Matrix{T}, ul::LapackChar)
123+
if ul != 'U' && ul != 'L'; error("Cholesky: uplo must be 'U' or 'L'"); end
124+
C = CholeskyDense{T}(Array(T, size(A)), ul)
125+
chol(C, A)
126+
end
127+
chol{T<:Real}(A::Matrix{T}, ul::LapackChar) = chol(float64(A), ul)
128+
chol(A) = chol(A, 'U')
129+
130+
function _chol{T<:LapackScalar}(C::CholeskyDense{T})
131+
if _jl_lapack_potrf(C.uplo, C.LR) != 0
132+
error("Cholesky: Matrix is not positive-definite")
122133
end
134+
if C.uplo == 'U'
135+
triu!(C.LR)
136+
else
137+
tril!(C.LR)
138+
end
139+
C
140+
end
141+
function chol{T}(C::CholeskyDense{T}, A::Matrix{T})
142+
copy_to(C.LR, A)
143+
_chol(C)
144+
end
145+
function chol!{T<:LapackScalar}(A::Matrix{T}, ul::LapackChar)
146+
C = CholeskyDense{T}(A, ul)
147+
_chol(C)
123148
end
149+
150+
factors(C::CholeskyDense) = C.LR
124151

125-
Cholesky(A::Matrix) = Cholesky{eltype(A)}(A, 'U')
126152

127-
(\){T<:Union(Float64,Float32,Complex128,Complex64)}(C::Cholesky{T}, B::StridedVecOrMat{T}) =
153+
(\){T<:LapackScalar}(C::CholeskyDense{T}, B::StridedVecOrMat{T}) =
128154
_jl_lapack_potrs(C.uplo, C.LR, copy(B))
129155

130-
inv(C::Cholesky) = _jl_lapack_potri(C.uplo, copy(C.LR)) # should symmetrize the result
156+
inv{T<:LapackScalar}(C::CholeskyDense{T}) = _jl_lapack_potri(C.uplo, copy(C.LR)) # should symmetrize the result
131157

132-
type LU{T} <: Factorization{T}
158+
type LUDense{T} <: Factorization{T}
133159
lu::Matrix{T}
134160
ipiv::Vector{Int32}
135-
function LU(lu::Matrix{T}, ipiv::Vector{Int32})
161+
function LUDense(lu::Matrix{T}, ipiv::Vector{Int32})
136162
m, n = size(lu)
137-
m == numel(ipiv) ? new(lu, ipiv) : error("LU: dimension mismatch")
163+
m == numel(ipiv) ? new(lu, ipiv) : error("LUDense: dimension mismatch")
138164
end
139165
end
166+
size(A::LUDense) = size(A.lu)
167+
size(A::LUDense,n) = size(A.lu,n)
140168

141-
function LU{T<:Union(Float64,Float32,Complex64,Complex128)}(A::Matrix{T})
142-
lu, ipiv = _jl_lapack_getrf(copy(A))
143-
LU{T}(lu, ipiv)
169+
lu{T<:LapackScalar}(A::Matrix{T}) = lu!(copy(A))
170+
function lu!{T<:LapackScalar}(A::Matrix{T})
171+
lu, ipiv = _jl_lapack_getrf(A)
172+
LUDense{T}(lu, ipiv)
144173
end
145174

146-
LU{T<:Number}(A::Matrix{T}) = LU(float64(A))
175+
lu{T<:Real}(A::Matrix{T}) = lu(float64(A))
147176

148-
function det(lu::LU)
177+
function det(lu::LUDense)
149178
m, n = size(lu.lu)
150179
if m != n error("det only defined for square matrices") end
151180
prod(diag(lu.lu)) * (bool(sum(lu.ipiv .!= 1:n) % 2) ? -1 : 1)
152181
end
153182

154-
det(A::Matrix) = det(LU(A))
183+
det(A::Matrix) = det(lu(A))
155184

156-
(\){T<:Union(Float64,Float32,Complex128,Complex64)}(lu::LU{T}, B::StridedVecOrMat{T}) =
185+
(\){T<:LapackScalar}(lu::LUDense{T}, B::StridedVecOrMat{T}) =
157186
_jl_lapack_getrs('N', lu.lu, lu.ipiv, copy(B))
158-
inv(lu::LU) = _jl_lapack_getri(copy(lu.lu), lu.ipiv)
187+
188+
inv{T<:LapackScalar}(lu::LUDense{T}) = _jl_lapack_getri(copy(lu.lu), lu.ipiv)
189+
190+
function factors{T<:LapackScalar}(lu::LUDense{T})
191+
LU, ipiv = lu.lu, lu.ipiv
192+
m, n = size(LU)
193+
194+
L = m >= n ? tril(LU, -1) + eye(m,n) : tril(LU, -1)[:, 1:m] + eye(m,m)
195+
U = m <= n ? triu(LU) : triu(LU)[1:n, :]
196+
P = [1:m]
197+
for i=1:min(m,n)
198+
t = P[i]
199+
P[i] = P[ipiv[i]]
200+
P[ipiv[i]] = t
201+
end
202+
L, U, P
203+
end
159204

160205
## Multiplication by Q or Q' from a QR factorization
161206
for (orm2r, elty) in
@@ -193,82 +238,80 @@ for (orm2r, elty) in
193238
end
194239
end
195240

196-
type QR{T} <: Factorization{T}
241+
abstract QRFactorization{T} <: Factorization{T}
242+
243+
## QR decomposition without column pivots
244+
type QRDense{T} <: QRFactorization{T}
197245
hh::Matrix{T} # Householder transformations and R
198246
tau::Vector{T} # Scalar factors of transformations
199-
function QR(hh::Matrix{T}, tt::Vector{T})
247+
function QRDense(hh::Matrix{T}, tt::Vector{T})
200248
numel(tt) == min(size(hh)) ? new(hh, tt) : error("QR: mismatched dimensions")
201249
end
202250
end
251+
size(A::QRFactorization) = size(A.hh)
252+
size(A::QRFactorization,n) = size(A.hh,n)
203253

204-
function QR(A::Matrix)
254+
function qr{T<:LapackScalar}(A::StridedMatrix{T})
205255
hh, tt = _jl_lapack_geqrf(copy(A))
206-
QR{typeof(A[1])}(hh, tt)
256+
QRDense{eltype(A)}(hh, tt)
207257
end
208258

209-
size{T<:Union(Float64,Float32,Complex128,Complex64)}(A::QR{T}) = size(A.hh)
210-
size{T<:Union(Float64,Float32,Complex128,Complex64)}(A::QR{T},n) = size(A.hh,n)
259+
qr{T<:Real}(x::StridedMatrix{T}) = qr(float64(x))
260+
261+
function factors{T<:LapackScalar}(qrd::QRDense{T})
262+
aa, tau = qrd.hh, qrd.tau
263+
R = triu(aa[1:min(size(qrd)),:])
264+
_jl_lapack_orgqr(aa, tau), R
265+
end
211266

212267
## Multiplication by Q from the QR decomposition
213-
function (*){T<:Union(Float64,Float32,Complex128,Complex64)}(A::QR{T},
214-
B::StridedVecOrMat{T})
268+
(*){T<:LapackScalar}(A::QRFactorization{T}, B::StridedVecOrMat{T}) =
215269
_jl_lapack_orm2r('L', 'N', A.hh, size(A, 2), A.tau, copy(B))
216-
end
217270

218271
## Multiplication by Q' from the QR decomposition
219-
function Ac_mul_B{T<:Union(Float64,Float32,Complex128,Complex64)}(A::QR{T},
220-
B::StridedVecOrMat{T})
272+
Ac_mul_B{T<:LapackScalar}(A::QRFactorization{T}, B::StridedVecOrMat{T}) =
221273
_jl_lapack_orm2r('L', iscomplex(A.tau) ? 'C' : 'T', A.hh, size(A, 2), A.tau, copy(B))
222-
end
223274

224275
## Least squares solution. Should be more careful about cases with m < n
225-
function (\){T<:Union(Float64,Float32,Complex128,Complex64)}(A::QR{T},
226-
B::StridedVecOrMat{T})
276+
function (\){T<:LapackScalar}(A::QRDense{T}, B::StridedVecOrMat{T})
227277
n = numel(A.tau)
228278
qtb = isa(B, Vector) ? (A' * B)[1:n] : (A' * B)[1:n, :]
229279
## Not sure if this avoids copying A.hh[1:n,:] but at least it is not all of A.hh
230280
_jl_lapack_trtrs('U','N','N', A.hh[1:n,:], qtb)
231281
end
232282

233-
type QRP{T} <: Factorization{T}
283+
type QRPDense{T} <: QRFactorization{T}
234284
hh::Matrix{T}
235285
tau::Vector{T}
236286
jpvt::Vector{Int32}
237-
function QRP(hh::Matrix{T}, tt::Vector{T}, jj::Vector{Int32})
287+
function QRPDense(hh::Matrix{T}, tt::Vector{T}, jj::Vector{Int32})
238288
m, n = size(hh)
239-
numel(tt) == min(m,n) && numel(jj) == n ? new(hh,tt,jj) : error("QRP: mismatched dimensions")
289+
numel(tt) == min(m,n) && numel(jj) == n ? new(hh,tt,jj) : error("QRPDense: mismatched dimensions")
240290
end
241291
end
242292

243-
function QRP(A::Matrix)
244-
hh, tt, jj = _jl_lapack_geqp3(copy(A))
245-
QRP{typeof(A[1])}(hh, tt, jj)
246-
end
247-
248-
## Not sure how to avoid cut-and-paste programming on these.
249-
## Create another abstract type with both QR{T} and QRP{T} as subtypes?
250-
size{T<:Union(Float64,Float32,Complex128,Complex64)}(A::QRP{T}) = size(A.hh)
251-
size{T<:Union(Float64,Float32,Complex128,Complex64)}(A::QRP{T},n) = size(A.hh,n)
252-
253-
function (*){T<:Union(Float64,Float32,Complex128,Complex64)}(A::QRP{T},
254-
B::StridedVecOrMat{T})
255-
_jl_lapack_orm2r('L', 'N', A.hh, size(A, 2), A.tau, copy(B))
293+
function qrp{T<:LapackScalar}(A::StridedMatrix{T})
294+
aa, tau, jpvt = _jl_lapack_geqp3(copy(A))
295+
QRPDense{T}(aa, tau, jpvt)
256296
end
297+
qrp{T<:Real}(x::StridedMatrix{T}) = qrp(float64(x))
257298

258-
function Ac_mul_B{T<:Union(Float64,Float32,Complex128,Complex64)}(A::QRP{T},
259-
B::StridedVecOrMat{T})
260-
_jl_lapack_orm2r('L', iscomplex(A.tau) ? 'C' : 'T', A.hh, size(A, 2), A.tau, copy(B))
299+
function factors{T<:LapackScalar}(qrpd::QRPDense{T})
300+
aa, tau = qrpd.hh, qrpd.tau
301+
R = triu(aa[1:min(size(qrpd)),:])
302+
_jl_lapack_orgqr(aa, tau), R, qrpd.jpvt
261303
end
262304

263-
function (\){T<:Union(Float64,Float32,Complex128,Complex64)}(A::QRP{T},
305+
# FIXME \
306+
function (\){T<:Union(Float64,Float32,Complex128,Complex64)}(A::QRPDense{T},
264307
B::StridedVecOrMat{T})
265308
n = numel(A.tau)
266309
## Replace this with a direct call to _jl_lapack_trtrs to save copying A.hh?
267310
## Actually would need to call the appropriate Lapack subroutine to save copying.
268311
triu(A.hh[1:n,:]) \ (A' * B)[1:n]
269312
end
270313

271-
function (\){T<:Union(Float64,Float32,Complex128,Complex64)}(A::QRP{T},
314+
function (\){T<:Union(Float64,Float32,Complex128,Complex64)}(A::QRPDense{T},
272315
B::StridedVecOrMat{T})
273316
## may be better to define one method for B::Vector{T} and another for StridedMatrix
274317
BV = isa(B, Vector)
@@ -288,13 +331,12 @@ type LDLTTridiagonal{T} <: Factorization{T}
288331
D::Vector{T}
289332
E::Vector{T}
290333
end
291-
function LDLTTridiagonal{T<:LapackScalar}(A::Tridiagonal{T})
334+
function ldlt{T<:LapackScalar}(A::Tridiagonal{T})
292335
D = copy(A.d)
293336
E = copy(A.dl)
294337
_jl_lapack_pttrf(D, E)
295-
LDLTTridiagonal(D, E)
338+
LDLTTridiagonal{T}(D, E)
296339
end
297-
LDLT(A::Tridiagonal) = LDLTTridiagonal(A)
298340

299341
(\){T<:LapackScalar}(C::LDLTTridiagonal{T}, B::StridedVecOrMat{T}) =
300342
_jl_lapack_pttrs(C.D, C.E, copy(B))
@@ -304,25 +346,21 @@ type LUTridiagonal{T} <: Factorization{T}
304346
ipiv::Vector{Int32}
305347
function LUTridiagonal(lu::Tridiagonal{T}, ipiv::Vector{Int32})
306348
m, n = size(lu)
307-
m == numel(ipiv) ? new(lu, ipiv) : error("LU: dimension mismatch")
349+
m == numel(ipiv) ? new(lu, ipiv) : error("LUTridiagonal: dimension mismatch")
308350
end
309351
end
310352
show(io, lu::LUTridiagonal) = print(io, "LU decomposition of ", summary(lu.lu))
311353

312-
function LU{T<:LapackScalar}(A::Tridiagonal{T})
354+
function lu{T<:LapackScalar}(A::Tridiagonal{T})
313355
lu, ipiv = _jl_lapack_gttrf(copy(A))
314356
LUTridiagonal{T}(lu, ipiv)
315357
end
316358

317-
function lu(A::Tridiagonal)
318-
error("lu(A) is not defined when A is Tridiagonal. Use LU(A) instead.")
319-
end
320-
321359
function det(lu::LUTridiagonal)
322360
prod(lu.lu.d) * (bool(sum(lu.ipiv .!= 1:n) % 2) ? -1 : 1)
323361
end
324362

325-
det(A::Tridiagonal) = det(LU(A))
363+
det(A::Tridiagonal) = det(lu(A))
326364

327365
(\){T<:LapackScalar}(lu::LUTridiagonal{T}, B::StridedVecOrMat{T}) =
328366
_jl_lapack_gttrs('N', lu.lu, lu.ipiv, copy(B))

base/linalg.jl

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ triu(M::AbstractMatrix) = triu(M,0)
2323
tril(M::AbstractMatrix) = tril(M,0)
2424
#triu{T}(M::AbstractMatrix{T}, k::Integer)
2525
#tril{T}(M::AbstractMatrix{T}, k::Integer)
26+
triu!(M::AbstractMatrix) = triu!(M,0)
27+
tril!(M::AbstractMatrix) = tril!(M,0)
2628

2729
#diff(a::AbstractVector)
2830
#diff(a::AbstractMatrix, dim::Integer)

base/linalg_dense.jl

+20
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,26 @@ triu{T}(M::Matrix{T}, k::Integer) = [ j-i >= k ? M[i,j] : zero(T) for
264264
i=1:size(M,1), j=1:size(M,2) ]
265265
tril{T}(M::Matrix{T}, k::Integer) = [ j-i <= k ? M[i,j] : zero(T) for
266266
i=1:size(M,1), j=1:size(M,2) ]
267+
function triu!{T}(M::Matrix{T}, k::Integer)
268+
m, n = size(M)
269+
for i = 1:m
270+
for j = 1:n
271+
if j-i < k
272+
M[i,j] = zero(T)
273+
end
274+
end
275+
end
276+
end
277+
function tril!{T}(M::Matrix{T}, k::Integer)
278+
m, n = size(M)
279+
for i = 1:m
280+
for j = 1:n
281+
if j-i > k
282+
M[i,j] = zero(T)
283+
end
284+
end
285+
end
286+
end
267287

268288
diff(a::Vector) = [ a[i+1] - a[i] for i=1:length(a)-1 ]
269289

0 commit comments

Comments
 (0)