diff options
Diffstat (limited to 'lib/GSL/Matrix.hs')
-rw-r--r-- | lib/GSL/Matrix.hs | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/lib/GSL/Matrix.hs b/lib/GSL/Matrix.hs new file mode 100644 index 0000000..919c2d9 --- /dev/null +++ b/lib/GSL/Matrix.hs | |||
@@ -0,0 +1,311 @@ | |||
1 | ----------------------------------------------------------------------------- | ||
2 | -- | | ||
3 | -- Module : 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 GSL (<http://www.gnu.org/software/gsl>). | ||
12 | -- | ||
13 | ----------------------------------------------------------------------------- | ||
14 | |||
15 | module GSL.Matrix( | ||
16 | eigSg, eigHg, | ||
17 | svdg, | ||
18 | qr, | ||
19 | chol, | ||
20 | luSolveR, luSolveC, | ||
21 | luR, luC, | ||
22 | fromFile | ||
23 | ) where | ||
24 | |||
25 | import Data.Packed.Internal | ||
26 | import Data.Packed.Matrix(fromLists,ident,takeDiag) | ||
27 | import GSL.Vector | ||
28 | import Foreign | ||
29 | import Foreign.C.Types | ||
30 | import Complex | ||
31 | import Foreign.C.String | ||
32 | |||
33 | {- | eigendecomposition of a real symmetric matrix using /gsl_eigen_symmv/. | ||
34 | |||
35 | > > let (l,v) = eigS $ 'fromLists' [[1,2],[2,1]] | ||
36 | > > l | ||
37 | > 3.000 -1.000 | ||
38 | > | ||
39 | > > v | ||
40 | > 0.707 -0.707 | ||
41 | > 0.707 0.707 | ||
42 | > | ||
43 | > > v <> diag l <> trans v | ||
44 | > 1.000 2.000 | ||
45 | > 2.000 1.000 | ||
46 | |||
47 | -} | ||
48 | eigSg :: Matrix Double -> (Vector Double, Matrix Double) | ||
49 | eigSg (m@M {rows = r}) | ||
50 | | r == 1 = (fromList [cdat m `at` 0], singleton 1) | ||
51 | | otherwise = unsafePerformIO $ do | ||
52 | l <- createVector r | ||
53 | v <- createMatrix RowMajor r r | ||
54 | c_eigS // mat cdat m // vec l // mat dat v // check "eigSg" [cdat m] | ||
55 | return (l,v) | ||
56 | foreign import ccall "gsl-aux.h eigensystemR" c_eigS :: TMVM | ||
57 | |||
58 | ------------------------------------------------------------------ | ||
59 | |||
60 | |||
61 | |||
62 | {- | eigendecomposition of a complex hermitian matrix using /gsl_eigen_hermv/ | ||
63 | |||
64 | > > let (l,v) = eigH $ 'fromLists' [[1,2+i],[2-i,3]] | ||
65 | > | ||
66 | > > l | ||
67 | > 4.449 -0.449 | ||
68 | > | ||
69 | > > v | ||
70 | > -0.544 0.839 | ||
71 | > (-0.751,0.375) (-0.487,0.243) | ||
72 | > | ||
73 | > > v <> diag l <> (conjTrans) v | ||
74 | > 1.000 (2.000,1.000) | ||
75 | > (2.000,-1.000) 3.000 | ||
76 | |||
77 | -} | ||
78 | eigHg :: Matrix (Complex Double)-> (Vector Double, Matrix (Complex Double)) | ||
79 | eigHg (m@M {rows = r}) | ||
80 | | r == 1 = (fromList [realPart $ cdat m `at` 0], singleton 1) | ||
81 | | otherwise = unsafePerformIO $ do | ||
82 | l <- createVector r | ||
83 | v <- createMatrix RowMajor r r | ||
84 | c_eigH // mat cdat m // vec l // mat dat v // check "eigHg" [cdat m] | ||
85 | return (l,v) | ||
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@M {rows = r, cols = c} = if r>=c | ||
112 | then svd' x | ||
113 | else (v, s, u) where (u,s,v) = svd' (trans x) | ||
114 | |||
115 | svd' x@M {rows = r, cols = c} = 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 | foreign import ccall "gsl-aux.h svd" c_svd :: TMMVM | ||
122 | |||
123 | {- | QR decomposition of a real matrix using /gsl_linalg_QR_decomp/ and /gsl_linalg_QR_unpack/. | ||
124 | |||
125 | @\> let (q,r) = qr $ 'fromLists' [[1,3,5,7],[2,0,-2,4]] | ||
126 | \ | ||
127 | \> q | ||
128 | -0.447 -0.894 | ||
129 | -0.894 0.447 | ||
130 | \ | ||
131 | \> r | ||
132 | -2.236 -1.342 -0.447 -6.708 | ||
133 | 0. -2.683 -5.367 -4.472 | ||
134 | \ | ||
135 | \> q \<\> r | ||
136 | 1.000 3.000 5.000 7.000 | ||
137 | 2.000 0. -2.000 4.000@ | ||
138 | |||
139 | -} | ||
140 | qr :: Matrix Double -> (Matrix Double, Matrix Double) | ||
141 | qr x@M {rows = r, cols = c} = unsafePerformIO $ do | ||
142 | q <- createMatrix RowMajor r r | ||
143 | rot <- createMatrix RowMajor r c | ||
144 | c_qr // mat cdat x // mat dat q // mat dat rot // check "qr" [cdat x] | ||
145 | return (q,rot) | ||
146 | foreign import ccall "gsl-aux.h QR" c_qr :: TMMM | ||
147 | |||
148 | {- | Cholesky decomposition of a symmetric positive definite real matrix using /gsl_linalg_cholesky_decomp/. | ||
149 | |||
150 | @\> let c = chol $ 'fromLists' [[5,4],[4,5]] | ||
151 | \ | ||
152 | \> c | ||
153 | 2.236 0. | ||
154 | 1.789 1.342 | ||
155 | \ | ||
156 | \> c \<\> 'trans' c | ||
157 | 5.000 4.000 | ||
158 | 4.000 5.000@ | ||
159 | |||
160 | -} | ||
161 | chol :: Matrix Double -> Matrix Double | ||
162 | --chol x@(M r _ p) = createM [p] "chol" r r $ m c_chol x | ||
163 | chol x@M {rows = r} = unsafePerformIO $ do | ||
164 | res <- createMatrix RowMajor r r | ||
165 | c_chol // mat cdat x // mat dat res // check "chol" [cdat x] | ||
166 | return res | ||
167 | foreign import ccall "gsl-aux.h chol" c_chol :: TMM | ||
168 | |||
169 | -------------------------------------------------------- | ||
170 | |||
171 | {- -| efficient multiplication by the inverse of a matrix (for real matrices) | ||
172 | -} | ||
173 | luSolveR :: Matrix Double -> Matrix Double -> Matrix Double | ||
174 | luSolveR a@(M {rows = n1, cols = n2}) b@(M {rows = r, cols = c}) | ||
175 | | n1==n2 && n1==r = unsafePerformIO $ do | ||
176 | s <- createMatrix RowMajor r c | ||
177 | c_luSolveR // mat cdat a // mat cdat b // mat dat s // check "luSolveR" [cdat a, cdat b] | ||
178 | return s | ||
179 | | otherwise = error "luSolveR of nonsquare matrix" | ||
180 | |||
181 | foreign import ccall "gsl-aux.h luSolveR" c_luSolveR :: TMMM | ||
182 | |||
183 | {- -| efficient multiplication by the inverse of a matrix (for complex matrices). | ||
184 | -} | ||
185 | luSolveC :: Matrix (Complex Double) -> Matrix (Complex Double) -> Matrix (Complex Double) | ||
186 | luSolveC a@(M {rows = n1, cols = n2}) b@(M {rows = r, cols = c}) | ||
187 | | n1==n2 && n1==r = unsafePerformIO $ do | ||
188 | s <- createMatrix RowMajor r c | ||
189 | c_luSolveC // mat cdat a // mat cdat b // mat dat s // check "luSolveC" [cdat a, cdat b] | ||
190 | return s | ||
191 | | otherwise = error "luSolveC of nonsquare matrix" | ||
192 | |||
193 | foreign import ccall "gsl-aux.h luSolveC" c_luSolveC :: TCMCMCM | ||
194 | |||
195 | {- | lu decomposition of real matrix (packed as a vector including l, u, the permutation and sign) | ||
196 | -} | ||
197 | luRaux :: Matrix Double -> Vector Double | ||
198 | luRaux x@M {rows = r, cols = c} = unsafePerformIO $ do | ||
199 | res <- createVector (r*r+r+1) | ||
200 | c_luRaux // mat cdat x // vec res // check "luRaux" [cdat x] | ||
201 | return res | ||
202 | foreign import ccall "gsl-aux.h luRaux" c_luRaux :: TMV | ||
203 | |||
204 | {- | lu decomposition of complex matrix (packed as a vector including l, u, the permutation and sign) | ||
205 | -} | ||
206 | luCaux :: Matrix (Complex Double) -> Vector (Complex Double) | ||
207 | luCaux x@M {rows = r, cols = c} = unsafePerformIO $ do | ||
208 | res <- createVector (r*r+r+1) | ||
209 | c_luCaux // mat cdat x // vec res // check "luCaux" [cdat x] | ||
210 | return res | ||
211 | foreign import ccall "gsl-aux.h luCaux" c_luCaux :: TCMCV | ||
212 | |||
213 | {- | 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/gsl/manual/gsl-ref_13.html#SEC223>. | ||
214 | |||
215 | @\> let m = 'fromLists' [[1,2,-3],[2+3*i,-7,0],[1,-i,2*i]] | ||
216 | \> let (l,u,p,s) = luR m@ | ||
217 | |||
218 | L is the lower triangular: | ||
219 | |||
220 | @\> l | ||
221 | 1. 0. 0. | ||
222 | 0.154-0.231i 1. 0. | ||
223 | 0.154-0.231i 0.624-0.522i 1.@ | ||
224 | |||
225 | U is the upper triangular: | ||
226 | |||
227 | @\> u | ||
228 | 2.+3.i -7. 0. | ||
229 | 0. 3.077-1.615i -3. | ||
230 | 0. 0. 1.873+0.433i@ | ||
231 | |||
232 | p is a permutation: | ||
233 | |||
234 | @\> p | ||
235 | [1,0,2]@ | ||
236 | |||
237 | L \* U obtains a permuted version of the original matrix: | ||
238 | |||
239 | @\> 'extractRows' p m | ||
240 | 2.+3.i -7. 0. | ||
241 | 1. 2. -3. | ||
242 | 1. -1.i 2.i | ||
243 | \ | ||
244 | \> l \<\> u | ||
245 | 2.+3.i -7. 0. | ||
246 | 1. 2. -3. | ||
247 | 1. -1.i 2.i@ | ||
248 | |||
249 | s is the sign of the permutation, required to obtain sign of the determinant: | ||
250 | |||
251 | @\> s * product ('toList' $ 'takeDiag' u) | ||
252 | (-18.0) :+ (-16.000000000000004) | ||
253 | \> 'LinearAlgebra.Algorithms.det' m | ||
254 | (-18.0) :+ (-16.000000000000004)@ | ||
255 | |||
256 | -} | ||
257 | luR :: Matrix Double -> (Matrix Double, Matrix Double, [Int], Double) | ||
258 | luR m = (l,u,p, fromIntegral s') where | ||
259 | r = rows m | ||
260 | v = luRaux m | ||
261 | lu = reshape r $ subVector 0 (r*r) v | ||
262 | s':p = map round . toList . subVector (r*r) (r+1) $ v | ||
263 | u = triang r r 0 1`mul` lu | ||
264 | l = (triang r r 0 0 `mul` lu) `add` ident r | ||
265 | add = liftMatrix2 $ vectorZipR Add | ||
266 | mul = liftMatrix2 $ vectorZipR Mul | ||
267 | |||
268 | -- | Complex version of 'luR'. | ||
269 | luC :: Matrix (Complex Double) -> (Matrix (Complex Double), Matrix (Complex Double), [Int], Complex Double) | ||
270 | luC m = (l,u,p, fromIntegral s') where | ||
271 | r = rows m | ||
272 | v = luCaux m | ||
273 | lu = reshape r $ subVector 0 (r*r) v | ||
274 | s':p = map (round.realPart) . toList . subVector (r*r) (r+1) $ v | ||
275 | u = triang r r 0 1 `mul` lu | ||
276 | l = (triang r r 0 0 `mul` lu) `add` ident r | ||
277 | add = liftMatrix2 $ vectorZipC Add | ||
278 | mul = liftMatrix2 $ vectorZipC Mul | ||
279 | |||
280 | extract l is = [l!!i |i<-is] | ||
281 | |||
282 | {- auxiliary function to get triangular matrices | ||
283 | -} | ||
284 | triang r c h v = reshape c $ fromList [el i j | i<-[0..r-1], j<-[0..c-1]] | ||
285 | where el i j = if j-i>=h then v else 1 - v | ||
286 | |||
287 | {- | rearranges the rows of a matrix according to the order given in a list of integers. | ||
288 | |||
289 | > > extractRows [3,3,0,1] (ident 4) | ||
290 | > 0. 0. 0. 1. | ||
291 | > 0. 0. 0. 1. | ||
292 | > 1. 0. 0. 0. | ||
293 | > 0. 1. 0. 0. | ||
294 | |||
295 | -} | ||
296 | extractRows :: Field t => [Int] -> Matrix t -> Matrix t | ||
297 | extractRows l m = fromRows $ extract (toRows $ m) l | ||
298 | |||
299 | -------------------------------------------------------------- | ||
300 | |||
301 | -- | loads a matrix efficiently from formatted ASCII text file (the number of rows and columns must be known in advance). | ||
302 | fromFile :: FilePath -> (Int,Int) -> IO (Matrix Double) | ||
303 | fromFile filename (r,c) = do | ||
304 | charname <- newCString filename | ||
305 | res <- createMatrix RowMajor r c | ||
306 | c_gslReadMatrix charname // mat dat res // check "gslReadMatrix" [] | ||
307 | --free charname -- TO DO: free the auxiliary CString | ||
308 | return res | ||
309 | foreign import ccall "gsl-aux.h matrix_fscanf" c_gslReadMatrix:: Ptr CChar -> TM | ||
310 | |||
311 | --------------------------------------------------------------------------- | ||