abcBridge-0.14: src/Data/ABC/Internal/GIA.chs
{- |
Module : Data.ABC.Internal.GIA
Copyright : Galois, Inc. 2010-2014
License : BSD3
Maintainer : jhendrix@galois.com
Stability : experimental
Portability : non-portable (c2hs, language extensions)
Bindings to @aig\/gia\/gia.h@ for manipulating and
running algorithms on scalable and-inverter graphs (GIA), a
representation that is optimized for memory-efficiency. These
functions power the next-generation of ABC algorithms that have
not been officially released yet, and can be identified by the
prefix of an ampersand, as in @&cec@, in the interactive ABC
interface.
-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
{-# OPTIONS_GHC -fno-warn-unused-matches #-}
module Data.ABC.Internal.GIA (
Gia_Man_t
, Gia_Man_t_
, giaManNObjs
, giaManFanData
, Gia_Obj_t
, getGiaObjValue
, setGiaObjValue
, GiaVar(..)
, GiaLit(..)
, giaManConst0Lit
, giaManConst1Lit
, giaLitIsCompl
, giaLitVar
, giaVarLit
, giaLitNotCond
-- * Memory management
-- * Base
-- ** Network getters
, giaManCexComb
, giaManConst0
, giaManCis
, giaManCos
, giaManCiNum
, giaManCoNum
, giaManPiNum
, giaManPoNum
, giaManAndNum
, getGiaManRegNum
, setGiaManRegNum
, giaManCiVar
, giaManCoVar
, giaManCi
, giaManCo
, giaManObj
, gia_none
, giaObjIsCo
, giaObjDiff0
, giaObjDiff1
, giaObjFaninC0
, giaObjFaninC1
, giaObjMark0
, giaObjMark1
, giaObjChild0
, giaObjChild1
, giaObjFaninId0
, giaObjFaninId1
, giaObjIsTerm
, giaObjIsAndOrConst0
, giaObjId
, giaManObjNum
-- ** Handling literals
, giaLitNot
, giaRegular
, giaIsComplement
, giaObjToLit
, giaObjFromLit
-- ** Iterators
, giaManForEachObj1_
, giaManForEachCo
-- ** Construction
, giaManAppendCi
, giaManAppendCo
, giaManAppendAnd
-- * Functions
-- ** giaAiger.c
, giaAigerRead
, giaAigerWrite
-- ** giaDup.c
, giaManMiter
, giaDupLit
, giaManDupNormalize
-- ** giaHash.c
, giaManHashAlloc
, giaManHashStart
, giaManHashStop
, giaManHashAnd
, giaManHashXor
, giaManHashMux
-- ** giaMan.c
, giaManStart
, giaManStop
, p_giaManStop
, giaManCleanup
, giaManFillValue
-- ** misc
, clearGiaObj
) where
import Control.Applicative ((<$>), (<*>))
import Control.Exception
import Control.Monad
import Foreign hiding (void)
import Foreign.C
{#import Data.ABC.Internal.ABCGlobal #}
{#import Data.ABC.Internal.VecInt #}
import Data.ABC.Internal.Field
#include "abcbridge.h"
#include "gia.h"
-- Iterators
enumRange :: (Eq a, Enum a) => a -> a -> [a]
enumRange i n | i == n = []
| otherwise = i : enumRange (succ i) n
lazyAnd :: Monad m => m Bool -> m Bool -> m Bool
lazyAnd mx my = do
x <- mx
if x then my else return False
asWordPtr :: (WordPtr -> WordPtr) -> Ptr a -> Ptr b
asWordPtr f = wordPtrToPtr . f . ptrToWordPtr
------------------------------------------------------------------------
-- Gia_Obj_t
data Gia_Obj_t_
-- | A pointer to a GIA object.
-- GIA objects are pointers to structs in ABC, and represent literals
-- in the AIG. The low-order bit of the pointer is set to 1 if the
-- literal has been complemented, and so care must be taken to only
-- dereference positive pointers. The object is also a bitfield, so
-- care must be taken when accessing fields.
--
-- Pointers to GIA objects may be invalidated when adding a new
-- object.
{#pointer *Gia_Obj_t -> Gia_Obj_t_ #}
sizeOfGiaObj :: Int
sizeOfGiaObj = {#sizeof Gia_Obj_t #}
-- | Remove negation.
giaRegular :: Gia_Obj_t -> Gia_Obj_t
giaRegular = asWordPtr (.&. complement 0x1)
-- | Returns iDiff0 field of object
-- Note: iDiff0 is a bitfield, so this may be more likely to break on
-- unexpected compilers.
giaObjDiff0 :: Gia_Obj_t -> IO CUInt
giaObjDiff0 = {#get Gia_Obj_t->iDiff0 #}
-- | Get the complement attribute of first fanin
giaObjFaninC0 :: Gia_Obj_t -> IO Bool
giaObjFaninC0 o = toBool `fmap` {#get Gia_Obj_t->fCompl0 #} o
-- | Get first user defined mark
giaObjMark0 :: Gia_Obj_t -> IO Bool
giaObjMark0 o = toBool `fmap` {#get Gia_Obj_t->fMark0 #} o
giaObjIsTerm :: Gia_Obj_t -> IO Bool
giaObjIsTerm o = toBool `fmap` {#get Gia_Obj_t->fTerm #} o
-- | Returns iDiff1 field of object
-- Note: iDiff1 is a bitfield, so this may be more likely to break on
-- unexpected compilers.
giaObjDiff1 :: Gia_Obj_t -> IO CUInt
giaObjDiff1 = {#get Gia_Obj_t->iDiff1 #}
giaObjFaninC1 :: Gia_Obj_t -> IO Bool
giaObjFaninC1 o = toBool `fmap` {#get Gia_Obj_t->fCompl1 #} o
-- | Get second user defined mark
giaObjMark1 :: Gia_Obj_t -> IO Bool
giaObjMark1 o = toBool `fmap` {#get Gia_Obj_t->fMark1 #} o
getGiaObjValue :: Gia_Obj_t -> IO CUInt
getGiaObjValue = {#get Gia_Obj_t->Value #}
setGiaObjValue :: Gia_Obj_t -> CUInt -> IO ()
setGiaObjValue = {#set Gia_Obj_t->Value #}
-- GIA_NONE
gia_none :: CUInt
gia_none = 0x1FFFFFFF
giaObjIsAndOrConst0 :: Gia_Obj_t -> IO Bool
giaObjIsAndOrConst0 o = not <$> giaObjIsTerm o
giaObjDiff0Assigned :: Gia_Obj_t -> IO Bool
giaObjDiff0Assigned o = (/= gia_none) <$> giaObjDiff0 o
giaIsComplement :: Gia_Obj_t -> Bool
giaIsComplement o = ptrToWordPtr o `testBit` 0
giaNot :: Gia_Obj_t -> Gia_Obj_t
giaNot = asWordPtr (xor 1)
giaNotCond :: Gia_Obj_t -> Bool -> Gia_Obj_t
giaNotCond o b = if b then giaNot o else o
-- | Returns true if this is a combinational output (latch or primary output).
giaObjIsCo :: Gia_Obj_t -> IO Bool
giaObjIsCo o = lazyAnd (giaObjIsTerm o) (giaObjDiff0Assigned o)
incObjPtr :: Gia_Obj_t -> CInt -> Gia_Obj_t
incObjPtr o i = o `plusPtr` (sizeOfGiaObj * fromIntegral i)
decObjPtr :: Gia_Obj_t -> CUInt -> Gia_Obj_t
decObjPtr o i = incObjPtr o (negate (fromIntegral i))
objDiff :: Gia_Obj_t -> Gia_Obj_t -> Int
objDiff p q = (p `minusPtr` q) `div` sizeOfGiaObj
-- Gia_ObjFanin0
giaObjFanin0 :: Gia_Obj_t -> IO Gia_Obj_t
giaObjFanin0 o = decObjPtr o <$> giaObjDiff0 o
-- Gia_ObjFanin1
giaObjFanin1 :: Gia_Obj_t -> IO Gia_Obj_t
giaObjFanin1 o = decObjPtr o <$> giaObjDiff1 o
-- Gia_ObjChild0
giaObjChild0 :: Gia_Obj_t -> IO Gia_Obj_t
giaObjChild0 o = giaNotCond <$> giaObjFanin0 o <*> giaObjFaninC0 o
-- Gia_ObjChild1
giaObjChild1 :: Gia_Obj_t -> IO Gia_Obj_t
giaObjChild1 o = giaNotCond <$> giaObjFanin1 o <*> giaObjFaninC1 o
-- Gia_ObjFaninId0
giaObjFaninId0 :: Gia_Obj_t -> GiaVar -> IO GiaVar
giaObjFaninId0 o (GiaVar v) = (\d -> GiaVar (v - fromIntegral d)) <$> giaObjDiff0 o
-- Gia_ObjFaninId1
giaObjFaninId1 :: Gia_Obj_t -> GiaVar -> IO GiaVar
giaObjFaninId1 o (GiaVar v) = (\d -> GiaVar (v - fromIntegral d)) <$> giaObjDiff1 o
------------------------------------------------------------------------
-- GiaVar and GiaLit
-- | Also known as the node's id. No complement info.
newtype GiaVar = GiaVar { unGiaVar :: CInt } deriving (Eq, Ord, Storable)
-- | Literals store complement information.
newtype GiaLit = GiaLit { unGiaLit :: CInt } deriving (Eq, Ord, Storable)
giaManConst0Lit :: GiaLit
giaManConst0Lit = GiaLit 0
giaManConst1Lit :: GiaLit
giaManConst1Lit = GiaLit 1
giaLitIsCompl :: GiaLit -> Bool
giaLitIsCompl l = unGiaLit l `testBit` 0
giaLitVar :: GiaLit -> GiaVar
giaLitVar (GiaLit l) = GiaVar (l `shiftR` 1)
-- | Returns positive literal associated to var.
giaVarLit :: GiaVar -> GiaLit
giaVarLit (GiaVar v) = GiaLit (v `shiftL` 1)
giaLitNot :: GiaLit -> GiaLit
giaLitNot = GiaLit . xor 1 . unGiaLit
giaLitNotCond :: GiaLit -> Bool -> GiaLit
giaLitNotCond (GiaLit l) b = GiaLit (l `xor` (if b then 1 else 0))
------------------------------------------------------------------------
-- Gia_Man_t
data Gia_Man_t_
{#pointer *Gia_Man_t -> Gia_Man_t_ #}
-- member access
-- this structures are memory managed by Gia_Man_.
giaManCexComb :: Gia_Man_t -> IO Abc_Cex_t
giaManCexComb = {#get Gia_Man_t->pCexComb #}
giaManNObjs :: Field Gia_Man_t CInt
giaManNObjs = fieldFromOffset {#offsetof Gia_Man_t->nObjs #}
giaManObjs :: Field Gia_Man_t Gia_Obj_t
giaManObjs = fieldFromOffset {#offsetof Gia_Man_t->pObjs #}
giaManConst0 :: Gia_Man_t -> IO Gia_Obj_t
giaManConst0 = readAt giaManObjs
giaManCis :: Gia_Man_t -> IO Vec_Int_t
giaManCis = {#get Gia_Man_t->vCis #}
giaManCos :: Gia_Man_t -> IO Vec_Int_t
giaManCos = {#get Gia_Man_t->vCos #}
giaManFanData :: Gia_Man_t -> IO (Ptr CInt)
giaManFanData = {#get Gia_Man_t->pFanData#}
giaManObjNum :: Gia_Man_t -> IO CInt
giaManObjNum = readAt giaManNObjs
giaManCiNum :: Gia_Man_t -> IO CInt
giaManCiNum = vecIntSize <=< giaManCis
giaManCoNum :: Gia_Man_t -> IO CInt
giaManCoNum = vecIntSize <=< giaManCos
getGiaManRegNum :: Gia_Man_t -> IO CInt
getGiaManRegNum = {#get Gia_Man_t->nRegs #}
setGiaManRegNum :: Gia_Man_t -> CInt -> IO ()
setGiaManRegNum = {#set Gia_Man_t->nRegs #}
giaManPiNum :: Gia_Man_t -> IO CInt
giaManPiNum m = (-) <$> giaManCiNum m <*> getGiaManRegNum m
giaManPoNum :: Gia_Man_t -> IO CInt
giaManPoNum m = (-) <$> giaManCoNum m <*> getGiaManRegNum m
giaManAndNum :: Gia_Man_t -> IO CInt
giaManAndNum m = fn <$> giaManObjNum m <*> giaManCiNum m <*> giaManCoNum m
where fn t i o = t - i - o - 1
-- XXX refactor
giaManForEachObj1_ :: Gia_Man_t -> (Gia_Obj_t -> GiaVar -> IO b) -> IO ()
giaManForEachObj1_ fp action = do
nMax <- giaManObjNum fp
forM_ (enumRange 1 nMax) $ \i -> do
let var = GiaVar (fromIntegral i)
pObj <- giaManObj fp var
void $ action pObj var
giaManForEachCo :: Gia_Man_t -> (Gia_Obj_t -> Int -> IO b) -> IO [b]
giaManForEachCo fp action = do
nMax <- giaManCoNum fp
forM (enumRange 0 nMax) $ \i -> do
pObj <- giaManCo fp i
action pObj (fromIntegral i)
foreign import ccall unsafe "AbcBridge_Gia_ManAppendCi"
giaManAppendCi_ :: Gia_Man_t -> IO CInt
giaManAppendCi :: Gia_Man_t -> IO GiaLit
giaManAppendCi m = GiaLit <$> giaManAppendCi_ m
foreign import ccall unsafe "AbcBridge_Gia_ManAppendAnd"
giaManAppendAnd_ :: Gia_Man_t -> CInt -> CInt -> IO CInt
-- | This directly appends the literal to the GIA bypassing
-- any hash-consing.
giaManAppendAnd :: Gia_Man_t -> GiaLit -> GiaLit -> IO GiaLit
giaManAppendAnd m (GiaLit x) (GiaLit y) =
GiaLit <$> giaManAppendAnd_ m x y
foreign import ccall unsafe "AbcBridge_Gia_ManAppendCo"
giaManAppendCo_ :: Gia_Man_t -> CInt -> IO CInt
giaManAppendCo :: Gia_Man_t -> GiaLit -> IO GiaLit
giaManAppendCo m (GiaLit l) = GiaLit <$> giaManAppendCo_ m l
-- | Return object associated with gia var.
giaManObj :: Gia_Man_t -> GiaVar -> IO Gia_Obj_t
giaManObj m (GiaVar v) = do
cnt <- giaManObjNum m
assert (0 <= v && v < cnt) $ do
(`incObjPtr` v) <$> giaManConst0 m
-- | Get var index of combinational input at given index.
giaManCiVar :: Gia_Man_t -> CInt -> IO GiaVar
giaManCiVar m i = do
v <- giaManCis m
GiaVar <$> vecIntEntry v i
-- | Get combinational input at given index.
giaManCi :: Gia_Man_t -> CInt -> IO Gia_Obj_t
giaManCi m i = giaManObj m =<< giaManCiVar m i
-- | Get combinational output at given index.
giaManCoVar :: Gia_Man_t -> CInt -> IO GiaVar
giaManCoVar m i = do
v <- giaManCos m
GiaVar <$> vecIntEntry v i
-- | Get combinational output at given index.
giaManCo :: Gia_Man_t -> CInt -> IO Gia_Obj_t
giaManCo m i = giaManObj m =<< giaManCoVar m i
-- | Returns the variable index associated with the object.
giaObjId :: Gia_Man_t -> Gia_Obj_t -> IO GiaVar
giaObjId p pObj = do
objs <- giaManConst0 p
nObjs <- readAt giaManNObjs p
assert (objs <= pObj && pObj < objs `incObjPtr` nObjs) $ do
return $ GiaVar $ fromIntegral $ pObj `objDiff` objs
{#fun AbcBridge_Gia_ObjToLit as giaObjToLit
{ id `Gia_Man_t'
, id `Gia_Obj_t'
} -> `GiaLit' GiaLit #}
{#fun AbcBridge_Gia_ObjFromLit as giaObjFromLit
{ id `Gia_Man_t'
, unGiaLit `GiaLit'
} -> `Gia_Obj_t' id #}
-- giaAiger.c
{#fun Gia_AigerRead as ^
{ `String' -- pFileName
, `Bool' -- fSkipStrash
, `Bool' -- fCheck (doesn't do anything)
} -> `Gia_Man_t' id #}
{#fun Gia_AigerWrite as giaAigerWrite
{ id `Gia_Man_t'
, `String' -- pFileName
, `Bool' -- fWriteSymbols
, `Bool' -- fCompact
} -> `()' #}
{#fun Gia_ManMiter as giaManMiter
{ id `Gia_Man_t' -- pAig0cd
, id `Gia_Man_t' -- pAig1
, `Int' -- nInsDup
, `Bool' -- fDualOut
, `Bool' -- fSeq
, `Bool' -- fImplic
, `Bool' -- fVerbose
} -> `Gia_Man_t' id #}
foreign import ccall unsafe "Gia_ManDupNormalize" giaManDupNormalize
:: Gia_Man_t -> IO Gia_Man_t
-- | @giaManDupDfsLazyLit pNew p l@ copies a lit @l@ in @p@ to @pNew@
-- and returns the lit in @pNew@.
giaDupLit :: Gia_Man_t -> Gia_Man_t -> GiaLit -> IO GiaLit
giaDupLit pNew p (GiaLit l) = GiaLit <$> giaDupLit' pNew p l
foreign import ccall unsafe "AbcBridge_Gia_DupLit" giaDupLit'
:: Gia_Man_t -> Gia_Man_t -> CInt -> IO CInt
-- giaHash.c
foreign import ccall unsafe "Gia_ManHashAlloc" giaManHashAlloc
:: Gia_Man_t -> IO ()
foreign import ccall unsafe "Gia_ManHashStart" giaManHashStart
:: Gia_Man_t -> IO ()
foreign import ccall unsafe "Gia_ManHashStop" giaManHashStop
:: Gia_Man_t -> IO ()
{#fun Gia_ManHashAnd as ^
{ id `Gia_Man_t' -- p
, unGiaLit `GiaLit' -- iLit0
, unGiaLit `GiaLit' -- iLit1
} -> `GiaLit' GiaLit #}
{#fun Gia_ManHashXor as ^
{ id `Gia_Man_t' -- p
, unGiaLit `GiaLit' -- iLit0
, unGiaLit `GiaLit' -- iLit1
} -> `GiaLit' GiaLit #}
{#fun Gia_ManHashMux as ^
{ id `Gia_Man_t' -- p
, unGiaLit `GiaLit' -- iCtrl
, unGiaLit `GiaLit' -- iData1
, unGiaLit `GiaLit' -- iData0
} -> `GiaLit' GiaLit #}
-- giaMan.c
foreign import ccall unsafe "Gia_ManStop"
giaManStop :: Gia_Man_t -> IO ()
foreign import ccall unsafe "gia.h &Gia_ManStop"
p_giaManStop :: FunPtr (Gia_Man_t -> IO ())
foreign import ccall unsafe "AbcBridge_Gia_ClearGiaObj"
clearGiaObj :: Gia_Obj_t -> IO ()
{#fun Gia_ManStart as ^ { id `CInt' } -> `Gia_Man_t' id #}
{#fun Gia_ManCleanup as ^
{ id `Gia_Man_t' -- p
} -> `Gia_Man_t' id #}
{#fun Gia_ManFillValue as ^
{ id `Gia_Man_t' -- p
} -> `()' #}