]> Git — Sourcephile - gargantext.git/blob - src/Gargantext/Core/Methods/Matrix/Accelerate/Utils.hs
Merge branch 'dev' into dev-node-board-add-text-cells
[gargantext.git] / src / Gargantext / Core / Methods / Matrix / Accelerate / Utils.hs
1 {-|
2 Module : Gargantext.Core.Methods.Matrix.Accelerate.Utils
3 Description :
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
8 Portability : POSIX
9
10 This module aims at implementig distances of terms context by context is
11 the same referential of corpus.
12
13 Implementation use Accelerate library which enables GPU and CPU computation:
14
15 * Manuel M. T. Chakravarty, Gabriele Keller, Sean Lee, Trevor L. McDonell, and Vinod Grover.
16 [Accelerating Haskell Array Codes with Multicore GPUs][CKLM+11].
17 In _DAMP '11: Declarative Aspects of Multicore Programming_, ACM, 2011.
18
19 * Trevor L. McDonell, Manuel M. T. Chakravarty, Vinod Grover, and Ryan R. Newton.
20 [Type-safe Runtime Code Generation: Accelerate to LLVM][MCGN15].
21 In _Haskell '15: The 8th ACM SIGPLAN Symposium on Haskell_, ACM, 2015.
22
23 -}
24
25 {-# LANGUAGE TypeFamilies #-}
26 {-# LANGUAGE TypeOperators #-}
27 {-# LANGUAGE ScopedTypeVariables #-}
28 {-# LANGUAGE ViewPatterns #-}
29
30 module Gargantext.Core.Methods.Matrix.Accelerate.Utils
31 where
32
33 import qualified Data.Foldable as P (foldl1)
34 import Debug.Trace (trace)
35 import Data.Array.Accelerate
36 import Data.Array.Accelerate.Interpreter (run)
37 import qualified Gargantext.Prelude as P
38
39 -- | Matrix cell by cell multiplication
40 (.*) :: ( Shape ix
41 , Slice ix
42 , Elt a
43 , P.Num (Exp a)
44 )
45 => Acc (Array ((ix :. Int) :. Int) a)
46 -> Acc (Array ((ix :. Int) :. Int) a)
47 -> Acc (Array ((ix :. Int) :. Int) a)
48 (.*) = zipWith (*)
49
50
51 (./) :: ( Shape ix
52 , Slice ix
53 , Elt a
54 , P.Num (Exp a)
55 , P.Fractional (Exp a)
56 )
57 => Acc (Array ((ix :. Int) :. Int) a)
58 -> Acc (Array ((ix :. Int) :. Int) a)
59 -> Acc (Array ((ix :. Int) :. Int) a)
60 (./) = zipWith (/)
61
62 -- | Term by term division where divisions by 0 produce 0 rather than NaN.
63 termDivNan :: ( Shape ix
64 , Slice ix
65 , Elt a
66 , Eq a
67 , P.Num (Exp a)
68 , P.Fractional (Exp a)
69 )
70 => Acc (Array ((ix :. Int) :. Int) a)
71 -> Acc (Array ((ix :. Int) :. Int) a)
72 -> Acc (Array ((ix :. Int) :. Int) a)
73 termDivNan = zipWith (\i j -> cond ((==) j 0) 0 ((/) i j))
74
75 (.-) :: ( Shape ix
76 , Slice ix
77 , Elt a
78 , P.Num (Exp a)
79 , P.Fractional (Exp a)
80 )
81 => Acc (Array ((ix :. Int) :. Int) a)
82 -> Acc (Array ((ix :. Int) :. Int) a)
83 -> Acc (Array ((ix :. Int) :. Int) a)
84 (.-) = zipWith (-)
85
86 (.+) :: ( Shape ix
87 , Slice ix
88 , Elt a
89 , P.Num (Exp a)
90 , P.Fractional (Exp a)
91 )
92 => Acc (Array ((ix :. Int) :. Int) a)
93 -> Acc (Array ((ix :. Int) :. Int) a)
94 -> Acc (Array ((ix :. Int) :. Int) a)
95 (.+) = zipWith (+)
96
97 -----------------------------------------------------------------------
98 matrixOne :: Num a => Dim -> Acc (Matrix a)
99 matrixOne n' = ones
100 where
101 ones = fill (index2 n n) 1
102 n = constant n'
103
104
105 matrixIdentity :: Num a => Dim -> Acc (Matrix a)
106 matrixIdentity n' =
107 let zeros = fill (index2 n n) 0
108 ones = fill (index1 n) 1
109 n = constant n'
110 in
111 permute const zeros (\(unindex1 -> i) -> index2 i i) ones
112
113
114 matrixEye :: Num a => Dim -> Acc (Matrix a)
115 matrixEye n' =
116 let ones = fill (index2 n n) 1
117 zeros = fill (index1 n) 0
118 n = constant n'
119 in
120 permute const ones (\(unindex1 -> i) -> index2 i i) zeros
121
122
123 diagNull :: Num a => Dim -> Acc (Matrix a) -> Acc (Matrix a)
124 diagNull n m = zipWith (*) m (matrixEye n)
125
126 -----------------------------------------------------------------------
127 _runExp :: Elt e => Exp e -> e
128 _runExp e = indexArray (run (unit e)) Z
129
130 -----------------------------------------------------------------------
131 -- | Define a vector
132 --
133 -- >>> vector 3
134 -- Vector (Z :. 3) [0,1,2]
135 vector :: Elt c => Int -> [c] -> (Array (Z :. Int) c)
136 vector n l = fromList (Z :. n) l
137
138 -- | Define a matrix
139 --
140 -- >>> matrix 3 ([1..] :: [Double])
141 -- Matrix (Z :. 3 :. 3)
142 -- [ 1.0, 2.0, 3.0,
143 -- 4.0, 5.0, 6.0,
144 -- 7.0, 8.0, 9.0]
145 matrix :: Elt c => Int -> [c] -> Matrix c
146 matrix n l = fromList (Z :. n :. n) l
147
148 -- | Two ways to get the rank (as documentation)
149 --
150 -- >>> rank (matrix 3 ([1..] :: [Int]))
151 -- 2
152 rank :: (Matrix a) -> Int
153 rank m = arrayRank $ arrayShape m
154
155 -----------------------------------------------------------------------
156 -- | Dimension of a square Matrix
157 -- How to force use with SquareMatrix ?
158 type Dim = Int
159
160 -- | Get Dimension of a square Matrix
161 --
162 -- >>> dim (matrix 3 ([1..] :: [Int]))
163 -- 3
164 dim :: Matrix a -> Dim
165 dim m = n
166 where
167 Z :. _ :. n = arrayShape m
168 -- indexTail (arrayShape m)
169
170 -----------------------------------------------------------------------
171
172 -- | Sum of a Matrix by Column
173 --
174 -- >>> run $ matSumCol 3 (use $ matrix 3 [1..])
175 -- Matrix (Z :. 3 :. 3)
176 -- [ 12.0, 15.0, 18.0,
177 -- 12.0, 15.0, 18.0,
178 -- 12.0, 15.0, 18.0]
179 matSumCol :: (Elt a, P.Num (Exp a)) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
180 matSumCol r mat = replicate (constant (Z :. (r :: Int) :. All)) $ sum $ transpose mat
181
182 matSumCol' :: (Elt a, P.Num (Exp a)) => Matrix a -> Matrix a
183 matSumCol' m = run $ matSumCol n m'
184 where
185 n = dim m
186 m' = use m
187
188
189 -- | Proba computes de probability matrix: all cells divided by thee sum of its column
190 -- if you need get the probability on the lines, just transpose it
191 --
192 -- >>> run $ matProba 3 (use $ matrix 3 [1..])
193 -- Matrix (Z :. 3 :. 3)
194 -- [ 8.333333333333333e-2, 0.13333333333333333, 0.16666666666666666,
195 -- 0.3333333333333333, 0.3333333333333333, 0.3333333333333333,
196 -- 0.5833333333333334, 0.5333333333333333, 0.5]
197 matProba :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
198 matProba d mat = zipWith (/) mat (matSumCol d mat)
199
200 -- | Diagonal of the matrix
201 --
202 -- >>> run $ diag (use $ matrix 3 ([1..] :: [Int]))
203 -- Vector (Z :. 3) [1,5,9]
204 diag :: Elt e
205 => Acc (Matrix e)
206 -> Acc (Vector e)
207 diag m = backpermute (indexTail (shape m))
208 (lift1 (\(Z :. x) -> (Z :. x :. (x :: Exp Int))))
209 m
210
211 -- | Divide by the Diagonal of the matrix
212 --
213 -- >>> run $ divByDiag 3 (use $ matrix 3 ([1..] :: [Double]))
214 -- Matrix (Z :. 3 :. 3)
215 -- [ 1.0, 0.4, 0.3333333333333333,
216 -- 4.0, 1.0, 0.6666666666666666,
217 -- 7.0, 1.6, 1.0]
218 divByDiag :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
219 divByDiag d mat = zipWith (/) mat (replicate (constant (Z :. (d :: Int) :. All)) $ diag mat)
220
221 -----------------------------------------------------------------------
222 -- | Filters the matrix with the minimum of maximums
223 --
224 -- >>> run $ matMiniMax $ use $ matrix 3 [1..]
225 -- Matrix (Z :. 3 :. 3)
226 -- [ 0.0, 4.0, 7.0,
227 -- 0.0, 5.0, 8.0,
228 -- 0.0, 6.0, 9.0]
229 matMiniMax :: (Elt a, Ord a, P.Num a)
230 => Acc (Matrix a)
231 -> Acc (Matrix a)
232 matMiniMax m = filterWith' miniMax' (constant 0) m
233 where
234 miniMax' = the $ minimum $ maximum m
235
236
237 -- | Filters the matrix with a constant
238 --
239 -- >>> run $ matFilter 5 $ use $ matrix 3 [1..]
240 -- Matrix (Z :. 3 :. 3)
241 -- [ 0.0, 0.0, 7.0,
242 -- 0.0, 0.0, 8.0,
243 -- 0.0, 6.0, 9.0]
244 filter' :: Double -> Acc (Matrix Double) -> Acc (Matrix Double)
245 filter' t m = filterWith t 0 m
246
247 filterWith :: Double -> Double -> Acc (Matrix Double) -> Acc (Matrix Double)
248 filterWith t v m = map (\x -> ifThenElse (x > (constant t)) x (constant v)) (transpose m)
249
250 filterWith' :: (Elt a, Ord a) => Exp a -> Exp a -> Acc (Matrix a) -> Acc (Matrix a)
251 filterWith' t v m = map (\x -> ifThenElse (x > t) x v) m
252
253
254 ------------------------------------------------------------------------
255 ------------------------------------------------------------------------
256
257
258
259 -- | TODO use Lenses
260 data Direction = MatCol (Exp Int) | MatRow (Exp Int) | Diag
261
262 nullOf :: Num a => Dim -> Direction -> Acc (Matrix a)
263 nullOf n' dir =
264 let ones = fill (index2 n n) 1
265 zeros = fill (index2 n n) 0
266 n = constant n'
267 in
268 permute const ones ( lift1 ( \(Z :. (i :: Exp Int) :. (_j:: Exp Int))
269 -> case dir of
270 MatCol m -> (Z :. i :. m)
271 MatRow m -> (Z :. m :. i)
272 Diag -> (Z :. i :. i)
273 )
274 )
275 zeros
276
277 nullOfWithDiag :: Num a => Dim -> Direction -> Acc (Matrix a)
278 nullOfWithDiag n dir = zipWith (*) (nullOf n dir) (nullOf n Diag)
279
280
281 divide :: (Elt a, Ord a, P.Fractional (Exp a), P.Num a)
282 => Acc (Matrix a) -> Acc (Matrix a) -> Acc (Matrix a)
283 divide = zipWith divide'
284 where
285 divide' a b = ifThenElse (b > (constant 0))
286 (a / b)
287 (constant 0)
288
289 -- | Nominator
290 sumRowMin :: (Num a, Ord a) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
291 sumRowMin n m = {-trace (P.show $ run m') $-} m'
292 where
293 m' = reshape (shape m) vs
294 vs = P.foldl1 (++)
295 $ P.map (\z -> sumRowMin1 n (constant z) m) [0..n-1]
296
297 sumRowMin1 :: (Num a, Ord a) => Dim -> Exp Int -> Acc (Matrix a) -> Acc (Vector a)
298 sumRowMin1 n x m = trace (P.show (run m,run $ transpose m)) $ m''
299 where
300 m'' = sum $ zipWith min (transpose m) m
301 _m' = zipWith (*) (zipWith (*) (nullOf n (MatCol x)) $ nullOfWithDiag n (MatRow x)) m
302
303 -- | Denominator
304 sumColMin :: (Num a, Ord a) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
305 sumColMin n m = reshape (shape m) vs
306 where
307 vs = P.foldl1 (++)
308 $ P.map (\z -> sumColMin1 n (constant z) m) [0..n-1]
309
310
311 sumColMin1 :: (Num a) => Dim -> Exp Int -> Acc (Matrix a) -> Acc (Matrix a)
312 sumColMin1 n x m = zipWith (*) (nullOfWithDiag n (MatCol x)) m
313
314
315
316 {- | WIP fun with indexes
317 selfMatrix :: Num a => Dim -> Acc (Matrix a)
318 selfMatrix n' =
319 let zeros = fill (index2 n n) 0
320 ones = fill (index2 n n) 1
321 n = constant n'
322 in
323 permute const ones ( lift1 ( \(Z :. (i :: Exp Int) :. (_j:: Exp Int))
324 -> -- ifThenElse (i /= j)
325 -- (Z :. i :. j)
326 (Z :. i :. i)
327 )) zeros
328
329 selfMatrix' :: (Elt a, P.Num (Exp a)) => Array DIM2 a -> Matrix a
330 selfMatrix' m' = run $ selfMatrix n
331 where
332 n = dim m'
333 m = use m'
334 -}
335 -------------------------------------------------
336 -------------------------------------------------
337 crossProduct :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
338 crossProduct n m = {-trace (P.show (run m',run m'')) $-} zipWith (*) m' m''
339 where
340 m' = cross n m
341 m'' = transpose $ cross n m
342
343
344 crossT :: Matrix Double -> Matrix Double
345 crossT = run . transpose . use
346
347 crossProduct' :: Matrix Double -> Matrix Double
348 crossProduct' m = run $ crossProduct n m'
349 where
350 n = dim m
351 m' = use m
352
353 runWith :: (Arrays c, Elt a1)
354 => (Dim -> Acc (Matrix a1) -> a2 -> Acc c)
355 -> Matrix a1
356 -> a2
357 -> c
358 runWith f m = run . f (dim m) (use m)
359
360 -- | cross
361 cross :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
362 cross n mat = diagNull n (matSumCol n $ diagNull n mat)
363
364 cross' :: Matrix Double -> Matrix Double
365 cross' mat = run $ cross n mat'
366 where
367 mat' = use mat
368 n = dim mat
369
370
371 {-
372 -- | Hypothesis to test maybe later (or not)
373 -- TODO ask accelerate for instances to ease such writtings:
374 p_ :: (Elt e, P.Fractional (Exp e)) => Acc (Array DIM2 e) -> Acc (Array DIM2 e)
375 p_ m = zipWith (/) m (n_ m)
376 where
377 n_ :: Elt e => Acc (SymetricMatrix e) -> Acc (Matrix e)
378 n_ m = backpermute (shape m)
379 (lift1 ( \(Z :. (i :: Exp Int) :. (j:: Exp Int))
380 -> (ifThenElse (i < j) (lift (Z :. j :. j)) (lift (Z :. i :. i)) :: Exp DIM2)
381 )
382 ) m
383 -}
384
385 theMatrixDouble :: Int -> Matrix Double
386 theMatrixDouble n = run $ map fromIntegral (use $ theMatrixInt n)
387
388 theMatrixInt :: Int -> Matrix Int
389 theMatrixInt n = matrix n (dataMatrix n)
390 where
391 dataMatrix :: Int -> [Int]
392 dataMatrix x | (P.==) x 2 = [ 1, 1
393 , 1, 2
394 ]
395
396 | (P.==) x 3 = [ 7, 4, 0
397 , 4, 5, 3
398 , 0, 3, 4
399 ]
400 | (P.==) x 4 = [ 4, 1, 2, 1
401 , 1, 4, 0, 0
402 , 2, 0, 3, 3
403 , 1, 0, 3, 3
404 ]
405
406
407 | P.otherwise = P.undefined
408
409 {-
410 theResult :: Int -> Matrix Double
411 theResult n | (P.==) n 2 = let r = 1.6094379124341003 in [ 0, r, r, 0]
412 | P.otherwise = [ 1, 1 ]
413 -}
414
415
416 colMatrix :: Elt e
417 => Int -> [e] -> Acc (Array ((Z :. Int) :. Int) e)
418 colMatrix n ns = replicate (constant (Z :. (n :: Int) :. All)) v
419 where
420 v = use $ vector (P.length ns) ns
421
422 -----------------------------------------------------------------------
423