Commit 6d939c69 authored by Alexandre Delanoë's avatar Alexandre Delanoë

Merge branch 'flouvain' of ssh://gitlab.iscpif.fr:20022/gargantext/clustering-louvain into flouvain

parents 1141e6bd 5fa87bd9
...@@ -4,7 +4,7 @@ cabal-version: 1.12 ...@@ -4,7 +4,7 @@ cabal-version: 1.12
-- --
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
-- --
-- hash: e6499237b0dc8ea9c12e2947a7c59bbd3dcc7a327e44c0d2d4ee5fff351e6ac6 -- hash: d5768235cb674d3617c860c0be6df203e51373bd36995a8e7df1f612778cdeee
name: clustering-louvain name: clustering-louvain
version: 0.1.0.0 version: 0.1.0.0
...@@ -20,6 +20,7 @@ build-type: Simple ...@@ -20,6 +20,7 @@ build-type: Simple
library library
exposed-modules: exposed-modules:
Data.Graph.Clustering.Example
Data.Graph.Clustering.FLouvain Data.Graph.Clustering.FLouvain
Data.Graph.Clustering.Louvain Data.Graph.Clustering.Louvain
Data.Graph.Clustering.Louvain.Utils Data.Graph.Clustering.Louvain.Utils
...@@ -28,7 +29,6 @@ library ...@@ -28,7 +29,6 @@ library
Data.Graph.Clustering.Louvain.CplusPlus Data.Graph.Clustering.Louvain.CplusPlus
Data.Graph.FGL Data.Graph.FGL
other-modules: other-modules:
Data.Graph.Clustering.Example
Data.Graph.Clustering.HLouvain Data.Graph.Clustering.HLouvain
Data.Graph.Clustering.ILouvain Data.Graph.Clustering.ILouvain
Paths_clustering_louvain Paths_clustering_louvain
...@@ -51,6 +51,25 @@ library ...@@ -51,6 +51,25 @@ library
, vector , vector
default-language: Haskell2010 default-language: Haskell2010
executable run-example
main-is: Main.hs
other-modules:
Paths_clustering_louvain
hs-source-dirs:
app/run-example
default-extensions: ConstrainedClassMethods FlexibleInstances InstanceSigs NoImplicitPrelude OverloadedStrings ScopedTypeVariables TupleSections
ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
build-depends:
base
, clustering-louvain
, containers
, extra
, fgl
, protolude
, text
, vector
default-language: Haskell2010
test-suite louvain-test test-suite louvain-test
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
main-is: Spec.hs main-is: Spec.hs
......
...@@ -26,6 +26,7 @@ default-extensions: ...@@ -26,6 +26,7 @@ default-extensions:
- OverloadedStrings - OverloadedStrings
- ScopedTypeVariables - ScopedTypeVariables
- TupleSections - TupleSections
library: library:
source-dirs: src source-dirs: src
ghc-options: ghc-options:
...@@ -36,6 +37,7 @@ library: ...@@ -36,6 +37,7 @@ library:
- -Wunused-binds - -Wunused-binds
- -Wunused-imports - -Wunused-imports
exposed-modules: exposed-modules:
- Data.Graph.Clustering.Example
- Data.Graph.Clustering.FLouvain - Data.Graph.Clustering.FLouvain
- Data.Graph.Clustering.Louvain - Data.Graph.Clustering.Louvain
- Data.Graph.Clustering.Louvain.Utils - Data.Graph.Clustering.Louvain.Utils
...@@ -51,6 +53,20 @@ library: ...@@ -51,6 +53,20 @@ library:
- turtle - turtle
- foldl - foldl
- simple-reflect - simple-reflect
executables:
run-example:
source-dirs: app/run-example
main: Main.hs
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- base
- clustering-louvain
- fgl
tests: tests:
louvain-test: louvain-test:
main: Spec.hs main: Spec.hs
...@@ -66,7 +82,6 @@ tests: ...@@ -66,7 +82,6 @@ tests:
- hspec - hspec
- hspec-discover - hspec-discover
- HUnit-approx - HUnit-approx
- protolude
# louvain-doctest: # louvain-doctest:
# main: Main.hs # main: Main.hs
......
...@@ -19,7 +19,7 @@ import Data.Graph.Clustering.FLouvain ...@@ -19,7 +19,7 @@ import Data.Graph.Clustering.FLouvain
-- Example call: -- Example call:
-- putStrLn $ prettify $ iterateOnce cuiller -- putStrLn $ prettify $ iterateOnce cuiller
-- Prelude.map (fst3 . unCommunity . snd) $ labNodes $ iterateOnce karate -- Prelude.map (fst3 . unCommunity . snd) $ labNodes $ iterateOnce karate
iterateOnce :: Gr a Double -> CGr a iterateOnce :: Show a => Gr a Double -> CGr a
iterateOnce gr = iteration fgr cgr iterateOnce gr = iteration fgr cgr
where where
fgr = toFGraph gr fgr = toFGraph gr
...@@ -28,11 +28,14 @@ iterateOnce gr = iteration fgr cgr ...@@ -28,11 +28,14 @@ iterateOnce gr = iteration fgr cgr
runFLouvain :: (Show a, Eq a) => Int -> Int -> FGraph a () -> IO () runFLouvain :: (Show a, Eq a) => Int -> Int -> FGraph a () -> IO ()
runFLouvain 0 _ fgr = return () runFLouvain 0 _ fgr = return ()
runFLouvain cycles n fgr = do runFLouvain cycles n fgr = do
putStrLn ("-----------------" :: Text)
putStrLn ("Cycle: " <> show cycles :: Text)
cgr <- runFIterations n fgr cgr <- runFIterations n fgr
let fgrNext = louvainSecondStep fgr cgr let fgrNext = louvainSecondStep fgr cgr
putStrLn ("-----------------" :: Text) putStrLn ("-----------------" :: Text)
putStrLn ("New FGraph:" :: Text) putStrLn ("New FGraph:" :: Text)
putStrLn $ prettify fgrNext --putStrLn $ prettify fgrNext
putStrLn (show fgrNext :: Text)
runFLouvain (cycles - 1) n fgrNext runFLouvain (cycles - 1) n fgrNext
runIterations :: Show a => Int -> Gr a Double -> IO (CGr a) runIterations :: Show a => Int -> Gr a Double -> IO (CGr a)
...@@ -61,12 +64,13 @@ runFIterations n fgr = do ...@@ -61,12 +64,13 @@ runFIterations n fgr = do
runIteration fgr fgrWeight iterCgr i = do runIteration fgr fgrWeight iterCgr i = do
let iterNextCgr = iteration fgr iterCgr let iterNextCgr = iteration fgr iterCgr
putStrLn ("----- ITERATION " <> show i :: Text) putStrLn ("----- ITERATION " <> show i :: Text)
putStrLn $ prettify iterNextCgr --putStrLn $ prettify iterNextCgr
putStrLn (show iterNextCgr :: Text)
putStrLn (show i <> " iteration modularity: " :: Text) putStrLn (show i <> " iteration modularity: " :: Text)
putStrLn $ T.unpack $ show $ modularity fgr iterNextCgr fgrWeight putStrLn $ T.unpack $ show $ modularity fgr iterNextCgr fgrWeight
return iterNextCgr return iterNextCgr
runLouvainFirstStepIterate :: Int -> Gr a Double -> (Modularity, CGr a) runLouvainFirstStepIterate :: Show a => Int -> Gr a Double -> (Modularity, CGr a)
runLouvainFirstStepIterate n gr = (modularity fgr cgr m, cgr) runLouvainFirstStepIterate n gr = (modularity fgr cgr m, cgr)
where where
fgr = toFGraph gr fgr = toFGraph gr
......
...@@ -63,9 +63,9 @@ louvainSecondStep gr cgr = mkFGraph nodes edges ...@@ -63,9 +63,9 @@ louvainSecondStep gr cgr = mkFGraph nodes edges
--nodes = filter (\(_, com) -> length (comNodes com) > 0) $ labNodes cgr --nodes = filter (\(_, com) -> length (comNodes com) > 0) $ labNodes cgr
nodes = labNodes cgr nodes = labNodes cgr
edges :: [(Node, Node, Double)] edges :: [(Node, Node, Double)]
edges = concatMap comEdges $ labNodes cgr edges = concatMap comEdges nodes
comEdges :: LNode (Community c) -> [(Node, Node, Double)] comEdges :: LNode (Community c) -> [(Node, Node, Double)]
comEdges lnCom = mapMaybe (comToComEdge lnCom) $ labNodes cgr comEdges lnCom = mapMaybe (comToComEdge lnCom) nodes
comToComEdge :: LNode (Community c) -> LNode (Community c) -> Maybe (Node, Node, Double) comToComEdge :: LNode (Community c) -> LNode (Community c) -> Maybe (Node, Node, Double)
-- No self-edges -- No self-edges
comToComEdge lnCom1 lnCom2 | lnCom1 == lnCom2 = Nothing comToComEdge lnCom1 lnCom2 | lnCom1 == lnCom2 = Nothing
...@@ -113,7 +113,7 @@ initialCGr gr = gmap singletonCom gr ...@@ -113,7 +113,7 @@ initialCGr gr = gmap singletonCom gr
modularity :: FGraph a b -> CGr c -> GraphWeightSum -> Modularity modularity :: FGraph a b -> CGr c -> GraphWeightSum -> Modularity
modularity gr cgr m = Modularity $ coeff * ( ufold modularity' 0.0 cgr ) modularity gr cgr m = Modularity $ coeff * ( ufold modularity' 0.0 cgr )
where where
coeff = 0.5 / (unGraphWeightSum m) coeff = if (unGraphWeightSum m == 0.0) then 0.0 else 0.5 / (unGraphWeightSum m)
-- Sum over nodes in community -- Sum over nodes in community
-- \Sum A_ij is just the InWeightSum (in formula (1) it is sum of weights -- \Sum A_ij is just the InWeightSum (in formula (1) it is sum of weights
-- between nodes i and j both in the same community, as enforced by the -- between nodes i and j both in the same community, as enforced by the
...@@ -235,7 +235,7 @@ nodeNeighbours :: Node -> CGr c -> [LNode (Community c)] ...@@ -235,7 +235,7 @@ nodeNeighbours :: Node -> CGr c -> [LNode (Community c)]
nodeNeighbours n cgr = nodeNeighbours n cgr =
case nodeCommunity n cgr of case nodeCommunity n cgr of
Nothing -> [] Nothing -> []
Just (cn, _) -> mapMaybe (lnode cgr) (neighbors cgr cn) Just (cn, _) -> mapMaybe (lnode cgr) (neighbors cgr cn)
-- | Find 'Ajd CGrEdge's of 'Community' graph neighbouring a given node -- | Find 'Ajd CGrEdge's of 'Community' graph neighbouring a given node
-- nodeLNeighbours :: Node -> CGr -> Adj CGrEdge -- nodeLNeighbours :: Node -> CGr -> Adj CGrEdge
......
...@@ -91,6 +91,17 @@ spec = do ...@@ -91,6 +91,17 @@ spec = do
mMod mMod
(unModularity mod) (unModularity mod)
it "tests that single community has modularity 0" $ do
let cgr = mkGraph [
(1, Community(nodes simpleGraph, InWeightSum $ sumEdgeWeights $ edges simpleGraph, TotWeightSum 0.0, ()))
] []
m = graphWeight simpleGraph
mod = modularity simpleGraph cgr m
assertApproxEqual "modularities don't match"
0.000001
0.0
(unModularity mod)
it "nodeCommunity works correctly" $ do it "nodeCommunity works correctly" $ do
let cgr = initialCGr simpleGraph let cgr = initialCGr simpleGraph
communities = lnodes cgr communities = lnodes cgr
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment