packages feed

aig 0.2.4 → 0.2.5

raw patch · 5 files changed

+453/−10 lines, 5 filesdep +aigdep +tastydep +tasty-ant-xmlPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: aig, tasty, tasty-ant-xml, tasty-quickcheck

API changes (from Hackage documentation)

- Data.AIG.Interface: Network :: g s -> [l s] -> Network l g
- Data.AIG.Interface: Proxy :: (forall a. a -> a) -> Proxy l g
- Data.AIG.Interface: SomeGraph :: g s -> SomeGraph g
+ Data.AIG.Interface: [Network] :: IsAIG l g => g s -> [l s] -> Network l g
+ Data.AIG.Interface: [Proxy] :: IsAIG l g => (forall a. a -> a) -> Proxy l g
+ Data.AIG.Interface: [SomeGraph] :: g s -> SomeGraph g
+ Data.AIG.Interface: basicProxy :: Proxy BasicLit BasicGraph
+ Data.AIG.Interface: data BasicGraph s
+ Data.AIG.Interface: data BasicLit s
+ Data.AIG.Interface: instance Data.AIG.Interface.IsAIG Data.AIG.Interface.BasicLit Data.AIG.Interface.BasicGraph
+ Data.AIG.Interface: instance Data.AIG.Interface.IsLit Data.AIG.Interface.BasicLit
+ Data.AIG.Interface: instance GHC.Show.Show (Data.AIG.Interface.BasicLit s)
+ Data.AIG.Interface: negateLitView :: LitView a -> LitView a
+ Data.AIG.Interface: newBasicGraph :: IO (BasicGraph s)
- Data.AIG.Operations: pmod :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
+ Data.AIG.Operations: pmod :: forall l g s. IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))

Files

aig.cabal view
@@ -1,10 +1,10 @@ Name:               aig-Version:            0.2.4+Version:            0.2.5 License:            BSD3 License-file:       LICENSE Author:             Galois Inc. Maintainer:         jhendrix@galois.com-Copyright:          (c) 2014-2015 Galois Inc.+Copyright:          (c) 2014-2017 Galois Inc. Category:           Data build-type:         Simple cabal-Version:      >= 1.10@@ -38,4 +38,23 @@     base-compat >= 0.6.0,     mtl,     vector,+    QuickCheck >= 2.7++test-suite aig-test+  type: exitcode-stdio-1.0+  hs-source-dirs: tests++  ghc-options: -Wall+  default-language: Haskell2010++  main-is: aig-test.hs+  other-modules:+    Tests.Operations++  build-depends:+    base == 4.*,+    aig,+    tasty,+    tasty-ant-xml,+    tasty-quickcheck >= 0.8.1,     QuickCheck >= 2.7
src/Data/AIG/Interface.hs view
@@ -1,6 +1,6 @@ {- | Module      : Data.AIG.Interface-Copyright   : (c) Galois, Inc. 2014+Copyright   : (c) Galois, Inc. 2014-2017 License     : BSD3 Maintainer  : jhendrix@galois.com Stability   : experimental@@ -28,6 +28,7 @@   , networkOutputCount   -- * Literal representations   , LitView(..)+  , negateLitView   , LitTree(..)   , toLitTree   , fromLitTree@@ -50,11 +51,16 @@   , getMaxInput   , buildNetwork   , randomNetwork+  , BasicGraph+  , BasicLit+  , basicProxy+  , newBasicGraph   ) where +import qualified Prelude as Prelude import Control.Applicative import Control.Monad-import Prelude()+import Data.IORef import Prelude.Compat hiding (not, and, or, mapM) import Test.QuickCheck (Gen, Arbitrary(..), generate, oneof, sized, choose) @@ -69,6 +75,16 @@   | FalseLit  deriving (Eq,Show,Ord,Functor,Foldable,Traversable) +negateLitView :: LitView a -> LitView a+negateLitView l = case l of+     TrueLit    -> FalseLit+     FalseLit   -> TrueLit+     Input i    -> NotInput i+     NotInput i -> Input i+     And x y    -> NotAnd x y+     NotAnd x y -> And x y++ newtype LitTree = LitTree { unLitTree :: LitView LitTree }  deriving (Eq,Show,Ord) @@ -391,3 +407,105 @@ --   and using that to construct a network. randomNetwork :: IsAIG l g => Proxy l g -> IO (Network l g) randomNetwork proxy = generate arbitrary >>= buildNetwork proxy++------------------------------------------------------------------+-- | A basic "Graph" datastructure based on LitTrees.  This is a totally+--   naive implementation of the AIG structure that exists+--   exclusively for testing purposes.+newtype BasicGraph s = BasicGraph (IORef Int)++------------------------------------------------------------------+-- | A basic AIG literal datastructure based on LitTrees.+--   This is a totally+--   naive implementation of the AIG structure that exists+--   exclusively for testing purposes.+newtype BasicLit s = BasicLit LitTree+ deriving (Show)++basicProxy :: Proxy BasicLit BasicGraph+basicProxy = Proxy (\x -> x)++notTree :: LitTree -> LitTree+notTree (LitTree x) = LitTree . negateLitView $ x++andTree :: LitTree -> LitTree -> LitTree+andTree (LitTree FalseLit) _    = LitTree FalseLit+andTree _ (LitTree FalseLit)    = LitTree FalseLit+andTree (LitTree TrueLit) y     = y+andTree x (LitTree TrueLit)     = x+andTree x y                     = LitTree (And x y)++newBasicGraph :: IO (BasicGraph s)+newBasicGraph =+  do r <- newIORef 0+     return (BasicGraph r)++instance IsLit BasicLit where+  not (BasicLit x) = BasicLit . notTree $ x+  (BasicLit x) === (BasicLit y) = x == y++instance IsAIG BasicLit BasicGraph where+  withNewGraph _proxy k = k =<< newBasicGraph++  aigerNetwork _proxy _fp =+    fail "Cannot read AIGER files from the BasicGraph implementation"++  trueLit  _g = BasicLit . LitTree $ TrueLit+  falseLit _g = BasicLit . LitTree $ FalseLit++  newInput (BasicGraph r) =+     atomicModifyIORef' r (\n -> (n+1, BasicLit . LitTree . Input $ n))++  and _g (BasicLit x) (BasicLit  y) = return . BasicLit $ andTree x y++  inputCount (BasicGraph r) = readIORef r++  -- | Get input at given index in the graph.+  getInput _g i = return . BasicLit . LitTree . Input $ i++  writeAiger _fp _ntk =+     fail "Cannot write AIGER files from the BasicGraph implementation"++  writeCNF _g _l _fp =+     fail "Cannot write CNF files from the BasicGraph implementation"++  checkSat _g _l =+     fail "Cannot SAT check graphs in the BasicGraph implementation"++  cec _g1 _g2 =+     fail "Cannot CEC graphs in the BasicGraph implementation"++  asConstant _g (BasicLit bl) = go bl+    where+     go (LitTree l) = go' l++     go' l = case l of+         TrueLit    -> pure True+         FalseLit   -> pure False+         And x y    -> (&&) <$> go x <*> go y+         NotAnd x y -> Prelude.not <$> go' (And x y)+         Input _    -> Nothing+         NotInput _ -> Nothing++  -- | Evaluate the network on a set of concrete inputs.+  evaluator _g xs = return (\(BasicLit x) -> eval x)+    where+     eval :: LitTree -> Bool+     eval (LitTree x) = eval' x++     eval' :: LitView LitTree -> Bool+     eval' TrueLit      = True+     eval' FalseLit     = False+     eval' (And x y)    = eval x && eval y+     eval' (NotAnd x y) = Prelude.not (eval' (And x y))+     eval' (Input i)    = case drop i xs of+                            (b:_) -> b+                            []    -> error $ unwords ["Input value out of bounds", show i]+     eval' (NotInput i) = Prelude.not (eval' (Input i))++  -- | Examine the outermost structure of a literal to see how it was constructed+  litView _ (BasicLit (LitTree x)) = return (fmap BasicLit x)++  -- | Build an evaluation function over an AIG using the provided view function+  abstractEvaluateAIG _g f = return (\(BasicLit x) -> h x)+   where h (LitTree x) = f =<< traverse h x
src/Data/AIG/Operations.hs view
@@ -877,9 +877,12 @@     -> BV (l s)    -- ^ the value to rotate     -> BV (l s)    -- ^ how many places to rotate     -> IO (BV (l s))-rol g x y = do-  r <- urem g y (bvFromInteger g (length y) (toInteger (length x)))-  muxInteger (iteM g) (length x - 1) r (return . rolC x)+rol g x0 (BV ys) = fst <$> V.foldM f (x0, 1) (V.reverse ys)+  where+    f (x, p) y = do+      x' <- ite g y (rolC x p) x+      let p' = (2*p) `mod` length x0+      return (x', p')  -- | Rotate right. ror :: IsAIG l g@@ -887,9 +890,12 @@     -> BV (l s)    -- ^ the value to rotate     -> BV (l s)    -- ^ how many places to rotate     -> IO (BV (l s))-ror g x y = do-  r <- urem g y (bvFromInteger g (length y) (toInteger (length x)))-  muxInteger (iteM g) (length x - 1) r (return . rorC x)+ror g x0 (BV ys) = fst <$> V.foldM f (x0, 1) (V.reverse ys)+  where+    f (x, p) y = do+      x' <- ite g y (rorC x p) x+      let p' = (2*p) `mod` length x0+      return (x', p')   -- | Compute the rounded-down base2 logarithm of the input bitvector.
+ tests/Tests/Operations.hs view
@@ -0,0 +1,271 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE PartialTypeSignatures #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -fno-warn-partial-type-signatures #-}+module Tests.Operations (op_tests) where++import Test.Tasty+import Test.Tasty.QuickCheck+--import Test.QuickCheck++import           Data.AIG.Interface (BasicGraph, BasicLit, newBasicGraph)+import qualified Data.AIG.Interface as AIG+import qualified Data.AIG.Operations as AIG+import Data.Bits+import Data.Int+import Data.Word++type BV s = AIG.BV (BasicLit s)++--------------------------------------------------------------------------+-- Some test harness stuff to make writing down unit tests easier++class Precond x where+  precond :: x -> Bool+  precond _ = True++class Arbitrary x => AIGTestableValue g x y where+  injectArg  :: g -> x -> y+  extractArg :: g -> y -> Maybe x++class PushIO y where+  pushIO  :: (a -> y) -> IO a -> y++instance PushIO (IO b) where+  pushIO f x = x >>= f++instance PushIO b => PushIO (a -> b) where+  pushIO f x a = pushIO (\x' -> f x' a) x++class (Testable p, PushIO y) => AIGTestable g x y p | g x y -> p where+  runTest :: IO g -> x -> y -> Bool -> p++newtype Denom a = Denom a+ deriving (Eq, Ord, Show)++instance Precond Bool+instance Precond Word32+instance Precond Word64+instance Precond Int32+instance Precond Int64+instance Precond Integer++instance (Integral a, Eq a) => Precond (Denom a) where+  precond (Denom x) = x /= 0+instance Precond Int where+  precond x = 0 <= x && x < 64++instance Arbitrary a => Arbitrary (Denom a) where+  arbitrary = Denom <$> arbitrary++instance (AIGTestableValue g a x, AIGTestableValue g b y) =>+    AIGTestableValue g (a,b) (x,y) where+  injectArg g (a,b) = (injectArg g a, injectArg g b)+  extractArg g (x,y) = (,) <$> extractArg g x <*> extractArg g y++instance AIGTestableValue g a b => AIGTestableValue g (Denom a) b where+  injectArg g (Denom x) = injectArg g x+  extractArg g x = Denom <$> extractArg g x++instance AIGTestableValue (BasicGraph s) Int (BV s) where+  injectArg g x  = AIG.bvFromInteger g (finiteBitSize x) (toInteger x)+  extractArg g x = fromInteger <$> AIG.asSigned g x++instance AIGTestableValue (BasicGraph s) Word32 (BV s) where+  injectArg g x  = AIG.bvFromInteger g (finiteBitSize x) (toInteger x)+  extractArg g x = fromInteger <$> AIG.asUnsigned g x++instance AIGTestableValue (BasicGraph s) Word64 (BV s) where+  injectArg g x  = AIG.bvFromInteger g (finiteBitSize x) (toInteger x)+  extractArg g x = fromInteger <$> AIG.asUnsigned g x++instance AIGTestableValue (BasicGraph s) Int32 (BV s) where+  injectArg g x  = AIG.bvFromInteger g (finiteBitSize x) (toInteger x)+  extractArg g x = fromInteger <$> AIG.asSigned g x++instance AIGTestableValue (BasicGraph s) Int64 (BV s) where+  injectArg g x  = AIG.bvFromInteger g (finiteBitSize x) (toInteger x)+  extractArg g x = fromInteger <$> AIG.asSigned g x++instance AIGTestableValue (BasicGraph s) Integer Integer where+  injectArg _g x = x+  extractArg _g x = Just x++instance AIGTestableValue (BasicGraph s) Bool (BasicLit s) where+  injectArg g x  = AIG.constant g x+  extractArg g x = AIG.asConstant g x++instance (Eq x, Show x, AIGTestableValue g x y) => AIGTestable g x (IO y) Property+ where+   runTest gph x y pre = pre ==> ioProperty $+     do gph' <- gph+        y' <- y+        case extractArg gph' y' of+          Nothing -> fail $ unwords ["Expected concrete output"]+          Just z+            | x == z    -> return True+            | otherwise -> fail $ unwords ["Expected", show x, "but got", show z]++instance+   (Precond x, Show x, AIGTestableValue g x y, AIGTestable g a b p) =>+   AIGTestable g (x -> a) (y -> b) (x -> p)+ where+   runTest gph f g pre = \x ->+     let y = (gph >>= \gph' -> return $ injectArg gph' x)+      in runTest gph (f x) (pushIO g y) (precond x && pre)+++------------------------------------------------------------------------------------+-- Make a unit test from a concrete operation and an operation on AIGs++mkTest :: forall a b p+        . (Testable p, AIGTestable (BasicGraph ()) a b p)+       => String+       -> a+       -> (BasicGraph () -> b)+       -> TestTree+mkTest nm a b =+  withResource newBasicGraph (\_ -> return ()) $ \(g :: IO (BasicGraph ())) ->+    testProperty nm $ (runTest g a (pushIO b g) True :: p)+++op_tests :: [TestTree]+op_tests =+  [ mkTest "ite"  (\b (x :: Word64) y -> if b then x else y) AIG.ite++  , mkTest "neg"  (negate :: Int64 -> Int64) AIG.neg+  , mkTest "add"  ((+)  :: Word64 -> Word64 -> Word64) AIG.add+  , mkTest "addC" addC AIG.addC+  , mkTest "sub"  ((-)  :: Word64 -> Word64 -> Word64) AIG.sub+  , mkTest "subC" subC AIG.subC+  , mkTest "addConst" addConst AIG.addConst+  , mkTest "subConst" subConst AIG.subConst++  , mkTest "mul"  ((*)  :: Word64 -> Word64 -> Word64) AIG.mul+  , mkTest "mulFull"  mulFull  AIG.mulFull+  , mkTest "smulFull" smulFull AIG.smulFull+  , mkTest "squot" squot AIG.squot+  , mkTest "srem"  srem  AIG.srem+  , mkTest "uquot" uquot AIG.uquot+  , mkTest "urem"  urem  AIG.urem++  , mkTest "shl"  (shiftL  :: Word64 -> Int -> Word64) AIG.shl+  , mkTest "ushr" (shiftR  :: Word64 -> Int -> Word64) AIG.ushr+  , mkTest "sshr" (shiftR  :: Int64  -> Int -> Int64)  AIG.sshr+  , mkTest "rol"  (rotateL :: Word64 -> Int -> Word64) AIG.rol+  , mkTest "ror"  (rotateR :: Word64 -> Int -> Word64) AIG.ror++  , mkTest "bvEq"    ((==) :: Word64 -> Word64 -> Bool) AIG.bvEq+  , mkTest "isZero"  (\x -> (x :: Word64) == 0) AIG.isZero+  , mkTest "nonZero" (\x -> (x :: Word64) /= 0) AIG.nonZero+  , mkTest "sle"  ((<=) :: Int64 -> Int64 -> Bool) AIG.sle+  , mkTest "slt"  ((<)  :: Int64 -> Int64 -> Bool) AIG.slt+  , mkTest "ule"  ((<=) :: Word64 -> Word64 -> Bool) AIG.ule+  , mkTest "ult"  ((<)  :: Word64 -> Word64 -> Bool) AIG.ult+  , mkTest "sabs" (abs  :: Int64 -> Int64) AIG.sabs++  , mkTest "sext" sext (\g x -> (return $ AIG.sext g x 64) :: IO _)+  , mkTest "zext" zext (\g x -> (return $ AIG.zext g x 64) :: IO _)+  , mkTest "trunc" trunc (\(_ :: BasicGraph ()) (x :: BV ()) -> (return $ AIG.trunc 64 x) :: IO _)++  , mkTest "priorityEncode" priorityEncode (\g -> AIG.priorityEncode g 32)+  , mkTest "logBase2_down" log2down AIG.logBase2_down+  , mkTest "logBase2_up"   log2up   AIG.logBase2_up+  , mkTest "clz"  clz AIG.countLeadingZeros+  , mkTest "ctz"  ctz AIG.countTrailingZeros++  , mkTest "pmul" pmul AIG.pmul+  , mkTest "pdiv" pdiv AIG.pdiv+  , mkTest "pmod" pmod AIG.pmod+  ]++addC :: Word32 -> Word32 -> (Word32, Bool)+addC x y = ( fromIntegral z, testBit z 32 )+ where z :: Word64+       z = fromIntegral x + fromIntegral y++subC :: Word32 -> Word32 -> (Word32, Bool)+subC x y = ( fromIntegral z, testBit z 32 )+ where z :: Word64+       z = fromIntegral x - fromIntegral y++addConst :: Word64 -> Integer -> Word64+addConst x y = x + fromInteger y++subConst :: Word64 -> Integer -> Word64+subConst x y = x - fromInteger y++mulFull :: Word32 -> Word32 -> Word64+mulFull x y = fromIntegral x * fromIntegral y++smulFull :: Int32 -> Int32 -> Int64+smulFull x y = fromIntegral x * fromIntegral y++uquot :: Word64 -> Denom Word64 -> Word64+uquot x (Denom y) = quot x y++urem :: Word64 -> Denom Word64 -> Word64+urem x (Denom y) = rem x y++squot :: Int64 -> Denom Int64 -> Int64+squot x (Denom y) = quot x y++srem :: Int64 -> Denom Int64 -> Int64+srem x (Denom y) = rem x y++sext :: Int32 -> Int64+sext = fromIntegral++zext :: Word32 -> Word64+zext = fromIntegral++trunc :: Word64 -> Word32+trunc = fromIntegral++log2down :: Word64 -> Int64+log2down x = fromIntegral (finiteBitSize x) - 1 - fromIntegral (countLeadingZeros x)++log2up :: Word64 -> Int64+log2up x = log2down (x - 1) + 1++clz :: Word64 -> Word64+clz = fromIntegral . countLeadingZeros++ctz :: Word64 -> Word64+ctz = fromIntegral . countTrailingZeros++pmul :: Word32 -> Word32 -> Word64+pmul x y = foldr xor zeroBits pprods+ where+  pprods = [ if testBit y i+                then shiftL (fromIntegral x) i+                else 0+           | i <- [0 .. finiteBitSize y - 1]+           ]++priorityEncode :: Word64 -> (Bool, Word32)+priorityEncode x+  | x == 0    = (False, 0)+  | otherwise = (True, fromIntegral (finiteBitSize x) - 1 - fromIntegral (countLeadingZeros x))++pdiv :: Word64 -> Denom Word32 -> Word64+pdiv x (Denom y) = fst $ pdivmod x y++pmod :: Word64 -> Denom Word32 -> Word32+pmod x (Denom y) = snd $ pdivmod x y++pdivmod :: Word64 -> Word32 -> (Word64, Word32)+pdivmod x y = go 0 x (finiteBitSize x - 1) start+  where+   start = finiteBitSize x - finiteBitSize y + countLeadingZeros y+   y'    = fromIntegral y++   go q r i j+     | j <  0      = (q,fromIntegral r)+     | testBit r i = go (setBit q j) (r `xor` (y' `shiftL` j)) (i-1) (j-1)+     | otherwise   = go q            r                         (i-1) (j-1)
+ tests/aig-test.hs view
@@ -0,0 +1,29 @@+module Main (main) where++import Test.Tasty+import Test.Tasty.Ingredients+import Test.Tasty.Runners.AntXML++import Tests.Operations++------------------------------------------------------------------------+-- Runner+------------------------------------------------------------------------++main :: IO ()+main = do+  defaultMainWithIngredients ingrs tests++ingrs :: [Ingredient]+ingrs =+   [ antXMLRunner+   ]+   +++   defaultIngredients+++tests :: TestTree+tests =+    testGroup "AIG"+    [ testGroup "Bitvector operations" $ op_tests+    ]