diff options
-rw-r--r-- | examples/tests.hs | 32 | ||||
-rw-r--r-- | lib/Numeric/LinearAlgebra/Algorithms.hs | 49 |
2 files changed, 72 insertions, 9 deletions
diff --git a/examples/tests.hs b/examples/tests.hs index 90437bb..3fea81e 100644 --- a/examples/tests.hs +++ b/examples/tests.hs | |||
@@ -298,9 +298,34 @@ schurTest2 m = m |~| u <> s <> ctrans u && unitary u && upperHessenberg s -- fix | |||
298 | 298 | ||
299 | --------------------------------------------------------------------- | 299 | --------------------------------------------------------------------- |
300 | 300 | ||
301 | expmTest m = expm (logm m) |~| complex m | 301 | nd1 = (3><3) [ 1/2, 1/4, 1/4 |
302 | , 0/1, 1/2, 1/4 | ||
303 | , 1/2, 1/4, 1/2 :: Double] | ||
304 | |||
305 | nd2 = (2><2) [1, 0, 1, 1:: Complex Double] | ||
306 | |||
307 | expmTest1 = expm nd1 :~14~: (3><3) | ||
308 | [ 1.762110887278176 | ||
309 | , 0.478085470590435 | ||
310 | , 0.478085470590435 | ||
311 | , 0.104719410945666 | ||
312 | , 1.709751181805343 | ||
313 | , 0.425725765117601 | ||
314 | , 0.851451530235203 | ||
315 | , 0.530445176063267 | ||
316 | , 1.814470592751009 ] | ||
317 | |||
318 | expmTest2 = expm nd2 :~15~: (2><2) | ||
319 | [ 2.718281828459045 | ||
320 | , 0.000000000000000 | ||
321 | , 2.718281828459045 | ||
322 | , 2.718281828459045 ] | ||
323 | |||
324 | expmTestDiag m = expm (logm m) |~| complex m | ||
302 | where logm m = matFunc Prelude.log m | 325 | where logm m = matFunc Prelude.log m |
303 | 326 | ||
327 | |||
328 | |||
304 | --------------------------------------------------------------------- | 329 | --------------------------------------------------------------------- |
305 | 330 | ||
306 | asFortran m = (rows m >|< cols m) $ toList (fdat m) | 331 | asFortran m = (rows m >|< cols m) $ toList (fdat m) |
@@ -389,8 +414,9 @@ tests = do | |||
389 | else quickCheck (schurTest1 . sqm ::SqM (Complex Double) -> Bool) | 414 | else quickCheck (schurTest1 . sqm ::SqM (Complex Double) -> Bool) |
390 | putStrLn "--------- expm --------" | 415 | putStrLn "--------- expm --------" |
391 | runTestTT $ TestList | 416 | runTestTT $ TestList |
392 | [ test "expmd" (expmTest $ (2><2) [1,2,3,5 :: Double]) | 417 | [ test "expmd" (expmTestDiag $ (2><2) [1,2,3,5 :: Double]) |
393 | --, test "expmnd" (expmTest $ (2><2) [1,0,1,1 :: Double]) | 418 | , test "expm1" (expmTest1) |
419 | , test "expm2" (expmTest2) | ||
394 | ] | 420 | ] |
395 | putStrLn "--------- nullspace ------" | 421 | putStrLn "--------- nullspace ------" |
396 | quickCheck (nullspaceTest :: RM -> Bool) | 422 | quickCheck (nullspaceTest :: RM -> Bool) |
diff --git a/lib/Numeric/LinearAlgebra/Algorithms.hs b/lib/Numeric/LinearAlgebra/Algorithms.hs index 52f9b6f..794ef69 100644 --- a/lib/Numeric/LinearAlgebra/Algorithms.hs +++ b/lib/Numeric/LinearAlgebra/Algorithms.hs | |||
@@ -26,7 +26,7 @@ module Numeric.LinearAlgebra.Algorithms ( | |||
26 | -- * Matrix factorizations | 26 | -- * Matrix factorizations |
27 | -- ** Singular value decomposition | 27 | -- ** Singular value decomposition |
28 | svd, | 28 | svd, |
29 | full, economy, | 29 | full, economy, --thin, |
30 | -- ** Eigensystems | 30 | -- ** Eigensystems |
31 | eig, eigSH, | 31 | eig, eigSH, |
32 | -- ** QR | 32 | -- ** QR |
@@ -101,8 +101,6 @@ class (Normed (Matrix t), Linear Matrix t) => GenMat t where | |||
101 | schur :: Matrix t -> (Matrix t, Matrix t) | 101 | schur :: Matrix t -> (Matrix t, Matrix t) |
102 | -- | Conjugate transpose. | 102 | -- | Conjugate transpose. |
103 | ctrans :: Matrix t -> Matrix t | 103 | ctrans :: Matrix t -> Matrix t |
104 | -- | Matrix exponential (currently implemented only for diagonalizable matrices). | ||
105 | expm :: Matrix t -> Matrix t | ||
106 | 104 | ||
107 | 105 | ||
108 | instance GenMat Double where | 106 | instance GenMat Double where |
@@ -117,7 +115,6 @@ instance GenMat Double where | |||
117 | qr = GSL.unpackQR . qrR | 115 | qr = GSL.unpackQR . qrR |
118 | hess = unpackHess hessR | 116 | hess = unpackHess hessR |
119 | schur = schurR | 117 | schur = schurR |
120 | expm = fst . fromComplex . expm' . comp | ||
121 | 118 | ||
122 | instance GenMat (Complex Double) where | 119 | instance GenMat (Complex Double) where |
123 | svd = svdC | 120 | svd = svdC |
@@ -131,7 +128,6 @@ instance GenMat (Complex Double) where | |||
131 | qr = unpackQR . qrC | 128 | qr = unpackQR . qrC |
132 | hess = unpackHess hessC | 129 | hess = unpackHess hessC |
133 | schur = schurC | 130 | schur = schurC |
134 | expm = expm' | ||
135 | 131 | ||
136 | -- | Eigenvalues and Eigenvectors of a complex hermitian or real symmetric matrix using lapack's dsyev or zheev. | 132 | -- | Eigenvalues and Eigenvectors of a complex hermitian or real symmetric matrix using lapack's dsyev or zheev. |
137 | -- | 133 | -- |
@@ -245,7 +241,11 @@ pnormCM Infinity m = vectorMax $ liftMatrix (liftVector magnitude) m `mXv` const | |||
245 | --pnormCM _ _ = error "p norm not yet defined" | 241 | --pnormCM _ _ = error "p norm not yet defined" |
246 | 242 | ||
247 | -- | Objects which have a p-norm. | 243 | -- | Objects which have a p-norm. |
248 | -- Using it you can define convenient shortcuts: @norm2 = pnorm PNorm2@, @frobenius = norm2 . flatten@, etc. | 244 | -- Using it you can define convenient shortcuts: |
245 | -- | ||
246 | -- @norm2 x = pnorm PNorm2 x@ | ||
247 | -- | ||
248 | -- @frobenius m = norm2 . flatten $ m@ | ||
249 | class Normed t where | 249 | class Normed t where |
250 | pnorm :: NormType -> t -> Double | 250 | pnorm :: NormType -> t -> Double |
251 | 251 | ||
@@ -385,3 +385,40 @@ matFunc :: GenMat t => (Complex Double -> Complex Double) -> Matrix t -> Matrix | |||
385 | matFunc f m = case diagonalize (complex m) of | 385 | matFunc f m = case diagonalize (complex m) of |
386 | Just (l,v) -> v `mXm` diag (liftVector f l) `mXm` inv v | 386 | Just (l,v) -> v `mXm` diag (liftVector f l) `mXm` inv v |
387 | Nothing -> error "Sorry, matFunc requieres a diagonalizable matrix" | 387 | Nothing -> error "Sorry, matFunc requieres a diagonalizable matrix" |
388 | |||
389 | -------------------------------------------------------------- | ||
390 | |||
391 | golubeps :: Integer -> Integer -> Double | ||
392 | golubeps p q = a * fromIntegral b / fromIntegral c where | ||
393 | a = 2^^(3-p-q) | ||
394 | b = fact p * fact q | ||
395 | c = fact (p+q) * fact (p+q+1) | ||
396 | fact n = product [1..n] | ||
397 | |||
398 | epslist = [ (fromIntegral k, golubeps k k) | k <- [1..]] | ||
399 | |||
400 | geps delta = head [ k | (k,g) <- epslist, g<delta] | ||
401 | |||
402 | expGolub m = iterate msq f !! j | ||
403 | where j = max 0 $ floor $ log2 $ pnorm Infinity m | ||
404 | log2 x = log x / log 2 | ||
405 | a = m */ fromIntegral (2^j) | ||
406 | q = geps eps -- 7 steps | ||
407 | eye = ident (rows m) | ||
408 | work (k,c,x,n,d) = (k',c',x',n',d') | ||
409 | where k' = k+1 | ||
410 | c' = c * fromIntegral (q-k+1) / fromIntegral ((2*q-k+1)*k) | ||
411 | x' = a <> x | ||
412 | n' = n `add` (c' `scale` x') | ||
413 | d' = d `add` (((-1)^k * c') `scale` x') | ||
414 | (_,_,_,n,d) = iterate work (1,1,eye,eye,eye) !! q | ||
415 | f = linearSolve d n | ||
416 | msq m = m <> m | ||
417 | (<>) = multiply | ||
418 | v */ x = scale (recip x) v | ||
419 | |||
420 | {- | Matrix exponential. It uses a direct translation of Algorithm 11.3.1 in Golub & Van Loan, | ||
421 | based on a scaled Pade approximation. | ||
422 | -} | ||
423 | expm :: GenMat t => Matrix t -> Matrix t | ||
424 | expm = expGolub | ||