Skip to content

Commit d2f501d

Browse files
committed
Merge pull request #5430 from JuliaLang/anj/lup
Add pivoting to LU decomposition.
2 parents 8566975 + 2b00f51 commit d2f501d

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

base/linalg/factorization.jl

+40-13
Original file line numberDiff line numberDiff line change
@@ -131,19 +131,42 @@ function lufact!{T}(A::AbstractMatrix{T})
131131
m, n = size(A)
132132
minmn = min(m,n)
133133
info = 0
134-
for k = 1:minmn-1
135-
if A[k,k] == 0; info = k; break; end
136-
for i = k+1:m
137-
A[i,k] /= A[k,k]
134+
ipiv = Array(BlasInt, minmn)
135+
for k = 1:minmn
136+
# find index max
137+
kp = 1
138+
amax = zero(T)
139+
for i = k:m
140+
absi = abs(A[i,k])
141+
if absi > amax
142+
kp = i
143+
amax = absi
144+
end
145+
end
146+
ipiv[k] = kp
147+
if A[kp,k] != 0
148+
# Interchange
149+
for i = 1:n
150+
tmp = A[k,i]
151+
A[k,i] = A[kp,i]
152+
A[kp,i] = tmp
153+
end
154+
# Scale first column
155+
for i = k+1:m
156+
A[i,k] /= A[k,k]
157+
end
158+
elseif info == 0
159+
info = k
138160
end
161+
# Update the rest
139162
for j = k+1:n
140163
for i = k+1:m
141164
A[i,j] -= A[i,k]*A[k,j]
142165
end
143166
end
144167
end
145168
if minmn > 0 && A[minmn,minmn] == 0; info = minmn; end
146-
LU(A, BlasInt[1:minmn], convert(BlasInt, info))
169+
LU(A, ipiv, convert(BlasInt, info))
147170
end
148171
lufact(A::StridedMatrix) = lufact!(copy(A))
149172
lufact(x::Number) = LU(fill(x, 1, 1), BlasInt[1], x == 0 ? one(BlasInt) : zero(BlasInt))
@@ -158,17 +181,20 @@ convert{T}(::Type{LU{T}}, F::LU) = LU(convert(Matrix{T}, F.factors), F.ipiv, F.i
158181
size(A::LU) = size(A.factors)
159182
size(A::LU,n) = size(A.factors,n)
160183

184+
function ipiv2perm{T}(v::AbstractVector{T}, maxi::Integer)
185+
p = T[1:maxi]
186+
@inbounds for i in 1:length(v)
187+
p[i], p[v[i]] = p[v[i]], p[i]
188+
end
189+
return p
190+
end
191+
161192
function getindex{T}(A::LU{T}, d::Symbol)
162193
m, n = size(A)
163194
d == :L && return tril(A.factors[1:m, 1:min(m,n)], -1) + eye(T, m, min(m,n))
164195
d == :U && return triu(A.factors[1:min(m,n),1:n])
165-
if d == :p
166-
p = [1:m]
167-
for i in 1:length(A.ipiv)
168-
p[i], p[A.ipiv[i]] = p[A.ipiv[i]], p[i]
169-
end
170-
return p
171-
elseif d == :P
196+
d == :p && return ipiv2perm(A.ipiv, m)
197+
if d == :P
172198
p = A[:p]
173199
P = zeros(T, m, m)
174200
for i in 1:m
@@ -207,7 +233,8 @@ function logdet{T<:Complex}(A::LU{T})
207233
end
208234

209235
A_ldiv_B!{T<:BlasFloat}(A::LU{T}, B::StridedVecOrMat{T}) = @assertnonsingular LAPACK.getrs!('N', A.factors, A.ipiv, B) A.info
210-
A_ldiv_B!(A::LU, B::StridedVecOrMat) = A_ldiv_B!(Triangular(A.factors, :U, false), A_ldiv_B!(Triangular(A.factors, :L, true), B))
236+
A_ldiv_B!(A::LU, b::StridedVector) = A_ldiv_B!(Triangular(A.factors, :U, false), A_ldiv_B!(Triangular(A.factors, :L, true), b[ipiv2perm(A.ipiv, length(b))]))
237+
A_ldiv_B!(A::LU, B::StridedMatrix) = A_ldiv_B!(Triangular(A.factors, :U, false), A_ldiv_B!(Triangular(A.factors, :L, true), B[ipiv2perm(A.ipiv, size(B, 1)),:]))
211238
At_ldiv_B{T<:BlasFloat}(A::LU{T}, B::StridedVecOrMat{T}) = @assertnonsingular LAPACK.getrs!('T', A.factors, A.ipiv, copy(B)) A.info
212239
Ac_ldiv_B{T<:BlasComplex}(A::LU{T}, B::StridedVecOrMat{T}) = @assertnonsingular LAPACK.getrs!('C', A.factors, A.ipiv, copy(B)) A.info
213240
At_ldiv_Bt{T<:BlasFloat}(A::LU{T}, B::StridedVecOrMat{T}) = @assertnonsingular LAPACK.getrs!('T', A.factors, A.ipiv, transpose(B)) A.info

0 commit comments

Comments
 (0)