OSDN Git Service

cl-jama : import. master
authorsouthly <southly@users.sourceforge.jp>
Sun, 21 Dec 2008 16:05:54 +0000 (01:05 +0900)
committersouthly <southly@users.sourceforge.jp>
Sun, 21 Dec 2008 16:05:54 +0000 (01:05 +0900)
17 files changed:
LICENSE [new file with mode: 0644]
cholesky.lisp [new file with mode: 0644]
cl-jama.asd [new file with mode: 0644]
eigenvalue.lisp [new file with mode: 0644]
lu.lisp [new file with mode: 0644]
package.lisp [new file with mode: 0644]
qr.lisp [new file with mode: 0644]
svd.lisp [new file with mode: 0644]
test/cholesky.lisp [new file with mode: 0644]
test/cl-jama-test.asd [new file with mode: 0644]
test/eigenvalue.lisp [new file with mode: 0644]
test/lu.lisp [new file with mode: 0644]
test/package.lisp [new file with mode: 0644]
test/qr.lisp [new file with mode: 0644]
test/svd.lisp [new file with mode: 0644]
test/utils.lisp [new file with mode: 0644]
utils.lisp [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..3aa8fa7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+ 
+Copyright (c) 2008 NANRI <southly@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/cholesky.lisp b/cholesky.lisp
new file mode 100644 (file)
index 0000000..fc76a93
--- /dev/null
@@ -0,0 +1,98 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+;;;  
+;;; Copyright (c) 2008 NANRI <southly@gmail.com>
+;;; 
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy
+;;; of this software and associated documentation files (the "Software"), to deal
+;;; in the Software without restriction, including without limitation the rights
+;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+;;; copies of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;; 
+;;; The above copyright notice and this permission notice shall be included in
+;;; all copies or substantial portions of the Software.
+;;; 
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+;;; THE SOFTWARE.
+
+(in-package :cl-jama)
+
+(defclass Cholesky ()
+  ((L_)
+   (isspd)))
+
+(defmethod is-spd ((A Cholesky))
+  (with-slots (isspd) A
+    isspd))
+
+(defmethod get-L ((A Cholesky))
+  (with-slots (L_) A
+    (copy-array L_)))
+
+(defmethod initialize-instance :after ((obj Cholesky) &key matrix)
+  (with-slots (L_ isspd) obj
+    (let ((m (array-dimension matrix 0))
+          (n (array-dimension matrix 1)))
+      (setf isspd (eql m n))
+      (unless (eql m n)
+        (setf L_ nil)
+        (return-from initialize-instance nil))
+      (setf L_ (make-array (list n n)))
+      ;; 
+      (loop :for j :from 0 :below n
+            :do (let ((d 0.0))
+                  (loop :for k :from 0 :below j
+                        :do (let ((s 0.0))
+                              (loop :for i :from 0 :below k
+                                    :do (incf s (* (aref L_ k i) (aref L_ j i))))
+                              (setf s (/ (- (aref matrix j k) s) (aref L_ k k)))
+                              (setf (aref L_ j k) s)
+                              (setf d (+ d (* s s)))
+                              (setf isspd (and isspd (eql (aref matrix k j) (aref matrix j k))))))
+                  (setf d (- (aref matrix j j) d))
+                  (setf isspd (and isspd (> d 0.0)))
+                  (setf (aref L_ j j) (sqrt (if (> d 0.0) d 0.0)))
+                  (loop :for k :from (1+ j) :below n
+                        :do (setf (aref L_ j k) 0.0)))))))
+
+(defmethod solve ((A Cholesky) (b vector))
+  (with-slots (L_) A
+    (unless (eql (array-dimension L_ 0)
+                 (array-dimension b 0))
+      (return-from solve nil))
+    (let ((n (array-dimension L_ 0))
+          (x (copy-array b)))
+      (loop :for k :from 0 :below n
+            :do (loop :for i :from 0 :below k
+                      :do (decf (aref x k) (* (aref x i) (aref L_ k i))))
+                (setf (aref x k) (/ (aref x k) (aref L_ k k))))
+      (loop :for k :from (1- n) :downto 0 
+            :do (loop :for i :from (1+ k) :below n
+                      :do (decf (aref x k) (* (aref x i) (aref L_ i k))))
+                (setf (aref x k) (/ (aref x k) (aref L_ k k))))
+      x)))
+
+(defmethod solve ((A Cholesky) (B array))
+  (with-slots (L_) A
+    (unless (eql (array-dimension L_ 0)
+                 (array-dimension B 0))
+      (return-from solve nil))
+    (let ((n (array-dimension L_ 0))
+          (X (copy-array B))
+          (nx (array-dimension B 1)))
+      (loop :for j :from 0 :below nx
+            :do (loop :for k :from 0 :below n
+                      :do (loop :for i :from 0 :below k
+                                :do (decf (aref X k j) (* (aref X i j) (aref L_ k i))))
+                          (setf (aref X k j) (/ (aref X k j) (aref L_ k k)))))
+      (loop :for j :from 0 :below nx
+            :do (loop :for k :from (1- n) :downto 0
+                      :do (loop :for i :from (1+ k) :below n
+                                :do (decf (aref X k j) (* (aref X i j) (aref L_ i k))))
+                          (setf (aref X k j) (/ (aref X k j) (aref L_ k k)))))
+      X)))
diff --git a/cl-jama.asd b/cl-jama.asd
new file mode 100644 (file)
index 0000000..08d3f55
--- /dev/null
@@ -0,0 +1,14 @@
+(asdf:defsystem :cl-jama
+  :description "The CL port of JAMA/C++ Linear Algebra Package"
+  :version     "1.2.5-1"
+  :author      "NANRI <southly@gmail.com>"
+  :licence     "The MIT License"
+  :depends-on ()
+  :components ((:file "package")
+               (:file "utils" :depends-on ("package"))
+               (:file "lu" :depends-on ("utils"))
+               (:file "cholesky" :depends-on ("utils"))
+               (:file "qr" :depends-on ("utils"))
+               (:file "svd" :depends-on ("utils"))
+               (:file "eigenvalue" :depends-on ("utils"))
+               ))
diff --git a/eigenvalue.lisp b/eigenvalue.lisp
new file mode 100644 (file)
index 0000000..5623acf
--- /dev/null
@@ -0,0 +1,597 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+;;;  
+;;; Copyright (c) 2008 NANRI <southly@gmail.com>
+;;; 
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy
+;;; of this software and associated documentation files (the "Software"), to deal
+;;; in the Software without restriction, including without limitation the rights
+;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+;;; copies of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;; 
+;;; The above copyright notice and this permission notice shall be included in
+;;; all copies or substantial portions of the Software.
+;;; 
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+;;; THE SOFTWARE.
+
+(in-package :cl-jama)
+
+(declaim (optimize (debug 3) (safety 3)))
+
+(defclass Eigenvalue ()
+  ((n)
+   (issymmetric)
+   (d)
+   (e)
+   (V)
+   (H)
+   (ort)
+   (cdivi)
+   (cdivr)))
+
+(defmethod tred2 ((A Eigenvalue))
+  (with-slots (n d e V) A
+    (loop :for j :from 0 :below n
+          :do (setf (aref d j) (aref V (1- n) j)))
+    ;; 
+    (loop :for i :from (1- n) :above 0
+          :for scale = 0.0 :then 0.0
+          :for h = 0.0 :then 0.0
+          :do (loop :for k :from 0 :below i
+                    :do (setf scale (+ scale (abs (aref d k)))))
+          :do (cond ((zerop scale)
+                     (setf (aref e i) (aref d (1- i)))
+                     (loop :for j :from 0 :below i
+                           :do (setf (aref d j) (aref V (1- i) j)
+                                     (aref V i j) 0.0
+                                     (aref V j i) 0.0)))
+                    (t
+                     (loop :for k :from 0 :below i
+                           :do (setf (aref d k) (/ (aref d k) scale))
+                               (incf h (* (aref d k) (aref d k))))
+                     (let ((f (aref d (1- i)))
+                           (g (sqrt h))
+                           hh)
+                       (when (plusp f)
+                         (setf g (- g)))
+                       (setf (aref e i) (* scale g)
+                             h (- h (* f g))
+                             (aref d (1- i)) (- f g))
+                       (loop :for j :from 0 :below i
+                             :do (setf (aref e j) 0.0))
+                       ;; 
+                       (loop :for j :from 0 :below i
+                             :do (setf f (aref d j)
+                                         (aref V j i) f
+                                       g (+ (aref e j) (* (aref V j j) f)))
+                             :do (loop :for k :from (1+ j) :to (1- i)
+                                       :do (incf g (* (aref V k j) (aref d k)))
+                                           (incf (aref e k) (* (aref V k j) f)))
+                             :do (setf (aref e j) g))
+                       (setf f 0.0)
+                       (loop :for j :from 0 :below i
+                             :do (setf (aref e j) (/ (aref e j) h))
+                                 (incf f (* (aref e j) (aref d j))))
+                       (setf hh (/ f (+ h h)))
+                       (loop :for j :from 0 :below i
+                             :do (decf (aref e j) (* hh (aref d j))))
+                       (loop :for j :from 0 :below i
+                             :do (setf f (aref d j)
+                                       g (aref e j))
+                             :do (loop :for k :from j :to (1- i)
+                                       :do (decf (aref V k j) (+ (* f (aref e k)) (* g (aref d k)))))
+                             :do (setf (aref d j) (aref V (1- i) j)
+                                       (aref V i j) 0.0)))))
+          :do (setf (aref d i) h))
+    ;; 
+    (loop :for i :from 0 :below (1- n)
+          :do (setf (aref V (1- n) i) (aref V i i)
+                    (aref V i i) 1.0)
+              (let ((h (aref d (1+ i))))
+                (when (not (zerop h))
+                  (loop :for k :from 0 :to i
+                        :do (setf (aref d k) (/ (aref V k (1+ i)) h)))
+                  (loop :for j :from 0 :to i
+                        :do (let ((g 0.0))
+                              (loop :for k :from 0 :to i
+                                    :do (incf g (* (aref V k (1+ i)) (aref V k j))))
+                              (loop :for k :from 0 :to i
+                                    :do (decf (aref V k j) (* g (aref d k))))))))
+              (loop :for k :from 0 :to i
+                    :do (setf (aref V k (1+ i)) 0.0)))
+    (loop :for j :from 0 :below n
+          :do (setf (aref d j) (aref V (1- n) j)
+                    (aref V (1- n) j) 0.0))
+    (setf (aref V (1- n) (1- n)) 1.0
+          (aref e 0) 0.0)))
+
+(defmethod tql2 ((A Eigenvalue))
+  (with-slots (n d e V) A
+    (loop :for i :from 1 :below n
+          :do (setf (aref e (1- i)) (aref e i)))
+    (setf (aref e (1- n)) 0.0)
+    (let ((f 0.0)
+          (tst1 0.0)
+          (eps (expt 2.0 -52.0)))
+      (loop :for l :from 0 :below n
+            :do (setf tst1 (max tst1 (+ (abs (aref d l)) (abs (aref e l)))))
+            :do (let ((m l))
+                  (loop :while (< m n)
+                        :thereis (<= (abs (aref e m)) (* eps tst1))
+                        :do (incf m))
+                  (when (> m l)
+                    (let ((iter 0))
+                      (loop :do (setf iter (1+ iter))
+                            :do (let* ((g (aref d l))
+                                       (p (/ (- (aref d (1+ l)) g) (* 2.0 (aref e l))))
+                                       (r (hypot p 1.0))
+                                       dl1 h c c2 c3 el1 s s2)
+                                  (when (minusp p)
+                                    (setf r (- r)))
+                                  (setf (aref d l) (/ (aref e l) (+ p r))
+                                        (aref d (1+ l)) (* (aref e l) (+ p r))
+                                        dl1 (aref d (1+ l))
+                                        h (- g (aref d l)))
+                                  (loop :for i :from (+ l 2) :below n
+                                        :do (decf (aref d i) h))
+                                  (setf f (+ f h))
+                                  ;; 
+                                  (setf p (aref d m)
+                                        c 1.0
+                                        c2 c
+                                        c3 c
+                                        el1 (aref e (1+ l))
+                                        s 0.0
+                                        s2 0.0)
+                                  (loop :for i :from (1- m) :downto l
+                                        :do (setf c3 c2
+                                                  c2 c
+                                                  s2 s
+                                                  g (* c (aref e i))
+                                                  h (* c p)
+                                                  r (hypot p (aref e i))
+                                                  (aref e (1+ i)) (* s r)
+                                                  s (/ (aref e i) r)
+                                                  c (/ p r)
+                                                  p (- (* c (aref d i)) (* s g))
+                                                  (aref d (1+ i)) (+ h (* s (+ (* c g) (* s (aref d i))))))
+                                        :do (loop :for k :from 0 :below n
+                                                  :do (setf h (aref V k (1+ i))
+                                                            (aref V k (1+ i)) (+ (* s (aref V k i)) (* c h))
+                                                            (aref V k i) (- (* c (aref V k i)) (* s h)))))
+                                  (setf p (/ (* (- s) s2 c3 el1 (aref e l)) dl1)
+                                        (aref e l) (* s p)
+                                        (aref d l) (* c p)))
+                            :while (> (abs (aref e l)) (* eps tst1)))))
+                  (setf (aref d l) (+ (aref d l) f)
+                        (aref e l) 0.0)))
+      ;; 
+      (loop :for i :from 0 :below (1- n)
+            :for k = i :then i
+            :for p = (aref d i) :then (aref d i)
+            :do (loop :for j :from (1+ i) :below n
+                      :do (when (< (aref d j) p)
+                            (setf k j
+                                  p (aref d j))))
+                (unless (eql k i)
+                  (setf (aref d k) (aref d i)
+                        (aref d i) p)
+                  (loop :for j :from 0 :below n
+                        :do (setf p (aref V j i)
+                                 (aref V j i) (aref V j k)
+                                 (aref V j k) p)))))))
+
+(defmethod orthes ((A Eigenvalue))
+  (with-slots (n ort H V) A
+    (let ((low 0)
+          (high (1- n)))
+      (loop :for m :from (1+ low) :to (1- high)
+            :do (let ((scale 0.0))
+                  (loop :for i :from m :to high
+                        :do (setf scale (+ scale (abs (aref H i (1- m))))))
+                  (unless (zerop scale)
+                    (let ((rh 0.0) g)
+                      (loop :for i :from high :downto m
+                            :do (setf (aref ort i) (/ (aref H i (1- m)) scale))
+                                (incf rh (* (aref ort i) (aref ort i))))
+                      (setf g (sqrt rh))
+                      (when (plusp (aref ort m))
+                        (setf g (- g)))
+                      (setf rh (- rh (* (aref ort m) g))
+                            (aref ort m) (- (aref ort m) g))
+                      (loop :for j :from m :below n
+                            :do (let ((f 0.0))
+                                  (loop :for i :from high :downto m
+                                        :do (incf f (* (aref ort i) (aref H i j))))
+                                  (setf f (/ f rh))
+                                  (loop :for i :from m :to high
+                                        :do (decf (aref H i j) (* f (aref ort i))))))
+                      (loop :for i :from 0 :to high
+                            :do (let ((f 0.0))
+                                  (loop :for j :from high :downto m
+                                        :do (incf f (* (aref ort j) (aref H i j))))
+                                  (setf f (/ f rh))
+                                  (loop :for j :from m :to high
+                                        :do (decf (aref H i j) (* f (aref ort j))))))
+                      (setf (aref ort m) (* scale (aref ort m))
+                            (aref H m (1- m)) (* scale g))))))
+      ;; 
+      (loop :for i :from 0 :below n
+            :do (loop :for j :from 0 :below n
+                      :do (setf (aref V i j) (if (eql i j) 1.0 0.0))))
+
+      (loop :for m :from (1- high) :downto (1+ low)
+            :do (unless (zerop (aref H m (1- m)))
+                  (loop :for i :from (1+ m) :to high
+                        :do (setf (aref ort i) (aref H i (1- m))))
+                  (loop :for j :from m :to high
+                        :do (let ((g 0.0))
+                              (loop :for i :from m :to high
+                                    :do (incf g (* (aref ort i) (aref V i j))))
+                              ;; 
+                              (setf g (/ (/ g (aref ort m)) (aref H m (1- m))))
+                              (loop :for i :from m :to high 
+                                    :do (incf (aref V i j) (* g (aref ort i)))))))))))
+
+
+(defmethod cdiv ((A Eigenvalue) xr xi yr yi)
+  (with-slots (cdivr cdivi) A
+    (let (r d)
+      (if (> (abs yr) (abs yi))
+          (setf r (/ yi yr)
+                d (+ yr (* r yi))
+                cdivr (/ (+ xr (* r xi)) d)
+                cdivi (/ (- xi (* r xr)) d))
+          (setf r (/ yr yi)
+                d (+ yi (* r yr))
+                cdivr (/ (+ (* r xr) xi) d)
+                cdivi (/ (- (* r xi) xr) d))))))
+
+(defmethod hqr2 ((A Eigenvalue))
+  (with-slots (d e H V cdivr cdivi) A
+    (let* ((nn (slot-value A 'n))
+           (n (1- nn))
+           (low 0)
+           (high (1- nn))
+           (eps (expt 2.0 -52.0))
+           (exshift 0.0)
+           (p 0.0) (q 0.0) (r 0.0) (s 0.0) (z 0.0)
+           rt w x y
+           ;; 
+           (norm 0.0)
+           (iter 0))
+      (loop :for i :from 0 :below nn
+            :do (when (or (< i low) (> i high))
+                  (setf (aref d i) (aref H i i)
+                        (aref e i) 0.0))
+            :do (loop :for j :from (max (1- i) 0) :below nn
+                      :do (setf norm (+ norm (abs (aref H i j))))))
+      ;; 
+      (loop :while (> n low)
+            :do (break "n = ~S~%~S~%~S" n d e)
+            :do (let ((l n))
+                  (loop :while (> l low)
+                        :do (setf s (+ (abs (aref H (1- l) (1- l))) (abs (aref H l l))))
+                            (when (zerop s)
+                              (setf s norm))
+                        :thereis (< (abs (aref H l (1- l))) (* eps s))
+                        :do (decf l))
+                  ;; 
+                  (cond ((eql l n)
+                         (setf (aref H n n) (+ (aref H n n) exshift)
+                               (aref d n) (aref H n n)
+                               (aref e n) 0.0)
+                         (decf n)
+                         (setf iter 0))
+                        ((eql l (1- n))
+                         (setf w (* (aref H n (1- n)) (aref H (1- n) n))
+                               p (/ (- (aref H (1- n) (1- n)) (aref H n n)) 2.0)
+                               q (+ (* p p) w)
+                               z (sqrt (abs q))
+                               (aref H n n) (+ (aref H n n) exshift)
+                               (aref H (1- n) (1- n)) (+ (aref H (1- n) (1- n)) exshift)
+                               x (aref H n n))
+                         (cond ((>= q 0)
+                                (if (>= p 0)
+                                    (setf z (+ p z))
+                                    (setf z (- p z)))
+                                (setf (aref d (1- n)) (+ x z)
+                                      (aref d n) (aref d (1- n)))
+                                (unless (zerop z)
+                                  (setf (aref d n) (- x (/ w z))))
+                                (setf (aref e (1- n)) 0.0
+                                      (aref e n) 0.0
+                                      x (aref H n (1- n))
+                                      s (+ (abs x) (abs z))
+                                      p (/ x s)
+                                      q (/ z s)
+                                      r (sqrt (+ (* p p) (* q q)))
+                                      p (/ p r)
+                                      q (/ q r))
+                                ;; 
+                                (loop :for j :from (1- n) :below nn
+                                      :do (setf z (aref H (1- n) j)
+                                                  (aref H (1- n) j) (+ (* q z) (* p (aref H n j)))
+                                                  (aref H n j) (- (* q (aref H n j)) (* p z))))
+                                ;; 
+                                (loop :for i :from 0 :to n
+                                      :do (setf z (aref H i (1- n))
+                                                  (aref H i (1- n)) (+ (* q z) (* p (aref H i n)))
+                                                  (aref H i n) (- (* q (aref H i n)) (* p z))))
+                                ;; 
+                                (loop :for i :from low :to high
+                                      :do (setf z (aref V i (1- n)) 
+                                                  (aref V i (1- n)) (+ (* q z) (* p (aref V i n)))
+                                                  (aref V i n) (- (* q (aref V i n)) (* p z)))))
+                               (t
+                                (setf (aref d (1- n)) (+ x p)
+                                      (aref d n) (+ x p)
+                                      (aref e (1- n)) z
+                                      (aref e n) (- z))))
+                         (setf n (- n 2)
+                               iter 0))
+                        (t
+                         (setf x (aref H n n)
+                               y 0.0
+                               w 0.0)
+                         (when (< l n)
+                           (setf y (aref H (1- n) (1- n))
+                                 w (* (aref H n (1- n)) (aref H (1- n) n))))
+                         ;; 
+                         (when (eql iter 10)
+                           (incf exshift x)
+                           (loop :for i :from low :to n
+                                 :do (decf (aref H i i) x))
+                           (setf s (+ (abs (aref H n (1- n))) (abs (aref H (1- n) (- n 2))))
+                                 x (* 0.75 s)
+                                 y (* 0.75 s)
+                                 w (* -0.4375 s s)))
+                         ;; 
+                         (when (eql iter 30)
+                           (setf s (/ (- y x) 2.0)
+                                 s (+ (* s s) w))
+                           (when (plusp s)
+                             (setf s (sqrt s))
+                             (when (< y x)
+                               (setf s (- s)))
+                             (setf s (- x (/ w (+ (/ (- y x) 2.0) s))))
+                             (loop :for i :from low :to n
+                                   :do (decf (aref H i i) s))
+                             (incf exshift s)
+                             (setf x 0.964
+                                   y 0.964
+                                   w 0.964)))
+                         (setf iter (+ iter 1))
+                         ;; 
+                         (let ((m (- n 2)))
+                           (loop :while (>= m l)
+                                 :do (setf z (aref H m m)
+                                           r (- x z)
+                                           s (- y z)
+                                           p (+ (/ (- (* r s) w) (aref H (1+ m) m)) (aref H m (1+ m)))
+                                           q (- (aref H (1+ m) (1+ m)) z r s)
+                                           r (aref H (+ m 2) (1+ m))
+                                           s (+ (abs p) (abs q) (abs r))
+                                           p (/ p s)
+                                           q (/ q s)
+                                           r (/ r s))
+                                 :thereis (eql m l)
+                                 :thereis (< (* (abs (aref H m (1- m))) (+ (abs q) (abs r)))
+                                             (* eps (* (abs p) (+ (abs (aref H (1- m) (1- m))) (abs z) (abs (aref H (1+ m) (1+ m)))))))
+                                 :do (decf m))
+                           (loop :for i :from (+ m 2) :to n
+                                 :do (setf (aref H i (- i 2)) 0.0)
+                                     (when (> i (+ m 2))
+                                       (setf (aref H i (- i 3)) 0.0)))
+                           ;; 
+                           (loop :for k :from m :to (1- n)
+                                 :do (let ((notlast (not (eql k (1- n)))))
+                                       (unless (eql k m)
+                                         (setf p (aref H k (1- k))
+                                               q (aref H (1+ k) (1- k))
+                                               r (if notlast (aref H (+ k 2) (1- k)) 0.0)
+                                               x (+ (abs p) (abs q) (abs r)))
+                                         (unless (zerop x)
+                                           (setf p (/ p x)
+                                                 q (/ q x)
+                                                 r (/ r x))))
+                                       (when (zerop x)
+                                         (return))
+                                       (setf s (sqrt (+ (* p p) (* q q) (* r r))))
+                                       (when (minusp p)
+                                         (setf s (- s)))
+                                       (unless (zerop s)
+                                         (cond ((not (eql k m))
+                                                (setf (aref H k (1- k)) (* (- s) x)))
+                                               ((not (eql l m))
+                                                (setf (aref H k (1- k)) (- (aref H k (1- k))))))
+                                         (setf p (+ p s)
+                                               x (/ p s)
+                                               y (/ q s)
+                                               z (/ r s)
+                                               q (/ q p)
+                                               r (/ r p))
+                                         ;; 
+                                         (loop :for j :from k :below nn
+                                               :do (setf p (+ (aref H k j) (* q (aref H (1+ k) j))))
+                                               :when notlast
+                                               :do (setf p (+ p (* r (aref H (+ k 2) j)))
+                                                           (aref H (+ k 2) j) (- (aref H (+ k 2) j) (* p z)))
+                                               :end
+                                               :do (setf (aref H k j) (- (aref H k j) (* p x))
+                                                         (aref H (1+ k) j) (- (aref H (1+ k) j) (* p y))))
+                                         ;; 
+                                         (loop :for i :from 0 :to (min n (+ k 3))
+                                               :do (setf p (+ (* x (aref H i k)) (* y (aref H i (1+ k)))))
+                                               :when notlast
+                                               :do (setf p (+ p (* z (aref H i (+ k 2))))
+                                                           (aref H i (+ k 2)) (- (aref H i (+ k 2)) (* p r)))
+                                               :end
+                                               :do (setf (aref H i k) (- (aref H i k) p)
+                                                         (aref H i (1+ k)) (- (aref H i (1+ k)) (* p q))))
+                                         ;; 
+                                         (loop :for i :from low :to high
+                                               :do (setf p (+ (* x (aref V i k)) (* y (aref V i (1+ k)))))
+                                               :when notlast
+                                               :do (setf p (+ p (* z (aref V i (+ k 2))))
+                                                           (aref V i (+ k 2)) (- (aref V i (+ k 2)) (* p r)))
+                                               :end
+                                               :do (setf (aref V i k) (- (aref V i k) p)
+                                                         (aref V i (1+ k)) (- (aref V i (1+ k)) (* p q))))))))))))
+      (when (zerop norm)
+        (return-from hqr2 nil))
+      (loop :for n :from (1- nn) :downto 0
+            :do (setf p (aref d n)
+                      q (aref e n))
+                (cond ((zerop q)
+                       (let ((l n))
+                         (setf (aref H n n) 1.0)
+                         (loop :for i :from (1- n) :downto 0
+                               :do (setf w (- (aref H i i) p)
+                                         r 0.0)
+                                   (loop :for j :from l :to n
+                                         :do (setf r (+ r (* (aref H i j) (aref H j n)))))
+                                   (cond ((minusp (aref e i))
+                                          (setf z w
+                                                s r))
+                                         (t
+                                          (setf l i)
+                                          (cond ((zerop (aref e i))
+                                                 (if (not (zerop w))
+                                                     (setf (aref H i n) (/ (- r) w))
+                                                     (setf (aref H i n) (/ (- r) (* eps norm)))))
+                                                (t
+                                                 (setf x (aref H i (1+ i))
+                                                       y (aref H (1+ i) i)
+                                                       q (+ (* (- (aref d i) p) (- (aref d i) p)) (* (aref e i) (aref e i)))
+                                                       rt (/ (- (* x s) (* z r)) q)
+                                                       (aref H i n) rt)
+                                                 (if (> (abs x) (abs z))
+                                                     (setf (aref H (1+ i) n) (/ (- (- r) (* w rt)) x))
+                                                     (setf (aref H (1+ i) n) (/ (- (- s) (* y rt)) z)))
+                                                 (setf rt (abs (aref H i n)))
+                                                 (when (> (* (* eps rt) rt) 1)
+                                                   (loop :for j :from i :to n
+                                                         :do (setf (aref H j n) (/ (aref H j n) rt)))))))))))
+                      ((< q 0)
+                       (let ((l (1- n)))
+                         (cond ((> (abs (aref H n (1- n))) (abs (aref H (1- n) n)))
+                                (setf (aref H (1- n) (1- n)) (/ q (aref H n (1- n)))
+                                      (aref H (1- n) n) (/ (- (- (aref H n n) p)) (aref H n (1- n)))))
+                               (t
+                                (cdiv A 0.0 (- (aref H (1- n) n)) (- (aref H (1- n) (1- n)) p) q)
+                                (setf (aref H (1- n) (1- n)) cdivr
+                                      (aref H (1- n) n) cdivi)))
+                         (setf (aref H n (1- n)) 0.0
+                               (aref H n n) 1.0)
+                         (loop :for i :from (- n 2) :downto 0
+                               :do (let (ra sa vr vi)
+                                     (setf ra 0.0
+                                           sa 0.0)
+                                     (loop :for j :from l :to n
+                                           :do (setf ra (+ ra (* (aref H i j) (aref H j (1- n))))
+                                                     sa (+ sa (* (aref H i j) (aref H j n)))))
+                                     (setf w (- (aref H i i) p))
+                                     (cond ((minusp (aref e i))
+                                            (setf z w
+                                                  r ra
+                                                  s sa))
+                                           (t
+                                            (setf l i)
+                                            (cond ((zerop (aref e i))
+                                                   (cdiv A (- ra) (- sa) w q)
+                                                   (setf (aref H i (1- n)) cdivr
+                                                         (aref H i n) cdivi))
+                                                  (t
+                                                   ;; 
+                                                   (setf x (aref H i (1+ i))
+                                                         y (aref H (1+ i) i)
+                                                         vr (- (+ (* (- (aref d i) p) (- (aref d i) p)) (* (aref e i) (aref e i))) (* q q))
+                                                         vi (* (- (aref d i) p) 2.0 q))
+                                                   (cond ((> (abs x) (+ (abs z) (abs q)))
+                                                          (setf (aref H (1+ i) (1- n)) (/ (+ (- (- ra) (* w (aref H i (1- n)))) (* q (aref H i n))) x)
+                                                                (aref H (1+ i) n) (/ (- (- sa) (* w (aref H i n)) (* q (aref H i (1- n)))) x)))
+                                                         (t
+                                                          (cdiv A (- (- r) (* y (aref H i (1- n)))) (- (- s) (* y (aref H i n))) z q)
+                                                          (setf (aref H (1+ i) (1- n)) cdivr
+                                                                (aref H (1+ i) n) cdivi)))))
+                                            ;; 
+                                            (setf rt (max (abs (aref H i (1- n))) (abs (aref H i n))))
+                                            (when (> (* (* eps rt) rt) 1)
+                                              (loop :for j :from i :to n
+                                                    :do (setf (aref H j (1- n)) (/ (aref H j (1- n)) rt)
+                                                              (aref H j n) (/ (aref H j n) rt))))))))
+                         ;; 
+                         (loop :for i :from 0 :below nn
+                               :when (or (< i low) (> i high))
+                               :do (loop :for j :from i :below nn
+                                         :do (setf (aref V i j) (aref H i j))))
+                         ;; 
+                         (loop :for j :from (1- nn) :downto low
+                               :do (loop :for i :from low :to high
+                                         :do (setf z 0.0)
+                                             (loop :for k :from low :to (min j high)
+                                                   :do (setf z (+ z (* (aref V i k) (aref H k j)))))
+                                             (setf (aref V i j) z))))))))))
+
+(defmethod initialize-instance :after ((obj Eigenvalue) &key matrix)
+  (with-slots (n issymmetric d e V H ort) obj
+    (setf n (array-dimension matrix 1)
+          V (make-array (list n n))
+          d (make-array (list n))
+          e (make-array (list n))
+          issymmetric t)
+    (loop :for j :from 0 :below n
+          :while issymmetric
+          :do (loop :for i :from 0 :below n
+                    :while issymmetric
+                    :do (setf issymmetric (= (aref matrix i j) (aref matrix j i)))))
+    (cond (issymmetric
+           (loop :for i :from 0 :below n
+                 :do (loop :for j :from 0 :below n
+                           :do (setf (aref V i j) (aref matrix i j))))
+           ;; 
+           (tred2 obj)
+           ;; 
+           (tql2 obj))
+          (t
+           (setf H (make-array (list n n))
+                 ort (make-array (list n)))
+           (loop :for j :from 0 :below n
+                 :do (loop :for i :from 0 :below n
+                           :do (setf (aref H i j) (aref matrix i j))))
+           ;; 
+           (orthes obj)
+           ;; 
+           (hqr2 obj)))))
+    
+(defmethod get-V ((A Eigenvalue))
+  (with-slots (V) A
+    (copy-array V)))
+
+(defmethod get-RealEigenvalues ((A Eigenvalue))
+  (with-slots (d) A
+    (copy-array d)))
+
+(defmethod get-ImagEigenvalues ((A Eigenvalue))
+  (with-slots (e) A
+    (copy-array e)))
+
+(defmethod get-D ((A Eigenvalue))
+  (with-slots (n d e) A
+    (let ((D_ (make-array (list n n))))
+      (loop :for i :from 0 :below n
+            :do (loop :for j :from 0 :below n
+                      :do (setf (aref D_ i j) 0.0))
+                (setf (aref D_ i i) (aref d i))
+                (cond ((plusp (aref e i))
+                       (setf (aref D_ i (1+ i)) (aref e i)))
+                      ((minusp (aref e i))
+                       (setf (aref D_ i (1- i)) (aref e i)))))
+      D_)))
diff --git a/lu.lisp b/lu.lisp
new file mode 100644 (file)
index 0000000..13bd50b
--- /dev/null
+++ b/lu.lisp
@@ -0,0 +1,163 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+;;;  
+;;; Copyright (c) 2008 NANRI <southly@gmail.com>
+;;; 
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy
+;;; of this software and associated documentation files (the "Software"), to deal
+;;; in the Software without restriction, including without limitation the rights
+;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+;;; copies of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;; 
+;;; The above copyright notice and this permission notice shall be included in
+;;; all copies or substantial portions of the Software.
+;;; 
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+;;; THE SOFTWARE.
+
+(in-package :cl-jama)
+
+(defclass LU ()
+  ((LU_)
+   (m)
+   (n)
+   (pivsign)
+   (piv)))
+
+(defun permute-copy-matrix (A piv j0 j1)
+  (let ((X (make-array (list (array-dimension piv 0) (1+ (- j1 j0))))))
+    (loop :for i :from 0 :below (array-dimension piv 0)
+          :do (loop :for j :from j0 :to j1
+                    :do (setf (aref X i (- j j0)) (aref A (aref piv i) j))))
+    X))
+
+(defun permute-copy-vector (A piv)
+  (unless (eql (array-dimension piv 0) (array-dimension A 0))
+    (return-from permute-copy-vector nil))
+  (let ((x (make-array (list (array-dimension piv 0)))))
+    (loop :for i :from 0 :below (array-dimension piv 0)
+          :do (setf (aref x i) (aref A (aref piv i))))
+    x))
+
+(defmethod initialize-instance :after ((obj LU) &key matrix)
+  (with-slots (LU_ m n pivsign piv) obj
+    (setf LU_ (copy-array matrix))
+    (setf m (array-dimension matrix 0))
+    (setf n (array-dimension matrix 1))
+    (setf piv (make-array (list (array-dimension matrix 0))))
+    ;; Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+    (loop :for i :from 0 :below m
+          :do (setf (aref piv i) i))
+    (setf pivsign 1)
+    (let ((LUcolj (make-array (list m)))
+          p)
+      ;; Outer loop.
+      (loop :for j :from 0 :below n
+            ;; Make a copy of the j-th column to localize references.
+            :do (loop :for i :from 0 :below m
+                      :do (setf (aref LUcolj i) (aref LU_ i j)))
+            ;; Apply previous transformations.
+            :do (loop :for i :from 0 :below m
+                      :do (decf (aref LUcolj i) (loop :for k :from 0 :below (min i j)
+                                                      :sum (* (aref LU_ i k) (aref LUcolj k))))
+                          (setf (aref LU_ i j) (aref LUcolj i)))
+             ;; Find pivot and exchange if necessary.
+            :do (setf p j)
+            :do (loop :for i :from (1+ j) :below m
+                      :when (> (abs (aref LUcolj i)) (abs (aref LUcolj p)))
+                      :do (setf p i))
+            :do (unless (eql p j)
+                  (loop :for k :from 0 :below n
+                        :do (psetf (aref LU_ p k) (aref LU_ j k)
+                                   (aref LU_ j k) (aref LU_ p k)))
+                  (psetf (aref piv p) (aref piv j)
+                         (aref piv j) (aref piv p))
+                  (setf pivsign (- pivsign)))
+            ;; Compute multipliers.
+            :do (when (and (< j m) (not (zerop (aref LU_ j j))))
+                  (loop :for i :from (1+ j) :below m
+                        :do (setf (aref LU_ i j) (/ (aref LU_ i j) (aref LU_ j j)))))))))
+
+(defmethod is-nonsingular ((A LU))
+  (with-slots (LU_ n) A
+    (loop :for j :from 0 :below n
+          :when (eql (aref LU_ j j) 0)
+          :do (return-from is-nonsingular nil)))
+  t)
+
+(defmethod get-L ((A LU))
+  (with-slots (LU_ m n) A
+    (let ((L_ (make-array (list m n))))
+      (loop :for i :from 0 :below m
+            :do (loop :for j :from 0 :below n
+                      :if (> i j)
+                      :do (setf (aref L_ i j) (aref LU_ i j))
+                      :else 
+                      :if (= i j)
+                      :do (setf (aref L_ i j) 1.0)
+                      :else 
+                      :do (setf (aref L_ i j) 0.0)))
+      L_)))
+
+(defmethod get-U ((A LU))
+  (with-slots (LU_ n) A
+    (let ((U_ (make-array (list n n))))
+      (loop :for i :from 0 :below n
+            :do (loop :for j :from 0 :below n
+                      :if (<= i j)
+                      :do (setf (aref U_ i j) (aref LU_ i j))
+                      :else 
+                      :do (setf (aref U_ i j) 0.0)))
+      U_)))
+
+(defmethod get-pivot ((A LU))
+  (with-slots (piv) A
+    (copy-array piv)))
+
+(defmethod det ((A LU))
+  (with-slots (m n pivsign LU_) A
+    (when (/= m n)
+      (return-from det 0))
+    (apply #'* pivsign (loop :for j :from 0 :below n
+                             :collect (aref LU_ j j)))))
+
+(defmethod solve ((A LU) (B array))
+  (with-slots (LU_ m n piv) A
+    (unless (eql m (array-dimension B 0))
+      (return-from solve nil))
+    (unless (is-nonsingular A)
+      (return-from solve nil))
+    (let* ((nx (array-dimension B 1))
+           (X (permute-copy-matrix B piv 0 (1- nx))))
+      (loop :for k :from 0 :below n
+            :do (loop :for i :from (1+ k) :below n
+                      :do (loop :for j :from 0 :below nx
+                                :do (decf (aref X i j) (* (aref X k j) (aref LU_ i k))))))
+      (loop :for k :from (1- n) :downto 0
+            :do (loop :for j :from 0 :below nx
+                      :do (setf (aref X k j) (/ (aref X k j) (aref LU_ k k))))
+            :do (loop :for i :from 0 :below k
+                      :do (loop :for j :from 0 :below nx
+                                :do (decf (aref X i j) (* (aref X k j) (aref LU_ i k))))))
+      X)))
+
+(defmethod solve ((A LU) (b vector))
+  (with-slots (LU_ m n piv) A
+    (unless (eql m (array-dimension b 0))
+      (return-from solve nil))
+    (unless (is-nonsingular A)
+      (return-from solve nil))
+    (let ((x (permute-copy-vector b piv)))
+      (loop :for k :from 0 :below n
+            :do (loop :for i :from (1+ k) :below n
+                      :do (decf (aref x i) (* (aref x k) (aref LU_ i k)))))
+      (loop :for k :from (1- n) :downto 0
+            :do (setf (aref x k) (/ (aref x k) (aref LU_ k k)))
+                (loop :for i :from 0 :below k
+                      :do (decf (aref x i) (* (aref x k) (aref LU_ i k)))))
+      x)))
diff --git a/package.lisp b/package.lisp
new file mode 100644 (file)
index 0000000..24c53f9
--- /dev/null
@@ -0,0 +1,85 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+;;;  
+;;; Copyright (c) 2008 NANRI <southly@gmail.com>
+;;; 
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy
+;;; of this software and associated documentation files (the "Software"), to deal
+;;; in the Software without restriction, including without limitation the rights
+;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+;;; copies of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;; 
+;;; The above copyright notice and this permission notice shall be included in
+;;; all copies or substantial portions of the Software.
+;;; 
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+;;; THE SOFTWARE.
+
+(defpackage :cl-jama
+    (:use :common-lisp)
+  (:nicknames :jama)
+  (:export :copy-array :transpose :multiply
+           :LU :is-nonsingular :get-L :get-U :get-pivot :det :solve
+           :Cholesky :get-L :is-spd
+           :QR :is-FullRank :get-Householder :get-R :get-Q
+           :SVD :get-V :get-singular-values :get-S :norm2 :norm2-of-condition-number :rank
+           :Eigenvalue :get-RealEigenvalues :get-ImagEigenvalues :get-D)
+  (:documentation ""))
+
+(in-package :cl-jama)
+
+(defgeneric cdiv (A xr xi yr yi)
+  )
+(defgeneric det (A)
+  )
+(defgeneric get-D (A)
+  )
+(defgeneric get-Householder (A)
+  )
+(defgeneric get-L (A)
+  )
+(defgeneric get-Q (A)
+  )
+(defgeneric get-R (A)
+  )
+(defgeneric get-RealEigenvalues (A)
+  )
+(defgeneric get-ImagEigenvalues (A)
+  )
+(defgeneric get-S (A)
+  )
+(defgeneric get-U (A)
+  )
+(defgeneric get-V (A)
+  )
+(defgeneric get-pivot (A)
+  )
+(defgeneric get-singular-values (A)
+  )
+(defgeneric hqr2 (A)
+  )
+(defgeneric is-FullRank (A)
+  )
+(defgeneric is-nonsingular (A)
+  )
+(defgeneric is-spd (A)
+  )
+(defgeneric norm2 (A)
+  )
+(defgeneric norm2-of-condition-number (A)
+  )
+(defgeneric orthes (A)
+  )
+(defgeneric rank (A)
+  )
+(defgeneric solve (A B)
+  )
+(defgeneric tql2 (A)
+  )
+(defgeneric tred2 (A)
+  )
diff --git a/qr.lisp b/qr.lisp
new file mode 100644 (file)
index 0000000..887da26
--- /dev/null
+++ b/qr.lisp
@@ -0,0 +1,157 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+;;;  
+;;; Copyright (c) 2008 NANRI <southly@gmail.com>
+;;; 
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy
+;;; of this software and associated documentation files (the "Software"), to deal
+;;; in the Software without restriction, including without limitation the rights
+;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+;;; copies of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;; 
+;;; The above copyright notice and this permission notice shall be included in
+;;; all copies or substantial portions of the Software.
+;;; 
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+;;; THE SOFTWARE.
+
+(in-package :cl-jama)
+
+(defclass QR ()
+  ((QR_)
+   (m)
+   (n)
+   (Rdiag)))
+
+(defmethod initialize-instance :after ((obj QR) &key matrix)
+  (with-slots (QR_ m n Rdiag) obj
+    (setf QR_ (copy-array matrix))
+    (setf m (array-dimension matrix 0))
+    (setf n (array-dimension matrix 1))
+    (setf Rdiag (make-array (list n)))
+    ;; 
+    (loop :for k :from 0 :below n 
+          :do (let ((nrm 0.0))
+                (loop :for i :from k :below m
+                      :do (setf nrm (hypot nrm (aref QR_ i k))))
+                (unless (zerop nrm)
+                  (when (minusp (aref QR_ k k))
+                    (setf nrm (- nrm)))
+                  (loop :for i :from k :below m
+                        :do (setf (aref QR_ i k) (/ (aref QR_ i k) nrm)))
+                  (incf (aref QR_ k k) 1.0)
+                  ;; 
+                  (loop :for j :from (1+ k) :below n
+                        :do (let ((s 0.0))
+                              (loop :for i :from k :below m
+                                    :do (incf s (* (aref QR_ i k) (aref QR_ i j))))
+                              (setf s (/ (- s) (aref QR_ k k)))
+                              (loop :for i :from k :below m
+                                    :do (incf (aref QR_ i j) (* s (aref QR_ i k)))))))
+                (setf (aref Rdiag k) (- nrm))))))
+
+(defmethod is-FullRank ((A QR))
+  (with-slots (n Rdiag) A
+    (loop :for j :from 0 :below n
+          :when (zerop (aref Rdiag j))
+          :do (return-from is-FullRank nil))
+    t))
+
+(defmethod get-Householder ((A QR))
+  (with-slots (QR_ m n) A
+    (let ((H (make-array (list m n))))
+      (loop :for i :from 0 :below m
+            :do (loop :for j :from 0 :below n
+                      :if (>= i j)
+                      :do (setf (aref H i j) (aref QR_ i j))
+                      :else 
+                      :do (setf (aref H i j) 0.0)))
+      H)))
+
+(defmethod get-R ((A QR))
+  (with-slots (QR_ n Rdiag) A
+    (let ((R (make-array (list n n))))
+      (loop :for i :from 0 :below n
+            :do (loop :for j :from 0 :below n
+                      :if (< i j)
+                      :do (setf (aref R i j) (aref QR_ i j))
+                      :else 
+                      :if (= i j)
+                      :do (setf (aref R i j) (aref Rdiag i))
+                      :else
+                      :do (setf (aref R i j) 0.0)))
+      R)))
+
+(defmethod get-Q ((A QR))
+  (with-slots (QR_ m n) A
+    (let ((Q (make-array (list m n))))
+      (loop :for k :from (1- n) :downto 0
+            :do (loop :for i :from 0 :below m
+                      :do (setf (aref Q i k) 0.0))
+                (setf (aref Q k k) 1.0)
+                (loop :for j :from k :below n
+                      :do (unless (zerop (aref QR_ k k))
+                            (let ((s 0.0))
+                              (loop :for i :from k :below m
+                                    :do (incf s (* (aref QR_ i k) (aref Q i j))))
+                              (setf s (/ (- s) (aref QR_ k k)))
+                              (loop :for i :from k :below m
+                                    :do (incf (aref Q i j) (* s (aref QR_ i k))))
+                              ))))
+      Q)))
+
+(defmethod solve ((A QR) (b vector))
+  (with-slots (QR_ m n Rdiag) A
+    (unless (eql m (array-dimension b 0))
+      (return-from solve nil))
+    (unless (is-FullRank A)
+      (return-from solve nil))
+    (let ((x (copy-array b))
+          (x_ (make-array (list n))))
+      (loop :for k :from 0 :below n
+            :do (let ((s 0.0))
+                  (loop :for i :from k :below m
+                        :do (incf s (* (aref QR_ i k) (aref x i))))
+                  (setf s (/ (- s) (aref QR_ k k)))
+                  (loop :for i :from k :below m
+                        :do (incf (aref x i) (* s (aref QR_ i k))))))
+      (loop :for k :from (1- n) :downto 0
+            :do (setf (aref x k) (/ (aref x k) (aref Rdiag k)))
+                (loop :for i :from 0 :below k
+                      :do (decf (aref x i) (* (aref x k) (aref QR_ i k)))))
+      (loop :for i :from 0 :below n
+            :do (setf (aref x_ i) (aref x i)))
+      x_)))
+
+(defmethod solve ((A QR) (B array))
+  (with-slots (QR_ m n Rdiag) A
+    (unless (eql m (array-dimension B 0))
+      (return-from solve nil))
+    (unless (is-FullRank A)
+      (return-from solve nil))
+    (let* ((nx (array-dimension B 1))
+           (X (copy-array B))
+           (X_ (make-array (list n nx))))
+      (loop :for k :from 0 :below n
+            :do (loop :for j :from 0 :below nx
+                      :do (let ((s 0.0))
+                            (loop :for i :from k :below m
+                                  :do (incf s (* (aref QR_ i k) (aref X i j))))
+                            (setf s (/ (- s) (aref QR_ k k)))
+                            (loop :for i :from k :below m
+                                  :do (incf (aref X i j) (* s (aref QR_ i k)))))))
+      (loop :for k :from (1- n) :downto 0
+            :do (loop :for j :from 0 :below nx
+                      :do (setf (aref X k j) (/ (aref X k j) (aref Rdiag k))))
+                (loop :for i :from 0 :below k
+                      :do (loop :for j :from 0 :below nx
+                                :do (decf (aref X i j) (* (aref X k j) (aref QR_ i k))))))
+      (loop :for i :from 0 :below n
+            :do (loop :for j :from 0 :below nx
+                      :do (setf (aref X_ i j) (aref X i j))))
+      X_)))
diff --git a/svd.lisp b/svd.lisp
new file mode 100644 (file)
index 0000000..7c21442
--- /dev/null
+++ b/svd.lisp
@@ -0,0 +1,326 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+;;;  
+;;; Copyright (c) 2008 NANRI <southly@gmail.com>
+;;; 
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy
+;;; of this software and associated documentation files (the "Software"), to deal
+;;; in the Software without restriction, including without limitation the rights
+;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+;;; copies of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;; 
+;;; The above copyright notice and this permission notice shall be included in
+;;; all copies or substantial portions of the Software.
+;;; 
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+;;; THE SOFTWARE.
+
+(in-package :cl-jama)
+
+(defclass SVD ()
+  ((U)
+   (V)
+   (s)
+   (m)
+   (n)))
+
+(defmethod initialize-instance :after ((obj SVD) &key matrix)
+  (with-slots (U V s m n) obj
+    (let (nu e work A (wantu t) (wantv t) nct nrt p pp eps iter)
+      (setf m (array-dimension matrix 0))
+      (setf n (array-dimension matrix 1))
+      (setf nu (min m n))
+      (setf s (make-array (list (min (1+ m) n))))
+      (setf U (make-array (list m nu) :initial-element 0.0))
+      (setf V (make-array (list n n)))
+      (setf e (make-array (list n)))
+      (setf work (make-array (list m)))
+      (setf A (copy-array matrix))
+      ;; 
+      (setf nct (min (1- m) n))
+      (setf nrt (max 0 (min (- n 2) m)))
+      (loop :for k :from 0 :below (max nct nrt)
+            :do (when (< k nct)
+                  ;; 
+                  (setf (aref s k) 0)
+                  (loop :for i :from k :below m
+                        :do (setf (aref s k) (hypot (aref s k) (aref A i k))))
+                  (unless (zerop (aref s k))
+                    (when (minusp (aref A k k))
+                      (setf (aref s k) (- (aref s k))))
+                    (loop :for i :from k :below m
+                          :do (setf (aref A i k) (/ (aref A i k) (aref s k))))
+                    (incf (aref A k k) 1.0))
+                  (setf (aref s k) (- (aref s k))))
+                (loop :for j :from (1+ k) :below n
+                      :do (when (and (< k nct) (not (zerop (aref s k))))
+                            ;; 
+                            (let ((rt 0.0))
+                              (loop :for i :from k :below m
+                                    :do (incf rt (* (aref A i k) (aref A i j))))
+                              (setf rt (/ (- rt) (aref A k k)))
+                              (loop :for i :from k :below m
+                                    :do (incf (aref A i j) (* rt (aref A i k))))))
+                          (setf (aref e j) (aref A k j)))
+                (when (and wantu (< k nct))
+                  (loop :for i :from k :below m
+                        :do (setf (aref U i k) (aref A i k))))
+                (when (< k nrt)
+                  ;; 
+                  (setf (aref e k) 0)
+                  (loop :for i :from (1+ k) :below n
+                        :do (setf (aref e k) (hypot (aref e k) (aref e i))))
+                  (unless (zerop (aref e k))
+                    (when (minusp (aref e (1+ k)))
+                      (setf (aref e k) (- (aref e k))))
+                    (loop :for i :from (1+ k) :below n
+                          :do (setf (aref e i) (/ (aref e i) (aref e k))))
+                    (incf (aref e (1+ k)) 1.0))
+                  (setf (aref e k) (- (aref e k)))
+                  (when (and (< (1+ k) m) (not (zerop (aref e k))))
+                    ;; 
+                    (loop :for i :from (1+ k) :below m
+                          :do (setf (aref work i) 0.0))
+                    (loop :for j :from (1+ k) :below n
+                          :do (loop :for i :from (1+ k) :below m
+                                    :do (incf (aref work i) (* (aref e j) (aref A i j)))))
+                    (loop :for j :from (1+ k) :below n
+                          :do (let ((rt (/ (- (aref e j)) (aref e (1+ k)))))
+                                (loop :for i :from (1+ k) :below m
+                                      :do (incf (aref A i j) (* rt (aref work i)))))))
+                  (when wantv
+                    ;; 
+                    (loop :for i :from (1+ k) :below n
+                          :do (setf (aref V i k) (aref e i))))))
+      ;; 
+      (setf p (min n (1+ m)))
+      (when (< nct n)
+        (setf (aref s nct) (aref A nct nct)))
+      (when (< m p)
+        (setf (aref s (1- p)) 0.0))
+      (when (< (1+ nrt) p)
+        (setf (aref e nrt) (aref A nrt (1- p))))
+      (setf (aref e (1- p)) 0.0)
+      ;; 
+      (when wantu
+        (loop :for j :from nct :below nu
+              :do (loop :for i :from 0 :below m
+                        :do (setf (aref U i j) 0.0))
+                  (setf (aref U j j) 1.0))
+        (loop :for k :from (1- nct) :downto 0
+              :do (cond ((not (zerop (aref s k)))
+                         (loop :for j :from (1+ k) :below nu
+                               :do (let ((rt 0.0))
+                                     (loop :for i :from k :below m
+                                           :do (incf rt (* (aref U i k) (aref U i j))))
+                                     (setf rt (/ (- rt) (aref U k k)))
+                                     (loop :for i :from k :below m
+                                           :do (incf (aref U i j) (* rt (aref U i k))))))
+                         (loop :for i :from k :below m
+                               :do (setf (aref U i k) (- (aref U i k))))
+                         (setf (aref U k k) (+ 1.0 (aref U k k)))
+                         (loop :for i :from 0 :below (1- k)
+                               :do (setf (aref U i k) 0.0)))
+                        (t
+                         (loop :for i :from 0 :below m
+                               :do (setf (aref U i k) 0.0))
+                         (setf (aref U k k) 1.0)))))
+      ;; 
+      (when wantv
+        (loop :for k :from (1- n) :downto 0
+              :do (when (and (< k nrt) (not (zerop (aref e k))))
+                    (loop :for j :from (1+ k) :below nu
+                          :do (let ((rt 0.0))
+                                (loop :for i :from (1+ k) :below n
+                                      :do (incf rt (* (aref V i k) (aref V i j))))
+                                (setf rt (/ (- rt) (aref V (1+ k) k)))
+                                (loop :for i :from (1+ k) :below n
+                                      :do (incf (aref V i j) (* rt (aref V i k)))))))
+                  (loop :for i :from 0 :below n
+                        :do (setf (aref V i k) 0.0))
+                  (setf (aref V k k) 1.0)))
+      ;; 
+      (setf pp (1- p))
+      (setf iter 0)
+      (setf eps (expt 2.0 -52.0))
+      (loop :while (plusp p)
+            :do (let ((k 0) (kase 0))
+                  ;; 
+                  (loop :for lk :from (- p 2) :downto -1
+                        :when (= lk -1)
+                        :return (setf k lk)
+                        :end
+                        :when (<= (abs (aref e lk)) (* eps (+ (abs (aref s lk)) (abs (aref s (1+ lk))))))
+                        :return (setf (aref e lk) 0.0
+                                      k lk)
+                        :end
+                        :finally (setf k lk)) ; XXX
+                  (cond ((= k (- p 2))
+                         (setf kase 4))
+                        (t
+                         (let ((ks 0))
+                           (loop :for lks :from (1- p) :downto k
+                                 :when (= lks k)
+                                 :return (setf ks lks)
+                                 :end
+                                 :when (<= (abs (aref s lks)) (* eps (+ (if (/= lks p) (abs (aref e lks)) 0.0)
+                                                                        (if (/= lks (1+ k)) (abs (aref e (1- lks))) 0.0))))
+                                 :return (setf (aref s lks) 0.0
+                                               ks lks)
+                                 :end
+                                 :finally (setf ks lks)) ; XXX
+                           (cond ((= ks k)
+                                  (setf kase 3))
+                                 ((= ks (1- p))
+                                  (setf kase 1))
+                                 (t
+                                  (setf kase 2)
+                                  (setf k ks))))))
+                  (incf k)
+                  ;; 
+                  ;; switch
+                  (case kase
+                    (1 (let ((f (aref e (- p 2))))
+                         (setf (aref e (- p 2)) 0.0)
+                         (loop :for j :from (- p 2) :downto k
+                               :for rt = (hypot (aref s j) f) :then (hypot (aref s j) f)
+                               :for cs = (/ (aref s j) rt) :then (/ (aref s j) rt)
+                               :for sn = (/ f rt) :then (/ f rt)
+                               :do (setf (aref s j) rt)
+                                   (unless (eql j k)
+                                     (setf f (* (- sn) (aref e (1- j))))
+                                     (setf (aref e (1- j)) (* cs (aref e (1- j)))))
+                                   (when wantv
+                                     (loop :for i :from 0 :below n
+                                           :do (setf rt (+ (* cs (aref V i j)) (* sn (aref V i (1- p)))))
+                                               (setf (aref V i (1- p)) (+ (* (- sn) (aref V i j)) (* cs (aref V i (1- p)))))
+                                               (setf (aref V i j) rt))))))
+                    (2 (let ((f (aref e (1- k))))
+                         (setf (aref e (1- k)) 0.0)
+                         (loop :for j :from k :below p
+                               :for rt = (hypot (aref s j) f) :then (hypot (aref s j) f)
+                               :for cs = (/ (aref s j) rt) :then (/ (aref s j) rt)
+                               :for sn = (/ f rt) :then (/ f rt)
+                               :do (setf (aref s j) rt)
+                                   (setf f (* (- sn) (aref e j)))
+                                   (setf (aref e j) (* cs (aref e j)))
+                                   (when wantu
+                                     (loop :for i :from 0 :below m
+                                           :do (setf rt (+ (* cs (aref U i j)) (* sn (aref U i (1- k)))))
+                                               (setf (aref U i (1- k)) (+ (* (- sn) (aref U i j)) (* cs (aref U i (1- k)))))
+                                               (setf (aref U i j) rt))))))
+                    (3 (let* ((scale (max (abs (aref s (- p 1))) (abs (aref s (- p 2))) (abs (aref e (- p 2)))
+                                          (abs (aref s k)) (abs (aref e k))))
+                              (sp (/ (aref s (1- p)) scale))
+                              (spm1 (/ (aref s (- p 2)) scale))
+                              (epm1 (/ (aref e (- p 2)) scale))
+                              (sk (/ (aref s k) scale))
+                              (ek (/ (aref e k) scale))
+                              (b (/ (+ (* (+ spm1 sp) (- spm1 sp)) (* epm1 epm1)) 2.0))
+                              (c (* sp epm1 sp epm1))
+                              (shift 0.0)
+                              f g)
+                         (when (or (not (zerop b)) (not (zerop c)))
+                           (setf shift (sqrt (+ (* b b) c)))
+                           (when (minusp b)
+                             (setf shift (- shift)))
+                           (setf shift (/ c (+ b shift))))
+                         (setf f (+ (* (+ sk sp) (- sk sp)) shift))
+                         (setf g (* sk ek))
+                         ;; 
+                         (loop :for j :from k :below (1- p)
+                               :do (let* ((rt (hypot f g))
+                                          (cs (/ f rt))
+                                          (sn (/ g rt)))
+                                     (when (/= j k)
+                                       (setf (aref e (1- j)) rt))
+                                     (setf f (+ (* cs (aref s j)) (* sn (aref e j)))
+                                           (aref e j) (- (* cs (aref e j)) (* sn (aref s j)))
+                                           g (* sn (aref s (1+ j)))
+                                           (aref s (1+ j)) (* cs (aref s (1+ j))))
+                                     (when wantv
+                                       (loop :for i :from 0 :below n
+                                             :do (setf rt (+ (* cs (aref V i j)) (* sn (aref V i (1+ j))))
+                                                       (aref V i (1+ j)) (+ (* (- sn) (aref V i j)) (* cs (aref V i (1+ j))))
+                                                       (aref V i j) rt)))
+                                     (setf rt (hypot f g))
+                                     (setf cs (/ f rt))
+                                     (setf sn (/ g rt))
+                                     (setf (aref s j) rt)
+                                     (setf f (+ (* cs (aref e j)) (* sn (aref s (1+ j)))))
+                                     (setf (aref s (1+ j)) (+ (* (- sn) (aref e j)) (* cs (aref s (1+ j)))))
+                                     (setf g (* sn (aref e (1+ j))))
+                                     (setf (aref e (1+ j)) (* cs (aref e (1+ j))))
+                                     (when (and wantu (< j (1- m)))
+                                       (loop :for i :from 0 :below m
+                                             :do (setf rt (+ (* cs (aref U i j)) (* sn (aref U i (1+ j))))
+                                                       (aref U i (1+ j)) (+ (* (- sn) (aref U i j)) (* cs (aref U i (1+ j))))
+                                                       (aref U i j) rt)))))
+                         (setf (aref e (- p 2)) f)
+                         (setf iter (1+ iter))))
+                    (4 (when (<= (aref s k) 0.0)
+                         (setf (aref s k) (if (minusp (aref s k)) (- (aref s k)) 0.0))
+                         (when wantv
+                           (loop :for i :from 0 :to pp
+                                 :do (setf (aref V i k) (- (aref V i k))))))
+                       (loop :while (< k pp)
+                             :thereis (>= (aref s k) (aref s (1+ k)))
+                             :do (psetf (aref s k) (aref s (1+ k))
+                                        (aref s (1+ k)) (aref s k))
+                             :when (and wantv (< k (1- n)))
+                             :do (loop :for i :from 0 :below n
+                                       :do (psetf (aref V i (1+ k)) (aref V i k)
+                                                  (aref V i k) (aref V i (1+ k))))
+                             :end
+                             :when (and wantu (< k (1- m)))
+                             :do (loop :for i :from 0 :below m
+                                       :do (psetf (aref U i (1+ k)) (aref U i k)
+                                                  (aref U i k) (aref U i (1+ k))))
+                             :do (incf k))
+                       (setf iter 0)
+                       (decf p))))))))
+
+(defmethod get-U ((A SVD))
+  (with-slots (U m n) A
+    (let* ((minm (min (1+ m) n))
+           (X (make-array (list m minm))))
+      (loop :for i :from 0 :below m
+            :do (loop :for j :from 0 :below minm
+                      :do (setf (aref X i j) (aref U i j))))
+      X)))
+
+(defmethod get-V ((A SVD))
+  (with-slots (V) A
+    (copy-array V)))
+
+(defmethod get-singular-values ((A SVD))
+  (with-slots (s) A
+    (copy-array s)))
+
+(defmethod get-S ((A SVD))
+  (with-slots (n s) A
+    (let ((X (make-array (list n n))))
+      (loop :for i :from 0 :below n
+            :do (loop :for j :from 0 :below n
+                      :do (setf (aref X i j) 0.0))
+                (setf (aref X i i) (aref s i)))
+      X)))
+(defmethod norm2 ((A SVD))
+  (with-slots (s) A
+    (aref s 0)))
+
+(defmethod norm2-of-condition-number ((A SVD))
+  (with-slots (m n s) A
+    (/ (aref s 0) (aref s (1- (min m n))))))
+
+(defmethod rank ((A SVD))
+  (with-slots (m n s) A
+    (let* ((eps (expt 2.0 -52.0))
+           (tol (* (max m n) (aref s 0) eps)))
+      (loop :for i :from 0 :below (array-dimension s 0)
+            :count (> (aref s 0) tol)))))
diff --git a/test/cholesky.lisp b/test/cholesky.lisp
new file mode 100644 (file)
index 0000000..825766e
--- /dev/null
@@ -0,0 +1,72 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+
+(in-package :cl-jama-test)
+(rem-all-tests)
+
+(defparameter *chol.1* (make-instance 'Cholesky
+                                      :matrix (make-matrix '((5.49 2.68 0.0 0.0)
+                                                             (2.68 5.63 -2.39 0.0)
+                                                             (0.0 -2.39 2.60 -2.22)
+                                                             (0.0 0.0 -2.22 5.17)))))
+(deftest cholesky.1
+    (with-output-to-string (os)
+      (dump-vector (solve *chol.1* (make-vector '(22.09 9.31 -5.24 11.83))) os))
+"     5.0000    -2.0000    -3.0000     1.0000
+")
+
+(deftest cholesky.2
+    (with-output-to-string (os)
+      (dump-matrix (get-L *chol.1*) os))
+"     2.3431     0.0000     0.0000     0.0000
+     1.1438     2.0789     0.0000     0.0000
+     0.0000    -1.1497     1.1306     0.0000
+     0.0000     0.0000    -1.9635     1.1465
+")
+
+(deftest cholesky.3
+    (with-output-to-string (os)
+      (dump-matrix (solve *chol.1* (make-matrix '((22.09 5.10)
+                                                  (9.31 30.81)
+                                                  (-5.24 -25.82)
+                                                  (11.83 22.90))))
+                   os))
+"     5.0000    -2.0000
+    -2.0000     6.0000
+    -3.0000    -1.0000
+     1.0000     4.0000
+")
+
+(defparameter *chol.2* (make-instance 'Cholesky
+                                      :matrix (make-matrix '((4.16 -3.12 0.56 -0.10)
+                                                             (-3.12 5.03 -0.83 1.18)
+                                                             (0.56 -0.83 0.76 0.34)
+                                                             (-0.10 1.18 0.34 1.18)))))
+(deftest cholesky.4
+    (with-output-to-string (os)
+      (dump-vector (solve *chol.2* (make-vector '(8.70 -13.35 1.89 -4.14))) os))
+"     1.0000    -1.0000     2.0000    -3.0000
+")
+
+(deftest cholesky.5
+    (with-output-to-string (os)
+      (dump-matrix (get-L *chol.2*) os))
+"     2.0396     0.0000     0.0000     0.0000
+    -1.5297     1.6401     0.0000     0.0000
+     0.2746    -0.2500     0.7887     0.0000
+    -0.0490     0.6737     0.6617     0.5347
+")
+
+(deftest cholesky.6
+    (with-output-to-string (os)
+      (dump-matrix (solve *chol.2* (make-matrix '((8.70 8.30)
+                                                  (-13.35 2.13)
+                                                  (1.89 1.61)
+                                                  (-4.14 5.00))))
+                   os))
+"     1.0000     4.0000
+    -1.0000     3.0000
+     2.0000     2.0000
+    -3.0000     1.0000
+")
+
+(do-tests)
diff --git a/test/cl-jama-test.asd b/test/cl-jama-test.asd
new file mode 100644 (file)
index 0000000..fed4548
--- /dev/null
@@ -0,0 +1,11 @@
+
+(asdf:defsystem :cl-jama-test
+  :depends-on (:cl-jama :rt)
+  :components ((:file "package")
+               (:file "utils" :depends-on ("package"))
+               (:file "lu" :depends-on ("utils"))
+               (:file "cholesky" :depends-on ("utils"))
+               (:file "qr" :depends-on ("utils"))
+               (:file "svd" :depends-on ("utils"))
+               (:file "eigenvalue" :depends-on ("utils"))
+               ))
diff --git a/test/eigenvalue.lisp b/test/eigenvalue.lisp
new file mode 100644 (file)
index 0000000..a8f679d
--- /dev/null
@@ -0,0 +1,53 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+
+(in-package :cl-jama-test)
+(rem-all-tests)
+
+(defparameter *A.1* (make-matrix '((4.0 1.0 1.0)
+                                   (1.0 2.0 3.0)
+                                   (1.0 3.0 6.0))))
+(defparameter *eig.1* (make-instance 'Eigenvalue
+                                     :matrix *A.1*))
+(defparameter *D.1* (get-D *eig.1*))
+(defparameter *V.1* (get-V *eig.1*))
+
+(deftest eig.1
+    (with-output-to-string (os)
+      (dump-matrix *D.1* os))
+"     0.3451     0.0000     0.0000
+     0.0000     3.5956     0.0000
+     0.0000     0.0000     8.0593
+")
+
+(deftest eig.2
+    (with-output-to-string (os)
+      (dump-matrix *V.1* os))
+"     0.1195    -0.9406     0.3178
+    -0.8856     0.0436     0.4623
+     0.4487     0.3367     0.8278
+")
+
+(deftest eig.3
+    (equal (with-output-to-string (os)
+             (dump-matrix (multiply *A.1* *V.1*) os))
+           (with-output-to-string (os)
+             (dump-matrix (multiply *V.1* *D.1*) os)))
+  T)
+
+(defparameter *A.2* (make-matrix '((0.0 1.0 0.0 0.0)
+                                   (1.0 0.0 2.0d-7 0.0)
+                                   (0.0 -2.0d-7 0.0 1.0)
+                                   (0.0 0.0 1.0 0.0))))
+(defparameter *eig.2* (make-instance 'Eigenvalue
+                                     :matrix *A.2*))
+(defparameter *D.2* (get-D *eig.2*))
+(defparameter *V.2* (get-V *eig.2*))
+
+(deftest eig.4
+    (equal (with-output-to-string (os)
+             (dump-matrix (multiply *A.2* *V.2*) os))
+           (with-output-to-string (os)
+             (dump-matrix (multiply *V.2* *D.2*) os)))
+  T)
+
+(do-tests)
diff --git a/test/lu.lisp b/test/lu.lisp
new file mode 100644 (file)
index 0000000..284a72b
--- /dev/null
@@ -0,0 +1,57 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+
+(in-package :cl-jama-test)
+
+(rem-all-tests)
+
+(defparameter *lu.1* (make-instance 'LU :matrix (make-matrix '((-0.23 2.54 -3.66  0.0)
+                                                               (-6.98 2.46 -2.73 -2.13)
+                                                               (0.0 2.56 2.46 4.07)
+                                                               (0.0 0.0 -4.78 -3.82)))))
+(deftest lu.1
+    (with-output-to-string (os)
+      (dump-vector (solve *lu.1* (make-vector '(4.42 27.13 -6.14 10.50))) os))
+"    -2.0000     3.0000     1.0000    -4.0000
+")
+
+(deftest lu.2
+    (with-output-to-string (os)
+      (dump-matrix (solve *lu.1* (make-matrix '((4.42 -36.01)
+                                                (27.13 -31.67)
+                                                (-6.14 -1.16)
+                                                (10.50 -25.82))))
+                   os))
+"    -2.0000     1.0000
+     3.0000    -4.0000
+     1.0000     7.0000
+    -4.0000    -2.0000
+")
+
+(defparameter *lu.2* (make-instance 'LU :matrix (make-matrix '((1.80 2.88 2.05 -0.89)
+                                                               (5.25 -2.95 -0.95 -3.80)
+                                                               (1.58 -2.69 -2.90 -1.04)
+                                                               (-1.11 -0.66 -0.59 0.80)))))
+(deftest lu.3
+    (with-output-to-string (os)
+      (dump-vector (solve *lu.2* (make-vector '(9.52 24.35 0.77 -6.22))) os))
+"     1.0000    -1.0000     3.0000    -5.0000
+")
+
+(defparameter *lu.3* (make-instance 'lu :matrix (make-matrix '((  1.80    2.88   2.05   -0.89)
+                                                               (525.00 -295.00 -95.00 -380.00)
+                                                               (  1.58   -2.69  -2.90   -1.04)
+                                                               ( -1.11   -0.66  -0.59    0.80)))))
+(deftest lu.4
+    (with-output-to-string (os)
+      (dump-matrix (solve *lu.3* (make-matrix '((9.52 18.47)
+                                                (2435.00 225.00)
+                                                (0.77 -13.28)
+                                                (-6.22 -6.21)))) 
+                   os))
+"     1.0000     3.0000
+    -1.0000     2.0000
+     3.0000     4.0000
+    -5.0000     1.0000
+")
+
+(do-tests)
diff --git a/test/package.lisp b/test/package.lisp
new file mode 100644 (file)
index 0000000..dbcc4c3
--- /dev/null
@@ -0,0 +1,8 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+
+(defpackage :cl-jama-test
+    (:use :cl :cl-jama :rt))
+
+(in-package :cl-jama-test)
+
+(rem-all-tests)
diff --git a/test/qr.lisp b/test/qr.lisp
new file mode 100644 (file)
index 0000000..f1467b0
--- /dev/null
@@ -0,0 +1,51 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+
+(in-package :cl-jama-test)
+(rem-all-tests)
+
+(defparameter *a.1* (make-matrix '((1.0d0 2.0d0) (3.0d0 4.0d0))))
+(defparameter *qr.1* (make-instance 'QR :matrix *a.1*))
+(defparameter *q.1* (get-Q *qr.1*))
+(defparameter *r.1* (get-R *qr.1*))
+
+(deftest qr.1
+    (equal (with-output-to-string (os)
+             (dump-matrix (multiply *q.1* *r.1*) os))
+           (with-output-to-string (os)
+             (dump-matrix *a.1* os)))
+  t)
+
+(deftest qr.2
+    (let ((X (multiply *q.1* (transpose *q.1*)))
+          (Y #(1 0 0 1))
+          (eps 1.0d10))
+      (reduce #'eql
+              (loop :for i :from 0 :below (array-total-size X)
+                    :collect (< (abs (- (row-major-aref X i) (aref Y i))) eps))))
+  T)
+
+(deftest qr.3
+    (let ((X (multiply (transpose *q.1*) *q.1*))
+          (Y #(1 0 0 1))
+          (eps 1.0d10))
+      (reduce #'eql
+              (loop :for i :from 0 :below (array-total-size X)
+                    :collect (< (abs (- (row-major-aref X i) (aref Y i))) eps))))
+  T)
+
+(defparameter *qr.2* (make-instance 'QR
+                                    :matrix (make-matrix '((-0.57d0  -1.28d0  -0.39d0   0.25d0)
+                                                           (-1.93d0   1.08d0  -0.31d0  -2.14d0)
+                                                           ( 2.30d0   0.24d0   0.40d0  -0.35d0)
+                                                           (-1.93d0   0.64d0  -0.66d0   0.08d0)
+                                                           ( 0.15d0   0.30d0   0.15d0  -2.13d0)
+                                                           (-0.02d0   1.03d0  -1.43d0   0.50d0)))))
+
+(deftest qr.4
+    (with-output-to-string (os)
+      (dump-vector (solve *qr.2* (make-vector '(-2.67d0 -0.55d0 3.34d0 -0.77d0 0.48d0 4.10d0)))
+                   os))
+"     1.5339     1.8707    -1.5241     0.0392
+")
+
+(do-tests)
diff --git a/test/svd.lisp b/test/svd.lisp
new file mode 100644 (file)
index 0000000..ee2541e
--- /dev/null
@@ -0,0 +1,80 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+
+(in-package :cl-jama-test)
+(rem-all-tests)
+
+(defparameter *hilb* (let ((A (make-array '(3 3))))
+                       (loop :for i :from 0 :below 3
+                             :do (loop :for j :from 0 :below 3
+                                       :do (setf (aref A i j) (/ 1.0d0 (+ i j 1)))))
+                       A))
+
+(defparameter *svd.1* (make-instance 'SVD :matrix *hilb*))
+(defparameter *u.1* (get-U *svd.1*))
+(defparameter *s.1* (get-S *svd.1*))
+(defparameter *v.1* (get-V *svd.1*))
+
+(deftest svd.1
+    (with-output-to-string (os)
+      (dump-matrix *u.1* os 11 5))
+"    0.82704   -0.54745    0.12766
+    0.45986    0.52829   -0.71375
+    0.32330    0.64901    0.68867
+")
+
+(deftest svd.2
+    (with-output-to-string (os)
+      (dump-matrix *s.1* os 11 5))
+"    1.40832    0.00000    0.00000
+    0.00000    0.12233    0.00000
+    0.00000    0.00000    0.00269
+")
+
+(deftest svd.3
+    (with-output-to-string (os)
+      (dump-matrix *v.1* os 11 5))
+"    0.82704   -0.54745    0.12766
+    0.45986    0.52829   -0.71375
+    0.32330    0.64901    0.68867
+")
+
+(deftest svd.4
+    (equal (with-output-to-string (os)
+             (dump-matrix (multiply *u.1* (multiply *s.1* (transpose *v.1*))) os 11 5))
+           (with-output-to-string (os)
+             (dump-matrix *hilb* os 11 5)))
+  T)
+
+(deftest svd.5
+    (let ((X (multiply *u.1* (transpose *u.1*)))
+          (Y #(1 0 0 0 1 0 0 0 1))
+          (eps 1.0d10))
+      (reduce #'eql
+              (loop :for i :from 0 :below (array-total-size X)
+                    :collect (< (abs (- (row-major-aref X i) (aref Y i))) eps))))
+  T)
+
+(deftest svd.6
+    (let ((X (multiply *v.1* (transpose *v.1*)))
+          (Y #(1 0 0 0 1 0 0 0 1))
+          (eps 1.0d10))
+      (reduce #'eql
+              (loop :for i :from 0 :below (array-total-size X)
+                    :collect (< (abs (- (row-major-aref X i) (aref Y i))) eps))))
+  T)
+
+(defparameter *svd.2* (make-instance 'SVD
+                                     :matrix (make-matrix '(( 2.27d0  -1.54d0   1.15d0  -1.94d0)
+                                                            ( 0.28d0  -1.67d0   0.94d0  -0.78d0)
+                                                            (-0.48d0  -3.09d0   0.99d0  -0.21d0)
+                                                            ( 1.07d0   1.22d0   0.79d0   0.63d0)
+                                                            (-2.35d0   2.93d0  -1.45d0   2.30d0)
+                                                            ( 0.62d0  -7.39d0   1.03d0  -2.57d0)))))
+
+(deftest svd.7
+    (with-output-to-string (os)
+      (dump-vector (get-singular-values *svd.2*) os))
+"     9.9966     3.6831     1.3569     0.5000
+")
+
+(do-tests)
diff --git a/test/utils.lisp b/test/utils.lisp
new file mode 100644 (file)
index 0000000..c22fd06
--- /dev/null
@@ -0,0 +1,63 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+
+(in-package :cl-jama-test)
+
+(defun make-matrix (x)
+  (let ((m (length x))
+        (n (length (first x))))
+    (make-array (list m n) :initial-contents x)))
+
+(defun make-vector (x)
+  (make-array (list (length x)) :initial-contents x))
+
+(defun dump-matrix (x &optional (s *standard-output*) (w 11) (d 4))
+  (loop :for i :from 0 :below (array-dimension x 0)
+        :do (loop :for j :from 0 :below (array-dimension x 1)
+                  :do (format s "~V,VF" w d (aref x i j)))
+            (terpri s))
+  (values))
+
+(defun dump-vector (x &optional (s *standard-output*))
+  (loop :for i :from 0 :below (array-dimension x 0)
+        :do (format s "~11,4F" (aref x i)))
+  (terpri s)
+  (values))
+
+(rem-all-tests)
+
+(deftest make-matrix.1
+    (make-matrix '((1.23 -2.34 3.45) (-4.56 5.67 -6.78)))
+  #2A((1.23 -2.34 3.45) (-4.56 5.67 -6.78)))
+
+(deftest make-vector.1
+    (make-vector '(9.87 -8.76 7.65))
+  #(9.87 -8.76 7.65))
+
+(deftest dump-matrix.1
+    (with-output-to-string (os) (dump-matrix #2A((1.23 -2.34 3.45) (-4.56 5.67 -6.78)) os))
+"     1.2300    -2.3400     3.4500
+    -4.5600     5.6700    -6.7800
+")
+
+(deftest dump-vector.1
+    (with-output-to-string (os) (dump-vector #(9.87 -8.76 7.65) os))
+"     9.8700    -8.7600     7.6500
+")
+
+(deftest copy-array.1
+    (copy-array #(1.23 -2.34 3.45))
+  #(1.23 -2.34 3.45))
+
+(deftest copy-array.2
+    (copy-array #2A((-4.56 5.67 -6.78) (7.89 -8.90 9.01)))
+  #2A((-4.56 5.67 -6.78) (7.89 -8.90 9.01)))
+
+(deftest transpose.1
+    (transpose #2A((-4.56 5.67 -6.78) (7.89 -8.90 9.01)))
+  #2A((-4.56 7.89) (5.67 -8.90) (-6.78 9.01)))
+
+(deftest multiply.1
+    (multiply #2A((1 1 1) (2 2 2) (3 3 3)) #2A((1 2 3) (1 2 3) (1 2 3)))
+  #2A((3 6 9) (6 12 18) (9 18 27)))
+
+(do-tests)
diff --git a/utils.lisp b/utils.lisp
new file mode 100644 (file)
index 0000000..ef74b97
--- /dev/null
@@ -0,0 +1,58 @@
+;;; -*- mode: lisp; coding: utf-8 -*-
+;;;  
+;;; Copyright (c) 2008 NANRI <southly@gmail.com>
+;;; 
+;;; Permission is hereby granted, free of charge, to any person obtaining a copy
+;;; of this software and associated documentation files (the "Software"), to deal
+;;; in the Software without restriction, including without limitation the rights
+;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+;;; copies of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;; 
+;;; The above copyright notice and this permission notice shall be included in
+;;; all copies or substantial portions of the Software.
+;;; 
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+;;; THE SOFTWARE.
+
+(in-package :cl-jama)
+
+(defun copy-array (A)
+  (let ((X (make-array (array-dimensions A))))
+    (loop :for i :from 0 :below (array-total-size A)
+          :do (setf (row-major-aref X i) (row-major-aref A i)))
+    X))
+
+(defun hypot (a b)
+  (cond ((> (abs a) (abs b))
+         (* (abs a) (sqrt (1+ (expt (/ b a) 2)))))
+        ((not (zerop b))
+         (* (abs b) (sqrt (1+ (expt (/ a b) 2)))))
+        (t
+         0.0)))
+
+(defun transpose (X)
+  (let* ((m (array-dimension X 0))
+         (n (array-dimension X 1))
+         (Y (make-array (list n m))))
+    (loop :for i :from 0 :below m
+          :do (loop :for j :from 0 :below n
+                    :do (setf (aref Y j i) (aref X i j))))
+    Y))
+
+(defun multiply (A B)
+  (unless (eql (array-dimension A 1) (array-dimension B 0))
+    (return-from multiply nil))
+  (let* ((C (make-array (list (array-dimension A 0) (array-dimension B 1)))))
+    (loop :for i :from 0 :below (array-dimension A 0)
+          :do (loop :for j :from 0 :below (array-dimension B 1)
+                    :do (let ((sum 0))
+                          (loop :for k :from 0 :below (array-dimension A 1)
+                                :do (incf sum (* (aref A i k) (aref B k j))))
+                          (setf (aref C i j) sum))))
+    C))