2 Module : Gargantext.Core.Methods.Matrix.Accelerate.Utils
4 Copyright : (c) CNRS, 2017-Present
5 License : AGPL + CECILL v3
6 Maintainer : team@gargantext.org
7 Stability : experimental
10 This module aims at implementig distances of terms context by context is
11 the same referential of corpus.
13 Implementation use Accelerate library which enables GPU and CPU computation:
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.
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.
25 {-# LANGUAGE TypeFamilies #-}
26 {-# LANGUAGE TypeOperators #-}
27 {-# LANGUAGE ScopedTypeVariables #-}
28 {-# LANGUAGE ViewPatterns #-}
30 module Gargantext.Core.Methods.Matrix.Accelerate.Utils
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
39 -- | Matrix cell by cell multiplication
45 => Acc (Array ((ix :. Int) :. Int) a)
46 -> Acc (Array ((ix :. Int) :. Int) a)
47 -> Acc (Array ((ix :. Int) :. Int) a)
55 , P.Fractional (Exp a)
57 => Acc (Array ((ix :. Int) :. Int) a)
58 -> Acc (Array ((ix :. Int) :. Int) a)
59 -> Acc (Array ((ix :. Int) :. Int) a)
62 -- | Term by term division where divisions by 0 produce 0 rather than NaN.
63 termDivNan :: ( Shape ix
68 , P.Fractional (Exp a)
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))
79 , P.Fractional (Exp a)
81 => Acc (Array ((ix :. Int) :. Int) a)
82 -> Acc (Array ((ix :. Int) :. Int) a)
83 -> Acc (Array ((ix :. Int) :. Int) a)
90 , P.Fractional (Exp a)
92 => Acc (Array ((ix :. Int) :. Int) a)
93 -> Acc (Array ((ix :. Int) :. Int) a)
94 -> Acc (Array ((ix :. Int) :. Int) a)
97 -----------------------------------------------------------------------
98 matrixOne :: Num a => Dim -> Acc (Matrix a)
101 ones = fill (index2 n n) 1
105 matrixIdentity :: Num a => Dim -> Acc (Matrix a)
107 let zeros = fill (index2 n n) 0
108 ones = fill (index1 n) 1
111 permute const zeros (\(unindex1 -> i) -> index2 i i) ones
114 matrixEye :: Num a => Dim -> Acc (Matrix a)
116 let ones = fill (index2 n n) 1
117 zeros = fill (index1 n) 0
120 permute const ones (\(unindex1 -> i) -> index2 i i) zeros
123 diagNull :: Num a => Dim -> Acc (Matrix a) -> Acc (Matrix a)
124 diagNull n m = zipWith (*) m (matrixEye n)
126 -----------------------------------------------------------------------
127 _runExp :: Elt e => Exp e -> e
128 _runExp e = indexArray (run (unit e)) Z
130 -----------------------------------------------------------------------
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
140 -- >>> matrix 3 ([1..] :: [Double])
141 -- Matrix (Z :. 3 :. 3)
145 matrix :: Elt c => Int -> [c] -> Matrix c
146 matrix n l = fromList (Z :. n :. n) l
148 -- | Two ways to get the rank (as documentation)
150 -- >>> rank (matrix 3 ([1..] :: [Int]))
152 rank :: (Matrix a) -> Int
153 rank m = arrayRank $ arrayShape m
155 -----------------------------------------------------------------------
156 -- | Dimension of a square Matrix
157 -- How to force use with SquareMatrix ?
160 -- | Get Dimension of a square Matrix
162 -- >>> dim (matrix 3 ([1..] :: [Int]))
164 dim :: Matrix a -> Dim
167 Z :. _ :. n = arrayShape m
168 -- indexTail (arrayShape m)
170 -----------------------------------------------------------------------
172 -- | Sum of a Matrix by Column
174 -- >>> run $ matSumCol 3 (use $ matrix 3 [1..])
175 -- Matrix (Z :. 3 :. 3)
176 -- [ 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
182 matSumCol' :: (Elt a, P.Num (Exp a)) => Matrix a -> Matrix a
183 matSumCol' m = run $ matSumCol n m'
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
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)
200 -- | Diagonal of the matrix
202 -- >>> run $ diag (use $ matrix 3 ([1..] :: [Int]))
203 -- Vector (Z :. 3) [1,5,9]
207 diag m = backpermute (indexTail (shape m))
208 (lift1 (\(Z :. x) -> (Z :. x :. (x :: Exp Int))))
211 -- | Divide by the Diagonal of the matrix
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,
218 divByDiag :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
219 divByDiag d mat = zipWith (/) mat (replicate (constant (Z :. (d :: Int) :. All)) $ diag mat)
221 -----------------------------------------------------------------------
222 -- | Filters the matrix with the minimum of maximums
224 -- >>> run $ matMiniMax $ use $ matrix 3 [1..]
225 -- Matrix (Z :. 3 :. 3)
229 matMiniMax :: (Elt a, Ord a, P.Num a)
232 matMiniMax m = filterWith' miniMax' (constant 0) m
234 miniMax' = the $ minimum $ maximum m
237 -- | Filters the matrix with a constant
239 -- >>> run $ matFilter 5 $ use $ matrix 3 [1..]
240 -- Matrix (Z :. 3 :. 3)
244 filter' :: Double -> Acc (Matrix Double) -> Acc (Matrix Double)
245 filter' t m = filterWith t 0 m
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)
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
254 ------------------------------------------------------------------------
255 ------------------------------------------------------------------------
260 data Direction = MatCol (Exp Int) | MatRow (Exp Int) | Diag
262 nullOf :: Num a => Dim -> Direction -> Acc (Matrix a)
264 let ones = fill (index2 n n) 1
265 zeros = fill (index2 n n) 0
268 permute const ones ( lift1 ( \(Z :. (i :: Exp Int) :. (_j:: Exp Int))
270 MatCol m -> (Z :. i :. m)
271 MatRow m -> (Z :. m :. i)
272 Diag -> (Z :. i :. i)
277 nullOfWithDiag :: Num a => Dim -> Direction -> Acc (Matrix a)
278 nullOfWithDiag n dir = zipWith (*) (nullOf n dir) (nullOf n Diag)
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'
285 divide' a b = ifThenElse (b > (constant 0))
290 sumRowMin :: (Num a, Ord a) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
291 sumRowMin n m = {-trace (P.show $ run m') $-} m'
293 m' = reshape (shape m) vs
295 $ P.map (\z -> sumRowMin1 n (constant z) m) [0..n-1]
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''
300 m'' = sum $ zipWith min (transpose m) m
301 _m' = zipWith (*) (zipWith (*) (nullOf n (MatCol x)) $ nullOfWithDiag n (MatRow x)) m
304 sumColMin :: (Num a, Ord a) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
305 sumColMin n m = reshape (shape m) vs
308 $ P.map (\z -> sumColMin1 n (constant z) m) [0..n-1]
311 sumColMin1 :: (Num a) => Dim -> Exp Int -> Acc (Matrix a) -> Acc (Matrix a)
312 sumColMin1 n x m = zipWith (*) (nullOfWithDiag n (MatCol x)) m
316 {- | WIP fun with indexes
317 selfMatrix :: Num a => Dim -> Acc (Matrix a)
319 let zeros = fill (index2 n n) 0
320 ones = fill (index2 n n) 1
323 permute const ones ( lift1 ( \(Z :. (i :: Exp Int) :. (_j:: Exp Int))
324 -> -- ifThenElse (i /= j)
329 selfMatrix' :: (Elt a, P.Num (Exp a)) => Array DIM2 a -> Matrix a
330 selfMatrix' m' = run $ selfMatrix n
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''
341 m'' = transpose $ cross n m
344 crossT :: Matrix Double -> Matrix Double
345 crossT = run . transpose . use
347 crossProduct' :: Matrix Double -> Matrix Double
348 crossProduct' m = run $ crossProduct n m'
353 runWith :: (Arrays c, Elt a1)
354 => (Dim -> Acc (Matrix a1) -> a2 -> Acc c)
358 runWith f m = run . f (dim m) (use m)
361 cross :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
362 cross n mat = diagNull n (matSumCol n $ diagNull n mat)
364 cross' :: Matrix Double -> Matrix Double
365 cross' mat = run $ cross n mat'
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)
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)
385 theMatrixDouble :: Int -> Matrix Double
386 theMatrixDouble n = run $ map fromIntegral (use $ theMatrixInt n)
388 theMatrixInt :: Int -> Matrix Int
389 theMatrixInt n = matrix n (dataMatrix n)
391 dataMatrix :: Int -> [Int]
392 dataMatrix x | (P.==) x 2 = [ 1, 1
396 | (P.==) x 3 = [ 7, 4, 0
400 | (P.==) x 4 = [ 4, 1, 2, 1
407 | P.otherwise = P.undefined
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 ]
417 => Int -> [e] -> Acc (Array ((Z :. Int) :. Int) e)
418 colMatrix n ns = replicate (constant (Z :. (n :: Int) :. All)) v
420 v = use $ vector (P.length ns) ns
422 -----------------------------------------------------------------------