lu-decomp.scm 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  3. ; LU Decomposition (a rewriting of a Pascal program from `Numerical Recipes
  4. ; in Pascal'; look there for a detailed description of what is going on).
  5. ; A is an NxN matrix that is updated in place.
  6. ; This returns a row permutation vector and the sign of that vector.
  7. (define *lu-decomposition-epsilon* 1.0e-20)
  8. (define (lu-decomposition a)
  9. (let* ((n (car (array-shape a)))
  10. (indx (make-vector n))
  11. (sign 1.0)
  12. (vv (make-vector n)))
  13. (do ((i 0 (+ i 1)))
  14. ((>= i n))
  15. (do ((j 0 (+ j 1))
  16. (big 0.0 (max big (abs (array-ref a i j)))))
  17. ((>= j n)
  18. (if (= big 0.0)
  19. (assertion-violation 'lu-decomposition "matrix has a zero row" a i))
  20. (vector-set! vv i (/ big)))))
  21. (do ((j 0 (+ j 1)))
  22. ((>= j n))
  23. (let ()
  24. (define (sum-elts i end)
  25. (do ((k 0 (+ k 1))
  26. (sum (array-ref a i j)
  27. (- sum (* (array-ref a i k)
  28. (array-ref a k j)))))
  29. ((>= k end)
  30. sum)))
  31. (do ((i 0 (+ i 1)))
  32. ((>= i j))
  33. (array-set! a (sum-elts i i) i j))
  34. (receive (big imax)
  35. (let loop ((i j) (big 0.0) (imax 0))
  36. (if (>= i n)
  37. (values big imax)
  38. (let ((sum (sum-elts i j)))
  39. (array-set! a sum i j)
  40. (let ((temp (* (vector-ref vv i) (abs sum))))
  41. (if (>= temp big)
  42. (loop (+ i 1) temp i)
  43. (loop (+ i 1) big imax))))))
  44. (if (not (= j imax))
  45. (begin
  46. (do ((k 0 (+ k 1)))
  47. ((>= k n))
  48. (let ((temp (array-ref a imax k)))
  49. (array-set! a (array-ref a j k) imax k)
  50. (array-set! a temp j k)))
  51. (set! sign (- sign))
  52. (vector-set! vv imax (vector-ref vv j))))
  53. (vector-set! indx j imax)
  54. (if (= (array-ref a j j) 0.0)
  55. (array-set! a *lu-decomposition-epsilon* j j))
  56. (if (not (= j (- n 1)))
  57. (let ((temp (/ (array-ref a j j))))
  58. (do ((i (+ j 1) (+ i 1)))
  59. ((>= i n))
  60. (array-set! a (* (array-ref a i j) temp) i j)))))))
  61. (values indx sign)))
  62. (define (lu-back-substitute a indx b)
  63. (let ((n (car (array-shape a))))
  64. (let loop ((i 0) (ii #f))
  65. (if (< i n)
  66. (let* ((ip (vector-ref indx i))
  67. (temp (vector-ref b ip)))
  68. (vector-set! b ip (vector-ref b i))
  69. (let ((new (if ii
  70. (do ((j ii (+ j 1))
  71. (sum temp (- sum (* (array-ref a i j)
  72. (vector-ref b j)))))
  73. ((>= j i)
  74. sum))
  75. temp)))
  76. (vector-set! b i new)
  77. (loop (+ i 1)
  78. (if (or ii (= temp 0.0)) ii i))))))
  79. (do ((i (- n 1) (- i 1)))
  80. ((< i 0))
  81. (do ((j (+ i 1) (+ j 1))
  82. (sum (vector-ref b i) (- sum (* (array-ref a i j)
  83. (vector-ref b j)))))
  84. ((>= j n)
  85. (vector-set! b i (/ sum (array-ref a i i))))))))
  86. ;(define m
  87. ; (array '(4 4)
  88. ; 1.0 2.0 3.0 -2.0
  89. ; 8.0 -6.0 6.0 1.0
  90. ; 3.0 -2.0 0.0 -7.0
  91. ; 4.0 7.0 2.0 -1.0))
  92. ;
  93. ;(define b '#(2.0 1.0 3.0 -2.0))
  94. ;
  95. ;(define (test m b)
  96. ; (let* ((a (copy-array m))
  97. ; (n (car (array-shape m)))
  98. ; (x (make-vector n)))
  99. ;
  100. ; (do ((i 0 (+ i 1)))
  101. ; ((>= i n))
  102. ; (vector-set! x i (vector-ref b i)))
  103. ;
  104. ; (display "b = ")
  105. ; (display b)
  106. ; (newline)
  107. ;
  108. ; (call-with-values
  109. ; (lambda ()
  110. ; (lu-decomposition a))
  111. ; (lambda (indx sign)
  112. ; (lu-back-substitute a indx x)
  113. ;
  114. ; (display "x = ")
  115. ; (display x)
  116. ; (newline)
  117. ;
  118. ; (let ((y (make-vector (vector-length b))))
  119. ; (do ((i 0 (+ i 1)))
  120. ; ((>= i n))
  121. ; (do ((j 0 (+ j 1))
  122. ; (t 0.0 (+ t (* (array-ref m i j) (vector-ref x j)))))
  123. ; ((>= j n)
  124. ; (vector-set! y i t))))
  125. ;
  126. ; (display "a * x =")
  127. ; (display y)
  128. ; (newline))))))