Commit f4b3a1b2 authored by Kai Zhang's avatar Kai Zhang

0.3.0

parent d37ff712
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
-- documentation, see http://haskell.org/cabal/users-guide/ -- documentation, see http://haskell.org/cabal/users-guide/
name: haskell-igraph name: haskell-igraph
version: 0.2.3-dev version: 0.3.0
synopsis: Imcomplete igraph bindings synopsis: Imcomplete igraph bindings
description: This is an attempt to create a complete bindings for the description: This is an attempt to create a complete bindings for the
igraph<"http://igraph.org/c/"> library. igraph<"http://igraph.org/c/"> library.
...@@ -80,6 +80,7 @@ test-suite tests ...@@ -80,6 +80,7 @@ test-suite tests
other-modules: other-modules:
Test.Basic Test.Basic
Test.Structure Test.Structure
Test.Isomorphism
Test.Motif Test.Motif
Test.Utils Test.Utils
......
...@@ -17,8 +17,10 @@ module IGraph ...@@ -17,8 +17,10 @@ module IGraph
, pre , pre
, suc , suc
, filterNode , mapNodes
, filterEdge , mapEdges
, filterNodes
, filterEdges
, nmap , nmap
, emap , emap
...@@ -193,18 +195,39 @@ pre gr i = unsafePerformIO $ do ...@@ -193,18 +195,39 @@ pre gr i = unsafePerformIO $ do
vitToList vit vitToList vit
-- | Keep nodes that satisfy the constraint -- | Keep nodes that satisfy the constraint
filterNode :: (Hashable v, Eq v, Read v, Graph d) filterNodes :: (Hashable v, Eq v, Read v, Graph d)
=> (LGraph d v e -> Node -> Bool) -> LGraph d v e -> LGraph d v e => (LGraph d v e -> Node -> Bool) -> LGraph d v e -> LGraph d v e
filterNode f gr = runST $ do filterNodes f gr = runST $ do
let deleted = filter (not . f gr) $ nodes gr let deleted = filter (not . f gr) $ nodes gr
gr' <- thaw gr gr' <- thaw gr
delNodes deleted gr' delNodes deleted gr'
unsafeFreeze gr' unsafeFreeze gr'
-- | Apply a function to change nodes' labels.
mapNodes :: (Graph d, Read v1, Show v2, Hashable v2, Eq v2, Read v2)
=> (Node -> v1 -> v2) -> LGraph d v1 e -> LGraph d v2 e
mapNodes f gr = runST $ do
(MLGraph gptr) <- thaw gr
let gr' = MLGraph gptr
forM_ (nodes gr) $ \x -> setNodeAttr x (f x $ nodeLab gr x) gr'
unsafeFreeze gr'
-- | Apply a function to change edges' labels.
mapEdges :: (Graph d, Read e1, Show e2, Hashable v, Eq v, Read v)
=> (Edge -> e1 -> e2) -> LGraph d v e1 -> LGraph d v e2
mapEdges f gr = runST $ do
(MLGraph gptr) <- thaw gr
let gr' = MLGraph gptr
forM_ [0 .. nEdges gr - 1] $ \x -> do
e <- unsafePrimToPrim $ igraphEdge (_graph gr) x
setEdgeAttr x (f e $ edgeLabByEid gr x) gr'
unsafeFreeze gr'
-- | Keep nodes that satisfy the constraint -- | Keep nodes that satisfy the constraint
filterEdge :: (Hashable v, Eq v, Read v, Graph d) filterEdges :: (Hashable v, Eq v, Read v, Graph d)
=> (LGraph d v e -> Edge -> Bool) -> LGraph d v e -> LGraph d v e => (LGraph d v e -> Edge -> Bool) -> LGraph d v e -> LGraph d v e
filterEdge f gr = runST $ do filterEdges f gr = runST $ do
let deleted = filter (not . f gr) $ edges gr let deleted = filter (not . f gr) $ edges gr
gr' <- thaw gr gr' <- thaw gr
delEdges deleted gr' delEdges deleted gr'
......
...@@ -53,8 +53,8 @@ defaultEdgeAttributes = EdgeAttr ...@@ -53,8 +53,8 @@ defaultEdgeAttributes = EdgeAttr
{ _edgeLabel = "" { _edgeLabel = ""
, _edgeColour = opaque black , _edgeColour = opaque black
, _edgeWeight = 1.0 , _edgeWeight = 1.0
, _edgeArrowLength = 5.0 , _edgeArrowLength = 10
, _edgeZindex = 0 , _edgeZindex = 2
} }
genXMLTree :: (ArrowXml a, Graph d) => LGraph d NodeAttr EdgeAttr -> a XmlTree XmlTree genXMLTree :: (ArrowXml a, Graph d) => LGraph d NodeAttr EdgeAttr -> a XmlTree XmlTree
......
...@@ -26,19 +26,24 @@ graphToDiagram gr = mconcat $ fst $ unzip $ sortBy (flip (comparing snd)) $ ...@@ -26,19 +26,24 @@ graphToDiagram gr = mconcat $ fst $ unzip $ sortBy (flip (comparing snd)) $
, _nodeZindex nattr ) , _nodeZindex nattr )
where where
nattr = nodeLab gr x nattr = nodeLab gr x
drawEdge (from, to) = {-arrowBetween' drawEdge (from, to) = ( arrowBetween'
( with & arrowTail .~ noTail ( with & arrowTail .~ noTail
& arrowHead .~ arrowH & arrowHead .~ arrowH
& headStyle %~ fc red
& headLength .~ output (_edgeArrowLength eattr) & headLength .~ output (_edgeArrowLength eattr)
) start end-} ) start end # lwO (_edgeWeight eattr) # lcA (_edgeColour eattr), _edgeZindex eattr )
( fromVertices [start, end]
# lwO (_edgeWeight eattr) # lcA (_edgeColour eattr), _edgeZindex eattr )
where where
eattr = edgeLab gr (from, to) eattr = edgeLab gr (from, to)
start = _positionX nattr1 ^& _positionY nattr1 start = x1 ^& y1
end = _positionX nattr2 ^& _positionY nattr2 end = (alpha * x1 + (1 - alpha) * x2) ^& (alpha * y1 + (1 - alpha) * y2)
x1 = _positionX nattr1
y1 = _positionY nattr1
x2 = _positionX nattr2
y2 = _positionY nattr2
alpha = r / sqrt ((x1 - x2)**2 + (y1 - y2)**2)
r = _size nattr2
nattr1 = nodeLab gr from nattr1 = nodeLab gr from
nattr2 = nodeLab gr to nattr2 = nodeLab gr to
--arrowH | isDirected gr = dart arrowH | isDirected gr = dart
-- | otherwise = noHead | otherwise = noHead
{-# INLINE graphToDiagram #-} {-# INLINE graphToDiagram #-}
...@@ -53,4 +53,7 @@ igraphEdge g i = alloca $ \fr -> alloca $ \to -> do ...@@ -53,4 +53,7 @@ igraphEdge g i = alloca $ \fr -> alloca $ \to -> do
{#fun igraph_full as ^ { +, `Int', `Bool', `Bool' } -> `IGraphPtr' #} {#fun igraph_full as ^ { +, `Int', `Bool', `Bool' } -> `IGraphPtr' #}
{#fun igraph_erdos_renyi_game as ^ {+, `ErdosRenyi', `Int', `Double', `Bool', `Bool'} -> `IGraphPtr' #} {#fun igraph_erdos_renyi_game as ^ { +, `ErdosRenyi', `Int', `Double', `Bool'
, `Bool'} -> `IGraphPtr' #}
{#fun igraph_isoclass_create as ^ { +, `Int', `Int', `Bool' } -> `IGraphPtr' #}
...@@ -14,3 +14,5 @@ import Foreign.C.Types ...@@ -14,3 +14,5 @@ import Foreign.C.Types
id `FunPtr (Ptr IGraphPtr -> Ptr IGraphPtr -> CInt -> CInt -> Ptr () -> IO CInt)', id `FunPtr (Ptr IGraphPtr -> Ptr IGraphPtr -> CInt -> CInt -> Ptr () -> IO CInt)',
id `FunPtr (Ptr IGraphPtr -> Ptr IGraphPtr -> CInt -> CInt -> Ptr () -> IO CInt)', id `FunPtr (Ptr IGraphPtr -> Ptr IGraphPtr -> CInt -> CInt -> Ptr () -> IO CInt)',
id `Ptr ()'} -> `Int' #} id `Ptr ()'} -> `Int' #}
{#fun igraph_isomorphic as ^ { `IGraphPtr', `IGraphPtr', id `Ptr CInt' } -> `Int' #}
...@@ -15,3 +15,6 @@ import Foreign.C.Types ...@@ -15,3 +15,6 @@ import Foreign.C.Types
{#fun igraph_triad_census as ^ { `IGraphPtr' {#fun igraph_triad_census as ^ { `IGraphPtr'
, `VectorPtr' } -> `Int' #} , `VectorPtr' } -> `Int' #}
{#fun igraph_motifs_randesu as ^ { `IGraphPtr', `VectorPtr', `Int'
, `VectorPtr' } -> `Int' #}
module IGraph.Isomorphism (getSubisomorphisms) where module IGraph.Isomorphism
( getSubisomorphisms
, isomorphic
, isoclassCreate
, isoclass3
, isoclass4
) where
import Foreign import Foreign
import Foreign.C.Types import Foreign.C.Types
...@@ -6,7 +12,10 @@ import System.IO.Unsafe (unsafePerformIO) ...@@ -6,7 +12,10 @@ import System.IO.Unsafe (unsafePerformIO)
import IGraph import IGraph
import IGraph.Internal.Data import IGraph.Internal.Data
import IGraph.Internal.Graph
import IGraph.Internal.Initialization (igraphInit)
import IGraph.Internal.Isomorphism import IGraph.Internal.Isomorphism
import IGraph.Mutable
getSubisomorphisms :: Graph d getSubisomorphisms :: Graph d
=> LGraph d v1 e1 -- ^ graph to be searched in => LGraph d v1 e1 -- ^ graph to be searched in
...@@ -21,3 +30,36 @@ getSubisomorphisms g1 g2 = unsafePerformIO $ do ...@@ -21,3 +30,36 @@ getSubisomorphisms g1 g2 = unsafePerformIO $ do
gptr1 = _graph g1 gptr1 = _graph g1
gptr2 = _graph g2 gptr2 = _graph g2
{-# INLINE getSubisomorphisms #-} {-# INLINE getSubisomorphisms #-}
-- | Determine whether two graphs are isomorphic.
isomorphic :: Graph d
=> LGraph d v1 e1
-> LGraph d v2 e2
-> Bool
isomorphic g1 g2 = unsafePerformIO $ alloca $ \ptr -> do
_ <- igraphIsomorphic (_graph g1) (_graph g2) ptr
x <- peek ptr
return (x /= 0)
-- | Creates a graph from the given isomorphism class.
-- This function is implemented only for graphs with three or four vertices.
isoclassCreate :: Graph d
=> Int -- ^ The number of vertices to add to the graph.
-> Int -- ^ The isomorphism class
-> d
-> LGraph d () ()
isoclassCreate size idx d = unsafePerformIO $ do
gp <- igraphInit >> igraphIsoclassCreate size idx (isD d)
unsafeFreeze $ MLGraph gp
isoclass3 :: Graph d => d -> [LGraph d () ()]
isoclass3 d = map (flip (isoclassCreate 3) d) n
where
n | isD d = [0..15]
| otherwise = [0..3]
isoclass4 :: Graph d => d -> [LGraph d () ()]
isoclass4 d = map (flip (isoclassCreate 4) d) n
where
n | isD d = [0..217]
| otherwise = [0..10]
...@@ -56,3 +56,5 @@ triadCensus gr = unsafePerformIO $ do ...@@ -56,3 +56,5 @@ triadCensus gr = unsafePerformIO $ do
vptr <- igraphVectorNew 0 vptr <- igraphVectorNew 0
igraphTriadCensus (_graph gr) vptr igraphTriadCensus (_graph gr) vptr
map truncate <$> vectorPtrToList vptr map truncate <$> vectorPtrToList vptr
-- motifsRandesu
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
module IGraph.Mutable where module IGraph.Mutable where
import Foreign import Control.Monad (when)
import Control.Monad.Primitive import Control.Monad.Primitive
import qualified Data.ByteString.Char8 as B
import Foreign
import IGraph.Internal.Graph
import IGraph.Internal.Selector
import IGraph.Internal.Data
import IGraph.Internal.Attribute import IGraph.Internal.Attribute
import IGraph.Internal.Data
import IGraph.Internal.Graph
import IGraph.Internal.Initialization import IGraph.Internal.Initialization
import IGraph.Internal.Selector
-- constants -- constants
vertexAttr :: String vertexAttr :: String
...@@ -110,3 +112,21 @@ instance MGraph D where ...@@ -110,3 +112,21 @@ instance MGraph D where
return () return ()
where where
eids = flip map es $ \(fr, to) -> igraphGetEid g fr to True True eids = flip map es $ \(fr, to) -> igraphGetEid g fr to True True
setNodeAttr :: (PrimMonad m, Show v)
=> Int -- ^ Node id
-> v
-> MLGraph (PrimState m) d v e
-> m ()
setNodeAttr nodeId x (MLGraph gr) = unsafePrimToPrim $ do
err <- igraphCattributeVASSet gr vertexAttr nodeId $ show x
when (err /= 0) $ error "Fail to set node attribute!"
setEdgeAttr :: (PrimMonad m, Show v)
=> Int -- ^ Edge id
-> v
-> MLGraph (PrimState m) d v e
-> m ()
setEdgeAttr edgeId x (MLGraph gr) = unsafePrimToPrim $ do
err <- igraphCattributeEASSet gr edgeAttr edgeId $ show x
when (err /= 0) $ error "Fail to set edge attribute!"
flags:
haskell-igraph:
graphics: true
packages: packages:
- '.' - '.'
extra-deps: [] extra-deps: []
resolver: lts-8.5 resolver: lts-8.5
module Test.Isomorphism
( tests
) where
import Control.Arrow
import Control.Monad.ST
import Data.List
import qualified Data.Matrix.Unboxed as M
import System.IO.Unsafe
import Test.Tasty
import Test.Tasty.HUnit
import Test.Utils
import IGraph
import IGraph
import IGraph.Motif
import IGraph.Isomorphism
tests :: TestTree
tests = testGroup "Isomorphism"
[ graphIsomorphism ]
graphIsomorphism :: TestTree
graphIsomorphism = testCase "Graph isomorphism" $ assertBool "" $
and (zipWith isomorphic triad triad) &&
(not . or) (zipWith isomorphic triad $ reverse triad)
import qualified Test.Basic as Basic import qualified Test.Basic as Basic
import qualified Test.Isomorphism as Isomorphism
import qualified Test.Motif as Motif import qualified Test.Motif as Motif
import qualified Test.Structure as Structure import qualified Test.Structure as Structure
import Test.Tasty import Test.Tasty
...@@ -8,4 +9,5 @@ main = defaultMain $ testGroup "Haskell-igraph Tests" ...@@ -8,4 +9,5 @@ main = defaultMain $ testGroup "Haskell-igraph Tests"
[ Basic.tests [ Basic.tests
, Structure.tests , Structure.tests
, Motif.tests , Motif.tests
, Isomorphism.tests
] ]
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