lu.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; Linear System Solver -- LU
  21. (declare (usual-integrations))
  22. ;;; This file contains the following definitions:
  23. ;;;
  24. ;;; (lu-solve-linear-system A-matrix b-vector) => x-vector
  25. ;;;
  26. ;;; (lu-solve A b succeed fail)
  27. ;;; succeed = (lambda (x) ...)
  28. ;;; fail = (lambda (dismiss) ...)
  29. ;;;
  30. ;;; (lu-determinant A-matrix) ==> number
  31. ;;; (lu-invert A-matrix) ==> matrix
  32. ;;;
  33. ;;; (lu-null-space matrix) ==> (<vector> ... <vector>)
  34. ;;;
  35. ;;; (lu-decompose matrix succeed fail)
  36. ;;; succeed = (lambda (lu-matrix lu-permutation sign) ...)
  37. ;;; fail = (lambda (dismiss) ...)
  38. ;;;
  39. ;;; (lu-backsubstitute lu-matrix lu-permutation b-vector) => x-vector
  40. ;;; Solves an inhomogeneous system of linear equations, A*X=B,
  41. ;;; returning the vector X.
  42. (define (lu-solve-linear-system A b)
  43. (lu-solve-linear-system-internal (matrix->array A) b))
  44. (define (lu-solve A b succeed fail)
  45. (lu-solve-internal (matrix->array A) b succeed fail))
  46. (define (lu-determinant A)
  47. (lu-determinant-internal (matrix->array A)))
  48. (define (lu-invert A)
  49. (array->matrix (lu-invert-internal (matrix->array A))))
  50. (define (lu-decompose A succeed fail)
  51. (lu-decompose-internal (matrix->array A)
  52. (lambda (lu-array permutation sign)
  53. (succeed (array->matrix lu-array)
  54. permutation
  55. sign))
  56. fail))
  57. ;;; The following procedure assumes that the matrix is in LU form.
  58. (define (lu-backsubstitute lu-matrix lu-permutation b-vector)
  59. (lu-backsubstitute-internal (matrix->array lu-matrix) lu-permutation b-vector))
  60. ;;; The following programs work on arrays rather than matrices.
  61. (define (lu-solve-linear-system-internal A b)
  62. (lu-decompose-internal A
  63. (lambda (lumatrix lupermutations sign)
  64. (lu-backsubstitute-internal lumatrix lupermutations b))
  65. barf-on-zero-pivot))
  66. (define (lu-solve-internal A b succeed fail)
  67. (lu-decompose-internal A
  68. (lambda (lumatrix lupermutations sign)
  69. (succeed (lu-backsubstitute-internal lumatrix lupermutations b)))
  70. fail))
  71. (define (lu-invert-internal A)
  72. (let ((n (num-rows A)))
  73. (lu-decompose-internal A
  74. (lambda (lumat luperm sign)
  75. (let ((m (make-initialized-vector n
  76. (lambda (i)
  77. (let ((e (v:make-basis-unit n i)))
  78. (lu-backsubstitute-internal lumat luperm e))))))
  79. (transpose-array m)))
  80. barf-on-zero-pivot)))
  81. (define (lu-determinant-internal M)
  82. (let ((n (num-rows M)))
  83. (lu-decompose-internal M
  84. (lambda (A p s)
  85. (let loop ((i 0) (prod s))
  86. (if (fix:= i n)
  87. prod
  88. (loop (fix:+ i 1)
  89. (* prod (array-ref A i i))))))
  90. allow-zero-pivot)))
  91. ;;; LU decomposition -- uses Crout's algorithm (see Press, section 2.3).
  92. ;;; The LU decomposition returns a LIST of the resulting matrix, the
  93. ;;; permutation vector, and the sign (+1 or -1) of the permutation.
  94. ;;; The only currently-defined flag controls error-trapping on detection
  95. ;;; of a zero-pivot. This flag, if omitted, defaults to true.
  96. (define (lu-decompose-internal m succeed singular-matrix)
  97. (let* ((n (num-rows m))
  98. (perms (make-initialized-vector n (lambda (i) i))) ;row permutations
  99. (sign 1) ;1 for even permutations, -1 for odd
  100. ;; We must copy the matrix, since Crout's algorithm clobbers it.
  101. (m (array-copy m)))
  102. (let jloop ((j 0))
  103. (if (fix:< j n)
  104. (begin
  105. (let iloop ((i 0)) ;compute elements above diagonal
  106. (if (not (fix:> i j))
  107. (begin (array-set! m i j (lu-upper-eqn i j m))
  108. (iloop (fix:+ i 1)))))
  109. (let iloop ((i (fix:+ j 1))) ;compute elements below diagonal
  110. (if (fix:< i n)
  111. (begin (array-set! m i j (lu-lower-eqn i j m))
  112. (iloop (fix:+ i 1)))))
  113. (let* ((pivot-info (lu-find-best-pivot m j n))
  114. (pivot (car pivot-info))
  115. (pivot-index (cdr pivot-info)))
  116. (if (bad-pivot? pivot)
  117. (singular-matrix (lambda () (jloop (fix:+ j 1))))
  118. (let ((inverted-pivot (invert pivot)))
  119. (lu-row-swap m j pivot-index perms)
  120. (if (not (fix:= j pivot-index))
  121. (set! sign (fix:- 0 sign)))
  122. (let iloop ((i (fix:+ j 1))) ;divide through by pivot
  123. (if (fix:= i n)
  124. 'done
  125. (begin (array-set! m i j
  126. (* (array-ref m i j)
  127. inverted-pivot))
  128. (iloop (fix:+ i 1)))))
  129. (jloop (fix:+ j 1))))))
  130. (succeed m perms sign)))))
  131. (define tiny-pivot-bugger-factor
  132. ;; As a practical matter, the following theoretical factor need not
  133. ;; be adjusted if conditions of STP do not precisely apply.
  134. (/ 1.0 6.0238e23))
  135. (define (bad-pivot? pivot)
  136. (or (and (exact? pivot) (zero? pivot))
  137. (and (inexact? pivot)
  138. (< (magnitude pivot) tiny-pivot-bugger-factor))))
  139. ;;; Note that we start looping at the jth row in searching for the
  140. ;;; next pivot. We can make this somewhat better numerically by
  141. ;;; including scale factors for the columns, but i'm too lazy to do
  142. ;;; this now. -- HAL
  143. (define (lu-find-best-pivot m j n)
  144. (let ((column (make-initialized-vector n (lambda (i) (array-ref m i j)))))
  145. (let iloop ((i (fix:+ j 1))
  146. (bestindex j)
  147. (bestpivot (vector-ref column j)))
  148. (if (fix:= i n)
  149. (cons bestpivot bestindex)
  150. (let* ((p (vector-ref column i)))
  151. (if (better-pivot? p bestpivot)
  152. (iloop (fix:+ i 1) i p)
  153. (iloop (fix:+ i 1) bestindex bestpivot)))))))
  154. (define (better-pivot? p1 p2)
  155. (> (magnitude p1) (magnitude p2)))
  156. (define (lu-upper-eqn i j m)
  157. (if (fix:= i 0)
  158. (array-ref m i j)
  159. (let kloop ((k 0) (sum 0))
  160. (if (fix:= k i)
  161. (- (array-ref m i j) sum)
  162. (kloop (fix:+ k 1)
  163. (+ sum (* (array-ref m i k) (array-ref m k j))))))))
  164. (define (lu-lower-eqn i j m)
  165. (let kloop ((k 0) (sum 0))
  166. (if (fix:= k j)
  167. (- (array-ref m i j) sum)
  168. (kloop (fix:+ k 1)
  169. (+ sum (* (array-ref m i k) (array-ref m k j)))))))
  170. (define (lu-row-swap m i1 i2 perms)
  171. (define (swap-elements vector i j)
  172. (let ((temp (vector-ref vector i)))
  173. (vector-set! vector i (vector-ref vector j))
  174. (vector-set! vector j temp)))
  175. (if (not (fix:= i1 i2))
  176. (begin (swap-elements perms i1 i2)
  177. ;;uses fact that matrix is a vector of rows
  178. (swap-elements m i1 i2))))
  179. ;;; Back substitution (see Press, page 32)
  180. (define (lu-backsubstitute-internal m perm b)
  181. (let* ((n (vector-length b))
  182. (top (fix:- n 1))
  183. (y (make-vector n '()))
  184. (x (make-vector n '())))
  185. (let fdloop ((i 0))
  186. (if (fix:< i n)
  187. (begin
  188. (vector-set! y i
  189. (- (vector-ref b (vector-ref perm i))
  190. (let jloop ((j 0) (sum 0))
  191. (if (fix:= j i)
  192. sum
  193. (jloop (fix:+ j 1)
  194. (+ sum
  195. (* (vector-ref y j)
  196. (array-ref m i j))))))))
  197. (fdloop (fix:+ i 1)))))
  198. (let bkloop ((i top))
  199. (if (not (fix:< i 0))
  200. (begin
  201. (vector-set! x i
  202. (/ (- (vector-ref y i)
  203. (let jloop ((j (fix:+ i 1)) (sum 0))
  204. (if (fix:= j n)
  205. sum
  206. (jloop (fix:+ j 1)
  207. (+ sum
  208. (* (vector-ref x j)
  209. (array-ref m i j)))))))
  210. (array-ref m i i)))
  211. (bkloop (fix:- i 1)))))
  212. x))
  213. ;;; In the case of a homogeneous system we can solve if the matrix is
  214. ;;; singular.
  215. (define (lu-null-space A)
  216. (let* ((n (m:dimension A))
  217. (AA (matrix->array A))
  218. (maxel (vector-accumulate
  219. max
  220. (lambda (row)
  221. (vector-accumulate max g:magnitude :zero row))
  222. :zero
  223. AA)))
  224. (lu-decompose-internal AA
  225. (lambda (LU permutation sign)
  226. (let lp ((i 0))
  227. (if (fix:= i n)
  228. '()
  229. (let ((v (lu-null-vector-internal LU i maxel)))
  230. (cond ((heuristic-zero-vector? v maxel) '())
  231. ((heuristic-zero-vector? (matrix*vector A v) maxel)
  232. (cons (v:make-unit v) (lp (fix:+ i 1))))
  233. (else (lp (fix:+ i 1))))))))
  234. allow-zero-pivot)))
  235. ;;; For each non-negative integer index less than the nullity of the
  236. ;;; lu-matrix we can obtain an independent solution vector (the entire
  237. ;;; set spans the null space).
  238. ;;; In this case, the upper part of the matrix contains the U part of
  239. ;;; the LU decomposition. The L part is irrelevant to this process
  240. ;;; since we are solving a homogeneous equation. The algorithm is to
  241. ;;; work backwards, from n-1 to 0, solving the equations m[i,i]x[i] +
  242. ;;; m[i,i+1]x[i+1] + ... = 0.
  243. ;;; If m[i,i] is zero (to within the tolerance), then we can set x[i]
  244. ;;; to an arbitrary value. We set the kth arbitary unknown to 1 and
  245. ;;; the rest to 0 (0<=k<nullity). If a luser supplies a k>=nullity,
  246. ;;; he will get a zero vector.
  247. (define (lu-null-vector-internal m k maxel)
  248. (let* ((n (num-rows m))
  249. (top (fix:- n 1))
  250. (x (make-vector n '())))
  251. (let bkloop ((i top) (acount 0))
  252. (if (not (fix:< i 0))
  253. (let ((p (array-ref m i i)))
  254. (if (heuristically-zero? p maxel)
  255. (begin
  256. (if (fix:= acount k)
  257. (vector-set! x i 1)
  258. (vector-set! x i 0))
  259. (bkloop (fix:- i 1) (fix:+ acount 1)))
  260. (let ((s (let jloop ((j (fix:+ i 1)) (sum 0))
  261. (if (fix:= j n)
  262. sum
  263. (jloop (fix:+ j 1)
  264. (+ sum
  265. (* (vector-ref x j)
  266. (array-ref m i j))))))))
  267. (vector-set! x i (/ (- s) p))
  268. (bkloop (fix:- i 1) acount))))))
  269. x))
  270. (define heuristic-zero-test-bugger-factor
  271. ;; The following default number was assigned by HAL. -- GJS & MH.
  272. (* 1000 *machine-epsilon*))
  273. (define (heuristically-zero? z m)
  274. (< (magnitude z) (* heuristic-zero-test-bugger-factor (+ m 1))))
  275. (define (heuristic-zero-vector? v m)
  276. (for-all? (vector->list v) (lambda (x) (heuristically-zero? x m))))
  277. ;;; This is stuff to test the LU-decomposition
  278. (define (hilbert n)
  279. (m:generate n n
  280. (lambda (i j) (/ 1.0 (+ i j 2)))))
  281. (define (upper-matrix m)
  282. (let ((n (m:num-rows m)))
  283. (m:generate n n
  284. (lambda (i j)
  285. (if (fix:> i j)
  286. 0
  287. (matrix-ref m i j))))))
  288. (define (lower-matrix m)
  289. (let ((n (m:num-rows m)))
  290. (m:generate n n
  291. (lambda (i j)
  292. (cond ((fix:< i j) 0)
  293. ((fix:= i j) 1)
  294. (else (matrix-ref m i j)))))))
  295. (define (lower*upper m)
  296. (matrix*matrix (lower-matrix m)
  297. (upper-matrix m)))
  298. (define (checklu M)
  299. (lu-decompose M
  300. (lambda (ans-mat ans-perm sign)
  301. (let ((prod (lower*upper ans-mat)))
  302. (let ((n (m:num-rows M)))
  303. (m:generate n n
  304. (lambda (i j)
  305. (- (matrix-ref prod i j)
  306. (matrix-ref M
  307. (vector-ref ans-perm i)
  308. j)))))))
  309. allow-zero-pivot))