############################################################################
#
# File: lu.icn
#
# Subject: Procedures for LU manipulation
#
# Author: Ralph E. Griswold
#
# Date: August 14, 1996
#
############################################################################
#
# This file is in the public domain.
#
############################################################################
#
# lu_decomp(M, I) performs LU decomposition on the square matrix M
# using the vector I. Both M and I are modified in the process. The
# value returned is +1 or -1 depending on whether the number of row
# interchanges is even or odd. lu_decomp() is used in combination with
# lu_back_sub() to solve linear equations or invert matrices.
#
# lu_decomp() fails if the matrix is singular.
#
# lu_back_sub(M, I, B) solves the set of linear equations M x X = B. M
# is the matrix as modified by lu_decomp(). I is the index vector
# produced by lu_decomp(). B is the right-hand side vector and return
# with the solution vector. M and I are not modified by lu_back_sub()
# and can be used in successive calls of lu_back_sub() with different
# Bs.
#
############################################################################
#
# Acknowledgement: These procedures are based on algorithms given in
# "Numerical Recipes; The Art of Scientific Computing"; William H. Press,
# Brian P. Flannery, Saul A. Teukolsky. and William T. Vetterling;
# Cambridge University Press, 1986.
#
############################################################################
procedure lu_decomp(M, I)
local small, d, n, vv, i, largest, j, sum, k, pivot_val, imax
initial small := 1.0e-20
d := 1.0
n := *M
if n ~= *M[1] then stop("*** non-square matrix")
if n ~= *I then stop("*** index vector incorrect length")
vv := list(n, 0.0) # scaling vector
every i := 1 to n do {
largest := 0.0
every j := 1 to n do
largest <:= abs(M[i][j])
if largest = 0.0 then fail # matrix is singular
vv[i] := 1.0 / largest
}
every j := 1 to n do { # Crout's method
if j > 1 then {
every i := 1 to j - 1 do {
sum := M[i][j]
if i > 1 then {
every k := 1 to i - 1 do
sum -:= M[i][k] * M[k][j]
M[i][j] := sum
}
}
}
largest := 0.0 # search for largest pivot
every i := j to n do {
sum := M[i][j]
if j > 1 then {
every k := 1 to j - 1 do
sum -:= M[i][k] * M[k][j]
M[i][j] := sum
}
pivot_val := vv[i] * abs(sum)
if pivot_val > largest then {
largest := pivot_val
imax := i
}
}
if j ~= imax then { # interchange rows?
every k := 1 to n do {
pivot_val := M[imax][k]
M[imax][k] := M[j][k]
M[j][k] := pivot_val
}
d := -d # change parity
vv[imax] := vv[j] # and scale factor
}
I[j] := imax
if j ~= n then { # divide by the pivot element
if M[j][j] = 0.0 then M[j][j] := small # small value is better than
pivot_val := 1.0 / M[j][j] # zero for some applications
every i := j + 1 to n do
M[i][j] *:= pivot_val
}
}
if M[n][n] = 0.0 then M[n][n] := small
return d
end
procedure lu_back_sub(M, I, B)
local n, ii, i, ip, sum, j
n := *M
if n ~= *M[1] then stop("*** matrix not square")
if n ~= *I then stop("*** index vector wrong length")
if n ~= *B then stop("*** output vector wrong length")
ii := 0
every i := 1 to n do {
ip := I[i] | stop("failed in line ", &line)
sum := B[ip] | stop("failed in line ", &line)
B[ip] := B[i] | stop("failed in line ", &line)
if ii ~= 0 then
every j := ii to i - 1 do
sum -:= M[i][j] * B[j] | stop("failed in line ", &line)
else if sum ~= 0.0 then ii := i
B[i] := sum | stop("failed in line ", &line)
}
every i := n to 1 by -1 do {
sum := B[i] | stop("failed in line ", &line)
if i < n then {
every j := i + 1 to n do
sum -:= M[i][j] * B[j] | stop("failed in line ", &line)
}
B[i] := sum / M[i][i] | stop("failed in line ", &line)
}
return
end
This page produced by UniDoc on 2021/04/15 @ 23:59:44.