Commit 70af5ab8 authored by Kai Zhang's avatar Kai Zhang

add PageRank test

parent 59904c7f
...@@ -55,7 +55,6 @@ library ...@@ -55,7 +55,6 @@ library
, bytestring >= 0.9 , bytestring >= 0.9
, bytestring-lexing >= 0.5 , bytestring-lexing >= 0.5
, cereal , cereal
, cereal-conduit
, colour , colour
, conduit >= 1.3.0 , conduit >= 1.3.0
, data-ordlist , data-ordlist
......
...@@ -45,7 +45,6 @@ import Control.Arrow ((&&&)) ...@@ -45,7 +45,6 @@ import Control.Arrow ((&&&))
import Control.Monad (forM, forM_, liftM, replicateM, when) import Control.Monad (forM, forM_, liftM, replicateM, when)
import Control.Monad.Primitive import Control.Monad.Primitive
import Control.Monad.ST (runST) import Control.Monad.ST (runST)
import Data.Conduit.Cereal
import Data.Either (fromRight) import Data.Either (fromRight)
import Data.Hashable (Hashable) import Data.Hashable (Hashable)
import qualified Data.HashMap.Strict as M import qualified Data.HashMap.Strict as M
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
module IGraph.Generators module IGraph.Generators
( full ( full
, star
, ErdosRenyiModel(..) , ErdosRenyiModel(..)
, erdosRenyiGame , erdosRenyiGame
, degreeSequenceGame , degreeSequenceGame
...@@ -44,6 +45,20 @@ full n hasLoop = unsafePerformIO $ do ...@@ -44,6 +45,20 @@ full n hasLoop = unsafePerformIO $ do
, `Int', `Bool', `Bool' , `Int', `Bool', `Bool'
} -> `CInt' void- #} } -> `CInt' void- #}
-- | Return the Star graph. The center node is always associated with id 0.
star :: Int -- ^ The number of nodes
-> Graph 'U () ()
star n = unsafePerformIO $ do
gr <- MGraph <$> igraphStar n IgraphStarUndirected 0
M.initializeNullAttribute gr
unsafeFreeze gr
{# fun igraph_star as ^
{ allocaIGraph- `IGraph' addIGraphFinalizer*
, `Int'
, `StarMode'
, `Int'
} -> `CInt' void- #}
data ErdosRenyiModel = GNP Int Double data ErdosRenyiModel = GNP Int Double
| GNM Int Int | GNM Int Int
......
...@@ -55,6 +55,7 @@ module IGraph.Internal ...@@ -55,6 +55,7 @@ module IGraph.Internal
, allocaIGraph , allocaIGraph
, addIGraphFinalizer , addIGraphFinalizer
, igraphNew , igraphNew
, igraphCreate
-- * Selector and iterator for edge and vertex -- * Selector and iterator for edge and vertex
-- ** Igraph vertex selector -- ** Igraph vertex selector
...@@ -370,6 +371,18 @@ addIGraphFinalizer ptr = do ...@@ -370,6 +371,18 @@ addIGraphFinalizer ptr = do
, `IGraph' , `IGraph'
} -> `CInt' void- #} } -> `CInt' void- #}
{#fun igraph_create as ^
{ allocaIGraph- `IGraph' addIGraphFinalizer*
, castPtr `Ptr Vector' -- ^ The edges to add, the first two elements are
-- the first edge, etc.
, `Int' -- ^ The number of vertices in the graph, if smaller or equal to
-- the highest vertex id in the edges vector it will be
-- increased automatically. So it is safe to give 0 here.
, `Bool' -- ^ Whether to create a directed graph or not. If yes,
-- then the first edge points from the first vertex id in edges
-- to the second, etc.
} -> `CInt' void- #}
-- | Create a igraph object and attach a finalizer -- | Create a igraph object and attach a finalizer
igraphNew :: Int -> Bool -> HasInit -> IO IGraph igraphNew :: Int -> Bool -> HasInit -> IO IGraph
igraphNew n directed _ = igraphNew' n directed igraphNew n directed _ = igraphNew' n directed
......
...@@ -30,5 +30,8 @@ module IGraph.Internal.Constants where ...@@ -30,5 +30,8 @@ module IGraph.Internal.Constants where
{#enum igraph_rewiring_t as Rewiring {underscoreToCase} {#enum igraph_rewiring_t as Rewiring {underscoreToCase}
deriving (Show, Read, Eq) #} deriving (Show, Read, Eq) #}
{#enum igraph_star_mode_t as StarMode {underscoreToCase}
deriving (Show, Read, Eq) #}
{#enum igraph_degseq_t as Degseq {underscoreToCase} {#enum igraph_degseq_t as Degseq {underscoreToCase}
deriving (Show, Read, Eq) #} deriving (Show, Read, Eq) #}
...@@ -5,7 +5,6 @@ module IGraph.Structure ...@@ -5,7 +5,6 @@ module IGraph.Structure
, betweenness , betweenness
, eigenvectorCentrality , eigenvectorCentrality
, pagerank , pagerank
, personalizedPagerank
) where ) where
import Control.Monad import Control.Monad
...@@ -34,6 +33,12 @@ inducedSubgraph :: (Hashable v, Eq v, Serialize v) ...@@ -34,6 +33,12 @@ inducedSubgraph :: (Hashable v, Eq v, Serialize v)
inducedSubgraph gr nds = unsafePerformIO $ withVerticesList nds $ \vs -> inducedSubgraph gr nds = unsafePerformIO $ withVerticesList nds $ \vs ->
igraphInducedSubgraph (_graph gr) vs IgraphSubgraphCreateFromScratch >>= igraphInducedSubgraph (_graph gr) vs IgraphSubgraphCreateFromScratch >>=
unsafeFreeze . MGraph unsafeFreeze . MGraph
{#fun igraph_induced_subgraph as ^
{ `IGraph'
, allocaIGraph- `IGraph' addIGraphFinalizer*
, castPtr %`Ptr VertexSelector'
, `SubgraphImplementation'
} -> `CInt' void- #}
-- | Closeness centrality -- | Closeness centrality
closeness :: [Int] -- ^ vertices closeness :: [Int] -- ^ vertices
...@@ -46,6 +51,14 @@ closeness nds gr ws mode normal = unsafePerformIO $ allocaVector $ \result -> ...@@ -46,6 +51,14 @@ closeness nds gr ws mode normal = unsafePerformIO $ allocaVector $ \result ->
withVerticesList nds $ \vs -> withListMaybe ws $ \ws' -> do withVerticesList nds $ \vs -> withListMaybe ws $ \ws' -> do
igraphCloseness (_graph gr) result vs mode ws' normal igraphCloseness (_graph gr) result vs mode ws' normal
toList result toList result
{#fun igraph_closeness as ^
{ `IGraph'
, castPtr `Ptr Vector'
, castPtr %`Ptr VertexSelector'
, `Neimode'
, castPtr `Ptr Vector'
, `Bool' } -> `CInt' void- #}
-- | Betweenness centrality -- | Betweenness centrality
betweenness :: [Int] betweenness :: [Int]
...@@ -56,6 +69,13 @@ betweenness nds gr ws = unsafePerformIO $ allocaVector $ \result -> ...@@ -56,6 +69,13 @@ betweenness nds gr ws = unsafePerformIO $ allocaVector $ \result ->
withVerticesList nds $ \vs -> withListMaybe ws $ \ws' -> do withVerticesList nds $ \vs -> withListMaybe ws $ \ws' -> do
igraphBetweenness (_graph gr) result vs True ws' False igraphBetweenness (_graph gr) result vs True ws' False
toList result toList result
{#fun igraph_betweenness as ^
{ `IGraph'
, castPtr `Ptr Vector'
, castPtr %`Ptr VertexSelector'
, `Bool'
, castPtr `Ptr Vector'
, `Bool' } -> `CInt' void- #}
-- | Eigenvector centrality -- | Eigenvector centrality
eigenvectorCentrality :: Graph d v e eigenvectorCentrality :: Graph d v e
...@@ -65,77 +85,39 @@ eigenvectorCentrality gr ws = unsafePerformIO $ allocaArpackOpt $ \arparck -> ...@@ -65,77 +85,39 @@ eigenvectorCentrality gr ws = unsafePerformIO $ allocaArpackOpt $ \arparck ->
allocaVector $ \result -> withListMaybe ws $ \ws' -> do allocaVector $ \result -> withListMaybe ws $ \ws' -> do
igraphEigenvectorCentrality (_graph gr) result nullPtr True True ws' arparck igraphEigenvectorCentrality (_graph gr) result nullPtr True True ws' arparck
toList result toList result
{#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 -- | Google's PageRank algorithm, with option to
pagerank :: SingI d pagerank :: SingI d
=> Graph d v e => Graph d v e
-> Maybe [Double] -- ^ edge weights -> Maybe [Double] -- ^ Node weights or reset probability. If provided,
-- the personalized PageRank will be used
-> Maybe [Double] -- ^ Edge weights
-> Double -- ^ damping factor, usually around 0.85 -> Double -- ^ damping factor, usually around 0.85
-> [Double] -> [Double]
pagerank gr ws d pagerank gr reset ws d
| n == 0 = [] | n == 0 = []
| isJust ws && length (fromJust ws) /= m = error "incorrect length of edge weight vector" | isJust ws && length (fromJust ws) /= m = error "incorrect length of edge weight vector"
| otherwise = unsafePerformIO $ alloca $ \p -> allocaVector $ \result -> | otherwise = unsafePerformIO $ alloca $ \p -> allocaVector $ \result ->
withVerticesAll $ \vs -> withListMaybe ws $ \ws' -> do withVerticesAll $ \vs -> withListMaybe ws $ \ws' -> do
igraphPagerank (_graph gr) IgraphPagerankAlgoPrpack result p vs case reset of
(isDirected gr) d ws' nullPtr 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 toList result
where where
n = nNodes gr n = nNodes gr
m = nEdges gr m = nEdges gr
-- | Personalized PageRank.
personalizedPagerank :: SingI d
=> Graph d v e
-> [Double] -- ^ reset probability
-> Maybe [Double]
-> Double
-> [Double]
personalizedPagerank gr reset ws d
| n == 0 = []
| length reset /= n = error "incorrect length of reset vector"
| isJust ws && length (fromJust ws) /= m = error "incorrect length of edge weight vector"
| otherwise = unsafePerformIO $ alloca $ \p -> allocaVector $ \result ->
withList reset $ \reset' -> withVerticesAll $ \vs -> withListMaybe ws $ \ws' -> do
igraphPersonalizedPagerank (_graph gr) IgraphPagerankAlgoPrpack result p vs
(isDirected gr) d reset' ws' nullPtr
toList result
where
n = nNodes gr
m = nEdges gr
{#fun igraph_induced_subgraph as ^
{ `IGraph'
, allocaIGraph- `IGraph' addIGraphFinalizer*
, castPtr %`Ptr VertexSelector'
, `SubgraphImplementation'
} -> `CInt' void- #}
{#fun igraph_closeness as ^
{ `IGraph'
, castPtr `Ptr Vector'
, castPtr %`Ptr VertexSelector'
, `Neimode'
, castPtr `Ptr Vector'
, `Bool' } -> `CInt' void- #}
{#fun igraph_betweenness as ^
{ `IGraph'
, castPtr `Ptr Vector'
, castPtr %`Ptr VertexSelector'
, `Bool'
, castPtr `Ptr Vector'
, `Bool' } -> `CInt' void- #}
{#fun igraph_eigenvector_centrality as ^
{ `IGraph'
, castPtr `Ptr Vector'
, id `Ptr CDouble'
, `Bool'
, `Bool'
, castPtr `Ptr Vector'
, castPtr `Ptr ArpackOpt' } -> `CInt' void- #}
{#fun igraph_pagerank as ^ {#fun igraph_pagerank as ^
{ `IGraph' { `IGraph'
, `PagerankAlgo' , `PagerankAlgo'
......
...@@ -14,10 +14,12 @@ import Data.List ...@@ -14,10 +14,12 @@ import Data.List
import IGraph import IGraph
import IGraph.Mutable import IGraph.Mutable
import IGraph.Structure import IGraph.Structure
import IGraph.Generators
tests :: TestTree tests :: TestTree
tests = testGroup "Structure property tests" tests = testGroup "Structure property tests"
[ subGraphs [ subGraphs
, pagerankTest
] ]
subGraphs :: TestTree subGraphs :: TestTree
...@@ -32,3 +34,12 @@ subGraphs = testGroup "generate induced subgraphs" ...@@ -32,3 +34,12 @@ subGraphs = testGroup "generate induced subgraphs"
ns' = map (head . getNodes gr) ns ns' = map (head . getNodes gr) ns
gr' = inducedSubgraph gr ns' gr' = inducedSubgraph gr ns'
result = map (nodeLab gr' *** nodeLab gr') $ edges gr' result = map (nodeLab gr' *** nodeLab gr') $ edges gr'
pagerankTest :: TestTree
pagerankTest = testGroup "PageRank"
[ testCase "case 1" $ ranks @=? ranks' ]
where
gr = star 11
ranks = [0.47,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05,0.05]
ranks' = map ((/100) . fromIntegral . round. (*100)) $
pagerank gr Nothing Nothing 0.85
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