PageRenderTime 51ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/Data/SBV/SMT/SMTLib2.hs

http://github.com/LeventErkok/sbv
Haskell | 1344 lines | 989 code | 202 blank | 153 comment | 76 complexity | 147fcba7d4dd5ed48a1a7d09661a2a35 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. -----------------------------------------------------------------------------
  2. -- |
  3. -- Module : Data.SBV.SMT.SMTLib2
  4. -- Copyright : (c) Levent Erkok
  5. -- License : BSD3
  6. -- Maintainer: erkokl@gmail.com
  7. -- Stability : experimental
  8. --
  9. -- Conversion of symbolic programs to SMTLib format, Using v2 of the standard
  10. -----------------------------------------------------------------------------
  11. {-# LANGUAGE PatternGuards #-}
  12. {-# LANGUAGE ScopedTypeVariables #-}
  13. {-# LANGUAGE ViewPatterns #-}
  14. {-# OPTIONS_GHC -Wall -Werror #-}
  15. module Data.SBV.SMT.SMTLib2(cvt, cvtInc) where
  16. import Data.Bits (bit)
  17. import Data.List (intercalate, partition, nub, sort)
  18. import Data.Maybe (listToMaybe, fromMaybe, catMaybes)
  19. import qualified Data.Foldable as F (toList)
  20. import qualified Data.Map.Strict as M
  21. import qualified Data.IntMap.Strict as IM
  22. import Data.Set (Set)
  23. import qualified Data.Set as Set
  24. import Data.SBV.Core.Data
  25. import Data.SBV.Core.Symbolic (QueryContext(..), SetOp(..), OvOp(..), CnstMap, getUserName', getSV, regExpToSMTString)
  26. import Data.SBV.Core.Kind (smtType, needsFlattening)
  27. import Data.SBV.SMT.Utils
  28. import Data.SBV.Control.Types
  29. import Data.SBV.Utils.PrettyNum (smtRoundingMode, cvToSMTLib)
  30. import qualified Data.Generics.Uniplate.Data as G
  31. tbd :: String -> a
  32. tbd e = error $ "SBV.SMTLib2: Not-yet-supported: " ++ e
  33. -- | Translate a problem into an SMTLib2 script
  34. cvt :: SMTLibConverter [String]
  35. cvt ctx kindInfo isSat comments (inputs, trackerVars) skolemInps (allConsts, consts) tbls arrs uis axs (SBVPgm asgnsSeq) cstrs out cfg = pgm
  36. where hasInteger = KUnbounded `Set.member` kindInfo
  37. hasReal = KReal `Set.member` kindInfo
  38. hasFP = not (null [() | KFP{} <- Set.toList kindInfo])
  39. || KFloat `Set.member` kindInfo
  40. || KDouble `Set.member` kindInfo
  41. hasString = KString `Set.member` kindInfo
  42. hasChar = KChar `Set.member` kindInfo
  43. hasRounding = not $ null [s | (s, _) <- usorts, s == "RoundingMode"]
  44. hasBVs = not (null [() | KBounded{} <- Set.toList kindInfo])
  45. usorts = [(s, dt) | KUserSort s dt <- Set.toList kindInfo]
  46. trueUSorts = [s | (s, _) <- usorts, s /= "RoundingMode"]
  47. tupleArities = findTupleArities kindInfo
  48. hasNonBVArrays = (not . null) [() | (_, (_, (k1, k2), _)) <- arrs, not (isBounded k1 && isBounded k2)]
  49. hasArrayInits = (not . null) [() | (_, (_, _, ArrayFree (Just _))) <- arrs]
  50. hasOverflows = (not . null) [() | (_ :: OvOp) <- G.universeBi asgnsSeq]
  51. hasList = any isList kindInfo
  52. hasSets = any isSet kindInfo
  53. hasTuples = not . null $ tupleArities
  54. hasEither = any isEither kindInfo
  55. hasMaybe = any isMaybe kindInfo
  56. hasRational = any isRational kindInfo
  57. rm = roundingMode cfg
  58. solverCaps = capabilities (solver cfg)
  59. -- Is there a reason why we can't handle this problem?
  60. -- NB. There's probably a lot more checking we can do here, but this is a start:
  61. doesntHandle = listToMaybe [nope w | (w, have, need) <- checks, need && not have]
  62. where checks = [ ("data types", supportsDataTypes solverCaps, hasTuples || hasEither || hasMaybe)
  63. , ("set operations", supportsSets solverCaps, hasSets)
  64. , ("bit vectors", supportsBitVectors solverCaps, hasBVs)
  65. ]
  66. nope w = [ "*** Given problem requires support for " ++ w
  67. , "*** But the chosen solver (" ++ show (name (solver cfg)) ++ ") doesn't support this feature."
  68. ]
  69. setAll reason = ["(set-logic ALL) ; " ++ reason ++ ", using catch-all."]
  70. -- Determining the logic is surprisingly tricky!
  71. logic
  72. -- user told us what to do: so just take it:
  73. | Just l <- case [l | SetLogic l <- solverSetOptions cfg] of
  74. [] -> Nothing
  75. [l] -> Just l
  76. ls -> error $ unlines [ ""
  77. , "*** Only one setOption call to 'setLogic' is allowed, found: " ++ show (length ls)
  78. , "*** " ++ unwords (map show ls)
  79. ]
  80. = case l of
  81. Logic_NONE -> ["; NB. Not setting the logic per user request of Logic_NONE"]
  82. _ -> ["(set-logic " ++ show l ++ ") ; NB. User specified."]
  83. -- There's a reason why we can't handle this problem:
  84. | Just cantDo <- doesntHandle
  85. = error $ unlines $ [ ""
  86. , "*** SBV is unable to choose a proper solver configuration:"
  87. , "***"
  88. ]
  89. ++ cantDo
  90. ++ [ "***"
  91. , "*** Please report this as a feature request, either for SBV or the backend solver."
  92. ]
  93. -- Otherwise, we try to determine the most suitable logic.
  94. -- NB. This isn't really fool proof!
  95. -- we never set QF_S (ALL seems to work better in all cases)
  96. -- Things that require ALL
  97. | hasInteger = setAll "has unbounded values"
  98. | hasRational = setAll "has rational values"
  99. | hasReal = setAll "has algebraic reals"
  100. | not (null trueUSorts) = setAll "has user-defined sorts"
  101. | hasNonBVArrays = setAll "has non-bitvector arrays"
  102. | hasTuples = setAll "has tuples"
  103. | hasEither = setAll "has either type"
  104. | hasMaybe = setAll "has maybe type"
  105. | hasSets = setAll "has sets"
  106. | hasList = setAll "has lists"
  107. | hasChar = setAll "has chars"
  108. | hasString = setAll "has strings"
  109. | hasArrayInits = setAll "has array initializers"
  110. | hasOverflows = setAll "has overflow checks"
  111. | hasFP || hasRounding
  112. = if not (null foralls)
  113. then ["(set-logic ALL)"]
  114. else if hasBVs
  115. then ["(set-logic QF_FPBV)"]
  116. else ["(set-logic QF_FP)"]
  117. -- If we're in a user query context, we'll pick ALL, otherwise
  118. -- we'll stick to some bit-vector logic based on what we see in the problem.
  119. -- This is controversial, but seems to work well in practice.
  120. | True
  121. = case ctx of
  122. QueryExternal -> ["(set-logic ALL) ; external query, using all logics."]
  123. QueryInternal -> if supportsBitVectors solverCaps
  124. then ["(set-logic " ++ qs ++ as ++ ufs ++ "BV)"]
  125. else ["(set-logic ALL)"] -- fall-thru
  126. where qs | null foralls && null axs = "QF_" -- axioms are likely to contain quantifiers
  127. | True = ""
  128. as | null arrs = ""
  129. | True = "A"
  130. ufs | null uis && null tbls = "" -- we represent tables as UFs
  131. | True = "UF"
  132. -- SBV always requires the production of models!
  133. getModels = "(set-option :produce-models true)"
  134. : concat [flattenConfig | any needsFlattening kindInfo, Just flattenConfig <- [supportsFlattenedModels solverCaps]]
  135. -- process all other settings we're given. If an option cannot be repeated, we only take the last one.
  136. userSettings = map setSMTOption $ filter (not . isLogic) $ foldr comb [] $ solverSetOptions cfg
  137. where -- Logic is already processed, so drop it:
  138. isLogic SetLogic{} = True
  139. isLogic _ = False
  140. -- SBV sets diagnostic-output channel on some solvers. If the user also gives it, let's just
  141. -- take it by only taking the last one
  142. isDiagOutput DiagnosticOutputChannel{} = True
  143. isDiagOutput _ = False
  144. comb o rest
  145. | isDiagOutput o && any isDiagOutput rest = rest
  146. | True = o : rest
  147. settings = userSettings -- NB. Make sure this comes first!
  148. ++ getModels
  149. ++ logic
  150. pgm = map ("; " ++) comments
  151. ++ settings
  152. ++ [ "; --- uninterpreted sorts ---" ]
  153. ++ concatMap declSort usorts
  154. ++ [ "; --- tuples ---" ]
  155. ++ concatMap declTuple tupleArities
  156. ++ [ "; --- sums ---" ]
  157. ++ (if containsSum kindInfo then declSum else [])
  158. ++ (if containsMaybe kindInfo then declMaybe else [])
  159. ++ (if containsRationals kindInfo then declRationals else [])
  160. ++ [ "; --- literal constants ---" ]
  161. ++ concatMap (declConst cfg) consts
  162. ++ [ "; --- skolem constants ---" ]
  163. ++ concat [declareFun s (SBVType (map kindOf (ss ++ [s]))) (userName s) | Right (s, ss) <- skolemInps]
  164. ++ [ "; --- optimization tracker variables ---" | not (null trackerVars) ]
  165. ++ concat [declareFun s (SBVType [kindOf s]) (Just ("tracks " <> nm)) | var <- trackerVars, let s = getSV var, let nm = getUserName' var]
  166. ++ [ "; --- constant tables ---" ]
  167. ++ concatMap (uncurry (:) . constTable) constTables
  168. ++ [ "; --- skolemized tables ---" ]
  169. ++ map (skolemTable (unwords (map svType foralls))) skolemTables
  170. ++ [ "; --- arrays ---" ]
  171. ++ concat arrayConstants
  172. ++ [ "; --- uninterpreted constants ---" ]
  173. ++ concatMap declUI uis
  174. ++ [ "; --- user given axioms ---" ]
  175. ++ map declAx axs
  176. ++ [ "; --- preQuantifier assignments ---" ]
  177. ++ concatMap (declDef cfg skolemMap tableMap) preQuantifierAssigns
  178. ++ [ "; --- arrayDelayeds ---" ]
  179. ++ concat arrayDelayeds
  180. ++ [ "; --- arraySetups ---" ]
  181. ++ concat arraySetups
  182. ++ [ "; --- formula ---" ]
  183. ++ ["(assert (forall (" ++ intercalate "\n "
  184. ["(" ++ show s ++ " " ++ svType s ++ ")" | s <- foralls] ++ ")"
  185. | not (null foralls)
  186. ]
  187. ++ [ "; --- postQuantifier assignments ---" ]
  188. ++ concatMap mkAssign postQuantifierAssigns
  189. ++ [ "; --- delayedEqualities ---" ]
  190. ++ delayedAsserts delayedEqualities
  191. ++ [ "; -- finalAssert ---" ]
  192. ++ finalAssert
  193. -- identify the assignments that can come before the first quantifier
  194. (preQuantifierAssigns, postQuantifierAssigns)
  195. | null foralls
  196. = (asgns, [])
  197. | True
  198. = span pre asgns
  199. where first = nodeId (minimum foralls)
  200. pre (s, _) = nodeId s < first
  201. nodeId (SV _ n) = n
  202. noOfCloseParens
  203. | null foralls = 0
  204. | True = length postQuantifierAssigns + 2 + (if null delayedEqualities then 0 else 1)
  205. foralls = [s | Left s <- skolemInps]
  206. forallArgs = concatMap ((" " ++) . show) foralls
  207. (constTables, skolemTables) = ([(t, d) | (t, Left d) <- allTables], [(t, d) | (t, Right d) <- allTables])
  208. allTables = [(t, genTableData rm skolemMap (not (null foralls), forallArgs) (map fst consts) t) | t <- tbls]
  209. (arrayConstants, arrayDelayeds, arraySetups) = unzip3 $ map (declArray cfg (not (null foralls)) allConsts skolemMap) arrs
  210. delayedEqualities = concatMap snd skolemTables
  211. delayedAsserts [] = []
  212. delayedAsserts ds@(deH : deTs)
  213. | null foralls = map (\s -> "(assert " ++ s ++ ")") ds
  214. | True = map letShift (("(and " ++ deH) : map (align 5) deTs)
  215. letShift = align 12
  216. finalAssert
  217. | null foralls && noConstraints
  218. = []
  219. | null foralls
  220. = map (\(attr, v) -> "(assert " ++ addAnnotations attr (mkLiteral v) ++ ")") hardAsserts
  221. ++ map (\(attr, v) -> "(assert-soft " ++ addAnnotations attr (mkLiteral v) ++ ")") softAsserts
  222. | not (null namedAsserts)
  223. = error $ intercalate "\n" [ "SBV: Constraints with attributes and quantifiers cannot be mixed!"
  224. , " Quantified variables: " ++ unwords (map show foralls)
  225. , " Named constraints : " ++ intercalate ", " (map show namedAsserts)
  226. ]
  227. | not (null softAsserts)
  228. = error $ intercalate "\n" [ "SBV: Soft constraints and quantifiers cannot be mixed!"
  229. , " Quantified variables: " ++ unwords (map show foralls)
  230. , " Soft constraints : " ++ intercalate ", " (map show softAsserts)
  231. ]
  232. | True
  233. = [impAlign (letShift combined) ++ replicate noOfCloseParens ')']
  234. where mkLiteral (Left v) = cvtSV skolemMap v
  235. mkLiteral (Right v) = "(not " ++ cvtSV skolemMap v ++ ")"
  236. (noConstraints, assertions) = finalAssertions
  237. namedAsserts = [findName attrs | (_, attrs, _) <- assertions, not (null attrs)]
  238. where findName attrs = fromMaybe "<anonymous>" (listToMaybe [nm | (":named", nm) <- attrs])
  239. hardAsserts, softAsserts :: [([(String, String)], Either SV SV)]
  240. hardAsserts = [(attr, v) | (False, attr, v) <- assertions]
  241. softAsserts = [(attr, v) | (True, attr, v) <- assertions]
  242. combined = case lits of
  243. [] -> "true"
  244. [x] -> mkLiteral x
  245. xs | any bad xs -> "false"
  246. | True -> "(and " ++ unwords (map mkLiteral xs) ++ ")"
  247. where lits = filter (not . redundant) $ nub (sort (map snd hardAsserts))
  248. redundant (Left v) = v == trueSV
  249. redundant (Right v) = v == falseSV
  250. bad (Left v) = v == falseSV
  251. bad (Right v) = v == trueSV
  252. impAlign s
  253. | null delayedEqualities = s
  254. | True = " " ++ s
  255. align n s = replicate n ' ' ++ s
  256. finalAssertions :: (Bool, [(Bool, [(String, String)], Either SV SV)]) -- If Left: positive, Right: negative
  257. finalAssertions
  258. | null finals = (True, [(False, [], Left trueSV)])
  259. | True = (False, finals)
  260. where finals = cstrs' ++ maybe [] (\r -> [(False, [], r)]) mbO
  261. cstrs' = [(isSoft, attrs, c') | (isSoft, attrs, c) <- F.toList cstrs, Just c' <- [pos c]]
  262. mbO | isSat = pos out
  263. | True = neg out
  264. neg s
  265. | s == falseSV = Nothing
  266. | s == trueSV = Just $ Left falseSV
  267. | True = Just $ Right s
  268. pos s
  269. | s == trueSV = Nothing
  270. | s == falseSV = Just $ Left falseSV
  271. | True = Just $ Left s
  272. skolemMap = M.fromList [(s, ss) | Right (s, ss) <- skolemInps, not (null ss)]
  273. tableMap = IM.fromList $ map mkConstTable constTables ++ map mkSkTable skolemTables
  274. where mkConstTable (((t, _, _), _), _) = (t, "table" ++ show t)
  275. mkSkTable (((t, _, _), _), _) = (t, "table" ++ show t ++ forallArgs)
  276. asgns = F.toList asgnsSeq
  277. mkAssign a
  278. | null foralls = declDef cfg skolemMap tableMap a
  279. | True = [letShift (mkLet a)]
  280. mkLet (s, SBVApp (Label m) [e]) = "(let ((" ++ show s ++ " " ++ cvtSV skolemMap e ++ ")) ; " ++ m
  281. mkLet (s, e) = "(let ((" ++ show s ++ " " ++ cvtExp solverCaps rm skolemMap tableMap e ++ "))"
  282. userNameMap = M.fromList $ map ((\nSymVar -> (getSV nSymVar, getUserName' nSymVar)) . snd) inputs
  283. userName s = case M.lookup s userNameMap of
  284. Just u | show s /= u -> Just $ "tracks user variable " ++ show u
  285. _ -> Nothing
  286. -- | Declare new sorts
  287. declSort :: (String, Maybe [String]) -> [String]
  288. declSort (s, _)
  289. | s == "RoundingMode" -- built-in-sort; so don't declare.
  290. = []
  291. declSort (s, Nothing) = ["(declare-sort " ++ s ++ " 0) ; N.B. Uninterpreted sort." ]
  292. declSort (s, Just fs) = [ "(declare-datatypes ((" ++ s ++ " 0)) ((" ++ unwords (map (\c -> "(" ++ c ++ ")") fs) ++ ")))"
  293. , "(define-fun " ++ s ++ "_constrIndex ((x " ++ s ++ ")) Int"
  294. ] ++ [" " ++ body fs (0::Int)] ++ [")"]
  295. where body [] _ = ""
  296. body [_] i = show i
  297. body (c:cs) i = "(ite (= x " ++ c ++ ") " ++ show i ++ " " ++ body cs (i+1) ++ ")"
  298. -- | Declare tuple datatypes
  299. --
  300. -- eg:
  301. --
  302. -- @
  303. -- (declare-datatypes ((SBVTuple2 2)) ((par (T1 T2)
  304. -- ((mkSBVTuple2 (proj_1_SBVTuple2 T1)
  305. -- (proj_2_SBVTuple2 T2))))))
  306. -- @
  307. declTuple :: Int -> [String]
  308. declTuple arity
  309. | arity == 0 = ["(declare-datatypes ((SBVTuple0 0)) (((mkSBVTuple0))))"]
  310. | arity == 1 = error "Data.SBV.declTuple: Unexpected one-tuple"
  311. | True = (l1 ++ "(par (" ++ unwords [param i | i <- [1..arity]] ++ ")")
  312. : [pre i ++ proj i ++ post i | i <- [1..arity]]
  313. where l1 = "(declare-datatypes ((SBVTuple" ++ show arity ++ " " ++ show arity ++ ")) ("
  314. l2 = replicate (length l1) ' ' ++ "((mkSBVTuple" ++ show arity ++ " "
  315. tab = replicate (length l2) ' '
  316. pre 1 = l2
  317. pre _ = tab
  318. proj i = "(proj_" ++ show i ++ "_SBVTuple" ++ show arity ++ " " ++ param i ++ ")"
  319. post i = if i == arity then ")))))" else ""
  320. param i = "T" ++ show i
  321. -- | Find the set of tuple sizes to declare, eg (2-tuple, 5-tuple).
  322. -- NB. We do *not* need to recursively go into list/tuple kinds here,
  323. -- because register-kind function automatically registers all subcomponent
  324. -- kinds, thus everything we need is available at the top-level.
  325. findTupleArities :: Set Kind -> [Int]
  326. findTupleArities ks = Set.toAscList
  327. $ Set.map length
  328. $ Set.fromList [ tupKs | KTuple tupKs <- Set.toList ks ]
  329. -- | Is @Either@ being used?
  330. containsSum :: Set Kind -> Bool
  331. containsSum = not . Set.null . Set.filter isEither
  332. -- | Is @Maybe@ being used?
  333. containsMaybe :: Set Kind -> Bool
  334. containsMaybe = not . Set.null . Set.filter isMaybe
  335. -- | Is @Rational@ being used?
  336. containsRationals :: Set Kind -> Bool
  337. containsRationals = not . Set.null . Set.filter isRational
  338. declSum :: [String]
  339. declSum = [ "(declare-datatypes ((SBVEither 2)) ((par (T1 T2)"
  340. , " ((left_SBVEither (get_left_SBVEither T1))"
  341. , " (right_SBVEither (get_right_SBVEither T2))))))"
  342. ]
  343. declMaybe :: [String]
  344. declMaybe = [ "(declare-datatypes ((SBVMaybe 1)) ((par (T)"
  345. , " ((nothing_SBVMaybe)"
  346. , " (just_SBVMaybe (get_just_SBVMaybe T))))))"
  347. ]
  348. -- Internally, we do *not* keep the rationals in reduced form! So, the boolean operators explicitly do the math
  349. -- to make sure equivalent values are treated correctly.
  350. declRationals :: [String]
  351. declRationals = [ "(declare-datatype SBVRational ((SBV.Rational (sbv.rat.numerator Int) (sbv.rat.denominator Int))))"
  352. , ""
  353. , "(define-fun sbv.rat.eq ((x SBVRational) (y SBVRational)) Bool"
  354. , " (= (* (sbv.rat.numerator x) (sbv.rat.denominator y))"
  355. , " (* (sbv.rat.denominator x) (sbv.rat.numerator y)))"
  356. , ")"
  357. , ""
  358. , "(define-fun sbv.rat.notEq ((x SBVRational) (y SBVRational)) Bool"
  359. , " (not (sbv.rat.eq x y))"
  360. , ")"
  361. , ""
  362. , "(define-fun sbv.rat.lt ((x SBVRational) (y SBVRational)) Bool"
  363. , " (< (* (sbv.rat.numerator x) (sbv.rat.denominator y))"
  364. , " (* (sbv.rat.denominator x) (sbv.rat.numerator y)))"
  365. , ")"
  366. , ""
  367. , "(define-fun sbv.rat.leq ((x SBVRational) (y SBVRational)) Bool"
  368. , " (<= (* (sbv.rat.numerator x) (sbv.rat.denominator y))"
  369. , " (* (sbv.rat.denominator x) (sbv.rat.numerator y)))"
  370. , ")"
  371. , ""
  372. , "(define-fun sbv.rat.plus ((x SBVRational) (y SBVRational)) SBVRational"
  373. , " (SBV.Rational (+ (* (sbv.rat.numerator x) (sbv.rat.denominator y))"
  374. , " (* (sbv.rat.denominator x) (sbv.rat.numerator y)))"
  375. , " (* (sbv.rat.denominator x) (sbv.rat.denominator y)))"
  376. , ")"
  377. , ""
  378. , "(define-fun sbv.rat.minus ((x SBVRational) (y SBVRational)) SBVRational"
  379. , " (SBV.Rational (- (* (sbv.rat.numerator x) (sbv.rat.denominator y))"
  380. , " (* (sbv.rat.denominator x) (sbv.rat.numerator y)))"
  381. , " (* (sbv.rat.denominator x) (sbv.rat.denominator y)))"
  382. , ")"
  383. , ""
  384. , "(define-fun sbv.rat.times ((x SBVRational) (y SBVRational)) SBVRational"
  385. , " (SBV.Rational (* (sbv.rat.numerator x) (sbv.rat.numerator y))"
  386. , " (* (sbv.rat.denominator x) (sbv.rat.denominator y)))"
  387. , ")"
  388. , ""
  389. , "(define-fun sbv.rat.uneg ((x SBVRational)) SBVRational"
  390. , " (SBV.Rational (* (- 1) (sbv.rat.numerator x)) (sbv.rat.denominator x))"
  391. , ")"
  392. , ""
  393. , "(define-fun sbv.rat.abs ((x SBVRational)) SBVRational"
  394. , " (SBV.Rational (abs (sbv.rat.numerator x)) (sbv.rat.denominator x))"
  395. , ")"
  396. ]
  397. -- | Convert in a query context.
  398. -- NB. We do not store everything in @newKs@ below, but only what we need
  399. -- to do as an extra in the incremental context. See `Data.SBV.Core.Symbolic.registerKind`
  400. -- for a list of what we include, in case something doesn't show up
  401. -- and you need it!
  402. cvtInc :: SMTLibIncConverter [String]
  403. cvtInc inps newKs (allConsts, consts) arrs tbls uis (SBVPgm asgnsSeq) cstrs cfg =
  404. -- any new settings?
  405. settings
  406. -- sorts
  407. ++ concatMap declSort [(s, dt) | KUserSort s dt <- newKinds]
  408. -- tuples. NB. Only declare the new sizes, old sizes persist.
  409. ++ concatMap declTuple (findTupleArities newKs)
  410. -- sums
  411. ++ (if containsSum newKs then declSum else [])
  412. ++ (if containsMaybe newKs then declMaybe else [])
  413. -- constants
  414. ++ concatMap (declConst cfg) consts
  415. -- inputs
  416. ++ concatMap declInp inps
  417. -- arrays
  418. ++ concat arrayConstants
  419. -- uninterpreteds
  420. ++ concatMap declUI uis
  421. -- table declarations
  422. ++ tableDecls
  423. -- expressions
  424. ++ concatMap (declDef cfg skolemMap tableMap) (F.toList asgnsSeq)
  425. -- delayed equalities
  426. ++ concat arrayDelayeds
  427. -- table setups
  428. ++ concat tableAssigns
  429. -- array setups
  430. ++ concat arraySetups
  431. -- extra constraints
  432. ++ map (\(isSoft, attr, v) -> "(assert" ++ (if isSoft then "-soft " else " ") ++ addAnnotations attr (cvtSV skolemMap v) ++ ")") (F.toList cstrs)
  433. where -- NB. The below setting of skolemMap to empty is OK, since we do
  434. -- not support queries in the context of skolemized variables
  435. skolemMap = M.empty
  436. rm = roundingMode cfg
  437. newKinds = Set.toList newKs
  438. declInp (getSV -> s) = declareFun s (SBVType [kindOf s]) Nothing
  439. (arrayConstants, arrayDelayeds, arraySetups) = unzip3 $ map (declArray cfg False allConsts skolemMap) arrs
  440. allTables = [(t, either id id (genTableData rm skolemMap (False, []) (map fst consts) t)) | t <- tbls]
  441. (tableDecls, tableAssigns) = unzip $ map constTable allTables
  442. tableMap = IM.fromList $ map mkTable allTables
  443. where mkTable (((t, _, _), _), _) = (t, "table" ++ show t)
  444. -- If we need flattening in models, do emit the required lines if preset
  445. settings
  446. | any needsFlattening newKinds
  447. = concat (catMaybes [supportsFlattenedModels solverCaps])
  448. | True
  449. = []
  450. where solverCaps = capabilities (solver cfg)
  451. declDef :: SMTConfig -> SkolemMap -> TableMap -> (SV, SBVExpr) -> [String]
  452. declDef cfg skolemMap tableMap (s, expr) =
  453. case expr of
  454. SBVApp (Label m) [e] -> defineFun cfg (s, cvtSV skolemMap e) (Just m)
  455. e -> defineFun cfg (s, cvtExp caps rm skolemMap tableMap e) Nothing
  456. where caps = capabilities (solver cfg)
  457. rm = roundingMode cfg
  458. defineFun :: SMTConfig -> (SV, String) -> Maybe String -> [String]
  459. defineFun cfg (s, def) mbComment
  460. | hasDefFun = ["(define-fun " ++ varT ++ " " ++ def ++ ")" ++ cmnt]
  461. | True = [ "(declare-fun " ++ varT ++ ")" ++ cmnt
  462. , "(assert (= " ++ var ++ " " ++ def ++ "))"
  463. ]
  464. where var = show s
  465. varT = var ++ " " ++ svFunType [] s
  466. cmnt = maybe "" (" ; " ++) mbComment
  467. hasDefFun = supportsDefineFun $ capabilities (solver cfg)
  468. -- Declare constants. NB. We don't declare true/false; but just inline those as necessary
  469. declConst :: SMTConfig -> (SV, CV) -> [String]
  470. declConst cfg (s, c)
  471. | s == falseSV || s == trueSV
  472. = []
  473. | True
  474. = defineFun cfg (s, cvtCV (roundingMode cfg) c) Nothing
  475. declUI :: (String, SBVType) -> [String]
  476. declUI (i, t) = declareName i t Nothing
  477. -- NB. We perform no check to as to whether the axiom is meaningful in any way.
  478. declAx :: (String, [String]) -> String
  479. declAx (nm, ls) = (";; -- user given axiom: " ++ nm ++ "\n") ++ intercalate "\n" ls
  480. constTable :: (((Int, Kind, Kind), [SV]), [String]) -> (String, [String])
  481. constTable (((i, ak, rk), _elts), is) = (decl, zipWith wrap [(0::Int)..] is ++ setup)
  482. where t = "table" ++ show i
  483. decl = "(declare-fun " ++ t ++ " (" ++ smtType ak ++ ") " ++ smtType rk ++ ")"
  484. -- Arrange for initializers
  485. mkInit idx = "table" ++ show i ++ "_initializer_" ++ show (idx :: Int)
  486. initializer = "table" ++ show i ++ "_initializer"
  487. wrap index s = "(define-fun " ++ mkInit index ++ " () Bool " ++ s ++ ")"
  488. lis = length is
  489. setup
  490. | lis == 0 = [ "(define-fun " ++ initializer ++ " () Bool true) ; no initialization needed"
  491. ]
  492. | lis == 1 = [ "(define-fun " ++ initializer ++ " () Bool " ++ mkInit 0 ++ ")"
  493. , "(assert " ++ initializer ++ ")"
  494. ]
  495. | True = [ "(define-fun " ++ initializer ++ " () Bool (and " ++ unwords (map mkInit [0..lis - 1]) ++ "))"
  496. , "(assert " ++ initializer ++ ")"
  497. ]
  498. skolemTable :: String -> (((Int, Kind, Kind), [SV]), [String]) -> String
  499. skolemTable qsIn (((i, ak, rk), _elts), _) = decl
  500. where qs = if null qsIn then "" else qsIn ++ " "
  501. t = "table" ++ show i
  502. decl = "(declare-fun " ++ t ++ " (" ++ qs ++ smtType ak ++ ") " ++ smtType rk ++ ")"
  503. -- Left if all constants, Right if otherwise
  504. genTableData :: RoundingMode -> SkolemMap -> (Bool, String) -> [SV] -> ((Int, Kind, Kind), [SV]) -> Either [String] [String]
  505. genTableData rm skolemMap (_quantified, args) consts ((i, aknd, _), elts)
  506. | null post = Left (map (topLevel . snd) pre)
  507. | True = Right (map (nested . snd) (pre ++ post))
  508. where ssv = cvtSV skolemMap
  509. (pre, post) = partition fst (zipWith mkElt elts [(0::Int)..])
  510. t = "table" ++ show i
  511. mkElt x k = (isReady, (idx, ssv x))
  512. where idx = cvtCV rm (mkConstCV aknd k)
  513. isReady = x `Set.member` constsSet
  514. topLevel (idx, v) = "(= (" ++ t ++ " " ++ idx ++ ") " ++ v ++ ")"
  515. nested (idx, v) = "(= (" ++ t ++ args ++ " " ++ idx ++ ") " ++ v ++ ")"
  516. constsSet = Set.fromList consts
  517. -- TODO: We currently do not support non-constant arrays when quantifiers are present, as
  518. -- we might have to skolemize those. Implement this properly.
  519. -- The difficulty is with the Mutate/Merge: We have to postpone an init if
  520. -- the components are themselves postponed, so this cannot be implemented as a simple map.
  521. declArray :: SMTConfig -> Bool -> CnstMap -> SkolemMap -> (Int, ArrayInfo) -> ([String], [String], [String])
  522. declArray cfg quantified consts skolemMap (i, (_, (aKnd, bKnd), ctx)) = (adecl : zipWith wrap [(0::Int)..] (map snd pre), zipWith wrap [lpre..] (map snd post), setup)
  523. where constMapping = M.fromList [(s, c) | (c, s) <- M.assocs consts]
  524. constNames = M.keys constMapping
  525. topLevel = not quantified || case ctx of
  526. ArrayFree mbi -> maybe True (`elem` constNames) mbi
  527. ArrayMutate _ a b -> all (`elem` constNames) [a, b]
  528. ArrayMerge c _ _ -> c `elem` constNames
  529. (pre, post) = partition fst ctxInfo
  530. nm = "array_" ++ show i
  531. ssv sv
  532. | topLevel || sv `elem` constNames
  533. = cvtSV skolemMap sv
  534. | True
  535. = tbd "Non-constant array initializer in a quantified context"
  536. atyp = "(Array " ++ smtType aKnd ++ " " ++ smtType bKnd ++ ")"
  537. adecl = case ctx of
  538. ArrayFree (Just v) -> "(define-fun " ++ nm ++ " () " ++ atyp ++ " ((as const " ++ atyp ++ ") " ++ constInit v ++ "))"
  539. ArrayFree Nothing
  540. | bKnd == KChar -> -- Can't support yet, because we need to make sure all the elements are length-1 strings. So, punt for now.
  541. tbd "Free array declarations containing SChars"
  542. _ -> "(declare-fun " ++ nm ++ " () " ++ atyp ++ ")"
  543. -- CVC4 chokes if the initializer is not a constant. (Z3 is ok with it.) So, print it as
  544. -- a constant if we have it in the constants; otherwise, we merely print it and hope for the best.
  545. constInit v = case v `M.lookup` constMapping of
  546. Nothing -> ssv v -- Z3 will work, CVC4 will choke. Others don't even support this.
  547. Just c -> cvtCV (roundingMode cfg) c -- Z3 and CVC4 will work. Other's don't support this.
  548. ctxInfo = case ctx of
  549. ArrayFree _ -> []
  550. ArrayMutate j a b -> [(all (`elem` constNames) [a, b], "(= " ++ nm ++ " (store array_" ++ show j ++ " " ++ ssv a ++ " " ++ ssv b ++ "))")]
  551. ArrayMerge t j k -> [(t `elem` constNames, "(= " ++ nm ++ " (ite " ++ ssv t ++ " array_" ++ show j ++ " array_" ++ show k ++ "))")]
  552. -- Arrange for initializers
  553. mkInit idx = "array_" ++ show i ++ "_initializer_" ++ show (idx :: Int)
  554. initializer = "array_" ++ show i ++ "_initializer"
  555. wrap index s = "(define-fun " ++ mkInit index ++ " () Bool " ++ s ++ ")"
  556. lpre = length pre
  557. lAll = lpre + length post
  558. setup
  559. | lAll == 0 = [ "(define-fun " ++ initializer ++ " () Bool true) ; no initialization needed" | not quantified]
  560. | lAll == 1 = [ "(define-fun " ++ initializer ++ " () Bool " ++ mkInit 0 ++ ")"
  561. , "(assert " ++ initializer ++ ")"
  562. ]
  563. | True = [ "(define-fun " ++ initializer ++ " () Bool (and " ++ unwords (map mkInit [0..lAll - 1]) ++ "))"
  564. , "(assert " ++ initializer ++ ")"
  565. ]
  566. svType :: SV -> String
  567. svType s = smtType (kindOf s)
  568. svFunType :: [SV] -> SV -> String
  569. svFunType ss s = "(" ++ unwords (map svType ss) ++ ") " ++ svType s
  570. cvtType :: SBVType -> String
  571. cvtType (SBVType []) = error "SBV.SMT.SMTLib2.cvtType: internal: received an empty type!"
  572. cvtType (SBVType xs) = "(" ++ unwords (map smtType body) ++ ") " ++ smtType ret
  573. where (body, ret) = (init xs, last xs)
  574. type SkolemMap = M.Map SV [SV]
  575. type TableMap = IM.IntMap String
  576. -- Present an SV; inline true/false as needed
  577. cvtSV :: SkolemMap -> SV -> String
  578. cvtSV skolemMap s@(SV _ (NodeId n))
  579. | Just ss <- s `M.lookup` skolemMap
  580. = "(" ++ show s ++ concatMap ((" " ++) . show) ss ++ ")"
  581. | s == trueSV
  582. = "true"
  583. | s == falseSV
  584. = "false"
  585. | True
  586. = 's' : show n
  587. cvtCV :: RoundingMode -> CV -> String
  588. cvtCV = cvToSMTLib
  589. getTable :: TableMap -> Int -> String
  590. getTable m i
  591. | Just tn <- i `IM.lookup` m = tn
  592. | True = "table" ++ show i -- constant tables are always named this way
  593. cvtExp :: SolverCapabilities -> RoundingMode -> SkolemMap -> TableMap -> SBVExpr -> String
  594. cvtExp caps rm skolemMap tableMap expr@(SBVApp _ arguments) = sh expr
  595. where ssv = cvtSV skolemMap
  596. hasPB = supportsPseudoBooleans caps
  597. hasInt2bv = supportsInt2bv caps
  598. hasDistinct = supportsDistinct caps
  599. bvOp = all isBounded arguments
  600. intOp = any isUnbounded arguments
  601. ratOp = any isRational arguments
  602. realOp = any isReal arguments
  603. fpOp = any (\a -> isDouble a || isFloat a || isFP a) arguments
  604. boolOp = all isBoolean arguments
  605. charOp = any isChar arguments
  606. stringOp = any isString arguments
  607. listOp = any isList arguments
  608. bad | intOp = error $ "SBV.SMTLib2: Unsupported operation on unbounded integers: " ++ show expr
  609. | True = error $ "SBV.SMTLib2: Unsupported operation on real values: " ++ show expr
  610. ensureBVOrBool = bvOp || boolOp || bad
  611. ensureBV = bvOp || bad
  612. addRM s = s ++ " " ++ smtRoundingMode rm
  613. -- lift a binary op
  614. lift2 o _ [x, y] = "(" ++ o ++ " " ++ x ++ " " ++ y ++ ")"
  615. lift2 o _ sbvs = error $ "SBV.SMTLib2.sh.lift2: Unexpected arguments: " ++ show (o, sbvs)
  616. -- lift an arbitrary arity operator
  617. liftN o _ xs = "(" ++ o ++ " " ++ unwords xs ++ ")"
  618. -- lift a binary operation with rounding-mode added; used for floating-point arithmetic
  619. lift2WM o fo | fpOp = lift2 (addRM fo)
  620. | True = lift2 o
  621. lift1FP o fo | fpOp = lift1 fo
  622. | True = lift1 o
  623. liftAbs sgned args | fpOp = lift1 "fp.abs" sgned args
  624. | intOp = lift1 "abs" sgned args
  625. | bvOp, sgned = mkAbs (head args) "bvslt" "bvneg"
  626. | bvOp = head args
  627. | True = mkAbs (head args) "<" "-"
  628. where mkAbs x cmp neg = "(ite " ++ ltz ++ " " ++ nx ++ " " ++ x ++ ")"
  629. where ltz = "(" ++ cmp ++ " " ++ x ++ " " ++ z ++ ")"
  630. nx = "(" ++ neg ++ " " ++ x ++ ")"
  631. z = cvtCV rm (mkConstCV (kindOf (head arguments)) (0::Integer))
  632. lift2B bOp vOp
  633. | boolOp = lift2 bOp
  634. | True = lift2 vOp
  635. lift1B bOp vOp
  636. | boolOp = lift1 bOp
  637. | True = lift1 vOp
  638. eqBV = lift2 "="
  639. neqBV = liftN "distinct"
  640. equal sgn sbvs
  641. | fpOp = lift2 "fp.eq" sgn sbvs
  642. | True = lift2 "=" sgn sbvs
  643. -- Do not use distinct on floats; because +0/-0, and NaNs mess
  644. -- up the meaning. Just go with reqular equals.
  645. notEqual sgn sbvs
  646. | fpOp || not hasDistinct = liftP sbvs
  647. | True = liftN "distinct" sgn sbvs
  648. where liftP xs@[_, _] = "(not " ++ equal sgn xs ++ ")"
  649. liftP args = "(and " ++ unwords (walk args) ++ ")"
  650. walk [] = []
  651. walk (e:es) = map (\e' -> liftP [e, e']) es ++ walk es
  652. lift2S oU oS sgn = lift2 (if sgn then oS else oU) sgn
  653. liftNS oU oS sgn = liftN (if sgn then oS else oU) sgn
  654. lift2Cmp o fo | fpOp = lift2 fo
  655. | True = lift2 o
  656. unintComp o [a, b]
  657. | KUserSort s (Just _) <- kindOf (head arguments)
  658. = let idx v = "(" ++ s ++ "_constrIndex " ++ v ++ ")" in "(" ++ o ++ " " ++ idx a ++ " " ++ idx b ++ ")"
  659. unintComp o sbvs = error $ "SBV.SMT.SMTLib2.sh.unintComp: Unexpected arguments: " ++ show (o, sbvs, map kindOf arguments)
  660. stringOrChar KString = True
  661. stringOrChar KChar = True
  662. stringOrChar _ = False
  663. stringCmp swap o [a, b]
  664. | stringOrChar (kindOf (head arguments))
  665. = let [a1, a2] | swap = [b, a]
  666. | True = [a, b]
  667. in "(" ++ o ++ " " ++ a1 ++ " " ++ a2 ++ ")"
  668. stringCmp _ o sbvs = error $ "SBV.SMT.SMTLib2.sh.stringCmp: Unexpected arguments: " ++ show (o, sbvs)
  669. -- NB. Likewise for sequences
  670. seqCmp swap o [a, b]
  671. | KList{} <- kindOf (head arguments)
  672. = let [a1, a2] | swap = [b, a]
  673. | True = [a, b]
  674. in "(" ++ o ++ " " ++ a1 ++ " " ++ a2 ++ ")"
  675. seqCmp _ o sbvs = error $ "SBV.SMT.SMTLib2.sh.seqCmp: Unexpected arguments: " ++ show (o, sbvs)
  676. lift1 o _ [x] = "(" ++ o ++ " " ++ x ++ ")"
  677. lift1 o _ sbvs = error $ "SBV.SMT.SMTLib2.sh.lift1: Unexpected arguments: " ++ show (o, sbvs)
  678. -- We fully qualify the constructor with their types to work around type checking issues
  679. -- Note that this is rather bizarre, as we're tagging the constructor with its *result* type,
  680. -- not its full function type as one would expect. But this is per the spec: Pg. 27 of SMTLib 2.6 spec
  681. -- says:
  682. --
  683. -- To simplify sort checking, a function symbol in a term can be annotated with one of its result sorts sigma.
  684. --
  685. -- I wish it was the full type here not just the result, but we go with the spec. Also see: <http://github.com/Z3Prover/z3/issues/2135>
  686. -- and in particular <http://github.com/Z3Prover/z3/issues/2135#issuecomment-477636435>
  687. dtConstructor fld args res = "((as " ++ fld ++ " " ++ smtType res ++ ") " ++ unwords (map ssv args) ++ ")"
  688. -- Similarly, we fully qualify the accessors with their types to work around type checking issues
  689. -- Unfortunately, z3 and CVC4 are behaving differently, so we tie this ascription to a solver capability.
  690. dtAccessor fld params res
  691. | supportsDirectAccessors caps = dResult
  692. | True = aResult
  693. where dResult = "(_ is " ++ fld ++ ")"
  694. ps = " (" ++ unwords (map smtType params) ++ ") "
  695. aResult = "(_ is (" ++ fld ++ ps ++ smtType res ++ "))"
  696. sh (SBVApp Ite [a, b, c]) = "(ite " ++ ssv a ++ " " ++ ssv b ++ " " ++ ssv c ++ ")"
  697. sh (SBVApp (LkUp (t, aKnd, _, l) i e) [])
  698. | needsCheck = "(ite " ++ cond ++ ssv e ++ " " ++ lkUp ++ ")"
  699. | True = lkUp
  700. where needsCheck = case aKnd of
  701. KBool -> (2::Integer) > fromIntegral l
  702. KBounded _ n -> (2::Integer)^n > fromIntegral l
  703. KUnbounded -> True
  704. KReal -> error "SBV.SMT.SMTLib2.cvtExp: unexpected real valued index"
  705. KFloat -> error "SBV.SMT.SMTLib2.cvtExp: unexpected float valued index"
  706. KDouble -> error "SBV.SMT.SMTLib2.cvtExp: unexpected double valued index"
  707. KFP{} -> error "SBV.SMT.SMTLib2.cvtExp: unexpected arbitrary float valued index"
  708. KRational{} -> error "SBV.SMT.SMTLib2.cvtExp: unexpected rational valued index"
  709. KChar -> error "SBV.SMT.SMTLib2.cvtExp: unexpected char valued index"
  710. KString -> error "SBV.SMT.SMTLib2.cvtExp: unexpected string valued index"
  711. KList k -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected list valued: " ++ show k
  712. KSet k -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected set valued: " ++ show k
  713. KTuple k -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected tuple valued: " ++ show k
  714. KMaybe k -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected maybe valued: " ++ show k
  715. KEither k1 k2 -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected sum valued: " ++ show (k1, k2)
  716. KUserSort s _ -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected uninterpreted valued index: " ++ s
  717. lkUp = "(" ++ getTable tableMap t ++ " " ++ ssv i ++ ")"
  718. cond
  719. | hasSign i = "(or " ++ le0 ++ " " ++ gtl ++ ") "
  720. | True = gtl ++ " "
  721. (less, leq) = case aKnd of
  722. KBool -> error "SBV.SMT.SMTLib2.cvtExp: unexpected boolean valued index"
  723. KBounded{} -> if hasSign i then ("bvslt", "bvsle") else ("bvult", "bvule")
  724. KUnbounded -> ("<", "<=")
  725. KReal -> ("<", "<=")
  726. KFloat -> ("fp.lt", "fp.leq")
  727. KDouble -> ("fp.lt", "fp.leq")
  728. KRational -> ("sbv.rat.lt", "sbv.rat.leq")
  729. KFP{} -> ("fp.lt", "fp.leq")
  730. KChar -> error "SBV.SMT.SMTLib2.cvtExp: unexpected string valued index"
  731. KString -> error "SBV.SMT.SMTLib2.cvtExp: unexpected string valued index"
  732. KList k -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected sequence valued index: " ++ show k
  733. KSet k -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected set valued index: " ++ show k
  734. KTuple k -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected tuple valued index: " ++ show k
  735. KMaybe k -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected maybe valued index: " ++ show k
  736. KEither k1 k2 -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected sum valued index: " ++ show (k1, k2)
  737. KUserSort s _ -> error $ "SBV.SMT.SMTLib2.cvtExp: unexpected uninterpreted valued index: " ++ s
  738. mkCnst = cvtCV rm . mkConstCV (kindOf i)
  739. le0 = "(" ++ less ++ " " ++ ssv i ++ " " ++ mkCnst 0 ++ ")"
  740. gtl = "(" ++ leq ++ " " ++ mkCnst l ++ " " ++ ssv i ++ ")"
  741. sh (SBVApp (KindCast f t) [a]) = handleKindCast hasInt2bv f t (ssv a)
  742. sh (SBVApp (ArrEq i j) []) = "(= array_" ++ show i ++ " array_" ++ show j ++")"
  743. sh (SBVApp (ArrRead i) [a]) = "(select array_" ++ show i ++ " " ++ ssv a ++ ")"
  744. sh (SBVApp (Uninterpreted nm) []) = nm
  745. sh (SBVApp (Uninterpreted nm) args) = "(" ++ nm ++ " " ++ unwords (map ssv args) ++ ")"
  746. sh (SBVApp (Extract i j) [a]) | ensureBV = "((_ extract " ++ show i ++ " " ++ show j ++ ") " ++ ssv a ++ ")"
  747. sh (SBVApp (Rol i) [a])
  748. | bvOp = rot ssv "rotate_left" i a
  749. | True = bad
  750. sh (SBVApp (Ror i) [a])
  751. | bvOp = rot ssv "rotate_right" i a
  752. | True = bad
  753. sh (SBVApp Shl [a, i])
  754. | bvOp = shft ssv "bvshl" "bvshl" a i
  755. | True = bad
  756. sh (SBVApp Shr [a, i])
  757. | bvOp = shft ssv "bvlshr" "bvashr" a i
  758. | True = bad
  759. sh (SBVApp op args)
  760. | Just f <- lookup op smtBVOpTable, ensureBVOrBool
  761. = f (any hasSign args) (map ssv args)
  762. where -- The first 4 operators below do make sense for Integer's in Haskell, but there's
  763. -- no obvious counterpart for them in the SMTLib translation.
  764. -- TODO: provide support for these.
  765. smtBVOpTable = [ (And, lift2B "and" "bvand")
  766. , (Or, lift2B "or" "bvor")
  767. , (XOr, lift2B "xor" "bvxor")
  768. , (Not, lift1B "not" "bvnot")
  769. , (Join, lift2 "concat")
  770. ]
  771. sh (SBVApp (Label _) [a]) = cvtSV skolemMap a -- This won't be reached; but just in case!
  772. sh (SBVApp (IEEEFP (FP_Cast kFrom kTo m)) args) = handleFPCast kFrom kTo (ssv m) (unwords (map ssv args))
  773. sh (SBVApp (IEEEFP w ) args) = "(" ++ show w ++ " " ++ unwords (map ssv args) ++ ")"
  774. sh (SBVApp (NonLinear w) args) = "(" ++ show w ++ " " ++ unwords (map ssv args) ++ ")"
  775. sh (SBVApp (PseudoBoolean pb) args)
  776. | hasPB = handlePB pb args'
  777. | True = reducePB pb args'
  778. where args' = map ssv args
  779. -- NB: Z3 semantics have the predicates reversed: i.e., it returns true if overflow isn't possible. Hence the not.
  780. sh (SBVApp (OverflowOp op) args) = "(not (" ++ show op ++ " " ++ unwords (map ssv args) ++ "))"
  781. -- Note the unfortunate reversal in StrInRe..
  782. sh (SBVApp (StrOp (StrInRe r)) args) = "(str.in.re " ++ unwords (map ssv args) ++ " " ++ regExpToSMTString r ++ ")"
  783. -- StrUnit is no-op, since a character in SMTLib is the same as a string
  784. sh (SBVApp (StrOp StrUnit) [a]) = ssv a
  785. sh (SBVApp (StrOp op) args) = "(" ++ show op ++ " " ++ unwords (map ssv args) ++ ")"
  786. sh (SBVApp (SeqOp op) args) = "(" ++ show op ++ " " ++ unwords (map ssv args) ++ ")"
  787. sh (SBVApp (SetOp SetEqual) args) = "(= " ++ unwords (map ssv args) ++ ")"
  788. sh (SBVApp (SetOp SetMember) [e, s]) = "(select " ++ ssv s ++ " " ++ ssv e ++ ")"
  789. sh (SBVApp (SetOp SetInsert) [e, s]) = "(store " ++ ssv s ++ " " ++ ssv e ++ " true)"
  790. sh (SBVApp (SetOp SetDelete) [e, s]) = "(store " ++ ssv s ++ " " ++ ssv e ++ " false)"
  791. sh (SBVApp (SetOp SetIntersect) args) = "(intersection " ++ unwords (map ssv args) ++ ")"
  792. sh (SBVApp (SetOp SetUnion) args) = "(union " ++ unwords (map ssv args) ++ ")"
  793. sh (SBVApp (SetOp SetSubset) args) = "(subset " ++ unwords (map ssv args) ++ ")"
  794. sh (SBVApp (SetOp SetDifference) args) = "(setminus " ++ unwords (map ssv args) ++ ")"
  795. sh (SBVApp (SetOp SetComplement) args) = "(complement " ++ unwords (map ssv args) ++ ")"
  796. sh (SBVApp (SetOp SetHasSize) args) = "(set-has-size " ++ unwords (map ssv args) ++ ")"
  797. sh (SBVApp (TupleConstructor 0) []) = "mkSBVTuple0"
  798. sh (SBVApp (TupleConstructor n) args) = "((as mkSBVTuple" ++ show n ++ " " ++ smtType (KTuple (map kindOf args)) ++ ") " ++ unwords (map ssv args) ++ ")"
  799. sh (SBVApp (TupleAccess i n) [tup]) = "(proj_" ++ show i ++ "_SBVTuple" ++ show n ++ " " ++ ssv tup ++ ")"
  800. sh (SBVApp (EitherConstructor k1 k2 False) [arg]) = dtConstructor "left_SBVEither" [arg] (KEither k1 k2)
  801. sh (SBVApp (EitherConstructor k1 k2 True ) [arg]) = dtConstructor "right_SBVEither" [arg] (KEither k1 k2)
  802. sh (SBVApp (EitherIs k1 k2 False) [arg]) = '(' : dtAccessor "left_SBVEither" [k1] (KEither k1 k2) ++ " " ++ ssv arg ++ ")"
  803. sh (SBVApp (EitherIs k1 k2 True ) [arg]) = '(' : dtAccessor "right_SBVEither" [k2] (KEither k1 k2) ++ " " ++ ssv arg ++ ")"
  804. sh (SBVApp (EitherAccess False) [arg]) = "(get_left_SBVEither " ++ ssv arg ++ ")"
  805. sh (SBVApp (EitherAccess True ) [arg]) = "(get_right_SBVEither " ++ ssv arg ++ ")"
  806. sh (SBVApp RationalConstructor [t, b]) = "(SBV.Rational " ++ ssv t ++ " " ++ ssv b ++ ")"
  807. sh (SBVApp (MaybeConstructor k False) []) = dtConstructor "nothing_SBVMaybe" [] (KMaybe k)
  808. sh (SBVApp (MaybeConstructor k True) [arg]) = dtConstructor "just_SBVMaybe" [arg] (KMaybe k)
  809. sh (SBVApp (MaybeIs k False) [arg]) = '(' : dtAccessor "nothing_SBVMaybe" [] (KMaybe k) ++ " " ++ ssv arg ++ ")"
  810. sh (SBVApp (MaybeIs k True ) [arg]) = '(' : dtAccessor "just_SBVMaybe" [k] (KMaybe k) ++ " " ++ ssv arg ++ ")"
  811. sh (SBVApp MaybeAccess [arg]) = "(get_just_SBVMaybe " ++ ssv arg ++ ")"
  812. sh inp@(SBVApp op args)
  813. | intOp, Just f <- lookup op smtOpIntTable
  814. = f True (map ssv args)
  815. | boolOp, Just f <- lookup op boolComps
  816. = f (map ssv args)
  817. | bvOp, Just f <- lookup op smtOpBVTable
  818. = f (any hasSign args) (map ssv args)
  819. | realOp, Just f <- lookup op smtOpRealTable
  820. = f (any hasSign args) (map ssv args)
  821. | ratOp, Just f <- lookup op ratOpTable
  822. = f (map ssv args)
  823. | fpOp, Just f <- lookup op smtOpFloatDoubleTable
  824. = f (any hasSign args) (map ssv args)
  825. | charOp || stringOp, Just f <- lookup op smtStringTable
  826. = f (map ssv args)
  827. | listOp, Just f <- lookup op smtListTable
  828. = f (map ssv args)
  829. | Just f <- lookup op uninterpretedTable
  830. = f (map ssv args)
  831. | True
  832. = if not (null args) && isUserSort (head args)
  833. then error $ unlines [ ""
  834. , "*** Cannot translate operator : " ++ show op
  835. , "*** When applied to arguments of kind: " ++ intercalate ", " (nub (map (show . kindOf) args))
  836. , "*** Found as part of the expression : " ++ show inp
  837. , "***"
  838. , "*** Note that uninterpreted kinds only support equality."
  839. , "*** If you believe this is in error, please report!"
  840. ]
  841. else error $ "SBV.SMT.SMTLib2.cvtExp.sh: impossible happened; can't translate: " ++ show inp
  842. where smtOpBVTable = [ (Plus, lift2 "bvadd")
  843. , (Minus, lift2 "bvsub")
  844. , (Times, lift2 "bvmul")
  845. , (UNeg, lift1B "not" "bvneg")
  846. , (Abs, liftAbs)
  847. , (Quot, lift2S "bvudiv" "bvsdiv")
  848. , (Rem, lift2S "bvurem" "bvsrem")
  849. , (Equal, eqBV)
  850. , (NotEqual, neqBV)
  851. , (LessThan, lift2S "bvult" "bvslt")
  852. , (GreaterThan, lift2S "bvugt" "bvsgt")
  853. , (LessEq, lift2S "bvule" "bvsle")
  854. , (GreaterEq, lift2S "bvuge" "bvsge")
  855. ]
  856. -- Boolean comparisons.. SMTLib's bool type doesn't do comparisons, but Haskell does.. Sigh
  857. boolComps = [ (LessThan, blt)
  858. , (GreaterThan, blt . swp)
  859. , (LessEq, blq)
  860. , (GreaterEq, blq . swp)
  861. ]
  862. where blt [x, y] = "(and (not " ++ x ++ ") " ++ y ++ ")"
  863. blt xs = error $ "SBV.SMT.SMTLib2.boolComps.blt: Impossible happened, incorrect arity (expected 2): " ++ show xs
  864. blq [x, y] = "(or (not " ++ x ++ ") " ++ y ++ ")"
  865. blq xs = error $ "SBV.SMT.SMTLib2.boolComps.blq: Impossible happened, incorrect arity (expected 2): " ++ show xs
  866. swp [x, y] = [y, x]
  867. swp xs = error $ "SBV.SMT.SMTLib2.boolComps.swp: Impossible happened, incorrect arity (expected 2): " ++ show xs
  868. smtOpRealTable = smtIntRealShared
  869. ++ [ (Quot, lift2WM "/" "fp.div")
  870. ]
  871. smtOpIntTable = smtIntRealShared
  872. ++ [ (Quot, lift2 "div")
  873. , (Rem, lift2 "mod")
  874. ]
  875. smtOpFloatDoubleTable = smtIntRealShared
  876. ++ [(Quot, lift2WM "/" "fp.div")]
  877. smtIntRealShared = [ (Plus, lift2WM "+" "fp.add")
  878. , (Minus, lift2WM "-" "fp.sub")
  879. , (Times, lift2WM "*" "fp.mul")
  880. , (UNeg, lift1FP "-" "fp.neg")
  881. , (Abs, liftAbs)
  882. , (Equal, equal)
  883. , (NotEqual, notEqual)
  884. , (LessThan, lift2Cmp "<" "fp.lt")
  885. , (GreaterThan, lift2Cmp ">" "fp.gt")
  886. , (LessEq, lift2Cmp "<=" "fp.leq")
  887. , (GreaterEq, lift2Cmp ">=" "fp.geq")
  888. ]
  889. ratOpTable = [ (Plus, lift2Rat "sbv.rat.plus")
  890. , (Minus, lift2Rat "sbv.rat.minus")
  891. , (Times, lift2Rat "sbv.rat.times")
  892. , (UNeg, liftRat "sbv.rat.uneg")
  893. , (Abs, liftRat "sbv.rat.abs")
  894. , (Equal, lift2Rat "sbv.rat.eq")
  895. , (NotEqual, lift2Rat "sbv.rat.notEq")
  896. , (LessThan, lift2Rat "sbv.rat.lt")
  897. , (GreaterThan, lift2Rat "sbv.rat.lt" . swap)
  898. , (LessEq, lift2Rat "sbv.rat.leq")
  899. , (GreaterEq, lift2Rat "sbv.rat.leq" . swap)
  900. ]
  901. where lift2Rat o [x, y] = "(" ++ o ++ " " ++ x ++ " " ++ y ++ ")"
  902. lift2Rat o sbvs = error $ "SBV.SMTLib2.sh.lift2Rat: Unexpected arguments: " ++ show (o, sbvs)
  903. liftRat o [x] = "(" ++ o ++ " " ++ x ++ ")"
  904. liftRat o sbvs = error $ "SBV.SMTLib2.sh.lift2Rat: Unexpected arguments: " ++ show (o, sbvs)
  905. swap [x, y] = [y, x]
  906. swap sbvs = error $ "SBV.SMTLib2.sh.swap: Unexpected arguments: " ++ show sbvs
  907. -- equality and comparisons are the only thing that works on uninterpreted sorts and pretty much everything else
  908. uninterpretedTable = [ (Equal, lift2S "=" "=" True)
  909. , (NotEqual, liftNS "distinct" "distinct" True)
  910. , (LessThan, unintComp "<")
  911. , (GreaterThan, unintComp ">")
  912. , (LessEq, unintComp "<=")
  913. , (GreaterEq, unintComp ">=")
  914. ]
  915. -- For strings, equality and comparisons are the only operators
  916. smtStringTable = [ (Equal, lift2S "=" "=" True)
  917. , (NotEqual, liftNS "distinct" "distinct" True)
  918. , (LessThan, stringCmp False "str.<")
  919. , (GreaterThan, stringCmp True "str.<")
  920. , (LessEq, stringCmp False "str.<=")
  921. , (GreaterEq, stringCmp True "str.<=")
  922. ]
  923. -- For lists, equality is really the only operator
  924. -- Likewise here, things might change for comparisons
  925. smtListTable = [ (Equal, lift2S "=" "=" True)
  926. , (NotEqual, liftNS "distinct" "distinct" True)
  927. , (LessThan, seqCmp False "seq.<")
  928. , (GreaterThan, seqCmp True "seq.<")
  929. , (LessEq, seqCmp False "seq.<=")
  930. , (GreaterEq, seqCmp True "seq.<=")
  931. ]
  932. declareFun :: SV -> SBVType -> Maybe String -> [String]
  933. declareFun = declareName . show
  934. -- If we have a char, we have to make sure it's and SMTLib string of length exactly one
  935. -- If we have a rational, we have to make sure the denominator is > 0
  936. -- Otherwise, we just declare the name
  937. declareName :: String -> SBVType -> Maybe String -> [String]
  938. declareName s t@(SBVType inputKS) mbCmnt = decl : restrict
  939. where decl = "(declare-fun " ++ s ++ " " ++ cvtType t ++ ")" ++ maybe "" (" ; " ++) mbCmnt
  940. (args, result) = case inputKS of
  941. [] -> error $ "SBV.declareName: Unexpected empty type for: " ++ show s
  942. _ -> (init inputKS, last inputKS)
  943. -- Does the kind KChar and KRational *not* occur in the kind anywhere?
  944. charRatFree k = null $ [() | KChar <- G.universe k] ++ [() | KRational <- G.universe k]
  945. noCharOrRat = charRatFree result
  946. needsQuant = not $ null args
  947. resultVar | needsQuant = "result"
  948. | True = s
  949. argList = ["a" ++ show i | (i, _) <- zip [1::Int ..] args]
  950. argTList = ["(" ++ a ++ " " ++ smtType k ++ ")" | (a, k) <- zip argList args]
  951. resultExp = "(" ++ s ++ " " ++ unwords argList ++ ")"
  952. restrict | noCharOrRat = []
  953. | needsQuant = [ "(assert (forall (" ++ unwords argTList ++ ")"
  954. , " (let ((" ++ resultVar ++ " " ++ resultExp ++ "))"
  955. ]
  956. ++ (case constraints of
  957. [] -> [ " true"]
  958. [x] -> [ " " ++ x]
  959. (x:xs) -> ( " (and " ++ x)
  960. : [ " " ++ c | c <- xs]
  961. ++ [ " )"])
  962. ++ [ " )))"]
  963. | True = case constraints of
  964. [] -> []
  965. [x] -> ["(assert " ++ x ++ ")"]
  966. (x:xs) -> ( "(assert (and " ++ x)
  967. : [ " " ++ c | c <- xs]
  968. ++ [ " ))"]
  969. constraints = walk 0 resultVar cstr result
  970. where cstr KChar nm = ["(= 1 (str.len " ++ nm ++ "))"]
  971. cstr KRational nm = ["(< 0 (sbv.rat.denominator " ++ nm ++ "))"]
  972. cstr _ _ = []
  973. mkAnd [] = "true"
  974. mkAnd [c] = c
  975. mkAnd cs = "(and " ++ unwords cs ++ ")"
  976. walk :: Int -> String -> (Kind -> String -> [String]) -> Kind -> [String]
  977. walk _d nm f k@KBool {} = f k nm
  978. walk _d nm f k@KBounded {} = f k nm
  979. walk _d nm f k@KUnbounded{} = f k nm
  980. walk _d nm f k@KReal {} = f k nm
  981. walk _d nm f k@KUserSort {} = f k nm
  982. walk _d nm f k@KFloat {} = f k nm
  983. walk _d nm f k@KDouble {} = f k nm
  984. walk _d nm f k@KRational {} = f k nm
  985. walk _d nm f k@KFP {} = f k nm
  986. walk _d nm f k@KChar {} = f k nm
  987. walk _d nm f k@KString {} = f k nm
  988. walk d nm f (KList k)
  989. | charRatFree k = []
  990. | True = let fnm = "seq" ++ show d
  991. cstrs = walk (d+1) ("(seq.nth " ++ nm ++ " " ++ fnm ++ ")") f k
  992. in ["(forall ((" ++ fnm ++ " " ++ smtType KUnbounded ++ ")) " ++ "(=> (and (>= " ++ fnm ++ " 0) (< " ++ fnm ++ " (seq.len " ++ nm ++ "))) " ++ mkAnd cstrs ++ "))"]
  993. walk d nm f (KSet k)
  994. | charRatFree k = []
  995. | True = let fnm = "set" ++ show d
  996. cstrs = walk (d+1) nm (\sk snm -> ["(=> (select " ++ snm ++ " " ++ fnm ++ ") " ++ c ++ ")" | c <- f sk fnm]) k
  997. in ["(forall ((" ++ fnm ++ " " ++ smtType k ++ ")) " ++ mkAnd cstrs ++ ")"]
  998. walk d nm f (KTuple ks) = let tt = "SBVTuple" ++ show (length ks)
  999. project i = "(proj_" ++ show i ++ "_" ++ tt ++ " " ++ nm ++ ")"
  1000. nmks = [(project i, k) | (i, k) <- zip [1::Int ..] ks]
  1001. in concatMap (\(n, k) -> walk (d+1) n f k) nmks
  1002. walk d nm f km@(KMaybe k) = let n = "(get_just_SBVMaybe " ++ nm ++ ")"
  1003. in ["(=> " ++ "((_ is (just_SBVMaybe (" ++ smtType k ++ ") " ++ smtType km ++ ")) " ++ nm ++ ") " ++ c ++ ")" | c <- walk (d+1) n f k]
  1004. walk d nm f ke@(KEither k1 k2) = let n1 = "(get_left_SBVEither " ++ nm ++ ")"
  1005. n2 = "(get_right_SBVEither " ++ nm ++ ")"
  1006. c1 = ["(=> " ++ "((_ is (left_SBVEither (" ++ smtType k1 ++ ") " ++ smtType ke ++ ")) " ++ nm ++ ") " ++ c ++ ")" | c <- walk (d+1) n1 f k1]
  1007. c2 = ["(=> " ++ "((_ is (right_SBVEither (" ++ smtType k2 ++ ") " ++ smtType ke ++ ")) " ++ nm ++ ") " ++ c ++ ")" | c <- walk (d+1) n2 f k2]
  1008. in c1 ++ c2
  1009. -----------------------------------------------------------------------------------------------
  1010. -- Casts supported by SMTLib. (From: <http://smtlib.cs.uiowa.edu/theories-FloatingPoint.shtml>)
  1011. -- ; from another floating point sort
  1012. -- ((_ to_fp eb sb) RoundingMode (_ FloatingPoint mb nb) (_ FloatingPoint eb sb))
  1013. --
  1014. -- ; from real
  1015. -- ((_ to_fp eb sb) RoundingMode Real (_ FloatingPoint eb sb))
  1016. --
  1017. -- ; from signed machine integer, represented as a 2's complement bit vector
  1018. -- ((_ to_fp eb sb) RoundingMode (_ BitVec m) (_ FloatingPoint eb sb))
  1019. --
  1020. -- ; from unsigned machine integer, represented as bit vector
  1021. -- ((_ to_fp_unsigned eb sb) RoundingMode (_ BitVec m) (_ FloatingPoint eb sb))
  1022. --
  1023. -- ; to unsigned machine integer, represented as a bit vector
  1024. -- ((_ fp.to_ubv m) RoundingMode (_ FloatingPoint eb sb) (_ BitVec m))
  1025. --
  1026. -- ; to signed machine integer, represented as a 2's complement bit vector
  1027. -- ((_ fp.to_sbv m) RoundingMode (_ FloatingPoint eb sb) (_ BitVec m))
  1028. --
  1029. -- ; to real
  1030. -- (fp.to_real (_ FloatingPoint eb sb) Real)
  1031. -----------------------------------------------------------------------------------------------
  1032. handleFPCast :: Kind -> Kind -> String -> String -> String
  1033. handleFPCast kFromIn kToIn rm input
  1034. | kFrom == kTo
  1035. = input
  1036. | True
  1037. = "(" ++ cast kFrom kTo input ++ ")"
  1038. where addRM a s = s ++ " " ++ rm ++ " " ++ a
  1039. kFrom = simplify kFromIn
  1040. kTo = simplify kToIn
  1041. simplify KFloat = KFP 8 24
  1042. simplify KDouble = KFP 11 53
  1043. simplify k = k
  1044. size (eb, sb) = show eb ++ " " ++ show sb
  1045. -- To go and back from Ints, we detour through reals
  1046. cast KUnbounded (KFP eb sb) a = "(_ to_fp " ++ size (eb, sb) ++ ") " ++ rm ++ " (to_real " ++ a ++ ")"
  1047. cast KFP{} KUnbounded a = "to_int (fp.to_real " ++ a ++ ")"
  1048. -- To floats
  1049. cast (KBounded False _) (KFP eb sb) a = addRM a $ "(_ to_fp_unsigned " ++ size (eb, sb) ++ ")"
  1050. cast (KBounded True _) (KFP eb sb) a = addRM a $ "(_ to_fp " ++ size (eb, sb) ++ ")"
  1051. cast KReal (KFP eb sb) a = addRM a $ "(_ to_fp " ++ size (eb, sb) ++ ")"
  1052. cast KFP{} (KFP eb sb) a = addRM a $ "(_ to_fp " ++ size (eb, sb) ++ ")"
  1053. -- From float/double
  1054. cast KFP{} (KBounded False m) a = addRM a $ "(_ fp.to_ubv " ++ show m ++ ")"
  1055. cast KFP{} (KBounded True m) a = addRM a $ "(_ fp.to_sbv " ++ show m ++ ")"
  1056. -- To real
  1057. cast KFP{} KReal a = "fp.to_real" ++ " " ++ a
  1058. -- Nothing else should come up:
  1059. cast f d _ = error $ "SBV.SMTLib2: Unexpected FPCast from: " ++ show f ++ " to " ++ show d
  1060. rot :: (SV -> String) -> String -> Int -> SV -> String
  1061. rot ssv o c x = "((_ " ++ o ++ " " ++ show c ++ ") " ++ ssv x ++ ")"
  1062. shft :: (SV -> String) -> String -> String -> SV -> SV -> String
  1063. shft ssv oW oS x c = "(" ++ o ++ " " ++ ssv x ++ " " ++ ssv c ++ ")"
  1064. where o = if hasSign x then oS else oW
  1065. -- Various casts
  1066. handleKindCast :: Bool -> Kind -> Kind -> String -> String
  1067. handleKindCast hasInt2bv kFrom kTo a
  1068. | kFrom == kTo
  1069. = a
  1070. | True
  1071. = case kFrom of
  1072. KBounded s m -> case kTo of
  1073. KBounded _ n -> fromBV (if s then signExtend else zeroExtend) m n
  1074. KUnbounded -> b2i s m
  1075. _ -> tryFPCast
  1076. KUnbounded -> case kTo of
  1077. KReal -> "(to_real " ++ a ++ ")"
  1078. KBounded _ n -> i2b n
  1079. _ -> tryFPCast
  1080. KReal -> case kTo of
  1081. KUnbounded -> "(to_int " ++ a ++ ")"
  1082. _ -> tryFPCast
  1083. _ -> tryFPCast
  1084. where -- See if we can push this down to a float-cast, using sRNE. This happens if one of the kinds is a float/double.
  1085. -- Otherwise complain
  1086. tryFPCast
  1087. | any (\k -> isFloat k || isDouble k) [kFrom, kTo]
  1088. = handleFPCast kFrom kTo (smtRoundingMode RoundNearestTiesToEven) a
  1089. | True
  1090. = error $ "SBV.SMTLib2: Unexpected cast from: " ++ show kFrom ++ " to " ++ show kTo
  1091. fromBV upConv m n
  1092. | n > m = upConv (n - m)
  1093. | m == n = a
  1094. | True = extract (n - 1)
  1095. b2i False _ = "(bv2nat " ++ a ++ ")"
  1096. b2i True 1 = "(ite (= " ++ a ++ " #b0) 0 (- 1))"
  1097. b2i True m = "(ite (= " ++ msb ++ " #b0" ++ ") " ++ ifPos ++ " " ++ ifNeg ++ ")"
  1098. where offset :: Integer
  1099. offset = 2^(m-1)
  1100. rest = extract (m - 2)
  1101. msb = let top = show (m-1) in "((_ extract " ++ top ++ " " ++ top ++ ") " ++ a ++ ")"
  1102. ifPos = "(bv2nat " ++ rest ++")"
  1103. ifNeg = "(- " ++ ifPos ++ " " ++ show offset ++ ")"
  1104. signExtend i = "((_ sign_extend " ++ show i ++ ") " ++ a ++ ")"
  1105. zeroExtend i = "((_ zero_extend " ++ show i ++ ") " ++ a ++ ")"
  1106. extract i = "((_ extract " ++ show i ++ " 0) " ++ a ++ ")"
  1107. -- Some solvers support int2bv, but not all. So, we use a capability to determine.
  1108. --
  1109. -- NB. The "manual" implementation works regardless n < 0 or not, because the first thing we
  1110. -- do is to compute "reduced" to bring it down to the correct range. It also works
  1111. -- regardless were mapping to signed or unsigned bit-vector; because the representation
  1112. -- is the same.
  1113. i2b n
  1114. | hasInt2bv
  1115. = "((_ int2bv " ++ show n ++ ") " ++ a ++ ")"
  1116. | True
  1117. = "(let (" ++ reduced ++ ") (let (" ++ defs ++ ") " ++ body ++ "))"
  1118. where b i = show (bit i :: Integer)
  1119. reduced = "(__a (mod " ++ a ++ " " ++ b n ++ "))"
  1120. mkBit 0 = "(__a0 (ite (= (mod __a 2) 0) #b0 #b1))"
  1121. mkBit i = "(__a" ++ show i ++ " (ite (= (mod (div __a " ++ b i ++ ") 2) 0) #b0 #b1))"
  1122. defs = unwords (map mkBit [0 .. n - 1])
  1123. body = foldr1 (\c r -> "(concat " ++ c ++ " " ++ r ++ ")") ["__a" ++ show i | i <- [n-1, n-2 .. 0]]
  1124. -- Translation of pseudo-booleans, in case the solver supports them
  1125. handlePB :: PBOp -> [String] -> String
  1126. handlePB (PB_AtMost k) args = "((_ at-most " ++ show k ++ ") " ++ unwords args ++ ")"
  1127. handlePB (PB_AtLeast k) args = "((_ at-least " ++ show k ++ ") " ++ unwords args ++ ")"
  1128. handlePB (PB_Exactly k) args = "((_ pbeq " ++ unwords (map show (k : replicate (length args) 1)) ++ ") " ++ unwords args ++ ")"
  1129. handlePB (PB_Eq cs k) args = "((_ pbeq " ++ unwords (map show (k : cs)) ++ ") " ++ unwords args ++ ")"
  1130. handlePB (PB_Le cs k) args = "((_ pble " ++ unwords (map show (k : cs)) ++ ") " ++ unwords args ++ ")"
  1131. handlePB (PB_Ge cs k) args = "((_ pbge " ++ unwords (map show (k : cs)) ++ ") " ++ unwords args ++ ")"
  1132. -- Translation of pseudo-booleans, in case the solver does *not* support them
  1133. reducePB :: PBOp -> [String] -> String
  1134. reducePB op args = case op of
  1135. PB_AtMost k -> "(<= " ++ addIf (repeat 1) ++ " " ++ show k ++ ")"
  1136. PB_AtLeast k -> "(>= " ++ addIf (repeat 1) ++ " " ++ show k ++ ")"
  1137. PB_Exactly k -> "(= " ++ addIf (repeat 1) ++ " " ++ show k ++ ")"
  1138. PB_Le cs k -> "(<= " ++ addIf cs ++ " " ++ show k ++ ")"
  1139. PB_Ge cs k -> "(>= " ++ addIf cs ++ " " ++ show k ++ ")"
  1140. PB_Eq cs k -> "(= " ++ addIf cs ++ " " ++ show k ++ ")"
  1141. where addIf :: [Int] -> String
  1142. addIf cs = "(+ " ++ unwords ["(ite " ++ a ++ " " ++ show c ++ " 0)" | (a, c) <- zip args cs] ++ ")"