1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Mathias Preiner |
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_eval_unfold |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__QUANTIFIERS__SYGUS_EVAL_UNFOLD_H |
19 |
|
#define CVC5__THEORY__QUANTIFIERS__SYGUS_EVAL_UNFOLD_H |
20 |
|
|
21 |
|
#include <map> |
22 |
|
#include "expr/node.h" |
23 |
|
#include "theory/quantifiers/sygus/sygus_invariance.h" |
24 |
|
|
25 |
|
namespace cvc5 { |
26 |
|
namespace theory { |
27 |
|
namespace quantifiers { |
28 |
|
|
29 |
|
class TermDbSygus; |
30 |
|
|
31 |
|
/** SygusEvalUnfold |
32 |
|
* |
33 |
|
* This class implements techniques for eagerly unfolding sygus evaluation |
34 |
|
* functions. For example, given sygus datatype type corresponding to grammar: |
35 |
|
* A -> 0 | 1 | A+A |
36 |
|
* whose evaluation function is eval, this class adds lemmas that "eagerly |
37 |
|
* unfold" applications of eval based on the model values of evaluation heads |
38 |
|
* in refinement lemmas. |
39 |
|
*/ |
40 |
|
class SygusEvalUnfold |
41 |
|
{ |
42 |
|
public: |
43 |
|
SygusEvalUnfold(TermDbSygus* tds); |
44 |
1529 |
~SygusEvalUnfold() {} |
45 |
|
/** register evaluation term |
46 |
|
* |
47 |
|
* This is called by TermDatabase, during standard effort calls when a term |
48 |
|
* n is registered as an equivalence class in the master equality engine. |
49 |
|
* If this term is of the form: |
50 |
|
* eval( a, t1, ..., tn ) |
51 |
|
* where a is a symbolic term of sygus datatype type (not a application of a |
52 |
|
* constructor), then we remember that n is an evaluation function application |
53 |
|
* for evaluation head a. |
54 |
|
*/ |
55 |
|
void registerEvalTerm(Node n); |
56 |
|
/** register model value |
57 |
|
* |
58 |
|
* This notifies this class that the model value M(a) of an anchor term a is |
59 |
|
* currently v. Assume in the following that the top symbol of v is some sygus |
60 |
|
* datatype constructor C_op. |
61 |
|
* |
62 |
|
* If we have registered terms eval( a, T1 ), ..., eval( a, Tm ), then we |
63 |
|
* ensure that for each i=1,...,m, a lemma of one of the two forms is |
64 |
|
* generated: |
65 |
|
* [A] a=v => eval( a, Ti ) = [[unfold( eval( v, Ti ) )]] |
66 |
|
* [B] is-C_op(v) => eval(a, Ti ) = op(eval( a.1, Ti ), ..., eval( a.k, Ti )), |
67 |
|
* where this corresponds to a "one step folding" of the sygus evaluation |
68 |
|
* function, i.e. op is a builtin operator encoded by constructor C_op. |
69 |
|
* |
70 |
|
* We decide which kind of lemma to send ([A] or [B]) based on the symbol |
71 |
|
* C_op. If op is an ITE, or if C_op is a Boolean operator, then we add [B]. |
72 |
|
* Otherwise, we add [A]. The intuition of why [B] is better than [A] for the |
73 |
|
* former is that evaluation unfolding can lead to useful conflict analysis. |
74 |
|
* |
75 |
|
* For each lemma C => eval( a, T ) = T' we infer is necessary, we add C to |
76 |
|
* exps, eval( a, T ) to terms, and T' to vals. The caller should send the |
77 |
|
* corresponding lemma on the output channel. |
78 |
|
* |
79 |
|
* We do the above scheme *for each* selector chain (see d_subterms below) |
80 |
|
* applied to a. |
81 |
|
*/ |
82 |
|
void registerModelValue(Node a, |
83 |
|
Node v, |
84 |
|
std::vector<Node>& exps, |
85 |
|
std::vector<Node>& terms, |
86 |
|
std::vector<Node>& vals); |
87 |
|
/** unfold |
88 |
|
* |
89 |
|
* This method is called when a sygus term d (typically a variable for a SyGuS |
90 |
|
* enumerator) has a model value specified by the map vtm. The argument en |
91 |
|
* is an application of kind DT_SYGUS_EVAL, i.e. eval( d, c1, ..., cm ). |
92 |
|
* Typically, d is a shared selector chain, although it may also be a |
93 |
|
* non-constant application of a constructor. |
94 |
|
* |
95 |
|
* If doRec is false, this method returns the one-step unfolding of this |
96 |
|
* evaluation function application. An example of a one step unfolding is: |
97 |
|
* eval( C_+( d1, d2 ), t ) ---> +( eval( d1, t ), eval( d2, t ) ) |
98 |
|
* |
99 |
|
* This function does this unfolding for a (possibly symbolic) evaluation |
100 |
|
* head, where the argument "variable to model" vtm stores the model value of |
101 |
|
* variables from this head. This allows us to track an explanation of the |
102 |
|
* unfolding in the vector exp when track_exp is true. |
103 |
|
* |
104 |
|
* For example, if vtm[d] = C_+( C_x(), C_0() ) and track_exp is true, then |
105 |
|
* this method applied to eval( d, t ) will return |
106 |
|
* +( eval( d.0, t ), eval( d.1, t ) ), and is-C_+( d ) is added to exp. |
107 |
|
* |
108 |
|
* If the argument doRec is true, we do a multi-step unfolding instead of |
109 |
|
* a single-step unfolding. For example, if vtm[d] = C_+( C_x(), C_0() ), |
110 |
|
* then this method applied to eval(d,5) will return 5+0 = 0. |
111 |
|
* |
112 |
|
* Furthermore, notice that any-constant constructors are *never* expanded to |
113 |
|
* their concrete model values. This means that the multi-step unfolding when |
114 |
|
* vtm[d] = C_+( C_x(), any_constant(n) ), then this method applied to |
115 |
|
* eval(d,5) will return 5 + d.2.1, where the latter term is a shared selector |
116 |
|
* chain. In other words, this unfolding elaborates the connection between |
117 |
|
* the builtin integer field d.2.1 of d and the builtin interpretation of |
118 |
|
* this sygus term, for the given argument. |
119 |
|
*/ |
120 |
|
Node unfold(Node en, |
121 |
|
std::map<Node, Node>& vtm, |
122 |
|
std::vector<Node>& exp, |
123 |
|
bool track_exp = true, |
124 |
|
bool doRec = false); |
125 |
|
/** |
126 |
|
* Same as above, but without explanation tracking. This is used for concrete |
127 |
|
* evaluation heads |
128 |
|
*/ |
129 |
|
Node unfold(Node en); |
130 |
|
|
131 |
|
private: |
132 |
|
/** sygus term database associated with this utility */ |
133 |
|
TermDbSygus* d_tds; |
134 |
|
/** the set of evaluation terms we have already processed */ |
135 |
|
std::unordered_set<Node> d_eval_processed; |
136 |
|
/** map from evaluation heads to evaluation function applications */ |
137 |
|
std::map<Node, std::vector<Node> > d_evals; |
138 |
|
/** |
139 |
|
* Map from evaluation function applications to their arguments (minus the |
140 |
|
* evaluation head). For example, eval(x,0,1) is mapped to { 0, 1 }. |
141 |
|
*/ |
142 |
|
std::map<Node, std::vector<std::vector<Node> > > d_eval_args; |
143 |
|
/** |
144 |
|
* For each (a,M(a)) pair, the number of terms in d_evals that we have added |
145 |
|
* lemmas for |
146 |
|
*/ |
147 |
|
std::map<Node, std::map<Node, unsigned> > d_node_mv_args_proc; |
148 |
|
/** subterms map |
149 |
|
* |
150 |
|
* This maps anchor terms to the set of shared selector chains with |
151 |
|
* them as an anchor, for example x may map to { x, x.1, x.2, x.1.1 }. |
152 |
|
*/ |
153 |
|
std::map<Node, std::unordered_set<Node> > d_subterms; |
154 |
|
}; |
155 |
|
|
156 |
|
} // namespace quantifiers |
157 |
|
} // namespace theory |
158 |
|
} // namespace cvc5 |
159 |
|
|
160 |
|
#endif /* CVC5__THEORY__QUANTIFIERS__SYGUS_EVAL_UNFOLD_H */ |