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 import Debug.Trace (trace)
41 -- | Matrix cell by cell multiplication
47 => Acc (Array ((ix :. Int) :. Int) a)
48 -> Acc (Array ((ix :. Int) :. Int) a)
49 -> Acc (Array ((ix :. Int) :. Int) a)
57 , P.Fractional (Exp a)
59 => Acc (Array ((ix :. Int) :. Int) a)
60 -> Acc (Array ((ix :. Int) :. Int) a)
61 -> Acc (Array ((ix :. Int) :. Int) a)
64 -- | Term by term division where divisions by 0 produce 0 rather than NaN.
65 termDivNan :: ( Shape ix
70 , P.Fractional (Exp a)
72 => Acc (Array ((ix :. Int) :. Int) a)
73 -> Acc (Array ((ix :. Int) :. Int) a)
74 -> Acc (Array ((ix :. Int) :. Int) a)
75 termDivNan = trace "termDivNan" $ zipWith (\i j -> cond ((==) j 0) 0 ((/) i j))
81 , P.Fractional (Exp a)
83 => Acc (Array ((ix :. Int) :. Int) a)
84 -> Acc (Array ((ix :. Int) :. Int) a)
85 -> Acc (Array ((ix :. Int) :. Int) a)
92 , P.Fractional (Exp a)
94 => Acc (Array ((ix :. Int) :. Int) a)
95 -> Acc (Array ((ix :. Int) :. Int) a)
96 -> Acc (Array ((ix :. Int) :. Int) a)
99 -----------------------------------------------------------------------
100 matrixOne :: Num a => Dim -> Acc (Matrix a)
103 ones = fill (index2 n n) 1
107 matrixIdentity :: Num a => Dim -> Acc (Matrix a)
109 let zeros = fill (index2 n n) 0
110 ones = fill (index1 n) 1
113 permute const zeros (\(unindex1 -> i) -> Just_ $ index2 i i) ones
116 matrixEye :: Num a => Dim -> Acc (Matrix a)
118 let ones = fill (index2 n n) 1
119 zeros = fill (index1 n) 0
122 permute const ones (\(unindex1 -> i) -> Just_ $ index2 i i) zeros
125 diagNull :: Num a => Dim -> Acc (Matrix a) -> Acc (Matrix a)
126 diagNull n m = trace ("diagNull") $ zipWith (*) m (matrixEye n)
129 -- Returns an N-dimensional array with the values of x for the indices where
130 -- the condition is true, 0 everywhere else.
132 :: forall sh a. (Shape sh, Elt a)
133 => (Exp sh -> Exp Bool) -> Exp a -> Acc (Array sh a) -> Acc (Array sh a)
134 condOrDefault theCond def x = permute const zeros filterInd x
136 zeros = fill (shape x) (def)
137 filterInd ix = (cond (theCond ix)) (Just_ ix) Nothing_
139 -----------------------------------------------------------------------
140 _runExp :: Elt e => Exp e -> e
141 _runExp e = indexArray (run (unit e)) Z
143 -----------------------------------------------------------------------
147 -- Vector (Z :. 3) [0,1,2]
148 vector :: Elt c => Int -> [c] -> (Array (Z :. Int) c)
149 vector n l = fromList (Z :. n) l
153 -- >>> matrix 3 ([1..] :: [Double])
154 -- Matrix (Z :. 3 :. 3)
158 matrix :: Elt c => Int -> [c] -> Matrix c
159 matrix n l = fromList (Z :. n :. n) l
161 -- | Two ways to get the rank (as documentation)
163 -- >>> rank (matrix 3 ([1..] :: [Int]))
165 rank :: (Matrix a) -> Int
168 -----------------------------------------------------------------------
169 -- | Dimension of a square Matrix
170 -- How to force use with SquareMatrix ?
173 -- | Get Dimension of a square Matrix
175 -- >>> dim (matrix 3 ([1..] :: [Int]))
177 dim :: Matrix a -> Dim
180 Z :. _ :. n = arrayShape m
181 -- indexTail (arrayShape m)
183 -----------------------------------------------------------------------
185 -- | Sum of a Matrix by Column
187 -- >>> run $ matSumCol 3 (use $ matrix 3 [1..])
188 -- Matrix (Z :. 3 :. 3)
189 -- [ 12.0, 15.0, 18.0,
192 matSumCol :: (Elt a, P.Num (Exp a)) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
193 matSumCol r mat = replicate (constant (Z :. (r :: Int) :. All)) $ sum $ transpose mat
195 matSumCol' :: (Elt a, P.Num (Exp a)) => Matrix a -> Matrix a
196 matSumCol' m = run $ matSumCol n m'
202 -- | Proba computes de probability matrix: all cells divided by thee sum of its column
203 -- if you need get the probability on the lines, just transpose it
205 -- >>> run $ matProba 3 (use $ matrix 3 [1..])
206 -- Matrix (Z :. 3 :. 3)
207 -- [ 8.333333333333333e-2, 0.13333333333333333, 0.16666666666666666,
208 -- 0.3333333333333333, 0.3333333333333333, 0.3333333333333333,
209 -- 0.5833333333333334, 0.5333333333333333, 0.5]
210 matProba :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
211 matProba d mat = zipWith (/) mat (matSumCol d mat)
213 -- | Diagonal of the matrix
215 -- >>> run $ diag (use $ matrix 3 ([1..] :: [Int]))
216 -- Vector (Z :. 3) [1,5,9]
220 diag m = backpermute (indexTail (shape m))
221 (lift1 (\(Z :. x) -> (Z :. x :. (x :: Exp Int))))
224 -- | Divide by the Diagonal of the matrix
226 -- >>> run $ divByDiag 3 (use $ matrix 3 ([1..] :: [Double]))
227 -- Matrix (Z :. 3 :. 3)
228 -- [ 1.0, 0.4, 0.3333333333333333,
229 -- 4.0, 1.0, 0.6666666666666666,
231 divByDiag :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
232 divByDiag d mat = zipWith (/) mat (replicate (constant (Z :. (d :: Int) :. All)) $ diag mat)
234 -----------------------------------------------------------------------
235 -- | Filters the matrix with the minimum of maximums
237 -- >>> run $ matMiniMax $ use $ matrix 3 [1..]
238 -- Matrix (Z :. 3 :. 3)
242 matMiniMax :: (Elt a, Ord a, P.Num a)
245 matMiniMax m = trace "matMiniMax" $ filterWith' miniMax' (constant 0) m
247 miniMax' = the $ maximum $ minimum m
250 -- | Filters the matrix with a constant
252 -- >>> run $ matFilter 5 $ use $ matrix 3 [1..]
253 -- Matrix (Z :. 3 :. 3)
257 filter' :: Double -> Acc (Matrix Double) -> Acc (Matrix Double)
258 filter' t m = filterWith t 0 m
260 filterWith :: Double -> Double -> Acc (Matrix Double) -> Acc (Matrix Double)
261 filterWith t v m = map (\x -> ifThenElse (x > (constant t)) x (constant v)) (transpose m)
263 filterWith' :: (Elt a, Ord a) => Exp a -> Exp a -> Acc (Matrix a) -> Acc (Matrix a)
264 filterWith' t v m = map (\x -> ifThenElse (x > t) x v) m
267 ------------------------------------------------------------------------
268 ------------------------------------------------------------------------
273 data Direction = MatCol (Exp Int) | MatRow (Exp Int) | Diag
275 nullOf :: Num a => Dim -> Direction -> Acc (Matrix a)
277 let ones = fill (index2 n n) 1
278 zeros = fill (index2 n n) 0
281 permute const ones ( Just_ . lift1 ( \(Z :. (i :: Exp Int) :. (_j:: Exp Int))
283 MatCol m -> (Z :. i :. m)
284 MatRow m -> (Z :. m :. i)
285 Diag -> (Z :. i :. i)
290 nullOfWithDiag :: Num a => Dim -> Direction -> Acc (Matrix a)
291 nullOfWithDiag n dir = zipWith (*) (nullOf n dir) (nullOf n Diag)
294 divide :: (Elt a, Ord a, P.Fractional (Exp a), P.Num a)
295 => Acc (Matrix a) -> Acc (Matrix a) -> Acc (Matrix a)
296 divide = zipWith divide'
298 divide' a b = ifThenElse (b > (constant 0))
303 sumRowMin :: (Num a, Ord a) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
304 sumRowMin n m = {-trace (P.show $ run m') $-} m'
306 m' = reshape (shape m) vs
308 $ P.map (\z -> sumRowMin1 n (constant z) m) [0..n-1]
310 sumRowMin1 :: (Num a, Ord a) => Dim -> Exp Int -> Acc (Matrix a) -> Acc (Vector a)
311 sumRowMin1 n x m = {-trace (P.show (run m,run $ transpose m)) $-} m''
313 m'' = sum $ zipWith min (transpose m) m
314 _m' = zipWith (*) (zipWith (*) (nullOf n (MatCol x)) $ nullOfWithDiag n (MatRow x)) m
317 sumColMin :: (Num a, Ord a) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
318 sumColMin n m = reshape (shape m) vs
321 $ P.map (\z -> sumColMin1 n (constant z) m) [0..n-1]
324 sumColMin1 :: (Num a) => Dim -> Exp Int -> Acc (Matrix a) -> Acc (Matrix a)
325 sumColMin1 n x m = zipWith (*) (nullOfWithDiag n (MatCol x)) m
329 {- | WIP fun with indexes
330 selfMatrix :: Num a => Dim -> Acc (Matrix a)
332 let zeros = fill (index2 n n) 0
333 ones = fill (index2 n n) 1
336 permute const ones ( lift1 ( \(Z :. (i :: Exp Int) :. (_j:: Exp Int))
337 -> -- ifThenElse (i /= j)
342 selfMatrix' :: (Elt a, P.Num (Exp a)) => Array DIM2 a -> Matrix a
343 selfMatrix' m' = run $ selfMatrix n
348 -------------------------------------------------
349 -------------------------------------------------
350 crossProduct :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
351 crossProduct n m = {-trace (P.show (run m',run m'')) $-} zipWith (*) m' m''
354 m'' = transpose $ cross n m
357 crossT :: Matrix Double -> Matrix Double
358 crossT = run . transpose . use
360 crossProduct' :: Matrix Double -> Matrix Double
361 crossProduct' m = run $ crossProduct n m'
366 runWith :: (Arrays c, Elt a1)
367 => (Dim -> Acc (Matrix a1) -> a2 -> Acc c)
371 runWith f m = run . f (dim m) (use m)
374 cross :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
375 cross n mat = diagNull n (matSumCol n $ diagNull n mat)
377 cross' :: Matrix Double -> Matrix Double
378 cross' mat = run $ cross n mat'
385 -- | Hypothesis to test maybe later (or not)
386 -- TODO ask accelerate for instances to ease such writtings:
387 p_ :: (Elt e, P.Fractional (Exp e)) => Acc (Array DIM2 e) -> Acc (Array DIM2 e)
388 p_ m = zipWith (/) m (n_ m)
390 n_ :: Elt e => Acc (SymetricMatrix e) -> Acc (Matrix e)
391 n_ m = backpermute (shape m)
392 (lift1 ( \(Z :. (i :: Exp Int) :. (j:: Exp Int))
393 -> (ifThenElse (i < j) (lift (Z :. j :. j)) (lift (Z :. i :. i)) :: Exp DIM2)
398 theMatrixDouble :: Int -> Matrix Double
399 theMatrixDouble n = run $ map fromIntegral (use $ theMatrixInt n)
401 theMatrixInt :: Int -> Matrix Int
402 theMatrixInt n = matrix n (dataMatrix n)
404 dataMatrix :: Int -> [Int]
405 dataMatrix x | (P.==) x 2 = [ 1, 1
409 | (P.==) x 3 = [ 7, 4, 0
413 | (P.==) x 4 = [ 4, 1, 2, 1
420 | P.otherwise = P.undefined
423 theResult :: Int -> Matrix Double
424 theResult n | (P.==) n 2 = let r = 1.6094379124341003 in [ 0, r, r, 0]
425 | P.otherwise = [ 1, 1 ]
430 => Int -> [e] -> Acc (Array ((Z :. Int) :. Int) e)
431 colMatrix n ns = replicate (constant (Z :. (n :: Int) :. All)) v
433 v = use $ vector (P.length ns) ns
435 -----------------------------------------------------------------------