Commit 2183f77c authored by Kai Zhang's avatar Kai Zhang

fix memory leaks for more foreign structs

parent 174692fe
...@@ -466,6 +466,8 @@ int igraph_haskell_attribute_add_edges(igraph_t *graph, const igraph_vector_t *e ...@@ -466,6 +466,8 @@ int igraph_haskell_attribute_add_edges(igraph_t *graph, const igraph_vector_t *e
} }
if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) { if (oldrec->type == IGRAPH_ATTRIBUTE_STRING) {
if (ne != bsvector_size(newstr)) { if (ne != bsvector_size(newstr)) {
printf("number of edges: %d\n", ne);
printf("number of attributes: %d\n", bsvector_size(newstr));
IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL); IGRAPH_ERROR("Invalid string attribute length", IGRAPH_EINVAL);
} }
IGRAPH_CHECK(bsvector_append(oldstr, newstr)); IGRAPH_CHECK(bsvector_append(oldstr, newstr));
......
#include <igraph/igraph.h> #include <igraph/igraph.h>
#include "haskell_attributes.h" #include "haskell_attributes.h"
void my_igraph_vector_destroy(igraph_vector_t* v) {
printf("free vector\n");
igraph_vector_destroy(v);
}
const igraph_attribute_table_t igraph_haskell_attribute_table={ const igraph_attribute_table_t igraph_haskell_attribute_table={
&igraph_haskell_attribute_init, &igraph_haskell_attribute_destroy, &igraph_haskell_attribute_init, &igraph_haskell_attribute_destroy,
&igraph_haskell_attribute_copy, &igraph_haskell_attribute_add_vertices, &igraph_haskell_attribute_copy, &igraph_haskell_attribute_add_vertices,
......
...@@ -5,4 +5,6 @@ ...@@ -5,4 +5,6 @@
void haskelligraph_init(); void haskelligraph_init();
void my_igraph_vector_destroy(igraph_vector_t* v);
#endif #endif
...@@ -37,6 +37,7 @@ import Control.Monad.Primitive ...@@ -37,6 +37,7 @@ import Control.Monad.Primitive
import Control.Monad.ST (runST) import Control.Monad.ST (runST)
import qualified Data.ByteString as B import qualified Data.ByteString as B
import Data.Conduit.Cereal import Data.Conduit.Cereal
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
import qualified Data.HashSet as S import qualified Data.HashSet as S
...@@ -92,7 +93,8 @@ class MGraph d => Graph d where ...@@ -92,7 +93,8 @@ class MGraph d => Graph d where
-- | Return the label of given node. -- | Return the label of given node.
nodeLab :: Serialize v => LGraph d v e -> Node -> v nodeLab :: Serialize v => LGraph d v e -> Node -> v
nodeLab (LGraph g _) i = unsafePerformIO $ nodeLab (LGraph g _) i = unsafePerformIO $
igraphHaskellAttributeVAS g vertexAttr i >>= fromBS igraphHaskellAttributeVAS g vertexAttr i >>= bsToByteString >>=
return . fromRight (error "decode failed") . decode
{-# INLINE nodeLab #-} {-# INLINE nodeLab #-}
-- | Return all nodes that are associated with given label. -- | Return all nodes that are associated with given label.
...@@ -104,7 +106,8 @@ class MGraph d => Graph d where ...@@ -104,7 +106,8 @@ class MGraph d => Graph d where
edgeLab :: Serialize e => LGraph d v e -> Edge -> e edgeLab :: Serialize e => LGraph d v e -> Edge -> e
edgeLab (LGraph g _) (fr,to) = unsafePerformIO $ edgeLab (LGraph g _) (fr,to) = unsafePerformIO $
igraphGetEid g fr to True True >>= igraphGetEid g fr to True True >>=
igraphHaskellAttributeEAS g edgeAttr >>= fromBS igraphHaskellAttributeEAS g edgeAttr >>= bsToByteString >>=
return . fromRight (error "decode failed") . decode
{-# INLINE edgeLab #-} {-# INLINE edgeLab #-}
-- | Find the edge by edge ID. -- | Find the edge by edge ID.
...@@ -115,7 +118,8 @@ class MGraph d => Graph d where ...@@ -115,7 +118,8 @@ class MGraph d => Graph d where
-- | Find the edge label by edge ID. -- | Find the edge label by edge ID.
edgeLabByEid :: Serialize e => LGraph d v e -> Int -> e edgeLabByEid :: Serialize e => LGraph d v e -> Int -> e
edgeLabByEid (LGraph g _) i = unsafePerformIO $ edgeLabByEid (LGraph g _) i = unsafePerformIO $
igraphHaskellAttributeEAS g edgeAttr i >>= fromBS igraphHaskellAttributeEAS g edgeAttr i >>= bsToByteString >>=
return . fromRight (error "decode failed") . decode
{-# INLINE edgeLabByEid #-} {-# INLINE edgeLabByEid #-}
instance Graph U where instance Graph U where
...@@ -220,12 +224,12 @@ deserializeGraph nds ne = do ...@@ -220,12 +224,12 @@ deserializeGraph nds ne = do
let f i ((fr, to), attr) = unsafePrimToPrim $ do let f i ((fr, to), attr) = unsafePrimToPrim $ do
igraphVectorSet evec (i*2) $ fromIntegral fr igraphVectorSet evec (i*2) $ fromIntegral fr
igraphVectorSet evec (i*2+1) $ fromIntegral to igraphVectorSet evec (i*2+1) $ fromIntegral to
asBS attr $ \bs -> with bs $ \ptr -> bsvectorSet bsvec i $ castPtr ptr bsvectorSet bsvec i $ encode attr
return $ i + 1 return $ i + 1
foldMC f 0 foldMC f 0
gr@(MLGraph g) <- new 0 gr@(MLGraph g) <- new 0
addLNodes nds gr addLNodes nds gr
unsafePrimToPrim $ withEdgeAttr $ \eattr -> with (mkStrRec eattr bsvec) $ \ptr -> do unsafePrimToPrim $ withAttr edgeAttr bsvec $ \ptr -> do
vptr <- fromPtrs [castPtr ptr] vptr <- fromPtrs [castPtr ptr]
withVectorPtr vptr (igraphAddEdges g evec . castPtr) withVectorPtr vptr (igraphAddEdges g evec . castPtr)
unsafeFreeze gr unsafeFreeze gr
...@@ -245,7 +249,8 @@ unsafeFreeze :: (Hashable v, Eq v, Serialize v, PrimMonad m) ...@@ -245,7 +249,8 @@ unsafeFreeze :: (Hashable v, Eq v, Serialize v, PrimMonad m)
unsafeFreeze (MLGraph g) = unsafePrimToPrim $ do unsafeFreeze (MLGraph g) = unsafePrimToPrim $ do
nV <- igraphVcount g nV <- igraphVcount g
labels <- forM [0 .. nV - 1] $ \i -> labels <- forM [0 .. nV - 1] $ \i ->
igraphHaskellAttributeVAS g vertexAttr i >>= fromBS igraphHaskellAttributeVAS g vertexAttr i >>= bsToByteString >>=
return . fromRight (error "decode failed") . decode
return $ LGraph g $ M.fromListWith (++) $ zip labels $ map return [0..nV-1] return $ LGraph g $ M.fromListWith (++) $ zip labels $ map return [0..nV-1]
where where
...@@ -323,8 +328,7 @@ nmap fn gr = unsafePerformIO $ do ...@@ -323,8 +328,7 @@ nmap fn gr = unsafePerformIO $ do
(MLGraph g) <- thaw gr (MLGraph g) <- thaw gr
forM_ (nodes gr) $ \i -> do forM_ (nodes gr) $ \i -> do
let label = fn (i, nodeLab gr i) let label = fn (i, nodeLab gr i)
asBS label $ \bs -> asBS (encode label) (igraphHaskellAttributeVASSet g vertexAttr i)
with bs (igraphHaskellAttributeVASSet g vertexAttr i)
unsafeFreeze (MLGraph g) unsafeFreeze (MLGraph g)
-- | Map a function over the edge labels in a graph. -- | Map a function over the edge labels in a graph.
...@@ -335,6 +339,5 @@ emap fn gr = unsafePerformIO $ do ...@@ -335,6 +339,5 @@ emap fn gr = unsafePerformIO $ do
forM_ (edges gr) $ \(fr, to) -> do forM_ (edges gr) $ \(fr, to) -> do
i <- igraphGetEid g fr to True True i <- igraphGetEid g fr to True True
let label = fn ((fr,to), edgeLabByEid gr i) let label = fn ((fr,to), edgeLabByEid gr i)
asBS label $ \bs -> asBS (encode label) (igraphHaskellAttributeEASSet g edgeAttr i)
with bs (igraphHaskellAttributeEASSet g edgeAttr i)
unsafeFreeze (MLGraph g) unsafeFreeze (MLGraph g)
...@@ -18,51 +18,18 @@ import System.IO.Unsafe (unsafePerformIO) ...@@ -18,51 +18,18 @@ import System.IO.Unsafe (unsafePerformIO)
#include "igraph/igraph.h" #include "igraph/igraph.h"
#include "haskell_attributes.h" #include "haskell_attributes.h"
-- The returned object will not be trackced by Haskell's GC. It should be freed {#pointer *igraph_attribute_record_t as AttributeRecord foreign newtype#}
-- by foreign codes.
asBS :: Serialize a => a -> (BSLen -> IO b) -> IO b withAttr :: String
asBS x fn = unsafeUseAsCStringLen (encode x) (fn . BSLen) -> BSVector -> (Ptr AttributeRecord -> IO a) -> IO a
{-# INLINE asBS #-} withAttr name bs f = withBSVector bs $ \ptr -> do
fptr <- mallocForeignPtrBytes {#sizeof igraph_attribute_record_t #}
asBSVector :: Serialize a => [a] -> (BSVector -> IO b) -> IO b withForeignPtr fptr $ \attr -> withCString name $ \name' -> do
asBSVector values fn = loop [] values {#set igraph_attribute_record_t.name #} attr name'
where {#set igraph_attribute_record_t.type #} attr 2
loop acc (x:xs) = unsafeUseAsCStringLen (encode x) $ \ptr -> {#set igraph_attribute_record_t.value #} attr $ castPtr ptr
loop (BSLen ptr : acc) xs f attr
loop acc _ = toBSVector (reverse acc) >>= fn {-# INLINE withAttr #-}
{-# INLINE asBSVector #-}
fromBS :: Serialize a => Ptr BSLen -> IO a
fromBS ptr = do
BSLen x <- peek ptr
result <- decode <$> packCStringLen x
case result of
Left msg -> error msg
Right r -> return r
{-# INLINE fromBS #-}
mkStrRec :: CString -- ^ name of the attribute
-> BSVector -- ^ values of the attribute
-> AttributeRecord
mkStrRec name xs = AttributeRecord name 2 xs
{-# INLINE mkStrRec #-}
data AttributeRecord = AttributeRecord CString Int BSVector
instance Storable AttributeRecord where
sizeOf _ = {#sizeof igraph_attribute_record_t #}
alignment _ = {#alignof igraph_attribute_record_t #}
peek p = AttributeRecord
<$> ({#get igraph_attribute_record_t->name #} p)
<*> liftM fromIntegral ({#get igraph_attribute_record_t->type #} p)
<*> ( do ptr <- {#get igraph_attribute_record_t->value #} p
fptr <- newForeignPtr_ . castPtr $ ptr
return $ BSVector fptr )
poke p (AttributeRecord name t vptr) = do
{#set igraph_attribute_record_t.name #} p name
{#set igraph_attribute_record_t.type #} p $ fromIntegral t
withBSVector vptr $ \ptr ->
{#set igraph_attribute_record_t.value #} p $ castPtr ptr
{#fun igraph_haskell_attribute_has_attr as ^ { `IGraph', `AttributeElemtype', `String' } -> `Bool' #} {#fun igraph_haskell_attribute_has_attr as ^ { `IGraph', `AttributeElemtype', `String' } -> `Bool' #}
......
...@@ -26,6 +26,8 @@ module IGraph.Internal.Data ...@@ -26,6 +26,8 @@ module IGraph.Internal.Data
, toStrVector , toStrVector
, BSLen(..) , BSLen(..)
, asBS
, bsToByteString
, BSVector(..) , BSVector(..)
, withBSVector , withBSVector
, bsvectorNew , bsvectorNew
...@@ -49,6 +51,8 @@ module IGraph.Internal.Data ...@@ -49,6 +51,8 @@ module IGraph.Internal.Data
import Control.Monad import Control.Monad
import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Char8 as B
import Data.ByteString (packCStringLen)
import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
import Foreign import Foreign
import Foreign.C.Types import Foreign.C.Types
import Foreign.C.String import Foreign.C.String
...@@ -64,17 +68,19 @@ import Data.List.Split (chunksOf) ...@@ -64,17 +68,19 @@ import Data.List.Split (chunksOf)
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
{#pointer *igraph_vector_t as Vector foreign finalizer {#pointer *igraph_vector_t as Vector foreign finalizer
igraph_vector_destroy newtype#} my_igraph_vector_destroy newtype#}
-- Construtors and destructors -- Construtors and destructors
allocaVector :: (Ptr Vector -> IO a) -> IO a allocaVector :: (Ptr Vector -> IO a) -> IO a
allocaVector f = mallocBytes {# sizeof igraph_vector_t #} >>= f allocaVector f = mallocBytes {# sizeof igraph_vector_t #} >>= f
{-# INLINE allocaVector #-}
addVectorFinalizer :: Ptr Vector -> IO Vector addVectorFinalizer :: Ptr Vector -> IO Vector
addVectorFinalizer ptr = do addVectorFinalizer ptr = do
vec <- newForeignPtr igraph_vector_destroy ptr vec <- newForeignPtr my_igraph_vector_destroy ptr
return $ Vector vec return $ Vector vec
{-# INLINE addVectorFinalizer #-}
{#fun igraph_vector_init as igraphVectorNew {#fun igraph_vector_init as igraphVectorNew
{ allocaVector- `Vector' addVectorFinalizer* { allocaVector- `Vector' addVectorFinalizer*
...@@ -182,42 +188,55 @@ toStrVector xs = do ...@@ -182,42 +188,55 @@ toStrVector xs = do
-- Customized string vector -- Customized string vector
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
newtype BSLen = BSLen CStringLen {#pointer *bytestring_t as BSLen foreign newtype#}
instance Storable BSLen where bsToByteString :: Ptr BSLen -> IO B.ByteString
sizeOf _ = {#sizeof bytestring_t #} bsToByteString ptr = do
alignment _ = {#alignof bytestring_t #} n <- {#get bytestring_t->len #} ptr
peek p = do str <- {#get bytestring_t->value #} ptr
n <- ({#get bytestring_t->len #} p) packCStringLen (str, fromIntegral n)
ptr <- {#get bytestring_t->value #} p {-# INLINE bsToByteString #-}
return $ BSLen (ptr, fromIntegral n)
poke p (BSLen (ptr, n)) = {#set bytestring_t.len #} p (fromIntegral n) >> asBS :: B.ByteString -> (Ptr BSLen -> IO a) -> IO a
{#set bytestring_t.value #} p ptr asBS x f = unsafeUseAsCStringLen x $ \(str, n) -> do
fptr <- mallocForeignPtrBytes {#sizeof bytestring_t #}
withForeignPtr fptr $ \ptr -> do
{#set bytestring_t.len #} ptr (fromIntegral n)
{#set bytestring_t.value #} ptr str
f ptr
{-# INLINE asBS #-}
{#pointer *bsvector_t as BSVector foreign finalizer bsvector_destroy newtype#} {#pointer *bsvector_t as BSVector foreign finalizer bsvector_destroy newtype#}
{#fun bsvector_init as bsvectorNew { +, `Int' } -> `BSVector' #} allocaBSVector :: (Ptr BSVector -> IO a) -> IO a
allocaBSVector f = mallocBytes {# sizeof bsvector_t #} >>= f
{-# INLINE allocaBSVector #-}
addBSVectorFinalizer :: Ptr BSVector -> IO BSVector
addBSVectorFinalizer ptr = do
vec <- newForeignPtr bsvector_destroy ptr
return $ BSVector vec
{-# INLINE addBSVectorFinalizer #-}
--{#fun bsvector_get as bsVectorGet { `BSVectorPtr', `Int', + } -> `Ptr (Ptr BSLen)' id #} {#fun bsvector_init as bsvectorNew
{ allocaBSVector- `BSVector' addBSVectorFinalizer*
, `Int'
} -> `CInt' void- #}
{- {#fun bsvector_set as bsvectorSet' { `BSVector', `Int', castPtr `Ptr BSLen' } -> `()' #}
bsVectorGet :: BSVectorPtr -> Int -> BSLen
bsVectorGet vec i = unsafePerformIO $ do
ptrptr <- bsVectorGet vec i
peek ptrptr >>= peek
-}
{#fun bsvector_set as ^ { `BSVector', `Int', `Ptr ()'} -> `()' #} bsvectorSet :: BSVector -> Int -> B.ByteString -> IO ()
bsvectorSet vec i bs = asBS bs (bsvectorSet' vec i)
{-# INLINE bsvectorSet #-}
toBSVector :: [BSLen] -> IO BSVector toBSVector :: [B.ByteString] -> IO BSVector
toBSVector xs = do toBSVector xs = do
vec <- bsvectorNew n vec <- bsvectorNew n
forM_ (zip [0..] xs) $ \(i, x) -> with x $ \ptr -> bsvectorSet vec i $ castPtr ptr foldM_ (\i x -> bsvectorSet vec i x >> return (i+1)) 0 xs
return vec return vec
where where
n = length xs n = length xs
{#pointer *igraph_matrix_t as Matrix foreign finalizer igraph_matrix_destroy newtype#} {#pointer *igraph_matrix_t as Matrix foreign finalizer igraph_matrix_destroy newtype#}
{#fun igraph_matrix_init as igraphMatrixNew { +, `Int', `Int' } -> `Matrix' #} {#fun igraph_matrix_init as igraphMatrixNew { +, `Int', `Int' } -> `Matrix' #}
......
...@@ -19,9 +19,23 @@ import IGraph.Internal.C2HS ...@@ -19,9 +19,23 @@ import IGraph.Internal.C2HS
{#pointer *igraph_t as IGraph foreign finalizer igraph_destroy newtype#} {#pointer *igraph_t as IGraph foreign finalizer igraph_destroy newtype#}
{#fun igraph_empty as igraphNew' { +, `Int', `Bool' } -> `IGraph' #} allocaIGraph :: (Ptr IGraph -> IO a) -> IO a
allocaIGraph f = mallocBytes {# sizeof igraph_t #} >>= f
{#fun igraph_copy as ^ { +, `IGraph' } -> `IGraph' #}
addIGraphFinalizer :: Ptr IGraph -> IO IGraph
addIGraphFinalizer ptr = do
vec <- newForeignPtr igraph_destroy ptr
return $ IGraph vec
{#fun igraph_empty as igraphNew'
{ allocaIGraph- `IGraph' addIGraphFinalizer*
, `Int', `Bool'
} -> `CInt' void- #}
{#fun igraph_copy as ^
{ allocaIGraph- `IGraph' addIGraphFinalizer*
, `IGraph'
} -> `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
......
...@@ -13,7 +13,7 @@ module IGraph.Mutable ...@@ -13,7 +13,7 @@ module IGraph.Mutable
import Control.Monad (when, forM) import Control.Monad (when, forM)
import Control.Monad.Primitive import Control.Monad.Primitive
import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Char8 as B
import Data.Serialize (Serialize) import Data.Serialize (Serialize, encode)
import Foreign import Foreign
import Foreign.C.String (CString, withCString) import Foreign.C.String (CString, withCString)
...@@ -55,10 +55,11 @@ class MGraph d where ...@@ -55,10 +55,11 @@ class MGraph d where
addLNodes :: (Serialize v, PrimMonad m) addLNodes :: (Serialize v, PrimMonad m)
=> [v] -- ^ vertices' labels => [v] -- ^ vertices' labels
-> MLGraph (PrimState m) d v e -> m () -> MLGraph (PrimState m) d v e -> m ()
addLNodes labels (MLGraph g) = unsafePrimToPrim $ withVertexAttr $ addLNodes labels (MLGraph g) = unsafePrimToPrim $ do
\vattr -> asBSVector labels $ \bsvec -> with (mkStrRec vattr bsvec) $ bsvec <- toBSVector $ map encode labels
\ptr -> do vptr <- fromPtrs [castPtr ptr] withAttr vertexAttr bsvec $ \attr -> do
withVectorPtr vptr (igraphAddVertices g n . castPtr) vptr <- fromPtrs [castPtr attr]
withVectorPtr vptr (igraphAddVertices g n . castPtr)
where where
n = length labels n = length labels
...@@ -80,10 +81,11 @@ class MGraph d where ...@@ -80,10 +81,11 @@ class MGraph d where
-- | Add edges with labels to the graph. -- | Add edges with labels to the graph.
addLEdges :: (PrimMonad m, Serialize e) => [LEdge e] -> MLGraph (PrimState m) d v e -> m () addLEdges :: (PrimMonad m, Serialize e) => [LEdge e] -> MLGraph (PrimState m) d v e -> m ()
addLEdges es (MLGraph g) = unsafePrimToPrim $ withEdgeAttr $ \eattr -> addLEdges es (MLGraph g) = unsafePrimToPrim $ do
asBSVector vs $ \bsvec -> with (mkStrRec eattr bsvec) $ \ptr -> do bsvec <- toBSVector $ map encode vs
withAttr edgeAttr bsvec $ \attr -> do
vec <- fromList $ concat xs vec <- fromList $ concat xs
vptr <- fromPtrs [castPtr ptr] vptr <- fromPtrs [castPtr attr]
withVectorPtr vptr (igraphAddEdges g vec . castPtr) withVectorPtr vptr (igraphAddEdges g vec . castPtr)
where where
(xs, vs) = unzip $ map ( \((a,b),v) -> ([fromIntegral a, fromIntegral b], v) ) es (xs, vs) = unzip $ map ( \((a,b),v) -> ([fromIntegral a, fromIntegral b], v) ) es
...@@ -117,10 +119,9 @@ setNodeAttr :: (PrimMonad m, Serialize v) ...@@ -117,10 +119,9 @@ setNodeAttr :: (PrimMonad m, Serialize v)
-> v -> v
-> MLGraph (PrimState m) d v e -> MLGraph (PrimState m) d v e
-> m () -> m ()
setNodeAttr nodeId x (MLGraph gr) = unsafePrimToPrim $ asBS x $ \bs -> setNodeAttr nodeId x (MLGraph gr) = unsafePrimToPrim $ asBS (encode x) $ \bs -> do
with bs $ \bsptr -> do err <- igraphHaskellAttributeVASSet gr vertexAttr nodeId bs
err <- igraphHaskellAttributeVASSet gr vertexAttr nodeId bsptr when (err /= 0) $ error "Fail to set node attribute!"
when (err /= 0) $ error "Fail to set node attribute!"
-- | Set edge attribute. -- | Set edge attribute.
setEdgeAttr :: (PrimMonad m, Serialize e) setEdgeAttr :: (PrimMonad m, Serialize e)
...@@ -128,7 +129,6 @@ setEdgeAttr :: (PrimMonad m, Serialize e) ...@@ -128,7 +129,6 @@ setEdgeAttr :: (PrimMonad m, Serialize e)
-> e -> e
-> MLGraph (PrimState m) d v e -> MLGraph (PrimState m) d v e
-> m () -> m ()
setEdgeAttr edgeId x (MLGraph gr) = unsafePrimToPrim $ asBS x $ \bs -> setEdgeAttr edgeId x (MLGraph gr) = unsafePrimToPrim $ asBS (encode x) $ \bs -> do
with bs $ \bsptr -> do err <- igraphHaskellAttributeEASSet gr edgeAttr edgeId bs
err <- igraphHaskellAttributeEASSet gr edgeAttr edgeId bsptr when (err /= 0) $ error "Fail to set edge attribute!"
when (err /= 0) $ error "Fail to set edge attribute!"
...@@ -8,9 +8,10 @@ module IGraph.Structure ...@@ -8,9 +8,10 @@ module IGraph.Structure
) where ) where
import Control.Monad import Control.Monad
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
import Data.Serialize (Serialize) import Data.Serialize (Serialize, decode)
import Foreign import Foreign
import Foreign.C.Types import Foreign.C.Types
import System.IO.Unsafe (unsafePerformIO) import System.IO.Unsafe (unsafePerformIO)
...@@ -32,7 +33,8 @@ inducedSubgraph gr vs = unsafePerformIO $ do ...@@ -32,7 +33,8 @@ inducedSubgraph gr vs = unsafePerformIO $ do
g' <- igraphInducedSubgraph (_graph gr) vsptr IgraphSubgraphCreateFromScratch g' <- igraphInducedSubgraph (_graph gr) vsptr IgraphSubgraphCreateFromScratch
nV <- igraphVcount g' nV <- igraphVcount g'
labels <- forM [0 .. nV - 1] $ \i -> labels <- forM [0 .. nV - 1] $ \i ->
igraphHaskellAttributeVAS g' vertexAttr i >>= fromBS igraphHaskellAttributeVAS g' vertexAttr i >>= bsToByteString >>=
return . fromRight (error "decode failed") . decode
return $ LGraph g' $ M.fromListWith (++) $ zip labels $ map return [0..nV-1] return $ LGraph g' $ M.fromListWith (++) $ zip labels $ map return [0..nV-1]
-- | Closeness centrality -- | Closeness centrality
......
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