packages feed

haskell-igraph-0.1.0: src/IGraph/Structure.hs

module IGraph.Structure
    ( inducedSubgraph
    , closeness
    , betweenness
    , eigenvectorCentrality
    , pagerank
    , personalizedPagerank
    ) where

import Control.Monad
import Foreign
import Foreign.C.Types
import System.IO.Unsafe (unsafePerformIO)
import qualified Data.HashMap.Strict as M
import Data.Hashable (Hashable)

import IGraph
import IGraph.Mutable
import IGraph.Internal.Graph
import IGraph.Internal.Data
import IGraph.Internal.Selector
import IGraph.Internal.Structure
import IGraph.Internal.Arpack
import IGraph.Internal.Constants
import IGraph.Internal.Attribute

inducedSubgraph :: (Hashable v, Eq v, Read v) => LGraph d v e -> [Int] -> LGraph d v e
inducedSubgraph gr vs = unsafePerformIO $ do
    vs' <- listToVector $ map fromIntegral vs
    vsptr <- igraphVsVector vs'
    mallocForeignPtrBytes 160 >>= \gptr -> withForeignPtr gptr $ \p -> do
        igraphInducedSubgraph (_graph gr) p vsptr IgraphSubgraphCreateFromScratch
        let g' = IGraphPtr gptr
            labToId = M.fromListWith (++) $ zip labels $ map return [0..nV-1]
            nV = igraphVcount g'
            labels = map (read . igraphCattributeVAS g' vertexAttr) [0 .. nV-1]
        return $ LGraph g' labToId

-- | closeness centrality
closeness :: [Int]  -- ^ vertices
          -> LGraph d v e
          -> Maybe [Double]  -- ^ optional edge weights
          -> Neimode
          -> Bool   -- ^ whether to normalize
          -> [Double]
closeness vs gr ws mode normal = unsafePerformIO $ do
    vs' <- listToVector $ map fromIntegral vs
    vsptr <- igraphVsVector vs'
    vptr <- igraphVectorNew 0
    ws' <- case ws of
        Just w -> listToVector w
        _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr
    igraphCloseness (_graph gr) vptr vsptr mode ws' normal
    vectorPtrToList vptr

-- | betweenness centrality
betweenness :: [Int]
            -> LGraph d v e
            -> Maybe [Double]
            -> [Double]
betweenness vs gr ws = unsafePerformIO $ do
    vs' <- listToVector $ map fromIntegral vs
    vsptr <- igraphVsVector vs'
    vptr <- igraphVectorNew 0
    ws' <- case ws of
        Just w -> listToVector w
        _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr
    igraphBetweenness (_graph gr) vptr vsptr True ws' False
    vectorPtrToList vptr

-- | eigenvector centrality
eigenvectorCentrality :: LGraph d v e
                      -> Maybe [Double]
                      -> [Double]
eigenvectorCentrality gr ws = unsafePerformIO $ do
    vptr <- igraphVectorNew 0
    ws' <- case ws of
        Just w -> listToVector w
        _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr
    arparck <- igraphArpackNew
    igraphEigenvectorCentrality (_graph gr) vptr nullPtr True True ws' arparck
    vectorPtrToList vptr

-- | Google's PageRank
pagerank :: Graph d
         => LGraph d v e
         -> Maybe [Double]  -- ^ edge weights
         -> Double  -- ^ damping factor, usually around 0.85
         -> [Double]
pagerank gr ws d = unsafePerformIO $ alloca $ \p -> do
    vptr <- igraphVectorNew 0
    vsptr <- igraphVsAll
    ws' <- case ws of
        Just w -> listToVector w
        _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr
    igraphPagerank (_graph gr) IgraphPagerankAlgoPrpack vptr p vsptr
        (isDirected gr) d ws' nullPtr
    vectorPtrToList vptr

personalizedPagerank :: Graph d
                     => LGraph d v e
                     -> [Double]   -- ^ reset probability
                     -> Maybe [Double]
                     -> Double
                     -> [Double]
personalizedPagerank gr reset ws d = unsafePerformIO $ alloca $ \p -> do
    vptr <- igraphVectorNew 0
    vsptr <- igraphVsAll
    ws' <- case ws of
        Just w -> listToVector w
        _ -> liftM VectorPtr $ newForeignPtr_ $ castPtr nullPtr
    reset' <- listToVector reset
    igraphPersonalizedPagerank (_graph gr) IgraphPagerankAlgoPrpack vptr p vsptr
        (isDirected gr) d reset' ws' nullPtr
    vectorPtrToList vptr