gauss-jordan.scm 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. #!fold-case
  21. ;;;; Linear System Solver -- Gauss-Jordan
  22. (declare (usual-integrations))
  23. ;;; This file contains the following definitions:
  24. ;;;
  25. ;;; (gauss-jordan-solve-linear-system A b) => x-vector
  26. ;;;
  27. ;;; (gauss-jordan-invert-and-solve A b succeed fail)
  28. ;;;
  29. ;;; (destructive-gauss-jordan-solve-linear-system A b succeed fail)
  30. ;;; succeed = (lambda (x C) (assert A*C=I, A*x=b) ...)
  31. ;;; fail = (lambda (dismiss) ...)
  32. ;;; The destructive version works on arrays, not matrices.
  33. ;;; Solves an inhomogeneous system of linear equations, A*X=B, returning
  34. ;;; the vector X.
  35. (define (gauss-jordan-solve-linear-system A b)
  36. (let ((A (array-copy (matrix->array A))) ;routine clobbers A and b
  37. (b (vector-copy b)))
  38. (destructive-gauss-jordan-solve-linear-system
  39. A
  40. b
  41. (lambda (x Ainv) x)
  42. barf-on-zero-pivot)))
  43. (define (gauss-jordan-solve A b succeed fail)
  44. (let ((A (array-copy (matrix->array A))) ;routine clobbers A and b
  45. (b (vector-copy b)))
  46. (destructive-gauss-jordan-solve-linear-system
  47. A
  48. b
  49. (lambda (x Ainv) (succeed x))
  50. fail)))
  51. (define (gauss-jordan-invert-and-solve A b succeed fail)
  52. ;; succeed = (lambda (x C) where x = C*b, C*A = I)
  53. ;; fail = (lambda (dismiss) ... )
  54. (let ((A (array-copy (matrix->array A))) ;routine clobbers A and b
  55. (b (vector-copy b)))
  56. (destructive-gauss-jordan-solve-linear-system
  57. A
  58. b
  59. succeed
  60. fail)))
  61. (define *minimum-allowable-gj-pivot* 1.0e-30)
  62. ;;; Transliterated from Press, Fortran version, p.28., with prejudice.
  63. ;;; Replaces A by A^-1, and b by solution.
  64. (define (destructive-gauss-jordan-solve-linear-system A b succeed fail)
  65. (let* ((n (num-rows A))
  66. (ipiv (make-vector n false)) ;not a legitimate index
  67. (indxr (make-vector n 0))
  68. (indxc (make-vector n 0)))
  69. (if (not (fix:= n (num-cols A)))
  70. (error "Non-square matrix -- gj-solve-linear-system" n))
  71. (if (not (fix:= n (vector-length b)))
  72. (error "Incompatible sizes -- gj-solve-linear-system" n))
  73. (let iloop ((i 0)) ;runs over columns
  74. (if (fix:= i n)
  75. 'done
  76. (let ((big *minimum-allowable-gj-pivot*)
  77. (irow 0) (icol 0) (pivinv 0))
  78. ;; Find the position of the largest (in absolute value) element
  79. ;; in the matrix that is not in a column from which we
  80. ;; have already picked a pivot.
  81. (let jloop ((j 0)) ;runs over rows
  82. (if (fix:= j n)
  83. 'done
  84. (begin
  85. (if (not (vector-ref ipiv j)) ;row is free
  86. (let kloop ((k 0)) ;runs over columns
  87. (if (fix:= k n)
  88. 'done
  89. (begin
  90. (if (not (vector-ref ipiv k))
  91. (let ((ajk (magnitude (array-ref a j k))))
  92. (if (> ajk big)
  93. (begin (set! big ajk)
  94. (set! irow j)
  95. (set! icol k)))))
  96. (kloop (fix:+ k 1))))))
  97. (jloop (fix:+ j 1)))))
  98. ;(bkpt "gug")
  99. (if (= *minimum-allowable-gj-pivot* big) (fail (singular-matrix-error)))
  100. (vector-set! ipiv icol true)
  101. ;; Output of jloop (above) is summarized in IROW, ICOL, IPIV
  102. ;;(bkpt "pivot found")
  103. ;; Pivot element must be on diagonal.
  104. ;; The following swaps two rows unless they are already
  105. ;; the same row. It will work if the = test is removed.
  106. (if (not (fix:= irow icol))
  107. (begin
  108. (let lloop ((l 0))
  109. (if (fix:= l n)
  110. 'done
  111. (let ((dum (array-ref a irow l)))
  112. (array-set! a irow l
  113. (array-ref a icol l))
  114. (array-set! a icol l dum)
  115. (lloop (fix:+ l 1)))))
  116. ;;more generally, b can be a matrix
  117. ;;if so,replace this loop by one similar to the
  118. ;;one above
  119. (let ((dum (vector-ref b irow)))
  120. (vector-set! b irow (vector-ref b icol))
  121. (vector-set! b icol dum))))
  122. ;; We remember that we did this swap in information in INDXR and INDXC
  123. (vector-set! indxr i irow)
  124. (vector-set! indxc i icol)
  125. ;;(bkpt "after swap")
  126. ;; Scale the icol row by 1/pivot, and set the diag element to 1/pivot.
  127. (let ((aii (array-ref a icol icol)))
  128. (set! pivinv (invert aii))
  129. (array-set! a icol icol 1))
  130. (let lloop ((l 0))
  131. (if (fix:= l n)
  132. 'done
  133. (begin (array-set! a icol l
  134. (* (array-ref a icol l) pivinv))
  135. (lloop (fix:+ l 1)))))
  136. ;;more generally, as above....
  137. (vector-set! b icol (* (vector-ref b icol) pivinv))
  138. ;;for each row, except the pivot row, do row reduction by
  139. ;;subtracting the appropriate multiple of the pivot row.
  140. (let llloop ((ll 0))
  141. (if (fix:= ll n)
  142. 'done
  143. (begin
  144. (if (not (fix:= ll icol))
  145. (let ((dum (array-ref a ll icol)))
  146. (array-set! a ll icol 0)
  147. (let lloop ((l 0))
  148. (if (fix:= l n)
  149. 'done
  150. (begin
  151. (array-set! a ll l
  152. (- (array-ref a ll l)
  153. (* (array-ref a icol l)
  154. dum)))
  155. (lloop (fix:+ l 1)))))
  156. (vector-set! b ll
  157. (- (vector-ref b ll)
  158. (* (vector-ref b icol)
  159. dum)))))
  160. (llloop (fix:+ ll 1)))))
  161. (iloop (fix:+ i 1)))))
  162. ;;end of matrix reduction
  163. ;;interchange the columns of the matrix, according to the
  164. ;;permutation specified by INDEXR and INDEXC
  165. (let lloop ((l (fix:- n 1)))
  166. (if (fix:< l 0)
  167. 'done
  168. (let ((kswap (vector-ref indxr l))
  169. (cswap (vector-ref indxc l)))
  170. (if (not (fix:= kswap cswap))
  171. (let kloop ((k 0))
  172. (if (fix:= k n)
  173. 'done
  174. (let ((dum (array-ref a k kswap)))
  175. (array-set! a k kswap
  176. (array-ref a k cswap))
  177. (array-set! a k cswap dum)
  178. (kloop (fix:+ k 1))))))
  179. (lloop (fix:- l 1))))))
  180. (succeed b a))