-
Notifications
You must be signed in to change notification settings - Fork 53
/
Copy pathZ3Interfacing.hpp
427 lines (350 loc) · 13.7 KB
/
Z3Interfacing.hpp
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
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/*
* This file is part of the source code of the software program
* Vampire. It is protected by applicable
* copyright laws.
*
* This source code is distributed under the licence found here
* https://vprover.github.io/license.html
* and in the source directory
*/
/**
* @file Z3Interfacing.hpp
* Defines class Z3Interfacing
*/
#ifndef __Z3Interfacing__
#define __Z3Interfacing__
#include "Lib/Allocator.hpp"
#include <algorithm>
#if VZ3
/* an (imperfect and under development) version of tracing the Z3 interface
* so that vampire can be "factored-out" of runs which cause particular Z3
* behaviour. Should be useful for producing MWEs for the Z3 people.
*/
#define PRINT_CPP(X) // std::cout << X << std::endl;
#include <fstream>
#include "Lib/DHMap.hpp"
#include "Lib/Option.hpp"
#include "Lib/BiMap.hpp"
#include "Lib/Set.hpp"
#include "SATSolver.hpp"
#include "SATLiteral.hpp"
#include "SATClause.hpp"
#include "SATInference.hpp"
#include "SAT2FO.hpp"
#include "Lib/Option.hpp"
#include "Lib/Coproduct.hpp"
#include "Kernel/Theory.hpp"
#include "Kernel/Signature.hpp"
#define __EXCEPTIONS 1
#include "z3++.h"
#include "z3_api.h"
namespace SAT{
struct UninterpretedForZ3Exception : public ThrowableBase
{
UninterpretedForZ3Exception()
{
}
};
struct Z3MkDatatypesCall;
namespace ProblemExport {
struct NoExport {
NoExport() {}
NoExport(NoExport &&) = default;
void initialize() { }
void terminate() { }
void declare_array_sort(z3::sort array, z3::sort index, z3::sort result) { }
void declareSort(z3::sort sort) { }
void eval(z3::expr const& x) { }
void unsatCore() { }
void addAssert(z3::expr const& x) { }
void check(Stack<z3::expr> const& xs) { }
void get_model() { }
void reset() { }
template<class Value>
void set_param(const char* k, Value const& v) { }
void Z3_mk_datatypes(Z3MkDatatypesCall const& call) { }
void declare_fun(std::string const& name, z3::sort_vector domain, z3::sort codomain) { }
void declare_const(std::string const& name, z3::sort codomain) {}
void instantiate_expression(z3::expr const& e) {}
void enableTrace(const char*) { }
};
struct Smtlib {
std::ofstream out;
z3::context& _ctxt;
Smtlib(std::ofstream out, z3::context& context) : out(std::move(out)), _ctxt(context) {}
Smtlib(Smtlib &&) = default;
void initialize();
void terminate();
void declareSort(z3::sort sort);
void eval(z3::expr const& x);
void unsatCore();
void addAssert(z3::expr const& x);
void get_model();
void reset();
void enableTrace(const char*) { }
void declare_fun(std::string const& name, z3::sort_vector domain, z3::sort codomain);
void declare_const(std::string const& name, z3::sort codomain);
void check(Stack<z3::expr> const& assumptions);
void declare_array_sort(z3::sort array, z3::sort index, z3::sort result);
template<class Value>
void set_param(const char* k, Value const& v);
void instantiate_expression(z3::expr const& e);
void Z3_mk_datatypes(Z3MkDatatypesCall const& call);
};
struct ApiCalls {
std::ofstream out;
z3::context& _ctxt;
Map<std::string, std::string> _escapedNames; // <- maps string -> unique string that can be used as c++ variable
Map<std::string, Map<std::string, unsigned>> _escapePrefixes; // <- maps c++ variable prefix of _escapedNames -> strings that have been escaped to it
Set<std::string> _predeclaredConstants; // <- c++ variable names of been declard using declare_const
ApiCalls(ApiCalls &&) = default;
ApiCalls(std::ofstream out, z3::context& context) : out(std::move(out)), _ctxt(context) {}
template<class Outputable>
std::string _escapeVarName(Outputable const& sym);
std::string escapeVarName(z3::sort const& sym);
std::string escapeVarName(z3::symbol const& sym);
void initialize();
void terminate();
void declare_array_sort(z3::sort array, z3::sort index, z3::sort result);
struct EscapeString;
template<class C> struct Serialize { C const& inner; ApiCalls& state; };
template<class C> Serialize<C> serialize(C const& c){ return Serialize<C>{ c, *this, }; };
friend std::ostream& operator<<(std::ostream& out, Serialize<std::string> const& self);
friend std::ostream& operator<<(std::ostream& out, Serialize<bool> const& self);
friend std::ostream& operator<<(std::ostream& out, Serialize<z3::expr> const& self);
template<class A>
friend std::ostream& operator<<(std::ostream& out, Serialize<A> const& self);
friend std::ostream& operator<<(std::ostream& out, Serialize<z3::symbol> const& self);
void declareSort(z3::sort sort);
void eval(z3::expr const& x);
void unsatCore();
void addAssert(z3::expr const& x);
void check(Stack<z3::expr> const& xs);
void get_model();
void reset();
template<class Value>
void set_param(const char* k, Value const& v);
void Z3_mk_datatypes(Z3MkDatatypesCall const& call);
void declare_fun(std::string const& name, z3::sort_vector domain, z3::sort codomain);
void declare_const(std::string const& name, z3::sort codomain);
void enableTrace(const char*);
void instantiate_expression(z3::expr const& e);
};
std::ostream& operator<<(std::ostream& out, ApiCalls::Serialize<std::string> const& self);
std::ostream& operator<<(std::ostream& out, ApiCalls::Serialize<bool> const& self);
std::ostream& operator<<(std::ostream& out, ApiCalls::Serialize<z3::expr> const& self);
template<class A>
std::ostream& operator<<(std::ostream& out, ApiCalls::Serialize<A> const& self);
std::ostream& operator<<(std::ostream& out, ApiCalls::Serialize<z3::symbol> const& self);
} // namespace ProblemExport
class Z3Interfacing : public PrimitiveProofRecordingSATSolver
{
public:
Z3Interfacing(const Shell::Options& opts, SAT2FO& s2f, bool unsatCoresForAssumptions, std::string const& exportSmtlib,Shell::Options::ProblemExportSyntax s);
Z3Interfacing(SAT2FO& s2f, bool showZ3, bool unsatCoresForAssumptions, std::string const& exportSmtlib, Shell::Options::ProblemExportSyntax s);
~Z3Interfacing();
static char const* z3_full_version();
void addClause(SATClause* cl) override;
Status solve();
virtual Status solve(unsigned conflictCountLimit) override { return solve(); };
/**
* If status is @c SATISFIABLE, return assignment of variable @c var
*/
virtual VarAssignment getAssignment(unsigned var) override;
/**
* If status is @c SATISFIABLE, return 0 if the assignment of @c var is
* implied only by unit propagation (i.e. does not depend on any decisions)
*/
virtual bool isZeroImplied(unsigned var) override;
/**
* Collect zero-implied literals.
*
* Can be used in SATISFIABLE and UNKNOWN state.
*
* @see isZeroImplied()
*/
virtual void collectZeroImplied(SATLiteralStack& acc) override;
/**
* Return a valid clause that contains the zero-implied literal
* and possibly the assumptions that implied it. Return 0 if @c var
* was an assumption itself.
* If called on a proof producing solver, the clause will have
* a proper proof history.
*/
virtual SATClause* getZeroImpliedCertificate(unsigned var) override;
void ensureVarCount(unsigned newVarCnt) override {
while (_varCnt < newVarCnt) {
newVar();
}
}
unsigned newVar() override;
// Currently not implemented for Z3
virtual void suggestPolarity(unsigned var, unsigned pol) override {}
virtual void addAssumption(SATLiteral lit) override;
virtual void retractAllAssumptions() override;
virtual bool hasAssumptions() const override { return !_assumptions.isEmpty(); }
virtual Status solveUnderAssumptions(const SATLiteralStack& assumps, unsigned conflictCountLimit, bool onlyProperSubusets) override;
/**
* The set of inserted clauses may not be propositionally UNSAT
* due to theory reasoning inside Z3.
* We cannot later minimize this set with minisat.
*
* TODO: think of extracting true refutation from Z3 instead.
*/
SATClauseList* getRefutationPremiseList() override{ return 0; }
SATClause* getRefutation() override;
template<class F>
auto scoped(F f) -> decltype(f())
{
_solver.push();
auto result = f();
_solver.pop();
return result;
}
using FuncId = unsigned;
using PredId = unsigned;
using SortId = TermList;
struct FuncOrPredId
{
explicit FuncOrPredId(unsigned id, bool isPredicate, Term *forSorts = nullptr) : id(id), isPredicate(isPredicate), forSorts(forSorts) {}
explicit FuncOrPredId(Term* term) :
FuncOrPredId(
term->functor(),
term->isLiteral(),
term->numTypeArguments() == 0 ? nullptr : term
)
{}
static FuncOrPredId monomorphicFunction(FuncId id) { return FuncOrPredId (id, false); }
static FuncOrPredId monomorphicPredicate(PredId id) { return FuncOrPredId (id, true); }
unsigned id;
bool isPredicate;
/**
* polymorphic symbol application: treat e.g. f(<sorts>, ...) as f<sorts>(...) for Z3
* in the monomorphic case, nullptr
* in the polymorphic case, some term of the form f(<sorts>, ...) which we use only for sort information
*/
Term *forSorts;
friend struct std::hash<FuncOrPredId> ;
friend bool operator==(FuncOrPredId const& l, FuncOrPredId const& r)
{
if(l.id != r.id || l.isPredicate != r.isPredicate)
return false;
if(!l.forSorts)
return true;
ASS(r.forSorts != nullptr);
// compare sort arguments
for(unsigned i = 0; i < l.forSorts->numTypeArguments(); i++)
// sorts are perfectly shared
if(!l.forSorts->typeArg(i).sameContent(r.forSorts->typeArg(i)))
return false;
return true;
}
friend std::ostream& operator<<(std::ostream& out, FuncOrPredId const& self)
{
out << (self.isPredicate ? "pred " : "func ");
out << (
self.isPredicate
? env.signature->getPredicate(self.id)->name()
: env.signature->getFunction(self.id)->name()
);
if(self.forSorts)
for(unsigned i = 0; i < self.forSorts->numTypeArguments(); i++)
out << " " << self.forSorts->typeArg(i).toString();
return out;
}
};
private:
Map<SortId, z3::sort> _sorts;
struct Z3Hash {
static unsigned hash(z3::func_decl const& c) { return c.hash(); }
static unsigned hash(z3::expr const& c) { return c.hash(); }
static bool equals(z3::func_decl const& l, z3::func_decl const& r) { return z3::eq(l,r); }
static bool equals(z3::expr const& l, z3::expr const& r) { return z3::eq(l,r); }
};
Map<z3::func_decl, FuncOrPredId , Z3Hash > _fromZ3;
Map<FuncOrPredId, z3::func_decl, StlHash> _toZ3;
Set<SortId> _createdTermAlgebras;
z3::func_decl const& findConstructor(Term* t);
void createTermAlgebra(TermList sort);
z3::sort getz3sort(SortId s);
z3::func_decl z3Function(FuncOrPredId function);
friend struct ToZ3Expr;
friend struct EvaluateInModel;
public:
Term* evaluateInModel(Term* trm);
#if VDEBUG
z3::model& getModel() { return _model; }
#endif
private:
// we make this public for testing
#if VDEBUG
public:
#endif
struct Representation
{
Representation(z3::expr expr, Stack<z3::expr> defs) : expr(expr), defs(defs) {}
Representation(Representation&&) = default;
z3::expr expr;
Stack<z3::expr> defs;
};
Representation getRepresentation(Term* trm);
Representation getRepresentation(SATLiteral lit);
Representation getRepresentation(SATClause* cl);
// end of making this public for testing
#if VDEBUG
private:
#endif
// arrays are a bit fragile in Z3, so we need to do things differently for them
bool _hasSeenArrays;
unsigned _varCnt; // just to conform to the interface
SAT2FO& _sat2fo; // Memory belongs to Splitter
Shell::Options::ProblemExportSyntax const _outSyntax;
Status _status;
std::unique_ptr<z3::context> _context;
z3::solver _solver;
z3::model _model;
Stack<z3::expr> _assumptions;
const bool _showZ3;
const bool _unsatCore;
Coproduct<ProblemExport::NoExport, ProblemExport::Smtlib, ProblemExport::ApiCalls> _exporter;
BiMap<SATLiteral, z3::expr, DefaultHash, Z3Hash> _assumptionLookup;
Option<std::ofstream> _out;
Map<unsigned, z3::expr> _varNames;
Map<TermList, z3::expr> _termIndexedConstants;
Map<Signature::Symbol*, z3::expr> _constantNames;
bool isNamedExpr(unsigned var) const;
z3::expr getNameExpr(unsigned var);
z3::expr getNamingConstantFor(TermList name, z3::sort sort);
z3::expr getConst(Signature::Symbol* symb, z3::sort srt);
template<class Value>
void z3_set_param(const char* k, Value const& v);
z3::check_result z3_check();
z3::model z3_get_model();
// void z3_reset();
void z3_add(z3::expr const&);
z3::expr_vector z3_unsat_core();
z3::expr z3_eval(z3::expr const& x);
z3::sort z3_declare_sort(std::string const& name);
z3::sort z3_array_sort(z3::sort const& idxSort, z3::sort const& value_sort);
z3::func_decl z3_declare_fun(std::string const& name, z3::sort_vector domain, z3::sort codomain);
z3::expr z3_declare_const(std::string const& name, z3::sort sort);
void z3_enable_trace(const char* name);
void z3_output_initialize();
// template<class Clsr>
// void exportCall(Clsr f);
};
}//end SAT namespace
namespace std {
template<>
struct hash<SAT::Z3Interfacing::FuncOrPredId> {
size_t operator()(SAT::Z3Interfacing::FuncOrPredId const& self) {
unsigned hash = Lib::HashUtils::combine(self.id, self.isPredicate);
if(self.forSorts)
for(unsigned i = 0; i < self.forSorts->numTypeArguments(); i++)
hash = Lib::HashUtils::combine(hash, self.forSorts->typeArg(i).content());
return hash;
}
};
}
#endif /* if VZ3 */
#endif /*Z3Interfacing*/