1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
--- ----------------------------------------------------------------------------
--- This module provides some goodies and utility functions for SMT-LIB.
---
--- @author  Jan Tikovsky
--- @version January 2018
--- ----------------------------------------------------------------------------
module Language.SMTLIB.Goodies where

import Language.SMTLIB.Types

infixl 7 *%
infixl 6 +%, -%
infix  4 =%, /=%, <%, >%, <=%, >=%

--- Declare a list of variables
declVars :: [(Symbol, Sort)] -> [Command]
declVars = map (uncurry DeclareConst)

--------------------------------------------------------------------------------
-- Smart constructors for SMT terms
--------------------------------------------------------------------------------

--- Construct SMT-LIB term from given integer
tint :: Int -> Term
tint = TConst . Num

--- Construct SMT-LIB term from given float
tfloat :: Float -> Term
tfloat = TConst . Dec

--- Construct SMT-LIB term from given character
tchar :: Char -> Term
tchar = TConst . Str . (: [])

--- Construct SMT-LIB term from given variable index
tvar :: Int -> Term
tvar vi = tcomb (var2SMT vi) []

--- Construct SMT-LIB term from a string
var :: String -> Term
var str = tcomb str []

--- Construct SMT-LIB constructor term
tcomb :: Ident -> [Term] -> Term
tcomb i ts = TComb (Id i) ts

--- Construct qualified SMT-LIB constructor term
qtcomb :: QIdent -> [Term] -> Term
qtcomb qi ts = TComb qi ts

--- Construct universally quantified SMT-LIB term
forAll :: [Int] -> [Sort] -> Term -> Term
forAll vs ss t = case vs of
  [] -> t
  _  -> Forall (zipWith SV (map var2SMT vs) ss) t

--- Negate given numeral SMT-LIB term
tneg :: Term -> Term
tneg t = tcomb "-" [t]

--- Absolute value of an SMT-LIB term
tabs :: Term -> Term
tabs t = tcomb "abs" [t]

--- Add two SMT-LIB terms
(+%) :: Term -> Term -> Term
t1 +% t2 = tcomb "+" [t1, t2]

--- Subtract an SMT-LIB term from another one
(-%) :: Term -> Term -> Term
t1 -% t2 = tcomb "-" [t1, t2]

--- Multiply two SMT-LIB terms
(*%) :: Term -> Term -> Term
t1 *% t2 = tcomb "*" [t1, t2]

--- Divide an SMT-LIB term by another one
(/%) :: Term -> Term -> Term
t1 /% t2 = tcomb "/" [t1, t2]

--- SMT-LIB term `true`
true :: Term
true = qtcomb (As "true" boolSort) []

--- SMT-LIB term `false`
false :: Term
false = qtcomb (As "false" boolSort) []

--- Constrain two SMT-LIB terms to be equal
(=%) :: Term -> Term -> Term
t1 =% t2 = tcomb "=" [t1, t2]

--- Constrain two SMT-LIB terms to be different
(/=%) :: Term -> Term -> Term
t1 /=% t2 = tcomb "not" [tcomb "=" [t1, t2]]

--- Constrain two SMT-LIB terms with a less-than-relation
(<%) :: Term -> Term -> Term
t1 <% t2 = tcomb "<" [t1, t2]

--- Constrain two SMT-LIB terms with a less-than-or-equal-relation
(<=%) :: Term -> Term -> Term
t1 <=% t2 = tcomb "<=" [t1, t2]

--- Constrain two SMT-LIB terms with a greater-than-relation
(>%) :: Term -> Term -> Term
t1 >% t2 = tcomb ">" [t1, t2]

--- Constrain two SMT-LIB terms with a greater-than-or-equal-relation
(>=%) :: Term -> Term -> Term
t1 >=% t2 = tcomb ">=" [t1, t2]

--- Combine a list of SMT-LIB terms using a conjunction
tand :: [Term] -> Term
tand = tcomb "and"

--- Combine a list of SMT-LIB terms using a disjunction
tor :: [Term] -> Term
tor = tcomb "or"

--- Logical implication
(==>) :: Term -> Term -> Term
t1 ==> t2 = tcomb "=>" [t1, t2]

--- Logical negation of an SMT-LIB term
tnot :: Term -> Term
tnot t = tcomb "not" [t]

instance Num Term where
  t1 + t2 = t1 +% t2
  t1 - t2 = t1 -% t2
  t1 * t2 = t1 *% t2

  negate  = tneg
  abs     = tabs
  fromInt = tint

instance Fractional Term where
  t1 / t2 = t1 /% t2

  fromFloat = tfloat

--------------------------------------------------------------------------------
-- Smart constructors for SMT sorts
--------------------------------------------------------------------------------

--- Construct an SMT-LIB sort
scomb :: Ident -> [Sort] -> Sort
scomb i ss = SComb i ss

--- Representation of 'Ordering' type as SMT-LIB sort
orderingSort :: Sort
orderingSort = scomb "Ordering" []

--- Representation of 'Bool' type as SMT-LIB sort
boolSort :: Sort
boolSort = scomb "Bool" []

--- Representation of 'Int' type as SMT-LIB sort
intSort :: Sort
intSort = scomb "Int" []

--- Representation of 'Float' type as SMT-LIB sort
floatSort :: Sort
floatSort = scomb "Real" []

--- Representation of '->' type constructor as SMT-LIB sort constructor
funSC :: [Sort] -> Sort
funSC = scomb "Fun"

--- Generate a `nop` SMT-LIB command
nop :: Command
nop = echo ""

--- Generate an `assert` SMT-LIB command
assert :: [Term] -> Command
assert ts = case ts of
  []  -> nop
  [t] -> Assert t
  _   -> Assert $ tand ts

--- Get the unqualified identifier of a qualified SMT-LIB identifier
unqual :: QIdent -> Ident
unqual (Id   i) = i
unqual (As i _) = i

--- Is given SMT-LIB command a declaration of an algebraic data type
isDeclData :: Command -> Bool
isDeclData cmd = case cmd of
  DeclareDatatype _ _ -> True
  DeclareDatatypes  _ -> True
  _                   -> False

--- Is given SMT-LIB command an 'Echo'
isEcho :: Command -> Bool
isEcho cmd = case cmd of
  Echo _ -> True
  _      -> False

--- Smart constructor for the 'Echo' SMT-LIB command
--- marking every 'Echo' command with an initial '@' character
--- which is necessary to recognize 'Echo's during parsing
echo :: String -> Command
echo str = Echo ('@' : str)

--- Smart constructor to generate a comment in an SMT-LIB script
comment :: String -> Command
comment = Comment

--- Transform a FlatCurry variable index into an SMT-LIB symbol
var2SMT :: Int -> Symbol
var2SMT vi = 'x' : show (abs vi)