(load "./LU.scm") ; LU, perm

;; 連立一次方程式 Ax = b を解きます.

(define (solve A b)
    (define (inner* x y) (apply + (map * x y)))

    (receive (L U ord) (LU A)
    (let* ((b (perm ord b))
           (Ux
          (let loop ((i 0) (Ux '()))
              (if (= i (length A)) Ux
                  (loop (+ i 1) (append Ux (list
                          (- (ref b i) (inner* (ref L i) Ux)))))))))

    (let loop ((i (- (length U) 1)) (x '()))
        (if (< i 0) x
            (loop (- i 1)
             (cons (/ (- (ref Ux i)
                         (inner* (reverse (ref U i)) (reverse x)))
                      (ref (ref U i) i)) x)))))))

; 1x + 2y + 3z = 1
; 4x + 0y + 6z = 2
; -x -  y +  z = 3
; 
; gosh> (solve '((1 2 3) (4 0 6) (-1 -1 1)) '(1 2 3))
; (-16/13 -8/13 15/13)
; 
; [x, y, z] = [-16/13, -8/13, 15/13]