packages feed

haskell-igraph-0.8.5: src/IGraph/Algorithms/Isomorphism.chs

{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE ScopedTypeVariables #-}
module IGraph.Algorithms.Isomorphism
    ( isomorphic
    , getSubisomorphisms
    , isoclassCreate
    , isoclass3
    , isoclass4
    ) where

import           System.IO.Unsafe               (unsafePerformIO)
import Data.Singletons (SingI, Sing, sing, fromSing)

import Foreign
import Foreign.C.Types

import           IGraph
import           IGraph.Internal.Initialization (igraphInit)
{#import IGraph.Internal #}

#include "haskell_igraph.h"

-- | Determine whether two graphs are isomorphic.
isomorphic :: Graph d v1 e1
           -> Graph d v2 e2
           -> Bool
isomorphic g1 g2 = unsafePerformIO $ alloca $ \ptr -> do
    _ <- igraphIsomorphic (_graph g1) (_graph g2) ptr
    x <- peek ptr
    return (x /= 0)
{-# INLINE isomorphic #-}
{#fun igraph_isomorphic as ^ { `IGraph', `IGraph', id `Ptr CInt' } -> `CInt' void- #}

getSubisomorphisms :: Graph d v1 e1  -- ^ graph to be searched in
                   -> Graph d v2 e2   -- ^ smaller graph
                   -> [[Int]]
getSubisomorphisms g1 g2 = unsafePerformIO $ allocaVectorPtr $ \vpptr -> do
    igraphGetSubisomorphismsVf2 gptr1 gptr2 nullPtr nullPtr nullPtr nullPtr vpptr
        nullFunPtr nullFunPtr nullPtr
    (map.map) truncate <$> toLists vpptr
  where
    gptr1 = _graph g1
    gptr2 = _graph g2
{-# INLINE getSubisomorphisms #-}
{#fun igraph_get_subisomorphisms_vf2 as ^
    { `IGraph'
    , `IGraph'
    , id `Ptr ()'
    , id `Ptr ()'
    , id `Ptr ()'
    , id `Ptr ()'
    , castPtr `Ptr VectorPtr'
    , id `FunPtr (Ptr IGraph -> Ptr IGraph -> CInt -> CInt -> Ptr () -> IO CInt)'
    , id `FunPtr (Ptr IGraph -> Ptr IGraph -> CInt -> CInt -> Ptr () -> IO CInt)'
    , id `Ptr ()'
    } -> `CInt' void- #}

-- | Creates a graph from the given isomorphism class.
-- This function is implemented only for graphs with three or four vertices.
isoclassCreate :: forall d. SingI d
               => Int   -- ^ The number of vertices to add to the graph.
               -> Int   -- ^ The isomorphism class
               -> Graph d () ()
isoclassCreate size idx = unsafePerformIO $ do
    gp <- igraphInit >> igraphIsoclassCreate size idx directed
    return $ Graph gp $ mkLabelToId gp
  where
    directed = case fromSing (sing :: Sing d) of
        D -> True
        U -> False
{#fun igraph_isoclass_create as ^
    { allocaIGraph- `IGraph' addIGraphFinalizer*
    , `Int', `Int', `Bool'
    } -> `CInt' void- #}

isoclass3 :: forall d. SingI d => [Graph d () ()]
isoclass3 = map (isoclassCreate 3) (if directed then [0..15] else [0..3])
  where
    directed = case fromSing (sing :: Sing d) of
        D -> True
        U -> False

isoclass4 :: forall d. SingI d => [Graph d () ()]
isoclass4 = map (isoclassCreate 4) (if directed then [0..217] else [0..10])
  where
    directed = case fromSing (sing :: Sing d) of
        D -> True
        U -> False