diff options
Diffstat (limited to 'lib/Numeric/LinearAlgebra/Algorithms.hs')
-rw-r--r-- | lib/Numeric/LinearAlgebra/Algorithms.hs | 132 |
1 files changed, 51 insertions, 81 deletions
diff --git a/lib/Numeric/LinearAlgebra/Algorithms.hs b/lib/Numeric/LinearAlgebra/Algorithms.hs index 7e258de..0f3ff0e 100644 --- a/lib/Numeric/LinearAlgebra/Algorithms.hs +++ b/lib/Numeric/LinearAlgebra/Algorithms.hs | |||
@@ -1,5 +1,8 @@ | |||
1 | {-# LANGUAGE FlexibleContexts, FlexibleInstances #-} | 1 | {-# LANGUAGE FlexibleContexts, FlexibleInstances #-} |
2 | {-# LANGUAGE CPP #-} | 2 | {-# LANGUAGE CPP #-} |
3 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
4 | {-# LANGUAGE UndecidableInstances #-} | ||
5 | {-# LANGUAGE TypeFamilies #-} | ||
3 | ----------------------------------------------------------------------------- | 6 | ----------------------------------------------------------------------------- |
4 | {- | | 7 | {- | |
5 | Module : Numeric.LinearAlgebra.Algorithms | 8 | Module : Numeric.LinearAlgebra.Algorithms |
@@ -58,10 +61,9 @@ module Numeric.LinearAlgebra.Algorithms ( | |||
58 | nullspacePrec, | 61 | nullspacePrec, |
59 | nullVector, | 62 | nullVector, |
60 | nullspaceSVD, | 63 | nullspaceSVD, |
61 | -- * Norms | ||
62 | Normed(..), NormType(..), | ||
63 | -- * Misc | 64 | -- * Misc |
64 | eps, i, | 65 | eps, peps, i, |
66 | Normed(..), NormType(..), | ||
65 | -- * Util | 67 | -- * Util |
66 | haussholder, | 68 | haussholder, |
67 | unpackQR, unpackHess, | 69 | unpackQR, unpackHess, |
@@ -72,17 +74,15 @@ module Numeric.LinearAlgebra.Algorithms ( | |||
72 | 74 | ||
73 | 75 | ||
74 | import Data.Packed.Internal hiding ((//)) | 76 | import Data.Packed.Internal hiding ((//)) |
75 | --import Data.Packed.Vector | ||
76 | import Data.Packed.Matrix | 77 | import Data.Packed.Matrix |
77 | import Data.Complex | 78 | import Data.Complex |
78 | import Numeric.GSL.Vector | ||
79 | import Numeric.LinearAlgebra.LAPACK as LAPACK | 79 | import Numeric.LinearAlgebra.LAPACK as LAPACK |
80 | import Numeric.LinearAlgebra.Linear | 80 | import Numeric.LinearAlgebra.Linear |
81 | import Data.List(foldl1') | 81 | import Data.List(foldl1') |
82 | import Data.Array | 82 | import Data.Array |
83 | 83 | ||
84 | -- | Auxiliary typeclass used to define generic computations for both real and complex matrices. | 84 | -- | Auxiliary typeclass used to define generic computations for both real and complex matrices. |
85 | class (AutoReal t, Prod t, Linear Vector t, Linear Matrix t) => Field t where | 85 | class (Product t, Linear Vector t, Linear Matrix t) => Field t where |
86 | svd' :: Matrix t -> (Matrix t, Vector Double, Matrix t) | 86 | svd' :: Matrix t -> (Matrix t, Vector Double, Matrix t) |
87 | thinSVD' :: Matrix t -> (Matrix t, Vector Double, Matrix t) | 87 | thinSVD' :: Matrix t -> (Matrix t, Vector Double, Matrix t) |
88 | sv' :: Matrix t -> Vector Double | 88 | sv' :: Matrix t -> Vector Double |
@@ -172,6 +172,9 @@ thinSVD = {-# SCC "thinSVD" #-} thinSVD' | |||
172 | singularValues :: Field t => Matrix t -> Vector Double | 172 | singularValues :: Field t => Matrix t -> Vector Double |
173 | singularValues = {-# SCC "singularValues" #-} sv' | 173 | singularValues = {-# SCC "singularValues" #-} sv' |
174 | 174 | ||
175 | instance (Field t, RealOf t ~ Double) => Norm2 Matrix t where | ||
176 | norm2 m = singularValues m @> 0 | ||
177 | |||
175 | -- | A version of 'svd' which returns an appropriate diagonal matrix with the singular values. | 178 | -- | A version of 'svd' which returns an appropriate diagonal matrix with the singular values. |
176 | -- | 179 | -- |
177 | -- If @(u,d,v) = fullSVD m@ then @m == u \<> d \<> trans v@. | 180 | -- If @(u,d,v) = fullSVD m@ then @m == u \<> d \<> trans v@. |
@@ -379,80 +382,16 @@ ranksv teps maxdim s = k where | |||
379 | eps :: Double | 382 | eps :: Double |
380 | eps = 2.22044604925031e-16 | 383 | eps = 2.22044604925031e-16 |
381 | 384 | ||
382 | peps :: RealFloat x => x -> x | 385 | |
383 | peps x = 2.0**(fromIntegral $ 1-floatDigits x) | 386 | -- | 1 + 0.5*peps == 1, 1 + 0.6*peps /= 1 |
387 | peps :: RealFloat x => x | ||
388 | peps = x where x = 2.0**(fromIntegral $ 1-floatDigits x) | ||
384 | 389 | ||
385 | 390 | ||
386 | -- | The imaginary unit: @i = 0.0 :+ 1.0@ | 391 | -- | The imaginary unit: @i = 0.0 :+ 1.0@ |
387 | i :: Complex Double | 392 | i :: Complex Double |
388 | i = 0:+1 | 393 | i = 0:+1 |
389 | 394 | ||
390 | --------------------------------------------------------------------------- | ||
391 | |||
392 | norm2 :: Vector Double -> Double | ||
393 | norm2 = toScalarR Norm2 | ||
394 | |||
395 | norm1 :: Vector Double -> Double | ||
396 | norm1 = toScalarR AbsSum | ||
397 | |||
398 | data NormType = Infinity | PNorm1 | PNorm2 -- PNorm Int | ||
399 | |||
400 | pnormRV PNorm2 = norm2 | ||
401 | pnormRV PNorm1 = norm1 | ||
402 | pnormRV Infinity = vectorMax . vectorMapR Abs | ||
403 | --pnormRV _ = error "pnormRV not yet defined" | ||
404 | |||
405 | pnormCV PNorm2 = norm2 . asReal | ||
406 | pnormCV PNorm1 = norm1 . mapVector magnitude | ||
407 | pnormCV Infinity = vectorMax . mapVector magnitude | ||
408 | --pnormCV _ = error "pnormCV not yet defined" | ||
409 | |||
410 | pnormRM PNorm2 m = singularValues m @> 0 | ||
411 | pnormRM PNorm1 m = vectorMax $ constant 1 (rows m) `vXm` liftMatrix (vectorMapR Abs) m | ||
412 | pnormRM Infinity m = vectorMax $ liftMatrix (vectorMapR Abs) m `mXv` constant 1 (cols m) | ||
413 | --pnormRM _ _ = error "p norm not yet defined" | ||
414 | |||
415 | pnormCM PNorm2 m = singularValues m @> 0 | ||
416 | pnormCM PNorm1 m = vectorMax $ constant 1 (rows m) `vXm` liftMatrix (mapVector magnitude) m | ||
417 | pnormCM Infinity m = vectorMax $ liftMatrix (mapVector magnitude) m `mXv` constant 1 (cols m) | ||
418 | --pnormCM _ _ = error "p norm not yet defined" | ||
419 | |||
420 | -- | Objects which have a p-norm. | ||
421 | -- Using it you can define convenient shortcuts: | ||
422 | -- | ||
423 | -- @norm2 x = pnorm PNorm2 x@ | ||
424 | -- | ||
425 | -- @frobenius m = norm2 . flatten $ m@ | ||
426 | class Normed t where | ||
427 | pnorm :: NormType -> t -> Double | ||
428 | |||
429 | instance Normed (Vector Double) where | ||
430 | pnorm = pnormRV | ||
431 | |||
432 | instance Normed (Vector (Complex Double)) where | ||
433 | pnorm = pnormCV | ||
434 | |||
435 | instance Normed (Matrix Double) where | ||
436 | pnorm = pnormRM | ||
437 | |||
438 | instance Normed (Matrix (Complex Double)) where | ||
439 | pnorm = pnormCM | ||
440 | |||
441 | ----------------------------------------------------------------------- | ||
442 | -- to be optimized | ||
443 | |||
444 | instance Normed (Vector Float) where | ||
445 | pnorm t = pnorm t . double | ||
446 | |||
447 | instance Normed (Vector (Complex Float)) where | ||
448 | pnorm t = pnorm t . double | ||
449 | |||
450 | instance Normed (Matrix Float) where | ||
451 | pnorm t = pnorm t . double | ||
452 | |||
453 | instance Normed (Matrix (Complex Float)) where | ||
454 | pnorm t = pnorm t . double | ||
455 | |||
456 | ----------------------------------------------------------------------- | 395 | ----------------------------------------------------------------------- |
457 | 396 | ||
458 | -- | The nullspace of a matrix from its SVD decomposition. | 397 | -- | The nullspace of a matrix from its SVD decomposition. |
@@ -588,8 +527,8 @@ diagonalize m = if rank v == n | |||
588 | -- | 527 | -- |
589 | -- @logm = matFunc log@ | 528 | -- @logm = matFunc log@ |
590 | -- | 529 | -- |
591 | matFunc :: (Field t) => (Complex Double -> Complex Double) -> Matrix t -> Matrix (Complex Double) | 530 | matFunc :: (Complex Double -> Complex Double) -> Matrix (Complex Double) -> Matrix (Complex Double) |
592 | matFunc f m = case diagonalize (complex'' m) of | 531 | matFunc f m = case diagonalize m of |
593 | Just (l,v) -> v `mXm` diag (mapVector f l) `mXm` inv v | 532 | Just (l,v) -> v `mXm` diag (mapVector f l) `mXm` inv v |
594 | Nothing -> error "Sorry, matFunc requires a diagonalizable matrix" | 533 | Nothing -> error "Sorry, matFunc requires a diagonalizable matrix" |
595 | 534 | ||
@@ -607,7 +546,7 @@ epslist = [ (fromIntegral k, golubeps k k) | k <- [1..]] | |||
607 | geps delta = head [ k | (k,g) <- epslist, g<delta] | 546 | geps delta = head [ k | (k,g) <- epslist, g<delta] |
608 | 547 | ||
609 | expGolub m = iterate msq f !! j | 548 | expGolub m = iterate msq f !! j |
610 | where j = max 0 $ floor $ log2 $ pnorm Infinity m | 549 | where j = max 0 $ floor $ log2 $ normInf m |
611 | log2 x = log x / log 2 | 550 | log2 x = log x / log 2 |
612 | a = m */ fromIntegral ((2::Int)^j) | 551 | a = m */ fromIntegral ((2::Int)^j) |
613 | q = geps eps -- 7 steps | 552 | q = geps eps -- 7 steps |
@@ -630,7 +569,7 @@ expGolub m = iterate msq f !! j | |||
630 | {- | Matrix exponential. It uses a direct translation of Algorithm 11.3.1 in Golub & Van Loan, | 569 | {- | Matrix exponential. It uses a direct translation of Algorithm 11.3.1 in Golub & Van Loan, |
631 | based on a scaled Pade approximation. | 570 | based on a scaled Pade approximation. |
632 | -} | 571 | -} |
633 | expm :: (Normed (Matrix t), Field t) => Matrix t -> Matrix t | 572 | expm :: (Norm Vector t, Field t) => Matrix t -> Matrix t |
634 | expm = expGolub | 573 | expm = expGolub |
635 | 574 | ||
636 | -------------------------------------------------------------- | 575 | -------------------------------------------------------------- |
@@ -646,11 +585,11 @@ It only works with invertible matrices that have a real solution. For diagonaliz | |||
646 | [ 2.0, 2.25 | 585 | [ 2.0, 2.25 |
647 | , 0.0, 2.0 ]@ | 586 | , 0.0, 2.0 ]@ |
648 | -} | 587 | -} |
649 | sqrtm :: (Normed (Matrix t), Field t) => Matrix t -> Matrix t | 588 | sqrtm :: (Norm Vector t, Field t) => Matrix t -> Matrix t |
650 | sqrtm = sqrtmInv | 589 | sqrtm = sqrtmInv |
651 | 590 | ||
652 | sqrtmInv x = fst $ fixedPoint $ iterate f (x, ident (rows x)) | 591 | sqrtmInv x = fst $ fixedPoint $ iterate f (x, ident (rows x)) |
653 | where fixedPoint (a:b:rest) | pnorm PNorm1 (fst a |-| fst b) < eps = a | 592 | where fixedPoint (a:b:rest) | norm1 (fst a |-| fst b) < peps = a |
654 | | otherwise = fixedPoint (b:rest) | 593 | | otherwise = fixedPoint (b:rest) |
655 | fixedPoint _ = error "fixedpoint with impossible inputs" | 594 | fixedPoint _ = error "fixedpoint with impossible inputs" |
656 | f (y,z) = (0.5 .* (y |+| inv z), | 595 | f (y,z) = (0.5 .* (y |+| inv z), |
@@ -691,4 +630,35 @@ luFact (l_u,perm) | r <= c = (l ,u ,p, s) | |||
691 | (|+|) = add | 630 | (|+|) = add |
692 | (|*|) = mul | 631 | (|*|) = mul |
693 | 632 | ||
694 | -------------------------------------------------- | 633 | --------------------------------------------------------------------------- |
634 | |||
635 | data NormType = Infinity | PNorm1 | PNorm2 | ||
636 | |||
637 | -- | Old class | ||
638 | class Normed t where | ||
639 | pnorm :: NormType -> t -> Double | ||
640 | |||
641 | instance Norm Vector t => Normed (Vector t) where | ||
642 | pnorm PNorm1 = realToFrac . norm1 | ||
643 | pnorm PNorm2 = realToFrac . normFrob | ||
644 | pnorm Infinity = realToFrac . normInf | ||
645 | |||
646 | instance Normed (Matrix Double) where | ||
647 | pnorm PNorm1 = norm1 | ||
648 | pnorm PNorm2 = norm2 | ||
649 | pnorm Infinity = normInf | ||
650 | |||
651 | instance Normed (Matrix (Complex Double)) where | ||
652 | pnorm PNorm1 = norm1 | ||
653 | pnorm PNorm2 = norm2 | ||
654 | pnorm Infinity = normInf | ||
655 | |||
656 | instance Normed (Matrix Float) where | ||
657 | pnorm PNorm1 = realToFrac . norm1 | ||
658 | pnorm PNorm2 = norm2 . double -- not yet optimized for Float | ||
659 | pnorm Infinity = realToFrac . normInf | ||
660 | |||
661 | instance Normed (Matrix (Complex Float)) where | ||
662 | pnorm PNorm1 = realToFrac . norm1 | ||
663 | pnorm PNorm2 = norm2 . double -- not yet optimized for Float | ||
664 | pnorm Infinity = realToFrac . normInf | ||