]> gitweb.michael.orlitzky.com - numerical-analysis.git/blobdiff - src/Linear/QR.hs
Fix a bug in the relative error.
[numerical-analysis.git] / src / Linear / QR.hs
index b628c125e2b0f3b3fc44c449917e8045d72f2dd7..4c1c56446f836c348b1b7e65ad138fb650dd9ed3 100644 (file)
@@ -140,7 +140,8 @@ givens_rotator i j xi xj =
 --   True
 --
 qr :: forall m n a. (Arity m, Arity n, Eq a, Algebraic.C a, Ring.C a)
-   => Mat m n a -> (Mat m m a, Mat m n a)
+   => Mat (S m) (S n) a
+   -> (Mat (S m) (S m) a, Mat (S m) (S n) a)
 qr matrix =
   ifoldl col_function initial_qr columns
   where
@@ -155,14 +156,14 @@ qr matrix =
       ifoldl (f col_idx) (q,r) col
 
     -- | Process the entries in a column, doing basically the same
-    --   thing as col_dunction does. It updates the QR factorization,
+    --   thing as col_function does. It updates the QR factorization,
     --   maybe, and returns the current one.
     f col_idx (q,r) idx _ -- ignore the current element
       | idx <= col_idx = (q,r) -- leave it alone
       | otherwise = (q*rotator, (transpose rotator)*r)
           where
             y = r !!! (idx, col_idx)
-            rotator :: Mat m m a
+            rotator :: Mat (S m) (S m) a
             rotator = givens_rotator col_idx idx (r !!! (col_idx, col_idx)) y
 
 
@@ -171,6 +172,9 @@ qr matrix =
 --   iterated QR algorithm (see Golub and Van Loan, \"Matrix
 --   Computations\").
 --
+--   Warning: this may not converge if there are repeated eigenvalues
+--   (in magnitude).
+--
 --   Examples:
 --
 --   >>> import Linear.Matrix ( Col2, Col3, Mat2, Mat3 )
@@ -198,12 +202,20 @@ eigenvalues :: forall m a. (Arity m, Algebraic.C a, Eq a)
              => Int
              -> Mat (S m) (S m) a
              -> Col (S m) a
-eigenvalues iterations matrix =
-  diagonal (ut_approximation iterations)
-  where
-    ut_approximation :: Int -> Mat (S m) (S m) a
-    ut_approximation 0 = matrix
-    ut_approximation k = rk*qk where (qk,rk) = qr (ut_approximation (k-1))
+eigenvalues iterations matrix
+  | iterations <  0 = error "negative iterations requested"
+  | iterations == 0 = diagonal matrix
+  | otherwise =
+      diagonal (ut_approximation (iterations - 1))
+      where
+        ut_approximation :: Int -> Mat (S m) (S m) a
+        ut_approximation 0 = matrix
+        ut_approximation k = ut_next
+          where
+            ut_prev = ut_approximation (k-1)
+            (qk,rk) = qr ut_prev
+            ut_next = rk*qk
+
 
 
 -- | Compute the eigenvalues and eigenvectors of a symmetric matrix
@@ -214,10 +226,13 @@ eigenvalues iterations matrix =
 --   references see Goluv and Van Loan, \"Matrix Computations\", or
 --   \"Calculation of Gauss Quadrature Rules\" by Golub and Welsch.
 --
+--   Warning: this may not converge if there are repeated eigenvalues
+--   (in magnitude).
+--
 --   Examples:
 --
 --   >>> import Linear.Matrix ( Col2, Col3, Mat2, Mat3 )
---   >>> import Linear.Matrix ( column', frobenius_norm, fromList )
+--   >>> import Linear.Matrix ( column, frobenius_norm, fromList )
 --   >>> import Linear.Matrix ( identity_matrix, vec3d )
 --   >>> import Normed ( Normed(..) )
 --
@@ -239,11 +254,11 @@ eigenvalues iterations matrix =
 --   >>> let v1  = (1 / (norm v1') :: Double) *> v1'
 --   >>> let v2' = vec3d (-4, -2, 5) :: Col3 Double
 --   >>> let v2  = (1 / (norm v2') :: Double) *> v2'
---   >>> frobenius_norm ((column' vecs 0) - v0) < 1e-12
+--   >>> frobenius_norm ((column vecs 0) - v0) < 1e-12
 --   True
---   >>> frobenius_norm ((column' vecs 1) - v1) < 1e-12
+--   >>> frobenius_norm ((column vecs 1) - v1) < 1e-12
 --   True
---   >>> frobenius_norm ((column' vecs 2) - v2) < 1e-12
+--   >>> frobenius_norm ((column vecs 2) - v2) < 1e-12
 --   True
 --
 eigenvectors_symmetric :: forall m a. (Arity m, Algebraic.C a, Eq a)
@@ -268,8 +283,7 @@ eigenvectors_symmetric iterations matrix
                     where
                       (t_prev, p_prev) = tp_pair (k-1)
                       (qk,rk) = qr t_prev
-                      tk = rk*qk
                       pk = p_prev*qk
-
+                      tk = rk*qk
 
         (values, vectors) = (first diagonal) (tp_pair iterations)