diff options
Diffstat (limited to 'packages/base/src/Internal/Container.hs')
-rw-r--r-- | packages/base/src/Internal/Container.hs | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/packages/base/src/Internal/Container.hs b/packages/base/src/Internal/Container.hs new file mode 100644 index 0000000..b08f892 --- /dev/null +++ b/packages/base/src/Internal/Container.hs | |||
@@ -0,0 +1,297 @@ | |||
1 | {-# LANGUAGE FlexibleContexts #-} | ||
2 | {-# LANGUAGE FlexibleInstances #-} | ||
3 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
4 | {-# LANGUAGE FunctionalDependencies #-} | ||
5 | {-# LANGUAGE UndecidableInstances #-} | ||
6 | |||
7 | ----------------------------------------------------------------------------- | ||
8 | -- | | ||
9 | -- Module : Internal.Container | ||
10 | -- Copyright : (c) Alberto Ruiz 2010-14 | ||
11 | -- License : BSD3 | ||
12 | -- Maintainer : Alberto Ruiz | ||
13 | -- Stability : provisional | ||
14 | -- | ||
15 | -- Basic numeric operations on 'Vector' and 'Matrix', including conversion routines. | ||
16 | -- | ||
17 | -- The 'Container' class is used to define optimized generic functions which work | ||
18 | -- on 'Vector' and 'Matrix' with real or complex elements. | ||
19 | -- | ||
20 | -- Some of these functions are also available in the instances of the standard | ||
21 | -- numeric Haskell classes provided by "Numeric.LinearAlgebra". | ||
22 | -- | ||
23 | ----------------------------------------------------------------------------- | ||
24 | |||
25 | module Internal.Container where | ||
26 | |||
27 | import Internal.Vector | ||
28 | import Internal.Matrix | ||
29 | import Internal.Element | ||
30 | import Internal.Numeric | ||
31 | import Internal.Algorithms(Field,linearSolveSVD) | ||
32 | |||
33 | ------------------------------------------------------------------ | ||
34 | |||
35 | {- | Creates a real vector containing a range of values: | ||
36 | |||
37 | >>> linspace 5 (-3,7::Double) | ||
38 | fromList [-3.0,-0.5,2.0,4.5,7.0]@ | ||
39 | |||
40 | >>> linspace 5 (8,2+i) :: Vector (Complex Double) | ||
41 | fromList [8.0 :+ 0.0,6.5 :+ 0.25,5.0 :+ 0.5,3.5 :+ 0.75,2.0 :+ 1.0] | ||
42 | |||
43 | Logarithmic spacing can be defined as follows: | ||
44 | |||
45 | @logspace n (a,b) = 10 ** linspace n (a,b)@ | ||
46 | -} | ||
47 | linspace :: (Fractional e, Container Vector e) => Int -> (e, e) -> Vector e | ||
48 | linspace 0 _ = fromList[] | ||
49 | linspace 1 (a,b) = fromList[(a+b)/2] | ||
50 | linspace n (a,b) = addConstant a $ scale s $ fromList $ map fromIntegral [0 .. n-1] | ||
51 | where s = (b-a)/fromIntegral (n-1) | ||
52 | |||
53 | -------------------------------------------------------------------------------- | ||
54 | |||
55 | infixr 8 <.> | ||
56 | {- | An infix synonym for 'dot' | ||
57 | |||
58 | >>> vector [1,2,3,4] <.> vector [-2,0,1,1] | ||
59 | 5.0 | ||
60 | |||
61 | >>> let 𝑖 = 0:+1 :: C | ||
62 | >>> fromList [1+𝑖,1] <.> fromList [1,1+𝑖] | ||
63 | 2.0 :+ 0.0 | ||
64 | |||
65 | -} | ||
66 | |||
67 | (<.>) :: Numeric t => Vector t -> Vector t -> t | ||
68 | (<.>) = dot | ||
69 | |||
70 | |||
71 | |||
72 | |||
73 | |||
74 | {- | dense matrix-vector product | ||
75 | |||
76 | >>> let m = (2><3) [1..] | ||
77 | >>> m | ||
78 | (2><3) | ||
79 | [ 1.0, 2.0, 3.0 | ||
80 | , 4.0, 5.0, 6.0 ] | ||
81 | |||
82 | >>> let v = vector [10,20,30] | ||
83 | |||
84 | >>> m #> v | ||
85 | fromList [140.0,320.0] | ||
86 | |||
87 | -} | ||
88 | infixr 8 #> | ||
89 | (#>) :: Numeric t => Matrix t -> Vector t -> Vector t | ||
90 | (#>) = mXv | ||
91 | |||
92 | -- | dense matrix-vector product | ||
93 | app :: Numeric t => Matrix t -> Vector t -> Vector t | ||
94 | app = (#>) | ||
95 | |||
96 | infixl 8 <# | ||
97 | -- | dense vector-matrix product | ||
98 | (<#) :: Numeric t => Vector t -> Matrix t -> Vector t | ||
99 | (<#) = vXm | ||
100 | |||
101 | -------------------------------------------------------------------------------- | ||
102 | |||
103 | class Mul a b c | a b -> c where | ||
104 | infixl 7 <> | ||
105 | -- | Matrix-matrix, matrix-vector, and vector-matrix products. | ||
106 | (<>) :: Product t => a t -> b t -> c t | ||
107 | |||
108 | instance Mul Matrix Matrix Matrix where | ||
109 | (<>) = mXm | ||
110 | |||
111 | instance Mul Matrix Vector Vector where | ||
112 | (<>) m v = flatten $ m <> asColumn v | ||
113 | |||
114 | instance Mul Vector Matrix Vector where | ||
115 | (<>) v m = flatten $ asRow v <> m | ||
116 | |||
117 | -------------------------------------------------------------------------------- | ||
118 | |||
119 | {- | Least squares solution of a linear system, similar to the \\ operator of Matlab\/Octave (based on linearSolveSVD) | ||
120 | |||
121 | @ | ||
122 | a = (3><2) | ||
123 | [ 1.0, 2.0 | ||
124 | , 2.0, 4.0 | ||
125 | , 2.0, -1.0 ] | ||
126 | @ | ||
127 | |||
128 | @ | ||
129 | v = vector [13.0,27.0,1.0] | ||
130 | @ | ||
131 | |||
132 | >>> let x = a <\> v | ||
133 | >>> x | ||
134 | fromList [3.0799999999999996,5.159999999999999] | ||
135 | |||
136 | >>> a #> x | ||
137 | fromList [13.399999999999999,26.799999999999997,1.0] | ||
138 | |||
139 | It also admits multiple right-hand sides stored as columns in a matrix. | ||
140 | |||
141 | -} | ||
142 | infixl 7 <\> | ||
143 | (<\>) :: (LSDiv c, Field t) => Matrix t -> c t -> c t | ||
144 | (<\>) = linSolve | ||
145 | |||
146 | class LSDiv c | ||
147 | where | ||
148 | linSolve :: Field t => Matrix t -> c t -> c t | ||
149 | |||
150 | instance LSDiv Vector | ||
151 | where | ||
152 | linSolve m v = flatten (linearSolveSVD m (reshape 1 v)) | ||
153 | |||
154 | instance LSDiv Matrix | ||
155 | where | ||
156 | linSolve = linearSolveSVD | ||
157 | |||
158 | -------------------------------------------------------------------------------- | ||
159 | |||
160 | |||
161 | class Build d f c e | d -> c, c -> d, f -> e, f -> d, f -> c, c e -> f, d e -> f | ||
162 | where | ||
163 | -- | | ||
164 | -- >>> build 5 (**2) :: Vector Double | ||
165 | -- fromList [0.0,1.0,4.0,9.0,16.0] | ||
166 | -- | ||
167 | -- Hilbert matrix of order N: | ||
168 | -- | ||
169 | -- >>> let hilb n = build (n,n) (\i j -> 1/(i+j+1)) :: Matrix Double | ||
170 | -- >>> putStr . dispf 2 $ hilb 3 | ||
171 | -- 3x3 | ||
172 | -- 1.00 0.50 0.33 | ||
173 | -- 0.50 0.33 0.25 | ||
174 | -- 0.33 0.25 0.20 | ||
175 | -- | ||
176 | build :: d -> f -> c e | ||
177 | |||
178 | instance Container Vector e => Build Int (e -> e) Vector e | ||
179 | where | ||
180 | build = build' | ||
181 | |||
182 | instance Container Matrix e => Build (Int,Int) (e -> e -> e) Matrix e | ||
183 | where | ||
184 | build = build' | ||
185 | |||
186 | -------------------------------------------------------------------------------- | ||
187 | |||
188 | -- @dot u v = 'udot' ('conj' u) v@ | ||
189 | dot :: (Numeric t) => Vector t -> Vector t -> t | ||
190 | dot u v = udot (conj u) v | ||
191 | |||
192 | -------------------------------------------------------------------------------- | ||
193 | |||
194 | optimiseMult :: Monoid (Matrix t) => [Matrix t] -> Matrix t | ||
195 | optimiseMult = mconcat | ||
196 | |||
197 | -------------------------------------------------------------------------------- | ||
198 | |||
199 | |||
200 | {- | Compute mean vector and covariance matrix of the rows of a matrix. | ||
201 | |||
202 | >>> meanCov $ gaussianSample 666 1000 (fromList[4,5]) (diagl[2,3]) | ||
203 | (fromList [4.010341078059521,5.0197204699640405], | ||
204 | (2><2) | ||
205 | [ 1.9862461923890056, -1.0127225830525157e-2 | ||
206 | , -1.0127225830525157e-2, 3.0373954915729318 ]) | ||
207 | |||
208 | -} | ||
209 | meanCov :: Matrix Double -> (Vector Double, Matrix Double) | ||
210 | meanCov x = (med,cov) where | ||
211 | r = rows x | ||
212 | k = 1 / fromIntegral r | ||
213 | med = konst k r `vXm` x | ||
214 | meds = konst 1 r `outer` med | ||
215 | xc = x `sub` meds | ||
216 | cov = scale (recip (fromIntegral (r-1))) (trans xc `mXm` xc) | ||
217 | |||
218 | -------------------------------------------------------------------------------- | ||
219 | |||
220 | sortVector :: (Ord t, Element t) => Vector t -> Vector t | ||
221 | sortVector = sortV | ||
222 | |||
223 | {- | | ||
224 | |||
225 | >>> m <- randn 4 10 | ||
226 | >>> disp 2 m | ||
227 | 4x10 | ||
228 | -0.31 0.41 0.43 -0.19 -0.17 -0.23 -0.17 -1.04 -0.07 -1.24 | ||
229 | 0.26 0.19 0.14 0.83 -1.54 -0.09 0.37 -0.63 0.71 -0.50 | ||
230 | -0.11 -0.10 -1.29 -1.40 -1.04 -0.89 -0.68 0.35 -1.46 1.86 | ||
231 | 1.04 -0.29 0.19 -0.75 -2.20 -0.01 1.06 0.11 -2.09 -1.58 | ||
232 | |||
233 | >>> disp 2 $ m ?? (All, Pos $ sortIndex (m!1)) | ||
234 | 4x10 | ||
235 | -0.17 -1.04 -1.24 -0.23 0.43 0.41 -0.31 -0.17 -0.07 -0.19 | ||
236 | -1.54 -0.63 -0.50 -0.09 0.14 0.19 0.26 0.37 0.71 0.83 | ||
237 | -1.04 0.35 1.86 -0.89 -1.29 -0.10 -0.11 -0.68 -1.46 -1.40 | ||
238 | -2.20 0.11 -1.58 -0.01 0.19 -0.29 1.04 1.06 -2.09 -0.75 | ||
239 | |||
240 | -} | ||
241 | sortIndex :: (Ord t, Element t) => Vector t -> Vector I | ||
242 | sortIndex = sortI | ||
243 | |||
244 | ccompare :: (Ord t, Container c t) => c t -> c t -> c I | ||
245 | ccompare = ccompare' | ||
246 | |||
247 | cselect :: (Container c t) => c I -> c t -> c t -> c t -> c t | ||
248 | cselect = cselect' | ||
249 | |||
250 | {- | Extract elements from positions given in matrices of rows and columns. | ||
251 | |||
252 | >>> r | ||
253 | (3><3) | ||
254 | [ 1, 1, 1 | ||
255 | , 1, 2, 2 | ||
256 | , 1, 2, 3 ] | ||
257 | >>> c | ||
258 | (3><3) | ||
259 | [ 0, 1, 5 | ||
260 | , 2, 2, 1 | ||
261 | , 4, 4, 1 ] | ||
262 | >>> m | ||
263 | (4><6) | ||
264 | [ 0, 1, 2, 3, 4, 5 | ||
265 | , 6, 7, 8, 9, 10, 11 | ||
266 | , 12, 13, 14, 15, 16, 17 | ||
267 | , 18, 19, 20, 21, 22, 23 ] | ||
268 | |||
269 | >>> remap r c m | ||
270 | (3><3) | ||
271 | [ 6, 7, 11 | ||
272 | , 8, 14, 13 | ||
273 | , 10, 16, 19 ] | ||
274 | |||
275 | The indexes are autoconformable. | ||
276 | |||
277 | >>> c' | ||
278 | (3><1) | ||
279 | [ 1 | ||
280 | , 2 | ||
281 | , 4 ] | ||
282 | >>> remap r c' m | ||
283 | (3><3) | ||
284 | [ 7, 7, 7 | ||
285 | , 8, 14, 14 | ||
286 | , 10, 16, 22 ] | ||
287 | |||
288 | -} | ||
289 | remap :: Element t => Matrix I -> Matrix I -> Matrix t -> Matrix t | ||
290 | remap i j m | ||
291 | | minElement i >= 0 && maxElement i < fromIntegral (rows m) && | ||
292 | minElement j >= 0 && maxElement j < fromIntegral (cols m) = remapM i' j' m | ||
293 | | otherwise = error $ "out of range index in remap" | ||
294 | where | ||
295 | [i',j'] = conformMs [i,j] | ||
296 | |||
297 | |||