1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Mathias Preiner, Gereon Kremer |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* sygus explanations |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H |
19 |
|
#define CVC5__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H |
20 |
|
|
21 |
|
#include <vector> |
22 |
|
|
23 |
|
#include "expr/node.h" |
24 |
|
|
25 |
|
namespace cvc5 { |
26 |
|
namespace theory { |
27 |
|
namespace quantifiers { |
28 |
|
|
29 |
|
class SygusInvarianceTest; |
30 |
|
class TermDbSygus; |
31 |
|
|
32 |
|
/** Recursive term builder |
33 |
|
* |
34 |
|
* This is a utility used to generate variants |
35 |
|
* of a term n, where subterms of n can be replaced |
36 |
|
* by others via calls to replaceChild(...). |
37 |
|
* |
38 |
|
* This class maintains a "context", which indicates |
39 |
|
* a position in term n. Below, we call the subterm of |
40 |
|
* the initial term n at this position the "active term". |
41 |
|
* |
42 |
|
*/ |
43 |
12750 |
class TermRecBuild |
44 |
|
{ |
45 |
|
public: |
46 |
12750 |
TermRecBuild() {} |
47 |
|
/** set the initial term to n |
48 |
|
* |
49 |
|
* The context initially empty, that is, |
50 |
|
* the active term is initially n. |
51 |
|
*/ |
52 |
|
void init(Node n); |
53 |
|
|
54 |
|
/** push the context |
55 |
|
* |
56 |
|
* This updates the context so that the |
57 |
|
* active term is updated to curr[p], where |
58 |
|
* curr is the previously active term. |
59 |
|
*/ |
60 |
|
void push(unsigned p); |
61 |
|
|
62 |
|
/** pop the context */ |
63 |
|
void pop(); |
64 |
|
/** indicates that the i^th child of the active |
65 |
|
* term should be replaced by r in calls to build(). |
66 |
|
*/ |
67 |
|
void replaceChild(unsigned i, Node r); |
68 |
|
/** get the i^th child of the active term */ |
69 |
|
Node getChild(unsigned i); |
70 |
|
/** build the (modified) version of the term |
71 |
|
* we initialized via the call to init(). |
72 |
|
*/ |
73 |
|
Node build(unsigned p = 0); |
74 |
|
|
75 |
|
private: |
76 |
|
/** stack of active terms */ |
77 |
|
std::vector<Node> d_term; |
78 |
|
/** stack of children of active terms |
79 |
|
* Notice that these may be modified with calls to replaceChild(...). |
80 |
|
*/ |
81 |
|
std::vector<std::vector<Node> > d_children; |
82 |
|
/** stack the kind of active terms */ |
83 |
|
std::vector<Kind> d_kind; |
84 |
|
/** stack of whether the active terms had an operator */ |
85 |
|
std::vector<bool> d_has_op; |
86 |
|
/** stack of positions that were pushed via calls to push(...) */ |
87 |
|
std::vector<unsigned> d_pos; |
88 |
|
/** add term to the context stack */ |
89 |
|
void addTerm(Node n); |
90 |
|
}; |
91 |
|
|
92 |
|
/*The SygusExplain utility |
93 |
|
* |
94 |
|
* This class is used to produce explanations for refinement lemmas |
95 |
|
* in the counterexample-guided inductive synthesis (CEGIS) loop. |
96 |
|
* |
97 |
|
* When given an invariance test T traverses the AST of a given term, |
98 |
|
* uses TermRecBuild to replace various subterms by fresh variables and |
99 |
|
* recheck whether the invariant, as specified by T still holds. |
100 |
|
* If it does, then we may exclude the explanation for that subterm. |
101 |
|
* |
102 |
|
* For example, say we have that the current value of |
103 |
|
* (datatype) sygus term n is: |
104 |
|
* (if (gt x 0) 0 0) |
105 |
|
* where if, gt, x, 0 are datatype constructors. |
106 |
|
* The explanation returned by getExplanationForEquality |
107 |
|
* below for n and the above term is: |
108 |
|
* { ((_ is if) n), ((_ is geq) n.0), |
109 |
|
* ((_ is x) n.0.0), ((_ is 0) n.0.1), |
110 |
|
* ((_ is 0) n.1), ((_ is 0) n.2) } |
111 |
|
* |
112 |
|
* This class can also return more precise |
113 |
|
* explanations based on a property that holds for |
114 |
|
* variants of n. For instance, |
115 |
|
* say we find that n's builtin analog rewrites to 0: |
116 |
|
* ite( x>0, 0, 0 ) ----> 0 |
117 |
|
* and we would like to find the minimal explanation for |
118 |
|
* why the builtin analog of n rewrites to 0. |
119 |
|
* We use the invariance test EquivSygusInvarianceTest |
120 |
|
* (see sygus_invariance.h) for doing this. |
121 |
|
* Using the SygusExplain::getExplanationFor method below, |
122 |
|
* this will invoke the invariant test to check, e.g. |
123 |
|
* ite( x>0, 0, y1 ) ----> 0 ? fail |
124 |
|
* ite( x>0, y2, 0 ) ----> 0 ? fail |
125 |
|
* ite( y3, 0, 0 ) ----> 0 ? success |
126 |
|
* where y1, y2, y3 are fresh variables. |
127 |
|
* Hence the explanation for the condition x>0 is irrelevant. |
128 |
|
* This gives us the explanation: |
129 |
|
* { ((_ is if) n), ((_ is 0) n.1), ((_ is 0) n.2) } |
130 |
|
* indicating that all terms of the form: |
131 |
|
* (if _ 0 0) have a builtin equivalent that rewrites to 0. |
132 |
|
* |
133 |
|
* For details, see Reynolds et al SYNT 2017. |
134 |
|
* |
135 |
|
* Below, we let [[exp]]_n denote the term induced by |
136 |
|
* the explanation exp for n. |
137 |
|
* For example: |
138 |
|
* exp = { ((_ is plus) n), ((_ is y) n.1) } |
139 |
|
* is such that: |
140 |
|
* [[exp]]_n = (plus w y) |
141 |
|
* where w is a fresh variable. |
142 |
|
*/ |
143 |
|
class SygusExplain |
144 |
|
{ |
145 |
|
public: |
146 |
1417 |
SygusExplain(TermDbSygus* tdb) : d_tdb(tdb) {} |
147 |
1415 |
~SygusExplain() {} |
148 |
|
/** get explanation for equality |
149 |
|
* |
150 |
|
* This function constructs an explanation, stored in exp, such that: |
151 |
|
* - All formulas in exp are of the form ((_ is C) ns), where ns |
152 |
|
* is a chain of selectors applied to n, and |
153 |
|
* - exp => ( n = vn ) |
154 |
|
*/ |
155 |
|
void getExplanationForEquality(Node n, Node vn, std::vector<Node>& exp); |
156 |
|
/** returns the conjunction of exp computed in the above function */ |
157 |
|
Node getExplanationForEquality(Node n, Node vn); |
158 |
|
|
159 |
|
/** get explanation for equality |
160 |
|
* |
161 |
|
* This is identical to the above function except that we |
162 |
|
* take an additional argument cexc, which says which |
163 |
|
* children of vn should be excluded from the explanation. |
164 |
|
* |
165 |
|
* For example, if vn = plus( plus( x, x ), y ) and cexc is { 0 -> true }, |
166 |
|
* then the following is appended to exp : |
167 |
|
* { ((_ is plus) n), ((_ is y) n.1) } |
168 |
|
* where notice that the 0^th argument of vn is excluded. |
169 |
|
*/ |
170 |
|
void getExplanationForEquality(Node n, |
171 |
|
Node vn, |
172 |
|
std::vector<Node>& exp, |
173 |
|
std::map<unsigned, bool>& cexc); |
174 |
|
/** returns the conjunction of exp computed in the above function */ |
175 |
|
Node getExplanationForEquality(Node n, |
176 |
|
Node vn, |
177 |
|
std::map<unsigned, bool>& cexc); |
178 |
|
|
179 |
|
/** get explanation for |
180 |
|
* |
181 |
|
* This function constructs an explanation, stored in exp, such that: |
182 |
|
* - All formulas in exp are of the form ((_ is C) ns), where ns |
183 |
|
* is a chain of selectors applied to n, and |
184 |
|
* - The test et holds for [[exp]]_n, and |
185 |
|
* - (if applicable) exp => ( n != vnr ). |
186 |
|
* |
187 |
|
* This function updates sz to be the term size of [[exp]]_n. |
188 |
|
* |
189 |
|
* If strict is false, then we also test whether the invariance test holds |
190 |
|
* independently of the entire value of vn. |
191 |
|
* |
192 |
|
* The argument var_count is used for tracking the variables that we introduce |
193 |
|
* to generalize the shape of vn. This map is passed to |
194 |
|
* TermDbSygus::getFreeVarInc. This argument should be used if we are |
195 |
|
* calling this function multiple times and the generalization should not |
196 |
|
* introduce variables that shadow the variables introduced on previous calls. |
197 |
|
*/ |
198 |
|
void getExplanationFor(Node n, |
199 |
|
Node vn, |
200 |
|
std::vector<Node>& exp, |
201 |
|
SygusInvarianceTest& et, |
202 |
|
Node vnr, |
203 |
|
unsigned& sz); |
204 |
|
void getExplanationFor(Node n, |
205 |
|
Node vn, |
206 |
|
std::vector<Node>& exp, |
207 |
|
SygusInvarianceTest& et, |
208 |
|
Node vnr, |
209 |
|
std::map<TypeNode, int>& var_count, |
210 |
|
unsigned& sz); |
211 |
|
void getExplanationFor(Node n, |
212 |
|
Node vn, |
213 |
|
std::vector<Node>& exp, |
214 |
|
SygusInvarianceTest& et, |
215 |
|
bool strict = true); |
216 |
|
void getExplanationFor(Node n, |
217 |
|
Node vn, |
218 |
|
std::vector<Node>& exp, |
219 |
|
SygusInvarianceTest& et, |
220 |
|
std::map<TypeNode, int>& var_count, |
221 |
|
bool strict = true); |
222 |
|
|
223 |
|
private: |
224 |
|
/** sygus term database associated with this utility */ |
225 |
|
TermDbSygus* d_tdb; |
226 |
|
/** Helper function for getExplanationFor |
227 |
|
* var_count is the number of free variables we have introduced, |
228 |
|
* per type, for the purposes of generalizing subterms of n. |
229 |
|
* vnr_exp stores the explanation, if one exists, for |
230 |
|
* n != vnr. It is only non-null if vnr is non-null. |
231 |
|
*/ |
232 |
|
void getExplanationFor(TermRecBuild& trb, |
233 |
|
Node n, |
234 |
|
Node vn, |
235 |
|
std::vector<Node>& exp, |
236 |
|
std::map<TypeNode, int>& var_count, |
237 |
|
SygusInvarianceTest& et, |
238 |
|
Node vnr, |
239 |
|
Node& vnr_exp, |
240 |
|
int& sz); |
241 |
|
}; |
242 |
|
|
243 |
|
} // namespace quantifiers |
244 |
|
} // namespace theory |
245 |
|
} // namespace cvc5 |
246 |
|
|
247 |
|
#endif /* CVC5__THEORY__QUANTIFIERS__SYGUS_EXPLAIN_H */ |