packages feed

aig 0.2.1 → 0.2.3

raw patch · 5 files changed

+311/−17 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.AIG.Interface: instance Foldable LitView
+ Data.AIG.Interface: instance Traversable LitView
+ Data.AIG.Interface: litView :: IsAIG l g => g s -> l s -> IO (LitView (l s))
+ Data.AIG.Interface: writeCNF :: IsAIG l g => g s -> l s -> FilePath -> IO [Int]
+ Data.AIG.Operations: countLeadingZeros :: IsAIG l g => g s -> BV (l s) -> IO (BV (l s))
+ Data.AIG.Operations: countTrailingZeros :: IsAIG l g => g s -> BV (l s) -> IO (BV (l s))
+ Data.AIG.Operations: logBase2_down :: IsAIG l g => g s -> BV (l s) -> IO (BV (l s))
+ Data.AIG.Operations: logBase2_up :: IsAIG l g => g s -> BV (l s) -> IO (BV (l s))
+ Data.AIG.Operations: pdiv :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))
+ Data.AIG.Operations: priorityEncode :: IsAIG l g => g s -> Int -> BV (l s) -> IO (l s, BV (l s))
+ Data.AIG.Trace: instance TraceOutput l g a => TraceOutput l g [a]
+ Data.AIG.Trace: instance TraceOutput l g x => TraceOutput l g (LitView x)

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2014, Galois, Inc.+Copyright (c) 2014-2015, Galois, Inc.  All rights reserved. 
aig.cabal view
@@ -1,5 +1,5 @@ Name:               aig-Version:            0.2.1+Version:            0.2.3 License:            BSD3 License-file:       LICENSE Author:             Galois Inc.
src/Data/AIG/Interface.hs view
@@ -1,8 +1,3 @@-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE Rank2Types #-}-{-# LANGUAGE DeriveFunctor #-}- {- | Module      : Data.AIG.Interface Copyright   : (c) Galois, Inc. 2014@@ -13,7 +8,13 @@  Interfaces for building, simulating and analysing And-Inverter Graphs (AIG). -}-+{-# LANGUAGE CPP #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE Rank2Types #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveTraversable #-} module Data.AIG.Interface   ( -- * Main interface classes     IsLit(..)@@ -57,6 +58,11 @@ import Prelude hiding (not, and, or) import Test.QuickCheck (Gen, Arbitrary(..), generate, oneof, sized, choose) +#if !MIN_VERSION_base(4,8,0)+import Data.Foldable (Foldable)+import Data.Traversable (Traversable)+#endif+ -- | Concrete datatype representing the ways --   an AIG can be constructed. data LitView a@@ -66,7 +72,7 @@   | NotInput !Int   | TrueLit   | FalseLit- deriving (Eq,Show,Ord,Functor)+ deriving (Eq,Show,Ord,Functor,Foldable,Traversable)  newtype LitTree = LitTree { unLitTree :: LitView LitTree }  deriving (Eq,Show,Ord)@@ -85,8 +91,7 @@ data Proxy l g where   Proxy :: IsAIG l g => (forall a . a -> a) -> Proxy l g --- | An And-Inverter-Graph is a data structure storing bit-level--- nodes.+-- | An And-Inverter-Graph is a data structure storing bit-level nodes. -- -- Graphs are and-inverter graphs, which contain a number of input -- literals and Boolean operations for creating new literals.@@ -180,6 +185,12 @@   -- | Write network out to AIGER file.   writeAiger :: FilePath -> Network l g -> IO () +  -- | Write network out to DIMACS CNF file.+  -- Returns vector mapping combinational inputs to CNF Variable+  -- numbers.+  writeCNF :: g s -> l s -> FilePath -> IO [Int]+  -- TODO: add default implementation in terms of 'abstractEvalAIG'.+   -- | Check if literal is satisfiable in network.   checkSat :: g s -> l s -> IO SatResult @@ -198,6 +209,9 @@   evaluate (Network g outputs) inputs = do     f <- evaluator g inputs     return (f <$> outputs)++  -- | Examine the outermost structure of a literal to see how it was constructed+  litView :: g s -> l s -> IO (LitView (l s))    -- | Build an evaluation function over an AIG using the provided view function   abstractEvaluateAIG
src/Data/AIG/Operations.hs view
@@ -9,6 +9,7 @@ A collection of higher-level operations (mostly 2's complement arithmetic operations) that can be built from the primitive And-Inverter Graph interface. -}+{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveTraversable #-}@@ -109,18 +110,30 @@   , zeroIntCoerce   , signIntCoerce -    -- * Polynomial multiplication and modulus+    -- * Priority encoder, lg2, and related functions+  , priorityEncode+  , logBase2_down+  , logBase2_up+  , countLeadingZeros+  , countTrailingZeros++    -- * Polynomial multiplication, division and modulus in the finite+    --   Galois Field GF(2^n)   , pmul+  , pdiv   , pmod   ) where  import Control.Applicative hiding (empty)-import Control.Exception+import Control.Exception (assert) import qualified Control.Monad import Control.Monad.State hiding (zipWithM, replicateM, mapM) import Data.Bits ((.|.), setBit, shiftL, testBit)-import Data.Foldable (Foldable)-import Data.Traversable (Traversable)++#if MIN_VERSION_base(4,8,0)+import qualified Data.Bits as Bits+#endif+ import qualified Data.Vector as V import qualified Data.Vector.Generic.Mutable as MV @@ -130,9 +143,14 @@  import Data.AIG.Interface +#if !MIN_VERSION_base(4,8,0)+import Data.Foldable (Foldable)+import Data.Traversable (Traversable)+#endif  -- | A BitVector consists of a sequence of symbolic bits and can be used---   for symbolic machine-word arithmetic.+--   for symbolic machine-word arithmetic.  Bits are stored in+--   most-significant-bit first order. newtype BV l = BV { unBV :: V.Vector l }   deriving ( Eq            , Ord@@ -734,7 +752,7 @@  -- | Test if a bitvector is equal to zero isZero :: IsAIG l g => g s -> BV (l s) -> IO (l s)-isZero g (BV v) = V.foldM (\x y -> and g (lNot' g x) y) (trueLit g) v+isZero g (BV v) = V.foldM (\x y -> and g x (lNot' g y)) (trueLit g) v  -- | Test if a bitvector is distinct from zero nonZero :: IsAIG l g => g s -> BV (l s) -> IO (l s)@@ -878,6 +896,189 @@   r <- urem g y (bvFromInteger g (length y) (toInteger (length x)))   muxInteger (iteM g) (length x - 1) r (return . rorC x) ++-- | Compute the rounded-down base2 logarithm of the input bitvector.+--   For x > 0, this uniquely satisfies 2^(logBase2_down(x)) <= x < 2^(logBase2_down(x)+1).+--   For x = 0, we set logBase2(x) = -1.+--   The output bitvector has the same width as the input bitvector.+logBase2_down+        :: IsAIG l g+        => g s+        -> BV (l s)  -- ^ input bitvector+        -> IO (BV (l s))+logBase2_down g bv = do+   (v, c) <- priorityEncode g (length bv) bv+   iteM g v (return c)+            (return (bvFromInteger g (length bv) (-1)))++-- | Compute the rounded-up base2 logarithm of the input bitvector.+--   For x > 1, this uniquely satisfies 2^(logBase2_up(x) - 1) < x <= 2^(logBase2_up(x)).+--   For x = 1, logBase2_up 1 = 0.+--   For x = 0, we get logBase2_up 0 = <input bitvector length>; this just+--   happens to work out from the defining fomula+--   `logBase2_up x = logBase2_down (x-1) + 1`+--   when interpreted in 2's complement.+--   The output bitvector has the same width as the input bitvector.+logBase2_up+        :: IsAIG l g+        => g s+        -> BV (l s)  -- ^ input bitvector+        -> IO (BV (l s))+logBase2_up g bv = do+   bv' <- subConst g bv 1+   i <- logBase2_down g bv'+   addConst g i 1++-- | Count the number of leading zeros in the input vector; that is,+--   the number of more-significant digits set to 0 above the most+--   significant digit that is set.  If the input vector is 0, the output of+--   this function is the length of the bitvector (i.e., all digits are+--   counted as leading zeros).+--   The output bitvector has the same width as the input bitvector.+countLeadingZeros+        :: IsAIG l g+        => g s+        -> BV (l s)  -- ^ input bitvector+        -> IO (BV (l s))+countLeadingZeros g bv = do+   lg <- logBase2_down g bv+   let w'= bvFromInteger g (length bv) (fromIntegral (length bv - 1))+   sub g w' lg++-- | Count the number of trailing zeros in the input vector; that is,+--   the number of less-significant digits set to 0 below the least+--   significant digit which is set.  If the input vector is 0, the+--   output of this function is the length of the bitvector (i.e.,+--   all digits are counted as trailing zeros).+--   The output bitvector has the same width as the input bitvector.+countTrailingZeros+        :: IsAIG l g+        => g s+        -> BV (l s)  -- ^ input bitvector+        -> IO (BV (l s))+countTrailingZeros g (BV v) = do+   countLeadingZeros g (BV (V.reverse v))++-- | Given positive x, find the unique i such that: 2^i <= x < 2^(i+1)+--   This is the floor of the lg2 function.  We extend the function so+--   intLog2_down 0 = -1.+intLog2_down :: Int -> Int+#if MIN_VERSION_base(4,8,0)+intLog2_down x = (Bits.finiteBitSize x - 1) - Bits.countLeadingZeros x+#else+intLog2_down x+   | x <= 0    = -1+intLog2_down 1 =  0+intLog2_down x =  1 + intLog2_down (x `div` 2)+#endif++-- | Given positive x, find the unique i such that: 2^(i-1) < x <= 2^i+--   This is the ceiling of the lg2 function.+--   Note: intLog2_up 1 = 0+intLog2_up :: Int -> Int+intLog2_up x = intLog2_down (x - 1) + 1++-- | Priority encoder.  Given a bitvector, calculate the+--   bit position of the most-significant 1 bit, with position+--   0 corresponding to the least-significant-bit.  Return+--   the "valid" bit, which is set iff at least one bit+--   in the input is set; and the calcuated bit position.+--   If no bits are set in the input (i.e. if the valid bit is false),+--   the calculated bit position is zero.+--   The indicated bitwidth must be large enough to hold the answer;+--   in particular, we must have (length bv <= 2^w).+priorityEncode :: IsAIG l g+               => g s+               -> Int       -- ^ width of the output bitvector+               -> BV (l s)  -- ^ input bitvector+               -> IO (l s, BV (l s)) -- ^ Valid bit and position bitvector+priorityEncode g w bv+  | w < 0 = fail $ unwords ["priorityEncode: asked for negative number of output bits", show w, show $ length bv]+  | length bv == 0 = return ( falseLit g, replicate w (falseLit g) )+  | length bv == 1 = return ( bv!0, replicate w (falseLit g) )+  | otherwise = do+       let w' = intLog2_up (length bv)++       unless ( w' <= w )+              (fail $ unwords ["priorityEncode: insufficent bits to encode priority output", show w, show $ length bv])++       (v, p) <- doPriorityEncode g w' bv++       unless (length p == w')+              (fail $ unwords ["priorityEncode: length check failed", show $ length p, show w'])++       -- zero extend as necessary to fit the requested bitwidth+       let p' = replicate (w - length p) (falseLit g)+       return (v, p'++p)++-- Invariants:+--     w > 0 and 2^(w-1) < length bv <= 2^w+--      OR+--     w = 0 and length bv = 1+--+--     length <output bv> = w+doPriorityEncode+    :: IsAIG l g+    => g s+    -> Int       -- ^ width of the output bitvector+    -> BV (l s)  -- ^ input bitvector+    -> IO (l s, BV (l s))+doPriorityEncode g w bv+   | w < 0 = fail "doPriorityEncode: negative w!"++   | length bv == 1 = do                      -- w = 0+        return ( bv!0, empty )++   | length bv == 2 = do                      -- w = 1+        v <- lOr' g (bv!0) (bv!1)+        return (v, singleton (bv!1))++   | length bv == 3 = do                      -- w = 2+        vlo <- lOr' g (bv!0) (bv!1)+        let vhi = bv!2+        v  <- lOr' g vlo vhi+        e0 <- lAnd' g (not vhi) (bv!1)+        return (v, BV $ V.fromList [vhi, e0])++   | length bv == 4 = do                      -- w = 2+        vlo <- lOr' g (bv!0) (bv!1)+        vhi <- lOr' g (bv!2) (bv!3)+        v   <- lOr' g vlo vhi+        e0  <- lazyMux g vhi (return (bv!3)) (return (bv!1))+        return (v, BV $ V.fromList [vhi, e0])++   | otherwise = do                           -- w >= 3; 2^(w-1) < length b <= 2^w+       unless (w >= 3)+              (fail "doPriorityEncode: w too small!")+       unless (2^(w-1) < length bv && length bv <= 2^w)+              (fail $ unwords ["doPriorityEncode: invariant check failed"+                              , show w, show $ length bv ])++       let bitsLo = 2^(w - 1)+       let wLo = w - 1++       let bitsHi = length bv - bitsLo+       let wHi = intLog2_up bitsHi++       unless (0 < bitsHi)+              (fail "doPriorityEnode: bitsHi nonpositive")+       unless (bitsHi <= bitsLo && wHi <= wLo)+              (fail $ unwords ["doPriorityEncode: bounds check failed",+                               show bitsHi, show bitsLo, show wHi, show wLo, show w, show $ length bv])++       let bvLo = drop bitsHi bv+       let bvHi = take bitsHi bv++       (vHi, pHi) <- doPriorityEncode g wHi bvHi+       (vLo, pLo) <- doPriorityEncode g wLo bvLo++       v <- lOr' g vHi vLo+       p <- iteM g vHi+                   (return (replicate (length pLo - length pHi) (falseLit g) ++ pHi))+                   (return pLo)+       return (v, singleton vHi ++ p)++ -- | Polynomial multiplication. Note that the algorithm works the same --   no matter which endianness convention is used.  Result length is --   @max 0 (m+n-1)@, where @m@ and @n@ are the lengths of the inputs.@@ -895,6 +1096,8 @@  -- | Polynomial mod with symbolic modulus. Return value has length one -- less than the length of the modulus.+-- This implementation is optimized for the (common) case where the modulus+-- is concrete. pmod :: forall l g s. IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s)) pmod g x y = findmsb (bvToList y)   where@@ -932,3 +1135,62 @@               acc' <- Control.Monad.zipWithM (xor g) px acc               p' <- next p               go (i+1) p' acc'+++-- | Polynomial division. Return value has length+--   equal to the first argument.+pdiv :: IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s))+pdiv g x y = do+  (q,_) <- pdivmod g x y+  return q++-- Polynomial div/mod: resulting lengths are as in Cryptol.++-- TODO: probably this function should be disentangled to only compute+-- division, given that we have a separate polynomial modulus algorithm.+pdivmod :: forall l g s. IsAIG l g => g s -> BV (l s) -> BV (l s) -> IO (BV (l s), BV (l s))+pdivmod g x y = findmsb (bvToList y)+  where+    findmsb :: [l s] -> IO (BV (l s), BV (l s))+    findmsb (c : cs) = lmuxPair c (usemask cs) (findmsb cs)+    findmsb [] = return (x, replicate (length y - 1) (falseLit g)) -- division by zero++    usemask :: [l s] -> IO (BV (l s), BV (l s))+    usemask mask = do+      (qs, rs) <- pdivmod_helper g (bvToList x) mask+      let z = falseLit g+      let qs' = Prelude.map (const z) rs Prelude.++ qs+      let rs' = Prelude.replicate (length y - 1 - Prelude.length rs) z Prelude.++ rs+      let q = BV $ V.fromList qs'+      let r = BV $ V.fromList rs'+      return (q, r)++    lmuxPair :: l s -> IO (BV (l s), BV (l s)) -> IO (BV (l s), BV (l s)) -> IO (BV (l s), BV (l s))+    lmuxPair c a b+      | c === trueLit g  = a+      | c === falseLit g = b+      | otherwise = join (muxPair c <$> a <*> b)++    muxPair :: l s -> (BV (l s), BV (l s)) -> (BV (l s), BV (l s)) -> IO (BV (l s), BV (l s))+    muxPair c (x1, y1) (x2, y2) = (,) <$> zipWithM (mux g c) x1 x2 <*> zipWithM (mux g c) y1 y2++-- Divide ds by (1 : mask), giving quotient and remainder. All+-- arguments and results are big-endian. Remainder has the same length+-- as mask (but limited by length ds); total length of quotient +++-- remainder = length ds.+pdivmod_helper :: forall l g s. IsAIG l g => g s -> [l s] -> [l s] -> IO ([l s], [l s])+pdivmod_helper g ds mask = go (Prelude.length ds - Prelude.length mask) ds+  where+    go :: Int -> [l s] -> IO ([l s], [l s])+    go n cs | n <= 0 = return ([], cs)+    go _ []          = fail "Data.AIG.Operations.pdiv: impossible"+    go n (c : cs)    = do cs' <- mux_add c cs mask+                          (qs, rs) <- go (n - 1) cs'+                          return (c : qs, rs)++    mux_add :: l s -> [l s] -> [l s] -> IO [l s]+    mux_add c (x : xs) (y : ys) = do z <- lazyMux g c (xor g x y) (return x)+                                     zs <- mux_add c xs ys+                                     return (z : zs)+    mux_add _ []       (_ : _ ) = fail "Data.AIG.Operations.pdiv: impossible"+    mux_add _ xs       []       = return xs
src/Data/AIG/Trace.hs view
@@ -22,6 +22,7 @@  import Prelude hiding (not, and, or) import Data.IORef+import Data.List (intersperse) import System.IO import Control.Exception import System.IO.Unsafe@@ -106,6 +107,10 @@             hFlush h             return x +instance TraceOutput l g a => TraceOutput l g [a] where+  traceOutput g xs =+     "[" ++ concat (intersperse ", " (map (traceOutput g) xs)) ++ "]"+ instance TraceOutput l g (TraceLit l s) where   traceOutput _g (TraceLit l) = showLit l @@ -121,6 +126,14 @@ instance TraceOutput l g VerifyResult where   traceOutput _g r = show r +instance TraceOutput l g x => TraceOutput l g (LitView x) where+  traceOutput g (And x y)    = "And ("++traceOutput g x++") ("++traceOutput g y++")"+  traceOutput g (NotAnd x y) = "NotAnd ("++traceOutput g x++") ("++traceOutput g y++")"+  traceOutput _ (Input i)    = "Input "++show i+  traceOutput _ (NotInput i) = "NotInput "++show i+  traceOutput _ TrueLit      = "TrueLit"+  traceOutput _ FalseLit     = "FalseLit"+ withNewGraphTracing :: (IsAIG l g, Traceable l)                     => Proxy l g                     -> FilePath@@ -157,6 +170,9 @@   writeAiger fp0 (Network g outs0) =        (traceOp g "writeAiger" $ \fp outs -> writeAiger fp (Network (tGraph g) (map unTraceLit outs))) fp0 outs0 +  writeCNF g =+       traceOp g "writeCNF" $ \out fp -> writeCNF (tGraph g) (unTraceLit out) fp+   checkSat g = traceOp g "checkSat" $ \(TraceLit x) -> checkSat (tGraph g) x    cec (Network g1 outs1') (Network g2 outs2') =@@ -175,6 +191,8 @@                      Just h  -> seq (unsafePerformIO (traceIO l x h)) x            ev <- evaluator (tGraph g) ins            return (\(TraceLit l) -> trace l $ ev l)++  litView g = traceOp g "litView" $ \(TraceLit l) -> fmap (fmap TraceLit) (litView (tGraph g) l)    abstractEvaluateAIG g f =         do mh <- readIORef (tActive g)