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.Array.Sugar (Elt(..), Shape(..), Slice(..), (:.))
37 import Data.Array.Accelerate.Smart (Exp(..))
38 import Data.Array.Accelerate.Interpreter (run)
39 import qualified Gargantext.Prelude as P
40 import Data.Array.Accelerate.LinearAlgebra hiding (Matrix, transpose, Vector)
42 -----------------------------------------------------------------------
44 -- Matrix Multiplication
50 => Acc (Array ((ix :. Int) :. Int) a)
51 -> Acc (Array ((ix :. Int) :. Int) a)
52 -> Acc (Array ((ix :. Int) :. Int) a)
53 (#*#) = multiplyMatrixMatrix
56 -- | Matrix cell by cell multiplication
62 => Acc (Array ((ix :. Int) :. Int) a)
63 -> Acc (Array ((ix :. Int) :. Int) a)
64 -> Acc (Array ((ix :. Int) :. Int) a)
71 , P.Fractional (Exp a)
73 => Acc (Array ((ix :. Int) :. Int) a)
74 -> Acc (Array ((ix :. Int) :. Int) a)
75 -> Acc (Array ((ix :. Int) :. Int) a)
79 -----------------------------------------------------------------------
80 matrixOne :: Num a => Dim -> Acc (Matrix a)
83 ones = fill (index2 n n) 1
87 matrixIdentity :: Num a => Dim -> Acc (Matrix a)
89 let zeros = fill (index2 n n) 0
90 ones = fill (index1 n) 1
93 permute const zeros (\(unindex1 -> i) -> index2 i i) ones
96 matrixEye :: Num a => Dim -> Acc (Matrix a)
98 let ones = fill (index2 n n) 1
99 zeros = fill (index1 n) 0
102 permute const ones (\(unindex1 -> i) -> index2 i i) zeros
105 diagNull :: Num a => Dim -> Acc (Matrix a) -> Acc (Matrix a)
106 diagNull n m = zipWith (*) m (matrixEye n)
108 -----------------------------------------------------------------------
109 _runExp :: Elt e => Exp e -> e
110 _runExp e = indexArray (run (unit e)) Z
112 -----------------------------------------------------------------------
116 -- Vector (Z :. 3) [0,1,2]
117 vector :: Elt c => Int -> [c] -> (Array (Z :. Int) c)
118 vector n l = fromList (Z :. n) l
122 -- >>> matrix 3 ([1..] :: [Double])
123 -- Matrix (Z :. 3 :. 3)
127 matrix :: Elt c => Int -> [c] -> Matrix c
128 matrix n l = fromList (Z :. n :. n) l
130 -- | Two ways to get the rank (as documentation)
132 -- >>> rank (matrix 3 ([1..] :: [Int]))
134 rank :: (Matrix a) -> Int
135 rank m = arrayRank $ arrayShape m
137 -----------------------------------------------------------------------
138 -- | Dimension of a square Matrix
139 -- How to force use with SquareMatrix ?
142 -- | Get Dimension of a square Matrix
144 -- >>> dim (matrix 3 ([1..] :: [Int]))
146 dim :: Matrix a -> Dim
149 Z :. _ :. n = arrayShape m
150 -- indexTail (arrayShape m)
152 -----------------------------------------------------------------------
154 -- | Sum of a Matrix by Column
156 -- >>> run $ matSumCol 3 (use $ matrix 3 [1..])
157 -- Matrix (Z :. 3 :. 3)
158 -- [ 12.0, 15.0, 18.0,
161 matSumCol :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
162 matSumCol r mat = replicate (constant (Z :. (r :: Int) :. All)) $ sum $ transpose mat
164 matSumCol' :: Matrix Double -> Matrix Double
165 matSumCol' m = run $ matSumCol n m'
171 -- | Proba computes de probability matrix: all cells divided by thee sum of its column
172 -- if you need get the probability on the lines, just transpose it
174 -- >>> run $ matProba 3 (use $ matrix 3 [1..])
175 -- Matrix (Z :. 3 :. 3)
176 -- [ 8.333333333333333e-2, 0.13333333333333333, 0.16666666666666666,
177 -- 0.3333333333333333, 0.3333333333333333, 0.3333333333333333,
178 -- 0.5833333333333334, 0.5333333333333333, 0.5]
179 matProba :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
180 matProba d mat = zipWith (/) mat (matSumCol d mat)
182 -- | Diagonal of the matrix
184 -- >>> run $ diag (use $ matrix 3 ([1..] :: [Int]))
185 -- Vector (Z :. 3) [1,5,9]
189 diag m = backpermute (indexTail (shape m))
190 (lift1 (\(Z :. x) -> (Z :. x :. (x :: Exp Int))))
193 -- | Divide by the Diagonal of the matrix
195 -- >>> run $ divByDiag 3 (use $ matrix 3 ([1..] :: [Double]))
196 -- Matrix (Z :. 3 :. 3)
197 -- [ 1.0, 0.4, 0.3333333333333333,
198 -- 4.0, 1.0, 0.6666666666666666,
200 divByDiag :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
201 divByDiag d mat = zipWith (/) mat (replicate (constant (Z :. (d :: Int) :. All)) $ diag mat)
203 -----------------------------------------------------------------------
204 -- | Filters the matrix with the minimum of maximums
206 -- >>> run $ matMiniMax $ use $ matrix 3 [1..]
207 -- Matrix (Z :. 3 :. 3)
211 matMiniMax :: (Elt a, Ord a, P.Num a)
214 matMiniMax m = filterWith' miniMax' (constant 0) m
216 miniMax' = the $ minimum $ maximum m
219 -- | Filters the matrix with a constant
221 -- >>> run $ matFilter 5 $ use $ matrix 3 [1..]
222 -- Matrix (Z :. 3 :. 3)
226 filter' :: Double -> Acc (Matrix Double) -> Acc (Matrix Double)
227 filter' t m = filterWith t 0 m
229 filterWith :: Double -> Double -> Acc (Matrix Double) -> Acc (Matrix Double)
230 filterWith t v m = map (\x -> ifThenElse (x > (constant t)) x (constant v)) (transpose m)
232 filterWith' :: (Elt a, Ord a) => Exp a -> Exp a -> Acc (Matrix a) -> Acc (Matrix a)
233 filterWith' t v m = map (\x -> ifThenElse (x > t) x v) m
236 ------------------------------------------------------------------------
237 ------------------------------------------------------------------------
242 data Direction = MatCol (Exp Int) | MatRow (Exp Int) | Diag
244 nullOf :: Num a => Dim -> Direction -> Acc (Matrix a)
246 let ones = fill (index2 n n) 1
247 zeros = fill (index2 n n) 0
250 permute const ones ( lift1 ( \(Z :. (i :: Exp Int) :. (_j:: Exp Int))
252 MatCol m -> (Z :. i :. m)
253 MatRow m -> (Z :. m :. i)
254 Diag -> (Z :. i :. i)
259 nullOfWithDiag :: Num a => Dim -> Direction -> Acc (Matrix a)
260 nullOfWithDiag n dir = zipWith (*) (nullOf n dir) (nullOf n Diag)
263 divide :: (Elt a, Ord a, P.Fractional (Exp a), P.Num a)
264 => Acc (Matrix a) -> Acc (Matrix a) -> Acc (Matrix a)
265 divide = zipWith divide'
267 divide' a b = ifThenElse (b > (constant 0))
272 sumRowMin :: (Num a, Ord a) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
273 sumRowMin n m = {-trace (P.show $ run m') $-} m'
275 m' = reshape (shape m) vs
277 $ P.map (\z -> sumRowMin1 n (constant z) m) [0..n-1]
279 sumRowMin1 :: (Num a, Ord a) => Dim -> Exp Int -> Acc (Matrix a) -> Acc (Vector a)
280 sumRowMin1 n x m = trace (P.show (run m,run $ transpose m)) $ m''
282 m'' = sum $ zipWith min (transpose m) m
283 _m' = zipWith (*) (zipWith (*) (nullOf n (MatCol x)) $ nullOfWithDiag n (MatRow x)) m
286 sumColMin :: (Num a, Ord a) => Dim -> Acc (Matrix a) -> Acc (Matrix a)
287 sumColMin n m = reshape (shape m) vs
290 $ P.map (\z -> sumColMin1 n (constant z) m) [0..n-1]
293 sumColMin1 :: (Num a) => Dim -> Exp Int -> Acc (Matrix a) -> Acc (Matrix a)
294 sumColMin1 n x m = zipWith (*) (nullOfWithDiag n (MatCol x)) m
298 {- | WIP fun with indexes
299 selfMatrix :: Num a => Dim -> Acc (Matrix a)
301 let zeros = fill (index2 n n) 0
302 ones = fill (index2 n n) 1
305 permute const ones ( lift1 ( \(Z :. (i :: Exp Int) :. (_j:: Exp Int))
306 -> -- ifThenElse (i /= j)
311 selfMatrix' :: (Elt a, P.Num (Exp a)) => Array DIM2 a -> Matrix a
312 selfMatrix' m' = run $ selfMatrix n
317 -------------------------------------------------
318 -------------------------------------------------
319 crossProduct :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
320 crossProduct n m = {-trace (P.show (run m',run m'')) $-} zipWith (*) m' m''
323 m'' = transpose $ cross n m
326 crossT :: Matrix Double -> Matrix Double
327 crossT = run . transpose . use
329 crossProduct' :: Matrix Double -> Matrix Double
330 crossProduct' m = run $ crossProduct n m'
335 runWith :: (Arrays c, Elt a1)
336 => (Dim -> Acc (Matrix a1) -> a2 -> Acc c)
340 runWith f m = run . f (dim m) (use m)
343 cross :: Dim -> Acc (Matrix Double) -> Acc (Matrix Double)
344 cross n mat = diagNull n (matSumCol n $ diagNull n mat)
346 cross' :: Matrix Double -> Matrix Double
347 cross' mat = run $ cross n mat'
354 -- | Hypothesis to test maybe later (or not)
355 -- TODO ask accelerate for instances to ease such writtings:
356 p_ :: (Elt e, P.Fractional (Exp e)) => Acc (Array DIM2 e) -> Acc (Array DIM2 e)
357 p_ m = zipWith (/) m (n_ m)
359 n_ :: Elt e => Acc (SymetricMatrix e) -> Acc (Matrix e)
360 n_ m = backpermute (shape m)
361 (lift1 ( \(Z :. (i :: Exp Int) :. (j:: Exp Int))
362 -> (ifThenElse (i < j) (lift (Z :. j :. j)) (lift (Z :. i :. i)) :: Exp DIM2)
367 theMatrix' :: Int -> Matrix Double
368 theMatrix' n = run $ map fromIntegral (use $ theMatrix n)
370 theMatrix :: Int -> Matrix Int
371 theMatrix n = matrix n (dataMatrix n)
373 dataMatrix :: Int -> [Int]
374 dataMatrix x | (P.==) x 2 = [ 1, 1
378 | (P.==) x 3 = [ 1, 1, 2
382 | (P.==) x 4 = [ 1, 1, 2, 3
387 | P.otherwise = P.undefined
390 theResult :: Int -> Matrix Double
391 theResult n | (P.==) n 2 = let r = 1.6094379124341003 in [ 0, r, r, 0]
392 | P.otherwise = [ 1, 1 ]
397 => Int -> [e] -> Acc (Array ((Z :. Int) :. Int) e)
398 colMatrix n ns = replicate (constant (Z :. (n :: Int) :. All)) v
400 v = use $ vector (P.length ns) ns
402 -----------------------------------------------------------------------