@@ -8,16 +8,16 @@ module SAWScript.Prover.ABC
88import Control.Monad (unless )
99import Control.Monad.IO.Class
1010import qualified Data.ByteString.Char8 as C8
11- import Data.Char (isSpace )
1211import Data.List (isPrefixOf )
1312import qualified Data.Map as Map
1413import Data.Maybe
1514import qualified Data.Text as Text
1615import Text.Read (readMaybe )
1716
1817import System.Directory
18+ import System.FilePath ((</>) )
1919import System.IO
20- import System.IO.Temp (emptySystemTempFile )
20+ import System.IO.Temp (createTempDirectory , getCanonicalTemporaryDirectory )
2121import System.Process (readProcessWithExitCode )
2222
2323import qualified Data.AIG as AIG
@@ -105,30 +105,33 @@ w4AbcExternal ::
105105 SATQuery ->
106106 TopLevel (Maybe CEX , String )
107107w4AbcExternal exporter argFn _hashcons satq =
108- -- Create temporary files
109- do let tpl = " abc_verilog.v "
110- tplCex = " abc_verilog.cex "
111- tmp <- liftIO $ emptySystemTempFile tpl
112- tmpCex <- liftIO $ emptySystemTempFile tplCex
108+ -- Create a temporary directory to put input and output files
109+ do canonTmpDir <- liftIO getCanonicalTemporaryDirectory
110+ tmpDir <- liftIO $ createTempDirectory canonTmpDir " saw_abc_external "
111+ let tmp = tmpDir </> " abc_verilog.v "
112+ tmpCex = tmpDir </> " abc_verilog.cex "
113113
114114 (argNames, argTys) <- unzip <$> exporter tmp satq
115115
116116 -- Run ABC and remove temporaries
117117 let execName = " abc"
118118 args = [" -q" , argFn tmp tmpCex]
119119 (_out, _err) <- liftIO $ readProcessExitIfFailure execName args
120- cexText <- liftIO $ C8. unpack <$> C8. readFile tmpCex
121- liftIO $ removeFile tmp
122- liftIO $ removeFile tmpCex
123-
124- -- Parse and report results
125- res <- if all isSpace cexText
126- then return Nothing
127- else do cex <- liftIO $ parseAigerCex cexText argTys
128- case cex of
129- Left parseErr -> fail parseErr
130- Right vs -> return $ Just model
131- where model = zip argNames (map toFirstOrderValue vs)
120+ cexExists <- liftIO $ doesFileExist tmpCex
121+ res <-
122+ if cexExists
123+ then do
124+ -- If a counterexample file exists, parse and report the results.
125+ cexText <- liftIO $ C8. unpack <$> C8. readFile tmpCex
126+ cex <- liftIO $ parseAigerCex cexText argTys
127+ case cex of
128+ Left parseErr -> fail parseErr
129+ Right vs -> return $ Just model
130+ where model = zip argNames (map toFirstOrderValue vs)
131+ else
132+ -- Otherwise, there is no counterexample.
133+ return Nothing
134+ liftIO $ removeDirectoryRecursive tmpDir
132135 return (res, " abc_verilog" )
133136
134137parseAigerCex :: String -> [FiniteType ] -> IO (Either String [FiniteValue ])
@@ -137,11 +140,15 @@ parseAigerCex text tys =
137140 -- Output from `write_cex`
138141 [cex] ->
139142 case words cex of
143+ -- Queries with no variables will result in a blank line of output.
144+ [] -> pure $ liftCexBB tys []
140145 [bits] -> liftCexBB tys <$> mapM bitToBool bits
141146 _ -> fail $ " invalid counterexample line: " ++ cex
142147 -- Output from `write_aiger_cex`
143148 [_, cex] ->
144149 case words cex of
150+ -- Queries with no variables will result in an empty vector of output.
151+ [_] -> pure $ liftCexBB tys []
145152 [bits, _] -> liftLECexBB tys <$> mapM bitToBool bits
146153 _ -> fail $ " invalid counterexample line: " ++ cex
147154 _ -> fail $ " invalid counterexample text: " ++ text
0 commit comments