1 {-| Module : Gargantext.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.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.Viz.Graph.FGL (Graph_Undirected, degree, neighbors, mkGraphUfromEdges)
63 import Gargantext.Viz.Graph.Tools (cooc2graph', Threshold)
64 import Gargantext.Viz.Graph.Index (createIndices, toIndex)
65 type Graph = Graph_Undirected
70 -- TODO chose distance order
71 getMaxCliques :: Ord a => Threshold -> Map (a, a) Int -> [[a]]
72 getMaxCliques t m = map fromIndices $ getMaxCliques' t m'
75 (to,from) = createIndices m
76 fromIndices = catMaybes . map (\n -> Map.lookup n from)
78 getMaxCliques' :: Threshold -> Map (Int, Int) Int -> [[Int]]
79 getMaxCliques' t' n = maxCliques graph
81 graph = mkGraphUfromEdges (Map.keys n')
84 maxCliques :: Graph -> [[Node]]
85 maxCliques g = map (\n -> subMaxCliques g (n:ns)) ns & concat & takeMax
88 ns = sortOn (degree g) $ nodes g
90 subMaxCliques :: Graph -> [Node] -> [[Node]]
91 subMaxCliques _ [] = [[]]
92 subMaxCliques g' (x:xs) = add x $ subMaxCliques g' ns'
94 ns' = [n | n <- xs, elem n $ neighborsOut g' x]
96 add :: Node -> [[Node]] -> [[Node]]
98 add n (m:ms) = [n:m] <> add n ms
99 -- | Note, it is same as :
100 -- add n ns = map (\m -> n : m) ns
101 -- -- (but using pattern matching and recursivity)
102 -- -- (map is redefined in fact)
104 -- | To be sure self is not in neighbors of self
105 -- (out to exclude the self)
106 neighborsOut :: Graph -> Node -> [Node]
107 neighborsOut g'' n = filter (/= n) $ neighbors g'' n
110 takeMax :: [[Node]] -> [[Node]]
117 purge :: [Set Node] -> [Set Node]
119 purge (x:xs) = x' <> purge xs
121 x' = if all (== False) (map (isSubsetOf x) xs)
126 ------------------------------------------------------------------------
128 -- test_graph = mkGraphUfromEdges [(1,1), (2,2), (3,3)]
129 test_graph = mkGraphUfromEdges [(1,2), (3,3)]
132 test_graph' = mkGraphUfromEdges [(1,2), (3,3), (3,2)]
134 test_graph'' :: Graph
135 test_graph'' = mkGraphUfromEdges [(1,2), (2,3), (1,3)]
137 test_graph''' :: Graph
138 test_graph''' = mkGraphUfromEdges [ (4,1)