@@ -10,6 +10,8 @@ The individual components of the factorization `F::LULinv` can be accessed via [
1010|:----------|:--------------------------------------------|
1111| `F.L` | `L` (unit lower triangular) part of `LUL⁻¹` |
1212| `F.U` | `U` (upper triangular) part of `LUL⁻¹` |
13+ | `F.p` | (right) permutation `Vector` |
14+ | `F.P` | (right) permutation `Matrix` |
1315
1416Iterating the factorization produces the components `F.L` and `F.U`.
1517
@@ -31,12 +33,12 @@ U factor:
3133 -0.772002 3.0
3234 0.0 7.772
3335
34- julia> F.L * F.U / F.L ≈ A
36+ julia> F.L * F.U / F.L ≈ A[F.p, F.p]
3537true
3638
37- julia> l, u = lulinv(A); # destructuring via iteration
39+ julia> l, u, p = lulinv(A); # destructuring via iteration
3840
39- julia> l == F.L && u == F.U
41+ julia> l == F.L && u == F.U && p == F.p
4042true
4143
4244julia> A = [-150 334 778; -89 195 464; 5 -10 -27]
@@ -58,25 +60,27 @@ U factor:
5860 0 -2 75
5961 0 0 3
6062
61- julia> F.L * F.U / F.L == A
63+ julia> F.L * F.U / F.L == A[F.p, F.p]
6264true
6365```
6466"""
65- struct LULinv{T, S <: AbstractMatrix{T} } <: Factorization{T}
67+ struct LULinv{T, S <: AbstractMatrix{T} , IPIV <: AbstractVector{<:Integer} } <: Factorization{T}
6668 factors:: S
67- function LULinv {T, S} (factors) where {T, S <: AbstractMatrix{T} }
69+ ipiv:: IPIV
70+ function LULinv {T, S, IPIV} (factors, ipiv) where {T, S <: AbstractMatrix{T} , IPIV <: AbstractVector{<:Integer} }
6871 require_one_based_indexing (factors)
69- new {T, S} (factors)
72+ new {T, S, IPIV } (factors, ipiv )
7073 end
7174end
7275
7376
74- LULinv (factors:: AbstractMatrix{T} ) where T = LULinv {T, typeof(factors)} (factors)
75- LULinv {T} (factors:: AbstractMatrix ) where T = LULinv (convert (AbstractMatrix{T}, factors))
76- LULinv {T} (F:: LULinv ) where T = LULinv {T} (F. factors)
77+ LULinv (factors:: AbstractMatrix{T} , ipiv :: AbstractVector{<:Integer} ) where T = LULinv {T, typeof(factors), typeof(ipiv) } (factors, ipiv )
78+ LULinv {T} (factors:: AbstractMatrix , ipiv :: AbstractVector{<:Integer} ) where T = LULinv (convert (AbstractMatrix{T}, factors), ipiv )
79+ LULinv {T} (F:: LULinv ) where T = LULinv {T} (F. factors, F . ipiv )
7780
7881iterate (F:: LULinv ) = (F. L, Val (:U ))
79- iterate (F:: LULinv , :: Val{:U} ) = (F. U, Val (:done ))
82+ iterate (F:: LULinv , :: Val{:U} ) = (F. U, Val (:p ))
83+ iterate (F:: LULinv , :: Val{:p} ) = (F. p, Val (:done ))
8084iterate (F:: LULinv , :: Val{:done} ) = nothing
8185
8286
@@ -116,17 +120,22 @@ function getU(F::LULinv)
116120end
117121
118122function getproperty (F:: LULinv{T, <: AbstractMatrix} , d:: Symbol ) where T
123+ n = size (F, 1 )
119124 if d === :L
120125 return getL (F)
121126 elseif d === :U
122127 return getU (F)
128+ elseif d === :p
129+ return getfield (F, :ipiv )
130+ elseif d === :P
131+ return Matrix {T} (I, n, n)[:, F. p]
123132 else
124133 getfield (F, d)
125134 end
126135end
127136
128137propertynames (F:: LULinv , private:: Bool = false ) =
129- (:L , :U , (private ? fieldnames (typeof (F)) : ()). .. )
138+ (:L , :U , :p , :P , (private ? fieldnames (typeof (F)) : ()). .. )
130139
131140function show (io:: IO , mime:: MIME{Symbol("text/plain")} , F:: LULinv )
132141 summary (io, F); println (io)
@@ -137,42 +146,60 @@ function show(io::IO, mime::MIME{Symbol("text/plain")}, F::LULinv)
137146end
138147
139148
140- lulinv (A:: AbstractMatrix ; kwds... ) = lulinv (A, eigvals (A); kwds... )
141- function lulinv (A:: AbstractMatrix{T} , λ:: AbstractVector{T} ; kwds... ) where T
149+ lulinv (A:: AbstractMatrix , pivot :: Union{Val{false}, Val{true}} = Val ( true ) ; kwds... ) = lulinv (A, eigvals (A), pivot ; kwds... )
150+ function lulinv (A:: AbstractMatrix{T} , λ:: AbstractVector{T} , pivot :: Union{Val{false}, Val{true}} = Val ( true ) ; kwds... ) where T
142151 S = lulinvtype (T)
143- lulinv! (copy_oftype (A, S), copy_oftype (λ, S); kwds... )
152+ lulinv! (copy_oftype (A, S), copy_oftype (λ, S), pivot ; kwds... )
144153end
145- function lulinv (A:: AbstractMatrix{T1} , λ:: AbstractVector{T2} ; kwds... ) where {T1, T2}
154+ function lulinv (A:: AbstractMatrix{T1} , λ:: AbstractVector{T2} , pivot :: Union{Val{false}, Val{true}} = Val ( true ) ; kwds... ) where {T1, T2}
146155 T = promote_type (T1, T2)
147156 S = lulinvtype (T)
148- lulinv! (copy_oftype (A, S), copy_oftype (λ, S); kwds... )
157+ lulinv! (copy_oftype (A, S), copy_oftype (λ, S), pivot ; kwds... )
149158end
150159
151- function lulinv! (A:: Matrix{T} , λ:: Vector{T} ; rtol:: Real = size (A, 1 )* eps (real (float (oneunit (T))))) where T
160+ function lulinv! (A:: Matrix{T} , λ:: Vector{T} , :: Val{Pivot} = Val ( true ) ; rtol:: Real = size (A, 1 )* eps (real (float (oneunit (T))))) where {T, Pivot}
152161 n = checksquare (A)
153162 n == length (λ) || throw (ArgumentError (" Eigenvalue count does not match matrix dimensions." ))
154163 v = zeros (T, n)
155- for i in 1 : n- 1
156- # We must find an eigenvector with nonzero "first" entry. A failed UL factorization of A-λI reveals this vector provided L₁₁ == 0.
157- for j in 1 : length (λ)
158- F = ul! (view (A, i: n, i: n) - λ[j]* I; check= false )
159- nrm = norm (F. L)
160- if norm (F. L[1 ]) ≤ rtol* nrm # v[i] is a free parameter; we set it to 1.
161- fill! (v, zero (T))
162- v[i] = one (T)
163- # Next, we must scan the remaining free parameters, set them to 0, so that we find a nonsingular lower-triangular linear system for the nontrivial remaining part of the eigenvector.
164- idx = Int[]
165- for k in 2 : n+ 1 - i
166- if norm (F. L[k, k]) > rtol* nrm
167- push! (idx, k)
168- end
164+ ipiv = collect (1 : n)
165+ for i in 1 : n
166+ F = ul! (view (A, i: n, i: n) - λ[i]* I; check = false )
167+ nrm = norm (F. L)
168+ if Pivot
169+ ip = n+ 1 - i
170+ while (ip > 1 ) && (norm (F. L[ip, ip]) > rtol* nrm)
171+ ip -= 1
172+ end
173+ fill! (v, zero (T))
174+ v[i] = one (T)
175+ idx = ip+ 1 : n+ 1 - i
176+ if ! isempty (idx)
177+ v[idx.+ (i- 1 )] .= - F. L[idx, ip]
178+ ldiv! (LowerTriangular (view (F. L, idx, idx)), view (v, idx.+ (i- 1 )))
179+ end
180+ ip = ip+ i- 1
181+ if ip ≠ i
182+ tmp = ipiv[i]
183+ ipiv[i] = ipiv[ip]
184+ ipiv[ip] = tmp
185+ for j in 1 : n
186+ tmp = A[i, j]
187+ A[i, j] = A[ip, j]
188+ A[ip, j] = tmp
169189 end
170- if ! isempty (idx)
171- v[idx.+ (i- 1 )] .= - F. L[idx, 1 ]
172- ldiv! (LowerTriangular (view (F. L, idx, idx)), view (v, idx.+ (i- 1 )))
190+ for j in 1 : n
191+ tmp = A[j, i]
192+ A[j, i] = A[j, ip]
193+ A[j, ip] = tmp
173194 end
174- deleteat! (λ, j)
175- break
195+ end
196+ else
197+ fill! (v, zero (T))
198+ v[i] = one (T)
199+ idx = 2 : n+ 1 - i
200+ if ! isempty (idx)
201+ v[idx.+ (i- 1 )] .= - F. L[idx, 1 ]
202+ ldiv! (LowerTriangular (view (F. L, idx, idx)), view (v, idx.+ (i- 1 )))
176203 end
177204 end
178205 for k in 1 : n
@@ -189,17 +216,23 @@ function lulinv!(A::Matrix{T}, λ::Vector{T}; rtol::Real = size(A, 1)*eps(real(f
189216 A[k, i] = v[k]
190217 end
191218 end
192- return LULinv (A)
219+ return LULinv (A, ipiv )
193220end
194221
195- function ldiv! (F:: LULinv , B:: AbstractVecOrMat )
196- L = UnitLowerTriangular (F. factors)
197- return lmul! (L, ldiv! (UpperTriangular (F. factors), ldiv! (L, B)))
222+ function ldiv! (A:: LULinv , B:: AbstractVecOrMat )
223+ B .= B[invperm (A. p), :] # Todo: fix me
224+ L = UnitLowerTriangular (A. factors)
225+ lmul! (L, ldiv! (UpperTriangular (A. factors), ldiv! (L, B)))
226+ B .= B[A. p, :] # Todo: fix me
227+ return B
198228end
199229
200- function rdiv! (B:: AbstractVecOrMat , F:: LULinv )
201- L = UnitLowerTriangular (F. factors)
202- return rdiv! (rdiv! (rmul! (B, L), UpperTriangular (F. factors)), L)
230+ function rdiv! (A:: AbstractVecOrMat , B:: LULinv )
231+ A .= A[:, B. p] # Todo: fix me
232+ L = UnitLowerTriangular (B. factors)
233+ rdiv! (rdiv! (rmul! (A, L), UpperTriangular (B. factors)), L)
234+ A .= A[:, invperm (B. p)] # Todo: fix me
235+ return A
203236end
204237
205238det (F:: LULinv ) = det (UpperTriangular (F. factors))
0 commit comments