summaryrefslogtreecommitdiff
path: root/lib/GSL/Matrix.hs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/GSL/Matrix.hs')
-rw-r--r--lib/GSL/Matrix.hs311
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
15module GSL.Matrix(
16 eigSg, eigHg,
17 svdg,
18 qr,
19 chol,
20 luSolveR, luSolveC,
21 luR, luC,
22 fromFile
23) where
24
25import Data.Packed.Internal
26import Data.Packed.Matrix(fromLists,ident,takeDiag)
27import GSL.Vector
28import Foreign
29import Foreign.C.Types
30import Complex
31import 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-}
48eigSg :: Matrix Double -> (Vector Double, Matrix Double)
49eigSg (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)
56foreign 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-}
78eigHg :: Matrix (Complex Double)-> (Vector Double, Matrix (Complex Double))
79eigHg (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)
86foreign 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
940.310 -0.951
950.951 0.310
96\
97\> s
988.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-}
110svdg :: Matrix Double -> (Matrix Double, Vector Double, Matrix Double)
111svdg 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
115svd' 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)
121foreign 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
1361.000 3.000 5.000 7.000
1372.000 0. -2.000 4.000@
138
139-}
140qr :: Matrix Double -> (Matrix Double, Matrix Double)
141qr 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)
146foreign 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
1532.236 0.
1541.789 1.342
155\
156\> c \<\> 'trans' c
1575.000 4.000
1584.000 5.000@
159
160-}
161chol :: Matrix Double -> Matrix Double
162--chol x@(M r _ p) = createM [p] "chol" r r $ m c_chol x
163chol 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
167foreign 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-}
173luSolveR :: Matrix Double -> Matrix Double -> Matrix Double
174luSolveR 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
181foreign import ccall "gsl-aux.h luSolveR" c_luSolveR :: TMMM
182
183{- -| efficient multiplication by the inverse of a matrix (for complex matrices).
184-}
185luSolveC :: Matrix (Complex Double) -> Matrix (Complex Double) -> Matrix (Complex Double)
186luSolveC 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
193foreign 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-}
197luRaux :: Matrix Double -> Vector Double
198luRaux 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
202foreign 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-}
206luCaux :: Matrix (Complex Double) -> Vector (Complex Double)
207luCaux 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
211foreign 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
218L is the lower triangular:
219
220@\> l
221 1. 0. 0.
2220.154-0.231i 1. 0.
2230.154-0.231i 0.624-0.522i 1.@
224
225U is the upper triangular:
226
227@\> u
2282.+3.i -7. 0.
229 0. 3.077-1.615i -3.
230 0. 0. 1.873+0.433i@
231
232p is a permutation:
233
234@\> p
235[1,0,2]@
236
237L \* 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
249s 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 -}
257luR :: Matrix Double -> (Matrix Double, Matrix Double, [Int], Double)
258luR 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'.
269luC :: Matrix (Complex Double) -> (Matrix (Complex Double), Matrix (Complex Double), [Int], Complex Double)
270luC 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
280extract l is = [l!!i |i<-is]
281
282{- auxiliary function to get triangular matrices
283-}
284triang 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-}
296extractRows :: Field t => [Int] -> Matrix t -> Matrix t
297extractRows 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).
302fromFile :: FilePath -> (Int,Int) -> IO (Matrix Double)
303fromFile 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
309foreign import ccall "gsl-aux.h matrix_fscanf" c_gslReadMatrix:: Ptr CChar -> TM
310
311---------------------------------------------------------------------------