{-|
Module      : Gargantext.Core.Viz.Graph.Tools.IGraph
Description : Tools to build Graph
Copyright   : (c) CNRS, 2017-Present
License     : AGPL + CECILL v3
Maintainer  : team@gargantext.org
Stability   : experimental
Portability : POSIX

Reference:
* Gábor Csárdi, Tamás Nepusz: The igraph software package for complex network research. InterJournal Complex Systems, 1695, 2006.

-}

module Gargantext.Core.Viz.Graph.Tools.IGraph
  where

import Data.Serialize
import Data.Singletons (SingI)
import IGraph hiding (mkGraph, neighbors, edges, nodes, Node, Graph)
import Protolude
import Gargantext.Core.Viz.Graph.Index
-- import Graph.Types
import Gargantext.Core.Viz.Graph.Types
import qualified Data.List                   as List
import qualified IGraph                      as IG
import qualified IGraph.Algorithms.Clique    as IG
import qualified IGraph.Algorithms.Community as IG
import qualified IGraph.Algorithms.Structure as IG
import qualified IGraph.Random               as IG
import qualified Data.Map                    as Map

------------------------------------------------------------------
-- | Main Types
type Graph_Undirected = IG.Graph 'U () ()
type Graph_Directed   = IG.Graph 'D () ()

type Node  = IG.Node
type Graph = IG.Graph

------------------------------------------------------------------
-- | Main Graph management Functions
neighbors :: IG.Graph d v e -> IG.Node -> [IG.Node]
neighbors :: Graph d v e -> Node -> [Node]
neighbors = Graph d v e -> Node -> [Node]
forall (d :: EdgeType) v e. Graph d v e -> Node -> [Node]
IG.neighbors

edges :: IG.Graph d v e -> [Edge]
edges :: Graph d v e -> [Edge]
edges = Graph d v e -> [Edge]
forall (d :: EdgeType) v e. Graph d v e -> [Edge]
IG.edges

nodes :: IG.Graph d v e -> [IG.Node]
nodes :: Graph d v e -> [Node]
nodes = Graph d v e -> [Node]
forall (d :: EdgeType) v e. Graph d v e -> [Node]
IG.nodes

------------------------------------------------------------------
-- | Partitions
maximalCliques :: IG.Graph d v e -> [[Int]]
maximalCliques :: Graph d v e -> [[Node]]
maximalCliques Graph d v e
g = Graph d v e -> Edge -> [[Node]]
forall (d :: EdgeType) v e. Graph d v e -> Edge -> [[Node]]
IG.maximalCliques Graph d v e
g (Node
min',Node
max')
  where
    min' :: Node
min' = Node
0
    max' :: Node
max' = Node
0

------------------------------------------------------------------
type Seed = Int

spinglass :: Seed -> Map (Int, Int) Double -> IO [ClusterNode]
spinglass :: Node -> Map Edge Double -> IO [ClusterNode]
spinglass Node
s Map Edge Double
g = [[Node]] -> [ClusterNode]
toClusterNode
             ([[Node]] -> [ClusterNode])
-> ([[Maybe Node]] -> [[Node]]) -> [[Maybe Node]] -> [ClusterNode]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([Maybe Node] -> [Node]) -> [[Maybe Node]] -> [[Node]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map [Maybe Node] -> [Node]
forall a. [Maybe a] -> [a]
catMaybes
             ([[Maybe Node]] -> [ClusterNode])
-> ([[Node]] -> [[Maybe Node]]) -> [[Node]] -> [ClusterNode]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([Node] -> [Maybe Node]) -> [[Node]] -> [[Maybe Node]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map ((Node -> Maybe Node) -> [Node] -> [Maybe Node]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (\Node
n -> Node -> Map Node Node -> Maybe Node
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Node
n Map Node Node
fromI))
             ([[Node]] -> [ClusterNode]) -> IO [[Node]] -> IO [ClusterNode]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Node -> Graph 'U () () -> IO [[Node]]
forall v e.
(Serialize v, Serialize e) =>
Node -> Graph 'U v e -> IO [[Node]]
partitions_spinglass' Node
s Graph 'U () ()
g'''
  where
    g' :: Map Edge Double
g'   = Map Node Node -> Map Edge Double -> Map Edge Double
forall t a. Ord t => Map t Node -> Map (t, t) a -> Map Edge a
toIndex Map Node Node
toI Map Edge Double
g
    g'' :: Graph 'U () ()
g''  = [Edge] -> Graph 'U () ()
mkGraphUfromEdges (Map Edge Double -> [Edge]
forall k a. Map k a -> [k]
Map.keys Map Edge Double
g')
    g''' :: Graph 'U () ()
g''' = case Graph 'U () () -> Bool
forall (d :: EdgeType) v e. Graph d v e -> Bool
IG.isConnected Graph 'U () ()
g'' of
      Bool
True -> Graph 'U () ()
g''
      Bool
False -> case [Graph 'U () ()] -> Maybe (Graph 'U () ())
forall (f :: * -> *) a. Foldable f => f a -> Maybe a
head (Graph 'U () () -> [Graph 'U () ()]
forall v (d :: EdgeType) e.
(Ord v, Serialize v) =>
Graph d v e -> [Graph d v e]
IG.decompose Graph 'U () ()
g'') of
        Maybe (Graph 'U () ())
Nothing    -> Text -> Graph 'U () ()
forall a. HasCallStack => Text -> a
panic Text
"[G.C.V.G.T.Igraph: not connected graph]"
        Just Graph 'U () ()
g'''' -> Graph 'U () ()
g''''

    (Map Node Node
toI, Map Node Node
fromI) = Map Edge Double -> (Map Node Node, Map Node Node)
forall t b. Ord t => Map (t, t) b -> (Map t Node, Map Node t)
createIndices Map Edge Double
g

-- | Tools to analyze graphs
partitions_spinglass' :: (Serialize v, Serialize e)
                         => Seed -> IG.Graph 'U v e -> IO [[Int]]
partitions_spinglass' :: Node -> Graph 'U v e -> IO [[Node]]
partitions_spinglass' Node
s Graph 'U v e
g = do
  Gen
gen <- Node -> (Gen -> IO Gen) -> IO Gen
forall a. Node -> (Gen -> IO a) -> IO a
IG.withSeed Node
s Gen -> IO Gen
forall (f :: * -> *) a. Applicative f => a -> f a
pure
  Graph 'U v e
-> Maybe (Node -> v -> Double)
-> Maybe (e -> Double)
-> CommunityMethod
-> Gen
-> IO [[Node]]
forall v e.
(Serialize v, Serialize e) =>
Graph 'U v e
-> Maybe (Node -> v -> Double)
-> Maybe (e -> Double)
-> CommunityMethod
-> Gen
-> IO [[Node]]
IG.findCommunity Graph 'U v e
g Maybe (Node -> v -> Double)
forall a. Maybe a
Nothing Maybe (e -> Double)
forall a. Maybe a
Nothing CommunityMethod
IG.spinglass Gen
gen


toClusterNode :: [[Int]] -> [ClusterNode]
toClusterNode :: [[Node]] -> [ClusterNode]
toClusterNode [[Node]]
ns = [[ClusterNode]] -> [ClusterNode]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
List.concat
                 ([[ClusterNode]] -> [ClusterNode])
-> [[ClusterNode]] -> [ClusterNode]
forall a b. (a -> b) -> a -> b
$ ((Node, [Node]) -> [ClusterNode])
-> [(Node, [Node])] -> [[ClusterNode]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (\(Node
cId, [Node]
ns') -> (Node -> ClusterNode) -> [Node] -> [ClusterNode]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
map (\Node
n -> Node -> Node -> ClusterNode
ClusterNode Node
n Node
cId) [Node]
ns')
                 ([(Node, [Node])] -> [[ClusterNode]])
-> [(Node, [Node])] -> [[ClusterNode]]
forall a b. (a -> b) -> a -> b
$ [Node] -> [[Node]] -> [(Node, [Node])]
forall a b. [a] -> [b] -> [(a, b)]
List.zip [Node
1..] [[Node]]
ns

------------------------------------------------------------------
mkGraph :: (SingI d, Ord v,
             Serialize v, Serialize e) =>
     [v] -> [LEdge e] -> IG.Graph d v e
mkGraph :: [v] -> [LEdge e] -> Graph d v e
mkGraph = [v] -> [LEdge e] -> Graph d v e
forall (d :: EdgeType) v e.
(SingI d, Serialize v, Ord v, Serialize e) =>
[v] -> [LEdge e] -> Graph d v e
IG.mkGraph

------------------------------------------------------------------
mkGraphUfromEdges :: [(Int, Int)] -> Graph_Undirected
mkGraphUfromEdges :: [Edge] -> Graph 'U () ()
mkGraphUfromEdges [Edge]
es = [()] -> [LEdge ()] -> Graph 'U () ()
forall (d :: EdgeType) v e.
(SingI d, Ord v, Serialize v, Serialize e) =>
[v] -> [LEdge e] -> Graph d v e
mkGraph (Node -> () -> [()]
forall a. Node -> a -> [a]
List.replicate Node
n ()) ([LEdge ()] -> Graph 'U () ()) -> [LEdge ()] -> Graph 'U () ()
forall a b. (a -> b) -> a -> b
$ [Edge] -> [()] -> [LEdge ()]
forall a b. [a] -> [b] -> [(a, b)]
zip [Edge]
es ([()] -> [LEdge ()]) -> [()] -> [LEdge ()]
forall a b. (a -> b) -> a -> b
$ () -> [()]
forall a. a -> [a]
repeat ()
  where
    ([Node]
a,[Node]
b) = [Edge] -> ([Node], [Node])
forall a b. [(a, b)] -> ([a], [b])
List.unzip [Edge]
es
    n :: Node
n = [Node] -> Node
forall (t :: * -> *) a. Foldable t => t a -> Node
List.length ([Node] -> [Node]
forall a. Eq a => [a] -> [a]
List.nub ([Node] -> [Node]) -> [Node] -> [Node]
forall a b. (a -> b) -> a -> b
$ [Node]
a [Node] -> [Node] -> [Node]
forall a. Semigroup a => a -> a -> a
<> [Node]
b)

{-
mkGraphDfromEdges :: [(Int, Int)] -> Graph_Directed
mkGraphDfromEdges = undefined
-}