1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Andres Noetzli, 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 |
|
* Rewriter for the theory of (co)inductive datatypes. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
#ifndef CVC5__THEORY__DATATYPES__DATATYPES_REWRITER_H |
19 |
|
#define CVC5__THEORY__DATATYPES__DATATYPES_REWRITER_H |
20 |
|
|
21 |
|
#include "theory/evaluator.h" |
22 |
|
#include "theory/theory_rewriter.h" |
23 |
|
|
24 |
|
namespace cvc5 { |
25 |
|
namespace theory { |
26 |
|
namespace datatypes { |
27 |
|
|
28 |
|
/** |
29 |
|
* The rewriter for datatypes. An invariant of the rewriter is that |
30 |
|
* postRewrite/preRewrite should not depend on the options, in particular, |
31 |
|
* they should not depend on whether shared selectors are enabled. Thus, |
32 |
|
* they should not use DTypeConstructor::getSelectorInternal. Instead, |
33 |
|
* the conversion from external to internal selectors is done in |
34 |
|
* expandDefinition. This invariant ensures that the rewritten form of a node |
35 |
|
* does not mix multiple option settings, which would lead to e.g. shared |
36 |
|
* selectors being used in an SolverEngine instance where they are disabled. |
37 |
|
*/ |
38 |
15266 |
class DatatypesRewriter : public TheoryRewriter |
39 |
|
{ |
40 |
|
public: |
41 |
|
DatatypesRewriter(Evaluator* sygusEval); |
42 |
|
RewriteResponse postRewrite(TNode in) override; |
43 |
|
RewriteResponse preRewrite(TNode in) override; |
44 |
|
|
45 |
|
/** normalize codatatype constant |
46 |
|
* |
47 |
|
* This returns the normal form of the codatatype constant n. This runs a |
48 |
|
* DFA minimization algorithm based on the private functions below. |
49 |
|
* |
50 |
|
* In particular, we first call collectRefs to setup initial information |
51 |
|
* about what terms occur in n. Then, we run a DFA minimization algorithm to |
52 |
|
* partition these subterms in equivalence classes. Finally, we call |
53 |
|
* normalizeCodatatypeConstantEqc to construct the normalized codatatype |
54 |
|
* constant that is equivalent to n. |
55 |
|
*/ |
56 |
|
static Node normalizeCodatatypeConstant(Node n); |
57 |
|
/** normalize constant |
58 |
|
* |
59 |
|
* This method returns the normal form of n, which calls the above function |
60 |
|
* on all top-level codatatype subterms of n. |
61 |
|
*/ |
62 |
|
static Node normalizeConstant(Node n); |
63 |
|
/** |
64 |
|
* Expand an APPLY_SELECTOR term n, return its expanded form. If n is |
65 |
|
* (APPLY_SELECTOR selC x) |
66 |
|
* its expanded form is |
67 |
|
* (ITE (APPLY_TESTER is-C x) |
68 |
|
* (APPLY_SELECTOR_TOTAL selC' x) |
69 |
|
* (f x)) |
70 |
|
* where f is a skolem function with id SELECTOR_WRONG, and selC' is the |
71 |
|
* internal selector function for selC (possibly a shared selector). |
72 |
|
*/ |
73 |
|
static Node expandApplySelector(Node n); |
74 |
|
/** expand defintions */ |
75 |
|
TrustNode expandDefinition(Node n) override; |
76 |
|
|
77 |
|
private: |
78 |
|
/** rewrite constructor term in */ |
79 |
|
static RewriteResponse rewriteConstructor(TNode in); |
80 |
|
/** rewrite selector term in */ |
81 |
|
static RewriteResponse rewriteSelector(TNode in); |
82 |
|
/** rewrite tester term in */ |
83 |
|
static RewriteResponse rewriteTester(TNode in); |
84 |
|
/** rewrite updater term in */ |
85 |
|
static RewriteResponse rewriteUpdater(TNode in); |
86 |
|
|
87 |
|
/** collect references |
88 |
|
* |
89 |
|
* This function, given as input a codatatype term n, collects the necessary |
90 |
|
* information for constructing a (canonical) codatatype constant that is |
91 |
|
* equivalent to n if one exists, or null otherwise. |
92 |
|
* |
93 |
|
* In particular it returns a term ret such that all non-codatatype datatype |
94 |
|
* subterms of n are replaced by a constant that is equal to them via a |
95 |
|
* (mutually) recursive call to normalizeConstant above. Additionally, this |
96 |
|
* function replaces references to mu-binders with fresh variables. |
97 |
|
* In detail, mu-terms are represented by uninterpreted constants of datatype |
98 |
|
* type that carry their Debruijn index. |
99 |
|
* |
100 |
|
* Consider the example of a codatatype representing a stream of integers: |
101 |
|
* Stream := cons( head : Int, tail : Stream ) |
102 |
|
* The stream 1,0,1,0,1,0... when written in mu-notation is the term: |
103 |
|
* mu x. cons( 1, mu y. cons( 0, x ) ) |
104 |
|
* This is represented in cvc5 by the Node: |
105 |
|
* cons( 1, cons( 0, c[1] ) ) |
106 |
|
* where c[1] is a uninterpreted constant datatype with Debruijn index 1, |
107 |
|
* indicating that c[1] is nested underneath 1 level on the path to the |
108 |
|
* term which it binds. On the other hand, the stream 1,0,0,0,0,... is |
109 |
|
* represented by the codatatype term: |
110 |
|
* cons( 1, cons( 0, c[0] ) ) |
111 |
|
* |
112 |
|
* Subterms that are references to mu-binders in n are replaced by a new |
113 |
|
* variable. If n contains any subterm that is a reference to a mu-binder not |
114 |
|
* bound in n, then we return null. For example we return null when n is: |
115 |
|
* cons( 1, cons( 0, c[2] ) ) |
116 |
|
* since c[2] is not bound by this codatatype term. |
117 |
|
* |
118 |
|
* All valid references to mu-binders are replaced by a variable that is |
119 |
|
* unique for the term it references. For example, for the infinite tree |
120 |
|
* codatatype: Tree : node( data : Int, left : Tree, right : Tree ) If n is |
121 |
|
* the term: node( 0, c[0], node( 1, c[0], c[1] ) ) then the return value ret |
122 |
|
* of this function is: node( 0, x, node( 1, y, x ) ) where x refers to the |
123 |
|
* root of the term and y refers to the right tree of the root. |
124 |
|
* |
125 |
|
* The argument sk stores the current set of node that we are traversing |
126 |
|
* beneath. The argument rf_pending stores, for each node that we are |
127 |
|
* traversing beneath either null or the free variable that we are using to |
128 |
|
* refer to its mu-binder. The remaining arguments store information that is |
129 |
|
* relevant when performing normalization of n using the value of ret: |
130 |
|
* |
131 |
|
* rf : maps subterms of n to the corresponding term in ret for all subterms |
132 |
|
* where the corresponding term in ret is different. |
133 |
|
* terms : stores all subterms of ret. |
134 |
|
* cdts : for each term t in terms, stores whether t is a codatatype. |
135 |
|
*/ |
136 |
|
static Node collectRef(Node n, |
137 |
|
std::vector<Node>& sk, |
138 |
|
std::map<Node, Node>& rf, |
139 |
|
std::vector<Node>& rf_pending, |
140 |
|
std::vector<Node>& terms, |
141 |
|
std::map<Node, bool>& cdts); |
142 |
|
/** normalize codatatype constant eqc |
143 |
|
* |
144 |
|
* This recursive function returns a codatatype constant that is equivalent to |
145 |
|
* n based on a pre-computed partition of the subterms of n into equivalence |
146 |
|
* classes, as stored in the mapping eqc, which maps the subterms of n to |
147 |
|
* equivalence class ids. The arguments eqc_stack and depth store information |
148 |
|
* about the traversal in a term we have recursed, where |
149 |
|
* |
150 |
|
* eqc_stack : maps the depth of each term we have traversed to its |
151 |
|
* equivalence class id. depth : the number of levels which we have traversed. |
152 |
|
*/ |
153 |
|
static Node normalizeCodatatypeConstantEqc(Node n, |
154 |
|
std::map<int, int>& eqc_stack, |
155 |
|
std::map<Node, int>& eqc, |
156 |
|
int depth); |
157 |
|
/** replace debruijn |
158 |
|
* |
159 |
|
* This function, given codatatype term n, returns a node |
160 |
|
* where all subterms of n that have Debruijn indices that refer to a |
161 |
|
* term of input depth are replaced by orig. For example, for the infinite |
162 |
|
* Tree datatype, replaceDebruijn( node( 0, c[0], node( 1, c[0], c[1] ) ), t, |
163 |
|
* Tree, 0 ) returns node( 0, t, node( 1, c[0], t ) ). |
164 |
|
*/ |
165 |
|
static Node replaceDebruijn(Node n, |
166 |
|
Node orig, |
167 |
|
TypeNode orig_tn, |
168 |
|
unsigned depth); |
169 |
|
|
170 |
|
/** Sygus to builtin eval |
171 |
|
* |
172 |
|
* This method returns the rewritten form of (DT_SYGUS_EVAL n args). Notice |
173 |
|
* that n does not necessarily need to be a constant. |
174 |
|
* |
175 |
|
* It does so by (1) converting constant subterms of n to builtin terms and |
176 |
|
* evaluating them on the arguments args, (2) unfolding non-constant |
177 |
|
* applications of sygus constructors in n with respect to args and (3) |
178 |
|
* converting all other non-constant subterms of n to applications of |
179 |
|
* DT_SYGUS_EVAL. |
180 |
|
* |
181 |
|
* For example, if |
182 |
|
* n = C_+( C_*( C_x(), C_y() ), n' ), and args = { 3, 4 } |
183 |
|
* where n' is a variable, then this method returns: |
184 |
|
* 12 + (DT_SYGUS_EVAL n' 3 4) |
185 |
|
* Notice that the subterm C_*( C_x(), C_y() ) is converted to its builtin |
186 |
|
* equivalent x*y and evaluated under the substition { x -> 3, y -> 4 } giving |
187 |
|
* 12. The subterm n' is non-constant and thus we return its evaluation under |
188 |
|
* 3,4, giving the term (DT_SYGUS_EVAL n' 3 4). Since the top-level |
189 |
|
* constructor is C_+, these terms are added together to give the result. |
190 |
|
*/ |
191 |
|
Node sygusToBuiltinEval(Node n, const std::vector<Node>& args); |
192 |
|
/** Pointer to the evaluator, used as an optimization for the above method */ |
193 |
|
Evaluator* d_sygusEval; |
194 |
|
}; |
195 |
|
|
196 |
|
} // namespace datatypes |
197 |
|
} // namespace theory |
198 |
|
} // namespace cvc5 |
199 |
|
|
200 |
|
#endif /* CVC5__THEORY__DATATYPES__DATATYPES_REWRITER_H */ |