1 {-| Module : Gargantext.Core.Viz.Graph.MaxClique
2 Description : MaxCliques function
3 Copyright : (c) CNRS, 2017-Present
4 License : AGPL + CECILL v3
5 Maintainer : team@gargantext.org
6 Stability : experimental
9 - First written by Bruno Gaume in Python (see below for details)
10 - Then written by Alexandre Delanoë in Haskell (see below for details)
13 def fast_maximal_cliques(g):
15 def rec_maximal_cliques(g, subv):
17 if subv == []: # stop condition
20 for i in range(len(subv)):
21 newsubv = [j for j in subv[i+1:len(subv)]
22 if (j in g.neighbors(subv[i]))]
23 mci = rec_maximal_cliques(g, newsubv)
30 clustset = [set(x) for x in clust]
32 for i in range(len(clustset)):
34 for j in range(len(clustset)):
35 if clustset[i].issubset(clustset[j]) and (not (len(clustset[i]) == len(clustset[j])) ):
37 if ok and (not (clustset[i] in new_clust)):
38 new_clust.append(clustset[i])
39 return [list(x) for x in new_clust]
41 # to optimize : rank the vertices on the degrees
42 subv = [(v.index, v.degree()) for v in g.vs()]
43 subv.sort(key = lambda z:z[1])
44 subv = [x for (x, y) in subv]
45 return purge(rec_maximal_cliques(g, subv))
51 module Gargantext.Core.Viz.Graph.MaxClique
54 import Data.Maybe (catMaybes)
55 import Gargantext.Prelude
57 import qualified Data.Map as Map
58 import Data.List (sortOn, nub, concat, length)
60 import Data.Set (fromList, toList, isSubsetOf)
61 import Data.Graph.Inductive hiding (Graph, neighbors, subgraph, (&))
62 import Gargantext.Core.Viz.Graph.FGL (Graph_Undirected, degree, neighbors, mkGraphUfromEdges)
63 import Gargantext.Core.Viz.Graph.Tools (cooc2graph', Threshold)
64 import Gargantext.Core.Viz.Graph.Distances (Distance)
65 import Gargantext.Core.Viz.Graph.Index (createIndices, toIndex)
66 type Graph = Graph_Undirected
71 -- TODO chose distance order
72 getMaxCliques :: Ord a => Distance -> Threshold -> Map (a, a) Int -> [[a]]
73 getMaxCliques d t m = map fromIndices $ getMaxCliques' t m'
76 (to,from) = createIndices m
77 fromIndices = catMaybes . map (\n -> Map.lookup n from)
79 getMaxCliques' :: Threshold -> Map (Int, Int) Int -> [[Int]]
80 getMaxCliques' t' n = maxCliques graph
82 graph = mkGraphUfromEdges (Map.keys n')
83 n' = cooc2graph' d t' n
85 maxCliques :: Graph -> [[Node]]
86 maxCliques g = map (\n -> subMaxCliques g (n:ns)) ns & concat & takeMax
89 ns = sortOn (degree g) $ nodes g
91 subMaxCliques :: Graph -> [Node] -> [[Node]]
92 subMaxCliques _ [] = [[]]
93 subMaxCliques g' (x:xs) = add x $ subMaxCliques g' ns'
95 ns' = [n | n <- xs, elem n $ neighborsOut g' x]
97 add :: Node -> [[Node]] -> [[Node]]
99 add n (m:ms) = [n:m] <> add n ms
100 -- | Note, it is same as :
101 -- add n ns = map (\m -> n : m) ns
102 -- -- (but using pattern matching and recursivity)
103 -- -- (map is redefined in fact)
105 -- | To be sure self is not in neighbors of self
106 -- (out to exclude the self)
107 neighborsOut :: Graph -> Node -> [Node]
108 neighborsOut g'' n = filter (/= n) $ neighbors g'' n
111 takeMax :: [[Node]] -> [[Node]]
118 purge :: [Set Node] -> [Set Node]
120 purge (x:xs) = x' <> purge xs
122 x' = if all (== False) (map (isSubsetOf x) xs)
127 ------------------------------------------------------------------------
129 -- test_graph = mkGraphUfromEdges [(1,1), (2,2), (3,3)]
130 test_graph = mkGraphUfromEdges [(1,2), (3,3)]
133 test_graph' = mkGraphUfromEdges [(1,2), (3,3), (3,2)]
135 test_graph'' :: Graph
136 test_graph'' = mkGraphUfromEdges [(1,2), (2,3), (1,3)]
138 test_graph''' :: Graph
139 test_graph''' = mkGraphUfromEdges [ (4,1)