diff options
Diffstat (limited to 'lib/Numeric/GSL/Matrix.hs')
-rw-r--r-- | lib/Numeric/GSL/Matrix.hs | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/lib/Numeric/GSL/Matrix.hs b/lib/Numeric/GSL/Matrix.hs new file mode 100644 index 0000000..eb1931a --- /dev/null +++ b/lib/Numeric/GSL/Matrix.hs | |||
@@ -0,0 +1,302 @@ | |||
1 | ----------------------------------------------------------------------------- | ||
2 | -- | | ||
3 | -- Module : Numeric.GSL.Matrix | ||
4 | -- Copyright : (c) Alberto Ruiz 2007 | ||
5 | -- License : GPL-style | ||
6 | -- | ||
7 | -- Maintainer : Alberto Ruiz <aruiz@um.es> | ||
8 | -- Stability : provisional | ||
9 | -- Portability : portable (uses FFI) | ||
10 | -- | ||
11 | -- A few linear algebra computations based on the Numeric.GSL (<http://www.gnu.org/software/Numeric.GSL>). | ||
12 | -- | ||
13 | ----------------------------------------------------------------------------- | ||
14 | -- #hide | ||
15 | |||
16 | module Numeric.GSL.Matrix( | ||
17 | eigSg, eigHg, | ||
18 | svdg, | ||
19 | qr, | ||
20 | cholR, -- cholC, | ||
21 | luSolveR, luSolveC, | ||
22 | luR, luC | ||
23 | ) where | ||
24 | |||
25 | import Data.Packed.Internal | ||
26 | import Data.Packed.Matrix(fromLists,ident,takeDiag) | ||
27 | import Numeric.GSL.Vector | ||
28 | import Foreign | ||
29 | import Complex | ||
30 | |||
31 | {- | eigendecomposition of a real symmetric matrix using /gsl_eigen_symmv/. | ||
32 | |||
33 | > > let (l,v) = eigS $ 'fromLists' [[1,2],[2,1]] | ||
34 | > > l | ||
35 | > 3.000 -1.000 | ||
36 | > | ||
37 | > > v | ||
38 | > 0.707 -0.707 | ||
39 | > 0.707 0.707 | ||
40 | > | ||
41 | > > v <> diag l <> trans v | ||
42 | > 1.000 2.000 | ||
43 | > 2.000 1.000 | ||
44 | |||
45 | -} | ||
46 | eigSg :: Matrix Double -> (Vector Double, Matrix Double) | ||
47 | eigSg m | ||
48 | | r == 1 = (fromList [cdat m `at` 0], singleton 1) | ||
49 | | otherwise = unsafePerformIO $ do | ||
50 | l <- createVector r | ||
51 | v <- createMatrix RowMajor r r | ||
52 | c_eigS // mat cdat m // vec l // mat dat v // check "eigSg" [cdat m] | ||
53 | return (l,v) | ||
54 | where r = rows m | ||
55 | foreign import ccall "gsl-aux.h eigensystemR" c_eigS :: TMVM | ||
56 | |||
57 | ------------------------------------------------------------------ | ||
58 | |||
59 | |||
60 | |||
61 | {- | eigendecomposition of a complex hermitian matrix using /gsl_eigen_hermv/ | ||
62 | |||
63 | > > let (l,v) = eigH $ 'fromLists' [[1,2+i],[2-i,3]] | ||
64 | > | ||
65 | > > l | ||
66 | > 4.449 -0.449 | ||
67 | > | ||
68 | > > v | ||
69 | > -0.544 0.839 | ||
70 | > (-0.751,0.375) (-0.487,0.243) | ||
71 | > | ||
72 | > > v <> diag l <> (conjTrans) v | ||
73 | > 1.000 (2.000,1.000) | ||
74 | > (2.000,-1.000) 3.000 | ||
75 | |||
76 | -} | ||
77 | eigHg :: Matrix (Complex Double)-> (Vector Double, Matrix (Complex Double)) | ||
78 | eigHg m | ||
79 | | r == 1 = (fromList [realPart $ cdat m `at` 0], singleton 1) | ||
80 | | otherwise = unsafePerformIO $ do | ||
81 | l <- createVector r | ||
82 | v <- createMatrix RowMajor r r | ||
83 | c_eigH // mat cdat m // vec l // mat dat v // check "eigHg" [cdat m] | ||
84 | return (l,v) | ||
85 | where r = rows m | ||
86 | foreign import ccall "gsl-aux.h eigensystemC" c_eigH :: TCMVCM | ||
87 | |||
88 | |||
89 | {- | Singular value decomposition of a real matrix, using /gsl_linalg_SV_decomp_mod/: | ||
90 | |||
91 | @\> let (u,s,v) = svdg $ 'fromLists' [[1,2,3],[-4,1,7]] | ||
92 | \ | ||
93 | \> u | ||
94 | 0.310 -0.951 | ||
95 | 0.951 0.310 | ||
96 | \ | ||
97 | \> s | ||
98 | 8.497 2.792 | ||
99 | \ | ||
100 | \> v | ||
101 | -0.411 -0.785 | ||
102 | 0.185 -0.570 | ||
103 | 0.893 -0.243 | ||
104 | \ | ||
105 | \> u \<\> 'diag' s \<\> 'trans' v | ||
106 | 1. 2. 3. | ||
107 | -4. 1. 7.@ | ||
108 | |||
109 | -} | ||
110 | svdg :: Matrix Double -> (Matrix Double, Vector Double, Matrix Double) | ||
111 | svdg x = if rows x >= cols x | ||
112 | then svd' x | ||
113 | else (v, s, u) where (u,s,v) = svd' (trans x) | ||
114 | |||
115 | svd' x = unsafePerformIO $ do | ||
116 | u <- createMatrix RowMajor r c | ||
117 | s <- createVector c | ||
118 | v <- createMatrix RowMajor c c | ||
119 | c_svd // mat cdat x // mat dat u // vec s // mat dat v // check "svdg" [cdat x] | ||
120 | return (u,s,v) | ||
121 | where r = rows x | ||
122 | c = cols x | ||
123 | foreign import ccall "gsl-aux.h svd" c_svd :: TMMVM | ||
124 | |||
125 | {- | QR decomposition of a real matrix using /gsl_linalg_QR_decomp/ and /gsl_linalg_QR_unpack/. | ||
126 | |||
127 | @\> let (q,r) = qr $ 'fromLists' [[1,3,5,7],[2,0,-2,4]] | ||
128 | \ | ||
129 | \> q | ||
130 | -0.447 -0.894 | ||
131 | -0.894 0.447 | ||
132 | \ | ||
133 | \> r | ||
134 | -2.236 -1.342 -0.447 -6.708 | ||
135 | 0. -2.683 -5.367 -4.472 | ||
136 | \ | ||
137 | \> q \<\> r | ||
138 | 1.000 3.000 5.000 7.000 | ||
139 | 2.000 0. -2.000 4.000@ | ||
140 | |||
141 | -} | ||
142 | qr :: Matrix Double -> (Matrix Double, Matrix Double) | ||
143 | qr x = unsafePerformIO $ do | ||
144 | q <- createMatrix RowMajor r r | ||
145 | rot <- createMatrix RowMajor r c | ||
146 | c_qr // mat cdat x // mat dat q // mat dat rot // check "qr" [cdat x] | ||
147 | return (q,rot) | ||
148 | where r = rows x | ||
149 | c = cols x | ||
150 | foreign import ccall "gsl-aux.h QR" c_qr :: TMMM | ||
151 | |||
152 | {- | Cholesky decomposition of a symmetric positive definite real matrix using /gsl_linalg_cholesky_decomp/. | ||
153 | |||
154 | @\> chol $ (2><2) [1,2, | ||
155 | 2,9::Double] | ||
156 | (2><2) | ||
157 | [ 1.0, 0.0 | ||
158 | , 2.0, 2.23606797749979 ]@ | ||
159 | |||
160 | -} | ||
161 | cholR :: Matrix Double -> Matrix Double | ||
162 | cholR x = unsafePerformIO $ do | ||
163 | res <- createMatrix RowMajor r r | ||
164 | c_cholR // mat cdat x // mat dat res // check "cholR" [cdat x] | ||
165 | return res | ||
166 | where r = rows x | ||
167 | foreign import ccall "gsl-aux.h cholR" c_cholR :: TMM | ||
168 | |||
169 | cholC :: Matrix (Complex Double) -> Matrix (Complex Double) | ||
170 | cholC x = unsafePerformIO $ do | ||
171 | res <- createMatrix RowMajor r r | ||
172 | c_cholC // mat cdat x // mat dat res // check "cholC" [cdat x] | ||
173 | return res | ||
174 | where r = rows x | ||
175 | foreign import ccall "gsl-aux.h cholC" c_cholC :: TCMCM | ||
176 | |||
177 | |||
178 | -------------------------------------------------------- | ||
179 | |||
180 | {- -| efficient multiplication by the inverse of a matrix (for real matrices) | ||
181 | -} | ||
182 | luSolveR :: Matrix Double -> Matrix Double -> Matrix Double | ||
183 | luSolveR a b | ||
184 | | n1==n2 && n1==r = unsafePerformIO $ do | ||
185 | s <- createMatrix RowMajor r c | ||
186 | c_luSolveR // mat cdat a // mat cdat b // mat dat s // check "luSolveR" [cdat a, cdat b] | ||
187 | return s | ||
188 | | otherwise = error "luSolveR of nonsquare matrix" | ||
189 | where n1 = rows a | ||
190 | n2 = cols a | ||
191 | r = rows b | ||
192 | c = cols b | ||
193 | foreign import ccall "gsl-aux.h luSolveR" c_luSolveR :: TMMM | ||
194 | |||
195 | {- -| efficient multiplication by the inverse of a matrix (for complex matrices). | ||
196 | -} | ||
197 | luSolveC :: Matrix (Complex Double) -> Matrix (Complex Double) -> Matrix (Complex Double) | ||
198 | luSolveC a b | ||
199 | | n1==n2 && n1==r = unsafePerformIO $ do | ||
200 | s <- createMatrix RowMajor r c | ||
201 | c_luSolveC // mat cdat a // mat cdat b // mat dat s // check "luSolveC" [cdat a, cdat b] | ||
202 | return s | ||
203 | | otherwise = error "luSolveC of nonsquare matrix" | ||
204 | where n1 = rows a | ||
205 | n2 = cols a | ||
206 | r = rows b | ||
207 | c = cols b | ||
208 | foreign import ccall "gsl-aux.h luSolveC" c_luSolveC :: TCMCMCM | ||
209 | |||
210 | {- | lu decomposition of real matrix (packed as a vector including l, u, the permutation and sign) | ||
211 | -} | ||
212 | luRaux :: Matrix Double -> Vector Double | ||
213 | luRaux x = unsafePerformIO $ do | ||
214 | res <- createVector (r*r+r+1) | ||
215 | c_luRaux // mat cdat x // vec res // check "luRaux" [cdat x] | ||
216 | return res | ||
217 | where r = rows x | ||
218 | c = cols x | ||
219 | foreign import ccall "gsl-aux.h luRaux" c_luRaux :: TMV | ||
220 | |||
221 | {- | lu decomposition of complex matrix (packed as a vector including l, u, the permutation and sign) | ||
222 | -} | ||
223 | luCaux :: Matrix (Complex Double) -> Vector (Complex Double) | ||
224 | luCaux x = unsafePerformIO $ do | ||
225 | res <- createVector (r*r+r+1) | ||
226 | c_luCaux // mat cdat x // vec res // check "luCaux" [cdat x] | ||
227 | return res | ||
228 | where r = rows x | ||
229 | c = cols x | ||
230 | foreign import ccall "gsl-aux.h luCaux" c_luCaux :: TCMCV | ||
231 | |||
232 | {- | The LU decomposition of a square matrix. Is based on /gsl_linalg_LU_decomp/ and /gsl_linalg_complex_LU_decomp/ as described in <http://www.gnu.org/software/Numeric.GSL/manual/Numeric.GSL-ref_13.html#SEC223>. | ||
233 | |||
234 | @\> let m = 'fromLists' [[1,2,-3],[2+3*i,-7,0],[1,-i,2*i]] | ||
235 | \> let (l,u,p,s) = luR m@ | ||
236 | |||
237 | L is the lower triangular: | ||
238 | |||
239 | @\> l | ||
240 | 1. 0. 0. | ||
241 | 0.154-0.231i 1. 0. | ||
242 | 0.154-0.231i 0.624-0.522i 1.@ | ||
243 | |||
244 | U is the upper triangular: | ||
245 | |||
246 | @\> u | ||
247 | 2.+3.i -7. 0. | ||
248 | 0. 3.077-1.615i -3. | ||
249 | 0. 0. 1.873+0.433i@ | ||
250 | |||
251 | p is a permutation: | ||
252 | |||
253 | @\> p | ||
254 | [1,0,2]@ | ||
255 | |||
256 | L \* U obtains a permuted version of the original matrix: | ||
257 | |||
258 | @\> extractRows p m | ||
259 | 2.+3.i -7. 0. | ||
260 | 1. 2. -3. | ||
261 | 1. -1.i 2.i | ||
262 | \ | ||
263 | \> l \<\> u | ||
264 | 2.+3.i -7. 0. | ||
265 | 1. 2. -3. | ||
266 | 1. -1.i 2.i@ | ||
267 | |||
268 | s is the sign of the permutation, required to obtain sign of the determinant: | ||
269 | |||
270 | @\> s * product ('toList' $ 'takeDiag' u) | ||
271 | (-18.0) :+ (-16.000000000000004) | ||
272 | \> 'LinearAlgebra.Algorithms.det' m | ||
273 | (-18.0) :+ (-16.000000000000004)@ | ||
274 | |||
275 | -} | ||
276 | luR :: Matrix Double -> (Matrix Double, Matrix Double, [Int], Double) | ||
277 | luR m = (l,u,p, fromIntegral s') where | ||
278 | r = rows m | ||
279 | v = luRaux m | ||
280 | lu = reshape r $ subVector 0 (r*r) v | ||
281 | s':p = map round . toList . subVector (r*r) (r+1) $ v | ||
282 | u = triang r r 0 1`mul` lu | ||
283 | l = (triang r r 0 0 `mul` lu) `add` ident r | ||
284 | add = liftMatrix2 $ vectorZipR Add | ||
285 | mul = liftMatrix2 $ vectorZipR Mul | ||
286 | |||
287 | -- | Complex version of 'luR'. | ||
288 | luC :: Matrix (Complex Double) -> (Matrix (Complex Double), Matrix (Complex Double), [Int], Complex Double) | ||
289 | luC m = (l,u,p, fromIntegral s') where | ||
290 | r = rows m | ||
291 | v = luCaux m | ||
292 | lu = reshape r $ subVector 0 (r*r) v | ||
293 | s':p = map (round.realPart) . toList . subVector (r*r) (r+1) $ v | ||
294 | u = triang r r 0 1 `mul` lu | ||
295 | l = (triang r r 0 0 `mul` lu) `add` liftMatrix comp (ident r) | ||
296 | add = liftMatrix2 $ vectorZipC Add | ||
297 | mul = liftMatrix2 $ vectorZipC Mul | ||
298 | |||
299 | {- auxiliary function to get triangular matrices | ||
300 | -} | ||
301 | triang r c h v = reshape c $ fromList [el i j | i<-[0..r-1], j<-[0..c-1]] | ||
302 | where el i j = if j-i>=h then v else 1 - v | ||