Distributional.hs 2.17 KB
Newer Older
1
{-|
2 3
Module      : Gargantext.Core.Methods.Distances.Distributional
Description :
4 5 6 7 8 9
Copyright   : (c) CNRS, 2017-Present
License     : AGPL + CECILL v3
Maintainer  : team@gargantext.org
Stability   : experimental
Portability : POSIX

10
Motivation and definition of the @Distributional@ distance.
11 12 13 14 15 16
-}

{-# LANGUAGE BangPatterns      #-}
{-# LANGUAGE Strict            #-}


17
module Gargantext.Core.Methods.Distances.Distributional
18 19 20 21 22 23 24
  where

import Data.Matrix hiding (identity)
import qualified Data.Map as M
import Data.Vector (Vector)
import qualified Data.Vector as V
import Gargantext.Prelude
25
import Gargantext.Core.Viz.Graph.Utils
26 27


28 29
distributional' :: (Floating a, Ord a) => Matrix a -> [((Int, Int), a)]
distributional' m = filter (\((x,y), d) -> foldl' (&&) True (conditions x y d) ) distriList
30 31 32 33 34 35 36
  where
    conditions x y d  =  [ (x /= y)
                         , (d > miniMax')
                         , ((M.lookup (x,y) distriMap) > (M.lookup (y,x) distriMap))
                         ]
    distriList   = toListsWithIndex distriMatrix
    distriMatrix = ri (mi m)
Alexandre Delanoë's avatar
Alexandre Delanoë committed
37

38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
    distriMap    = M.fromList $ distriList
    miniMax'     = miniMax distriMatrix

ri :: (Ord a, Fractional a) => Matrix a -> Matrix a
ri m = matrix c r doRi
  where
    doRi (x,y)     = doRi' x y m
    doRi' x y mi'' = sumMin x y mi'' / (V.sum $ ax Col x y mi'')

    sumMin x y mi' = V.sum $ V.map (\(a,b) -> min a b )
                           $ V.zip (ax Col x y mi') (ax Row x y mi')
    (c,r) = (nOf Col m, nOf Row m)

mi :: (Ord a, Floating a) => Matrix a -> Matrix a
mi m = matrix c r createMat
  where
    (c,r) = (nOf Col m, nOf Row m)
    createMat (x,y) = doMi x y m
56
    doMi x y m' = if x == y then 0 else (max (log (doMi' x y m')) 0 )
Alexandre Delanoë's avatar
Alexandre Delanoë committed
57

58
    doMi' x y m' = (getElem x y m) / ( cross x y m / total m' )
Alexandre Delanoë's avatar
Alexandre Delanoë committed
59

60
    cross x y m' = (V.sum $ ax Col x y m) * (V.sum $ ax Row x y m')
Alexandre Delanoë's avatar
Alexandre Delanoë committed
61

62 63 64 65 66 67 68 69 70 71 72 73 74


ax :: Axis -> Int -> Int -> Matrix a -> Vector a
ax a  i j m  = dropAt j' $ axis a i' m
                  where
                    i' = div i c + 1
                    j' = mod r j + 1
                    (c,r) = (nOf Col m, nOf Row m)

miniMax :: (Ord a) => Matrix a -> a
miniMax m = V.minimum $ V.map (\c -> V.maximum $ getCol c m) (V.enumFromTo 1 (nOf Col m))