diff options
Diffstat (limited to 'lib/Numeric/LinearAlgebra/Algorithms.hs')
-rw-r--r-- | lib/Numeric/LinearAlgebra/Algorithms.hs | 63 |
1 files changed, 46 insertions, 17 deletions
diff --git a/lib/Numeric/LinearAlgebra/Algorithms.hs b/lib/Numeric/LinearAlgebra/Algorithms.hs index e22246f..110619a 100644 --- a/lib/Numeric/LinearAlgebra/Algorithms.hs +++ b/lib/Numeric/LinearAlgebra/Algorithms.hs | |||
@@ -62,7 +62,9 @@ module Numeric.LinearAlgebra.Algorithms ( | |||
62 | -- * Util | 62 | -- * Util |
63 | haussholder, | 63 | haussholder, |
64 | unpackQR, unpackHess, | 64 | unpackQR, unpackHess, |
65 | pinvTol | 65 | pinvTol, |
66 | rankSVD, | ||
67 | nullspaceSVD | ||
66 | ) where | 68 | ) where |
67 | 69 | ||
68 | 70 | ||
@@ -248,18 +250,28 @@ full svdFun m = (u, d ,v) where | |||
248 | economy :: Element t | 250 | economy :: Element t |
249 | => (Matrix t -> (Matrix t, Vector Double, Matrix t)) -> Matrix t -> (Matrix t, Vector Double, Matrix t) | 251 | => (Matrix t -> (Matrix t, Vector Double, Matrix t)) -> Matrix t -> (Matrix t, Vector Double, Matrix t) |
250 | economy svdFun m = (u', subVector 0 d s, v') where | 252 | economy svdFun m = (u', subVector 0 d s, v') where |
251 | (u,s,v) = svdFun m | 253 | r@(u,s,v) = svdFun m |
252 | sl@(g:_) = toList s | 254 | d = rankSVD (1*eps) m r `max` 1 |
253 | s' = fromList . filter (>tol) $ sl | ||
254 | t = 1 | ||
255 | tol = (fromIntegral (max r c) * g * t * eps) | ||
256 | r = rows m | ||
257 | c = cols m | ||
258 | d = dim s' | ||
259 | u' = takeColumns d u | 255 | u' = takeColumns d u |
260 | v' = takeColumns d v | 256 | v' = takeColumns d v |
261 | 257 | ||
262 | 258 | ||
259 | -- | Numeric rank of a matrix from the SVD decomposition. | ||
260 | rankSVD :: Element t | ||
261 | => Double -- ^ numeric zero (e.g. 1*'eps') | ||
262 | -> Matrix t -- ^ input matrix m | ||
263 | -> (Matrix t, Vector Double, Matrix t) -- ^ 'svd' of m | ||
264 | -> Int -- ^ rank of m | ||
265 | rankSVD teps m (_,s,_) = k where | ||
266 | sl@(g:_) = toList s | ||
267 | r = rows m | ||
268 | c = cols m | ||
269 | tol = fromIntegral (max r c) * g * teps | ||
270 | s' = fromList . filter (>tol) $ sl | ||
271 | k = if g > teps | ||
272 | then dim s' | ||
273 | else 0 | ||
274 | |||
263 | -- | The machine precision of a Double: @eps = 2.22044604925031e-16@ (the value used by GNU-Octave). | 275 | -- | The machine precision of a Double: @eps = 2.22044604925031e-16@ (the value used by GNU-Octave). |
264 | eps :: Double | 276 | eps :: Double |
265 | eps = 2.22044604925031e-16 | 277 | eps = 2.22044604925031e-16 |
@@ -336,18 +348,36 @@ instance Normed (Matrix (Complex Double)) where | |||
336 | ----------------------------------------------------------------------- | 348 | ----------------------------------------------------------------------- |
337 | 349 | ||
338 | -- | The nullspace of a matrix from its SVD decomposition. | 350 | -- | The nullspace of a matrix from its SVD decomposition. |
351 | nullspaceSVD :: Field t | ||
352 | => Either Double Int -- ^ Left \"numeric\" zero (eg. 1*'eps'), | ||
353 | -- or Right \"theoretical\" matrix rank. | ||
354 | -> Matrix t -- ^ input matrix m | ||
355 | -> (Matrix t, Vector Double, Matrix t) -- ^ 'svd' of m | ||
356 | -> [Vector t] -- ^ list of unitary vectors spanning the nullspace | ||
357 | nullspaceSVD hint a z@(_,_,v) = vs where | ||
358 | r = rows a | ||
359 | c = cols a | ||
360 | tol = case hint of | ||
361 | Left t -> t | ||
362 | _ -> eps | ||
363 | k = case hint of | ||
364 | Right t -> t | ||
365 | _ -> rankSVD tol a z | ||
366 | nsol = c - k | ||
367 | vs = drop k (toColumns v) | ||
368 | |||
369 | |||
370 | -- | The nullspace of a matrix. See also 'nullspaceSVD'. | ||
339 | nullspacePrec :: Field t | 371 | nullspacePrec :: Field t |
340 | => Double -- ^ relative tolerance in 'eps' units | 372 | => Double -- ^ relative tolerance in 'eps' units |
341 | -> Matrix t -- ^ input matrix | 373 | -> Matrix t -- ^ input matrix |
342 | -> [Vector t] -- ^ list of unitary vectors spanning the nullspace | 374 | -> [Vector t] -- ^ list of unitary vectors spanning the nullspace |
343 | nullspacePrec t m = ns where | 375 | nullspacePrec t m = ns where |
344 | (_,s,v) = svd m | 376 | r@(_,_,v) = svd m |
345 | sl@(g:_) = toList s | 377 | k = rankSVD (t*eps) m r |
346 | tol = (fromIntegral (max (rows m) (cols m)) * g * t * eps) | 378 | ns = drop k $ toRows $ ctrans v |
347 | rank' = length (filter (> g*tol) sl) | ||
348 | ns = drop rank' $ toRows $ ctrans v | ||
349 | 379 | ||
350 | -- | The nullspace of a matrix, assumed to be one-dimensional, with default tolerance (shortcut for @last . nullspacePrec 1@). | 380 | -- | The nullspace of a matrix, assumed to be one-dimensional, with default tolerance 1*'eps'. |
351 | nullVector :: Field t => Matrix t -> Vector t | 381 | nullVector :: Field t => Matrix t -> Vector t |
352 | nullVector = last . nullspacePrec 1 | 382 | nullVector = last . nullspacePrec 1 |
353 | 383 | ||
@@ -436,8 +466,7 @@ rcond m = last s / head s | |||
436 | 466 | ||
437 | -- | Number of linearly independent rows or columns. | 467 | -- | Number of linearly independent rows or columns. |
438 | rank :: Field t => Matrix t -> Int | 468 | rank :: Field t => Matrix t -> Int |
439 | rank m | pnorm PNorm1 m < eps = 0 | 469 | rank m = rankSVD eps m (svd m) |
440 | | otherwise = dim s where (_,s,_) = economy svd m | ||
441 | 470 | ||
442 | {- | 471 | {- |
443 | expm' m = case diagonalize (complex m) of | 472 | expm' m = case diagonalize (complex m) of |