haskell-igraph-0.7.1: src/IGraph/Algorithms/Centrality.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module IGraph.Algorithms.Centrality
( closeness
, betweenness
, eigenvectorCentrality
, pagerank
) where
import Control.Monad
import Data.Serialize (Serialize)
import Data.List (foldl')
import System.IO.Unsafe (unsafePerformIO)
import Data.Maybe
import Data.Singletons (SingI)
import Foreign
import Foreign.C.Types
import IGraph
{#import IGraph.Internal #}
{#import IGraph.Internal.Constants #}
#include "haskell_igraph.h"
-- | The normalized closeness centrality of a node is the average length of the
-- shortest path between the node and all other nodes in the graph.
closeness :: Serialize e
=> [Int] -- ^ vertices
-> Graph d v e
-> Bool -- ^ whether to normalize the results
-> Maybe (e -> Double) -- ^ Function to get edge weights
-> [Double]
closeness nds gr normal getEdgeW = unsafePerformIO $ allocaVector $ \result ->
withVerticesList nds $ \vs -> withListMaybe ws $ \ws' -> do
igraphCloseness (_graph gr) result vs IgraphOut ws' normal
toList result
where
ws = case getEdgeW of
Nothing -> Nothing
Just f -> Just $ map (f . snd) $ labEdges gr
{#fun igraph_closeness as ^
{ `IGraph'
, castPtr `Ptr Vector'
, castPtr %`Ptr VertexSelector'
, `Neimode'
, castPtr `Ptr Vector'
, `Bool' } -> `CInt' void- #}
-- | Betweenness centrality
betweenness :: Serialize e
=> [Int]
-> Graph d v e
-> Maybe (e -> Double) -- ^ Function to get edge weights
-> [Double]
betweenness nds gr getEdgeW = unsafePerformIO $ allocaVector $ \result ->
withVerticesList nds $ \vs -> withListMaybe ws $ \ws' -> do
igraphBetweenness (_graph gr) result vs True ws' False
toList result
where
ws = case getEdgeW of
Nothing -> Nothing
Just f -> Just $ map (f . snd) $ labEdges gr
{#fun igraph_betweenness as ^
{ `IGraph'
, castPtr `Ptr Vector'
, castPtr %`Ptr VertexSelector'
, `Bool'
, castPtr `Ptr Vector'
, `Bool' } -> `CInt' void- #}
-- | Eigenvector centrality
eigenvectorCentrality :: Serialize e
=> Graph d v e
-> Maybe (e -> Double) -- ^ Function to get edge weights
-> [Double]
eigenvectorCentrality gr getEdgeW = unsafePerformIO $ allocaArpackOpt $ \arparck ->
allocaVector $ \result -> withListMaybe ws $ \ws' -> do
igraphEigenvectorCentrality (_graph gr) result nullPtr True True ws' arparck
toList result
where
ws = case getEdgeW of
Nothing -> Nothing
Just f -> Just $ map (f . snd) $ labEdges gr
{#fun igraph_eigenvector_centrality as ^
{ `IGraph'
, castPtr `Ptr Vector'
, id `Ptr CDouble'
, `Bool'
, `Bool'
, castPtr `Ptr Vector'
, castPtr `Ptr ArpackOpt' } -> `CInt' void- #}
-- | Google's PageRank algorithm, with option to
pagerank :: (SingI d, Serialize v, Serialize e)
=> Graph d v e
-> Double -- ^ damping factor, usually around 0.85
-> Maybe (v -> Double) -- ^ Node weights or reset probability. If provided,
-- the personalized PageRank will be used
-> Maybe (e -> Double) -- ^ Edge weights
-> [Double]
pagerank gr d getNodeW getEdgeW
| nNodes gr == 0 = []
| fmap (foldl' (+) 0) reset == Just 0 = error "sum of node weight vector must be non-zero"
| otherwise = unsafePerformIO $ alloca $ \p -> allocaVector $ \result ->
withVerticesAll $ \vs -> withListMaybe ws $ \ws' -> do
case reset of
Nothing -> igraphPagerank (_graph gr) IgraphPagerankAlgoPrpack
result p vs (isDirected gr) d ws' nullPtr
Just reset' -> withList reset' $ \reset'' -> igraphPersonalizedPagerank
(_graph gr) IgraphPagerankAlgoPrpack result p vs
(isDirected gr) d reset'' ws' nullPtr
toList result
where
reset = case getNodeW of
Nothing -> Nothing
Just f -> Just $ map (f . snd) $ labNodes gr
ws = case getEdgeW of
Nothing -> Nothing
Just f -> Just $ map (f . snd) $ labEdges gr
{#fun igraph_pagerank as ^
{ `IGraph'
, `PagerankAlgo'
, castPtr `Ptr Vector'
, id `Ptr CDouble'
, castPtr %`Ptr VertexSelector'
, `Bool'
, `Double'
, castPtr `Ptr Vector'
, id `Ptr ()'
} -> `CInt' void- #}
{#fun igraph_personalized_pagerank as ^
{ `IGraph'
, `PagerankAlgo'
, castPtr `Ptr Vector'
, id `Ptr CDouble'
, castPtr %`Ptr VertexSelector'
, `Bool'
, `Double'
, castPtr `Ptr Vector'
, castPtr `Ptr Vector'
, id `Ptr ()'
} -> `CInt' void- #}