1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Haniel Barbosa, Andrew Reynolds, Tim King |
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 |
|
* Implementation of class for for simplifying SyGuS grammars after they |
14 |
|
* are encoded into datatypes. |
15 |
|
*/ |
16 |
|
|
17 |
|
#include "theory/quantifiers/sygus/sygus_grammar_norm.h" |
18 |
|
|
19 |
|
#include <sstream> |
20 |
|
|
21 |
|
#include "expr/dtype_cons.h" |
22 |
|
#include "expr/node_manager_attributes.h" // for VarNameAttr |
23 |
|
#include "options/quantifiers_options.h" |
24 |
|
#include "theory/datatypes/theory_datatypes_utils.h" |
25 |
|
#include "theory/quantifiers/cegqi/ceg_instantiator.h" |
26 |
|
#include "theory/quantifiers/sygus/sygus_grammar_cons.h" |
27 |
|
#include "theory/quantifiers/sygus/sygus_grammar_red.h" |
28 |
|
#include "theory/quantifiers/sygus/term_database_sygus.h" |
29 |
|
#include "theory/quantifiers/term_util.h" |
30 |
|
|
31 |
|
#include <numeric> // for std::iota |
32 |
|
|
33 |
|
using namespace cvc5::kind; |
34 |
|
|
35 |
|
namespace cvc5 { |
36 |
|
namespace theory { |
37 |
|
namespace quantifiers { |
38 |
|
|
39 |
23083 |
bool OpPosTrie::getOrMakeType(TypeNode tn, |
40 |
|
TypeNode& unres_tn, |
41 |
|
const std::vector<unsigned>& op_pos, |
42 |
|
unsigned ind) |
43 |
|
{ |
44 |
23083 |
if (ind == op_pos.size()) |
45 |
|
{ |
46 |
|
/* Found type */ |
47 |
2430 |
if (!d_unres_tn.isNull()) |
48 |
|
{ |
49 |
3930 |
Trace("sygus-grammar-normalize-trie") |
50 |
1965 |
<< "\tFound type " << d_unres_tn << "\n"; |
51 |
1965 |
unres_tn = d_unres_tn; |
52 |
1965 |
return true; |
53 |
|
} |
54 |
|
/* Creating unresolved type */ |
55 |
930 |
std::stringstream ss; |
56 |
465 |
ss << tn << "_"; |
57 |
2698 |
for (unsigned i = 0, size = op_pos.size(); i < size; ++i) |
58 |
|
{ |
59 |
2233 |
ss << "_" << std::to_string(op_pos[i]); |
60 |
|
} |
61 |
1395 |
d_unres_tn = NodeManager::currentNM()->mkSort( |
62 |
1395 |
ss.str(), NodeManager::SORT_FLAG_PLACEHOLDER); |
63 |
930 |
Trace("sygus-grammar-normalize-trie") |
64 |
465 |
<< "\tCreating type " << d_unres_tn << "\n"; |
65 |
465 |
unres_tn = d_unres_tn; |
66 |
465 |
return false; |
67 |
|
} |
68 |
|
/* Go to next node */ |
69 |
20653 |
return d_children[op_pos[ind]].getOrMakeType(tn, unres_tn, op_pos, ind + 1); |
70 |
|
} |
71 |
|
|
72 |
205 |
SygusGrammarNorm::SygusGrammarNorm(TermDbSygus* tds) : d_tds(tds) {} |
73 |
|
|
74 |
465 |
SygusGrammarNorm::TypeObject::TypeObject(TypeNode src_tn, TypeNode unres_tn) |
75 |
|
: d_tn(src_tn), |
76 |
|
d_unres_tn(unres_tn), |
77 |
465 |
d_sdt(unres_tn.getAttribute(expr::VarNameAttr())) |
78 |
|
{ |
79 |
465 |
} |
80 |
|
|
81 |
2212 |
void SygusGrammarNorm::TypeObject::addConsInfo( |
82 |
|
SygusGrammarNorm* sygus_norm, |
83 |
|
const DTypeConstructor& cons) |
84 |
|
{ |
85 |
2212 |
Trace("sygus-grammar-normalize") << "...for " << cons.getName() << "\n"; |
86 |
|
/* Recover the sygus operator to not lose reference to the original |
87 |
|
* operator (NOT, ITE, etc) */ |
88 |
4424 |
Node sygus_op = cons.getSygusOp(); |
89 |
4424 |
Trace("sygus-grammar-normalize-debug") |
90 |
2212 |
<< ".....operator is " << sygus_op << std::endl; |
91 |
|
|
92 |
4424 |
std::vector<TypeNode> consTypes; |
93 |
2212 |
const std::vector<std::shared_ptr<DTypeSelector> >& args = cons.getArgs(); |
94 |
4437 |
for (const std::shared_ptr<DTypeSelector>& arg : args) |
95 |
|
{ |
96 |
|
// Collect unresolved type nodes corresponding to the typenode of the |
97 |
|
// arguments. |
98 |
4450 |
TypeNode atype = arg->getRangeType(); |
99 |
|
// normalize it recursively |
100 |
2225 |
atype = sygus_norm->normalizeSygusRec(atype); |
101 |
2225 |
consTypes.push_back(atype); |
102 |
|
} |
103 |
|
|
104 |
4424 |
d_sdt.addConstructor( |
105 |
2212 |
sygus_op, cons.getName(), consTypes, cons.getWeight()); |
106 |
2212 |
} |
107 |
|
|
108 |
465 |
void SygusGrammarNorm::TypeObject::initializeDatatype( |
109 |
|
SygusGrammarNorm* sygus_norm, const DType& dt) |
110 |
|
{ |
111 |
|
/* Use the sygus type to not lose reference to the original types (Bool, |
112 |
|
* Int, etc) */ |
113 |
930 |
TypeNode sygusType = dt.getSygusType(); |
114 |
1395 |
d_sdt.initializeDatatype(sygusType, |
115 |
|
sygus_norm->d_sygus_vars, |
116 |
465 |
dt.getSygusAllowConst(), |
117 |
465 |
dt.getSygusAllowAll()); |
118 |
930 |
Trace("sygus-grammar-normalize") |
119 |
465 |
<< "...built datatype " << d_sdt.getDatatype() << " "; |
120 |
|
/* Add to global accumulators */ |
121 |
465 |
sygus_norm->d_dt_all.push_back(d_sdt.getDatatype()); |
122 |
465 |
sygus_norm->d_unres_t_all.insert(d_unres_tn); |
123 |
465 |
Trace("sygus-grammar-normalize") << "---------------------------------\n"; |
124 |
465 |
} |
125 |
|
|
126 |
15 |
void SygusGrammarNorm::TransfDrop::buildType(SygusGrammarNorm* sygus_norm, |
127 |
|
TypeObject& to, |
128 |
|
const DType& dt, |
129 |
|
std::vector<unsigned>& op_pos) |
130 |
|
{ |
131 |
30 |
std::vector<unsigned> difference; |
132 |
15 |
std::set_difference(op_pos.begin(), |
133 |
|
op_pos.end(), |
134 |
|
d_drop_indices.begin(), |
135 |
|
d_drop_indices.end(), |
136 |
15 |
std::back_inserter(difference)); |
137 |
15 |
op_pos = difference; |
138 |
15 |
} |
139 |
|
|
140 |
|
/* TODO #1304: have more operators and types. Moreover, have more general ways |
141 |
|
of finding kind of operator, e.g. if op is (\lambda xy. x + y) this |
142 |
|
function should realize that it is chainable for integers */ |
143 |
|
bool SygusGrammarNorm::TransfChain::isChainable(TypeNode tn, Node op) |
144 |
|
{ |
145 |
|
/* Checks whether operator occurs chainable for its type */ |
146 |
|
if (tn.isInteger() && NodeManager::currentNM()->operatorToKind(op) == PLUS) |
147 |
|
{ |
148 |
|
return true; |
149 |
|
} |
150 |
|
return false; |
151 |
|
} |
152 |
|
|
153 |
|
/* TODO #1304: have more operators and types. Moreover, have more general ways |
154 |
|
of finding kind of operator, e.g. if op is (\lambda xy. x + y) this |
155 |
|
function should realize that it is chainable for integers */ |
156 |
|
bool SygusGrammarNorm::TransfChain::isId(TypeNode tn, Node op, Node n) |
157 |
|
{ |
158 |
|
if (tn.isInteger() && NodeManager::currentNM()->operatorToKind(op) == PLUS |
159 |
|
&& n == TermUtil::mkTypeValue(tn, 0)) |
160 |
|
{ |
161 |
|
return true; |
162 |
|
} |
163 |
|
return false; |
164 |
|
} |
165 |
|
|
166 |
|
void SygusGrammarNorm::TransfChain::buildType(SygusGrammarNorm* sygus_norm, |
167 |
|
TypeObject& to, |
168 |
|
const DType& dt, |
169 |
|
std::vector<unsigned>& op_pos) |
170 |
|
{ |
171 |
|
NodeManager* nm = NodeManager::currentNM(); |
172 |
|
std::vector<unsigned> claimed(d_elem_pos); |
173 |
|
claimed.push_back(d_chain_op_pos); |
174 |
|
unsigned nb_op_pos = op_pos.size(); |
175 |
|
/* TODO do this properly */ |
176 |
|
/* Remove from op_pos the positions claimed by the transformation */ |
177 |
|
std::sort(op_pos.begin(), op_pos.end()); |
178 |
|
std::sort(claimed.begin(), claimed.end()); |
179 |
|
std::vector<unsigned> difference; |
180 |
|
std::set_difference(op_pos.begin(), |
181 |
|
op_pos.end(), |
182 |
|
claimed.begin(), |
183 |
|
claimed.end(), |
184 |
|
std::back_inserter(difference)); |
185 |
|
op_pos = difference; |
186 |
|
if (Trace.isOn("sygus-grammar-normalize-chain")) |
187 |
|
{ |
188 |
|
Trace("sygus-grammar-normalize-chain") |
189 |
|
<< "OP at " << d_chain_op_pos << "\n" |
190 |
|
<< d_elem_pos.size() << " d_elem_pos: "; |
191 |
|
for (unsigned i = 0, size = d_elem_pos.size(); i < size; ++i) |
192 |
|
{ |
193 |
|
Trace("sygus-grammar-normalize-chain") << d_elem_pos[i] << " "; |
194 |
|
} |
195 |
|
Trace("sygus-grammar-normalize-chain") |
196 |
|
<< "\n" |
197 |
|
<< op_pos.size() << " remaining op_pos: "; |
198 |
|
for (unsigned i = 0, size = op_pos.size(); i < size; ++i) |
199 |
|
{ |
200 |
|
Trace("sygus-grammar-normalize-chain") << op_pos[i] << " "; |
201 |
|
} |
202 |
|
Trace("sygus-grammar-normalize-chain") << "\n"; |
203 |
|
} |
204 |
|
/* Build identity operator and empty callback */ |
205 |
|
Node iden_op = SygusGrammarNorm::getIdOp(dt.getSygusType()); |
206 |
|
/* If all operators are claimed, create a monomial */ |
207 |
|
if (nb_op_pos == d_elem_pos.size() + 1) |
208 |
|
{ |
209 |
|
Trace("sygus-grammar-normalize-chain") |
210 |
|
<< "\tCreating id type for " << d_elem_pos.back() << "\n"; |
211 |
|
/* creates type for element */ |
212 |
|
std::vector<unsigned> tmp; |
213 |
|
tmp.push_back(d_elem_pos.back()); |
214 |
|
TypeNode t = sygus_norm->normalizeSygusRec(to.d_tn, dt, tmp); |
215 |
|
/* consumes element */ |
216 |
|
d_elem_pos.pop_back(); |
217 |
|
/* adds to Root: "type" */ |
218 |
|
std::vector<TypeNode> ctypes; |
219 |
|
ctypes.push_back(t); |
220 |
|
to.d_sdt.addConstructor(iden_op, |
221 |
|
"id", |
222 |
|
ctypes, |
223 |
|
0); |
224 |
|
Trace("sygus-grammar-normalize-chain") |
225 |
|
<< "\tAdding " << t << " to " << to.d_unres_tn << "\n"; |
226 |
|
/* adds to Root: "type + Root" */ |
227 |
|
std::vector<TypeNode> ctypesp; |
228 |
|
ctypesp.push_back(t); |
229 |
|
ctypesp.push_back(to.d_unres_tn); |
230 |
|
to.d_sdt.addConstructor(nm->operatorOf(PLUS), kindToString(PLUS), ctypesp); |
231 |
|
Trace("sygus-grammar-normalize-chain") |
232 |
|
<< "\tAdding PLUS to " << to.d_unres_tn << " with arg types " |
233 |
|
<< to.d_unres_tn << " and " << t << "\n"; |
234 |
|
} |
235 |
|
/* In the initial case if not all operators claimed always creates a next */ |
236 |
|
Assert(nb_op_pos != d_elem_pos.size() + 1 || d_elem_pos.size() > 1); |
237 |
|
/* TODO #1304: consider case in which CHAIN op has different types than |
238 |
|
to.d_tn */ |
239 |
|
/* If no more elements to chain, finish */ |
240 |
|
if (d_elem_pos.size() == 0) |
241 |
|
{ |
242 |
|
return; |
243 |
|
} |
244 |
|
/* Creates a type do be added to root representing next step in the chain */ |
245 |
|
/* Add + to elems */ |
246 |
|
d_elem_pos.push_back(d_chain_op_pos); |
247 |
|
if (Trace.isOn("sygus-grammar-normalize-chain")) |
248 |
|
{ |
249 |
|
Trace("sygus-grammar-normalize-chain") |
250 |
|
<< "\tCreating type for next entry with sygus_ops "; |
251 |
|
for (unsigned i = 0, size = d_elem_pos.size(); i < size; ++i) |
252 |
|
{ |
253 |
|
Trace("sygus-grammar-normalize-chain") |
254 |
|
<< dt[d_elem_pos[i]].getSygusOp() << " "; |
255 |
|
} |
256 |
|
Trace("sygus-grammar-normalize-chain") << "\n"; |
257 |
|
} |
258 |
|
/* adds to Root: (\lambda x. x ) Next */ |
259 |
|
std::vector<TypeNode> ctypes; |
260 |
|
ctypes.push_back(sygus_norm->normalizeSygusRec(to.d_tn, dt, d_elem_pos)); |
261 |
|
to.d_sdt.addConstructor(iden_op, |
262 |
|
"id_next", |
263 |
|
ctypes, |
264 |
|
0); |
265 |
|
} |
266 |
|
|
267 |
9835 |
std::map<TypeNode, Node> SygusGrammarNorm::d_tn_to_id = {}; |
268 |
|
|
269 |
|
/* Traverse the constructors of dt according to the positions in op_pos. Collect |
270 |
|
* those that fit the kinds established by to_collect. Remove collected operator |
271 |
|
* positions from op_pos. Accumulate collected positions in collected |
272 |
|
* |
273 |
|
* returns true if collected anything |
274 |
|
*/ |
275 |
465 |
std::unique_ptr<SygusGrammarNorm::Transf> SygusGrammarNorm::inferTransf( |
276 |
|
TypeNode tn, const DType& dt, const std::vector<unsigned>& op_pos) |
277 |
|
{ |
278 |
465 |
NodeManager* nm = NodeManager::currentNM(); |
279 |
930 |
TypeNode sygus_tn = dt.getSygusType(); |
280 |
930 |
Trace("sygus-gnorm") << "Infer transf for " << dt.getName() << "..." |
281 |
465 |
<< std::endl; |
282 |
930 |
Trace("sygus-gnorm") << " #cons = " << op_pos.size() << " / " |
283 |
465 |
<< dt.getNumConstructors() << std::endl; |
284 |
|
// look for redundant constructors to drop |
285 |
465 |
if (options::sygusMinGrammar() && dt.getNumConstructors() == op_pos.size()) |
286 |
|
{ |
287 |
915 |
SygusRedundantCons src; |
288 |
465 |
src.initialize(d_tds, tn); |
289 |
915 |
std::vector<unsigned> rindices; |
290 |
465 |
src.getRedundant(rindices); |
291 |
465 |
if (!rindices.empty()) |
292 |
|
{ |
293 |
30 |
Trace("sygus-gnorm") << "...drop transf, " << rindices.size() << "/" |
294 |
15 |
<< op_pos.size() << " constructors." << std::endl; |
295 |
15 |
Assert(rindices.size() < op_pos.size()); |
296 |
15 |
return std::unique_ptr<Transf>(new TransfDrop(rindices)); |
297 |
|
} |
298 |
|
} |
299 |
|
|
300 |
|
// if normalization option is not enabled, we do not infer the transformations |
301 |
|
// below |
302 |
450 |
if (!options::sygusGrammarNorm()) |
303 |
|
{ |
304 |
450 |
return nullptr; |
305 |
|
} |
306 |
|
|
307 |
|
/* TODO #1304: step 1: look for singleton */ |
308 |
|
/* step 2: look for chain */ |
309 |
|
unsigned chain_op_pos = dt.getNumConstructors(); |
310 |
|
std::vector<unsigned> elem_pos; |
311 |
|
for (unsigned i = 0, size = op_pos.size(); i < size; ++i) |
312 |
|
{ |
313 |
|
Assert(op_pos[i] < dt.getNumConstructors()); |
314 |
|
Node sop = dt[op_pos[i]].getSygusOp(); |
315 |
|
/* Collects a chainable operator such as PLUS */ |
316 |
|
if (sop.getKind() == BUILTIN && TransfChain::isChainable(sygus_tn, sop)) |
317 |
|
{ |
318 |
|
Assert(nm->operatorToKind(sop) == PLUS); |
319 |
|
/* TODO #1304: be robust for this case */ |
320 |
|
/* For now only transforms applications whose arguments have the same type |
321 |
|
* as the root */ |
322 |
|
bool same_type_plus = true; |
323 |
|
const std::vector<std::shared_ptr<DTypeSelector> >& args = |
324 |
|
dt[op_pos[i]].getArgs(); |
325 |
|
for (const std::shared_ptr<DTypeSelector>& arg : args) |
326 |
|
{ |
327 |
|
if (arg->getRangeType() != tn) |
328 |
|
{ |
329 |
|
same_type_plus = false; |
330 |
|
break; |
331 |
|
} |
332 |
|
} |
333 |
|
if (!same_type_plus) |
334 |
|
{ |
335 |
|
Trace("sygus-grammar-normalize-infer") |
336 |
|
<< "\tFor OP " << PLUS << " did not collecting sop " << sop |
337 |
|
<< " in position " << op_pos[i] << "\n"; |
338 |
|
continue; |
339 |
|
} |
340 |
|
Assert(chain_op_pos == dt.getNumConstructors()); |
341 |
|
Trace("sygus-grammar-normalize-infer") |
342 |
|
<< "\tCollecting chainable OP " << sop << " in position " << op_pos[i] |
343 |
|
<< "\n"; |
344 |
|
chain_op_pos = op_pos[i]; |
345 |
|
continue; |
346 |
|
} |
347 |
|
/* TODO #1304: check this for each operator */ |
348 |
|
/* Collects elements that are not the identity (e.g. 0 is the id of PLUS) */ |
349 |
|
if (!TransfChain::isId(sygus_tn, nm->operatorOf(PLUS), sop)) |
350 |
|
{ |
351 |
|
Trace("sygus-grammar-normalize-infer") |
352 |
|
<< "\tCollecting for NON_ID_ELEMS the sop " << sop |
353 |
|
<< " in position " << op_pos[i] << "\n"; |
354 |
|
elem_pos.push_back(op_pos[i]); |
355 |
|
} |
356 |
|
} |
357 |
|
/* Typenode admits a chain transformation for normalization */ |
358 |
|
if (chain_op_pos != dt.getNumConstructors() && !elem_pos.empty()) |
359 |
|
{ |
360 |
|
Trace("sygus-gnorm") << "...chain transf." << std::endl; |
361 |
|
Trace("sygus-grammar-normalize-infer") |
362 |
|
<< "\tInfering chain transformation\n"; |
363 |
|
return std::unique_ptr<Transf>(new TransfChain(chain_op_pos, elem_pos)); |
364 |
|
} |
365 |
|
return nullptr; |
366 |
|
} |
367 |
|
|
368 |
2430 |
TypeNode SygusGrammarNorm::normalizeSygusRec(TypeNode tn, |
369 |
|
const DType& dt, |
370 |
|
std::vector<unsigned>& op_pos) |
371 |
|
{ |
372 |
2430 |
Assert(tn.isDatatype()); |
373 |
|
/* Corresponding type node to tn with the given operator positions. To be |
374 |
|
* retrieved (if cached) or defined (otherwise) */ |
375 |
2430 |
TypeNode unres_tn; |
376 |
2430 |
if (Trace.isOn("sygus-grammar-normalize-trie")) |
377 |
|
{ |
378 |
|
Trace("sygus-grammar-normalize-trie") |
379 |
|
<< "\tRecursing on " << tn << " with op_positions "; |
380 |
|
for (unsigned i = 0, size = op_pos.size(); i < size; ++i) |
381 |
|
{ |
382 |
|
Trace("sygus-grammar-normalize-trie") << op_pos[i] << " "; |
383 |
|
} |
384 |
|
Trace("sygus-grammar-normalize-trie") << "\n"; |
385 |
|
} |
386 |
|
/* Checks if unresolved type already created (and returns) or creates it |
387 |
|
* (and then proceeds to definition) */ |
388 |
2430 |
std::sort(op_pos.begin(), op_pos.end()); |
389 |
2430 |
if (d_tries[tn].getOrMakeType(tn, unres_tn, op_pos)) |
390 |
|
{ |
391 |
1965 |
if (Trace.isOn("sygus-grammar-normalize-trie")) |
392 |
|
{ |
393 |
|
Trace("sygus-grammar-normalize-trie") |
394 |
|
<< "\tTypenode " << tn << " has already been normalized with op_pos "; |
395 |
|
for (unsigned i = 0, size = op_pos.size(); i < size; ++i) |
396 |
|
{ |
397 |
|
Trace("sygus-grammar-normalize-trie") << op_pos[i] << " "; |
398 |
|
} |
399 |
|
Trace("sygus-grammar-normalize-trie") << " with tn " << unres_tn << "\n"; |
400 |
|
} |
401 |
1965 |
return unres_tn; |
402 |
|
} |
403 |
465 |
if (Trace.isOn("sygus-grammar-normalize-trie")) |
404 |
|
{ |
405 |
|
Trace("sygus-grammar-normalize-trie") |
406 |
|
<< "\tTypenode " << tn << " not yet normalized with op_pos "; |
407 |
|
for (unsigned i = 0, size = op_pos.size(); i < size; ++i) |
408 |
|
{ |
409 |
|
Trace("sygus-grammar-normalize-trie") << op_pos[i] << " "; |
410 |
|
} |
411 |
|
Trace("sygus-grammar-normalize-trie") << "\n"; |
412 |
|
} |
413 |
|
/* Creates type object for normalization */ |
414 |
930 |
TypeObject to(tn, unres_tn); |
415 |
|
|
416 |
465 |
if (dt.getSygusAllowConst()) |
417 |
|
{ |
418 |
84 |
TypeNode sygus_type = dt.getSygusType(); |
419 |
|
// must be handled by counterexample-guided instantiation |
420 |
|
// don't do it for Boolean (not worth the trouble, since it has only |
421 |
|
// minimal gain (1 any constant vs 2 constructors for true/false), and |
422 |
|
// we need to do a lot of special symmetry breaking, e.g. for ensuring |
423 |
|
// any constant constructors are not the 1st children of ITEs. |
424 |
126 |
if (CegInstantiator::isCbqiSort(sygus_type) >= CEG_HANDLED |
425 |
126 |
&& !sygus_type.isBoolean()) |
426 |
|
{ |
427 |
29 |
Trace("sygus-grammar-normalize") << "...add any constant constructor.\n"; |
428 |
58 |
TypeNode dtn = dt.getSygusType(); |
429 |
|
// we add this constructor first since we use left associative chains |
430 |
|
// and our symmetry breaking should group any constants together |
431 |
|
// beneath the same application |
432 |
|
// we set its weight to zero since it should be considered at the |
433 |
|
// same level as constants. |
434 |
29 |
to.d_sdt.addAnyConstantConstructor(dtn); |
435 |
|
} |
436 |
|
else |
437 |
|
{ |
438 |
|
// add default constant constructors |
439 |
26 |
std::vector<Node> ops; |
440 |
13 |
CegGrammarConstructor::mkSygusConstantsForType(sygus_type, ops); |
441 |
37 |
for (const Node& op : ops) |
442 |
|
{ |
443 |
48 |
std::stringstream ss; |
444 |
24 |
ss << op; |
445 |
48 |
std::vector<TypeNode> ctypes; |
446 |
24 |
to.d_sdt.addConstructor(op, ss.str(), ctypes); |
447 |
|
} |
448 |
|
} |
449 |
|
} |
450 |
|
|
451 |
|
/* Determine normalization transformation based on sygus type and given |
452 |
|
* operators */ |
453 |
930 |
std::unique_ptr<Transf> transformation = inferTransf(tn, dt, op_pos); |
454 |
|
/* If a transformation was selected, apply it */ |
455 |
465 |
if (transformation != nullptr) |
456 |
|
{ |
457 |
15 |
transformation->buildType(this, to, dt, op_pos); |
458 |
|
} |
459 |
|
|
460 |
|
// Remaining operators are rebuilt as they are. |
461 |
|
// Notice that we must extract the Datatype here to get the (Expr-layer) |
462 |
|
// sygus print callback. |
463 |
2677 |
for (unsigned i = 0, size = op_pos.size(); i < size; ++i) |
464 |
|
{ |
465 |
2212 |
unsigned oi = op_pos[i]; |
466 |
2212 |
Assert(oi < dt.getNumConstructors()); |
467 |
2212 |
to.addConsInfo(this, dt[oi]); |
468 |
|
} |
469 |
|
/* Build normalize datatype */ |
470 |
465 |
if (Trace.isOn("sygus-grammar-normalize")) |
471 |
|
{ |
472 |
|
Trace("sygus-grammar-normalize") << "\nFor positions "; |
473 |
|
for (unsigned i = 0, size = op_pos.size(); i < size; ++i) |
474 |
|
{ |
475 |
|
Trace("sygus-grammar-normalize") << op_pos[i] << " "; |
476 |
|
} |
477 |
|
Trace("sygus-grammar-normalize") << " and datatype " << dt << " \n"; |
478 |
|
} |
479 |
465 |
to.initializeDatatype(this, dt); |
480 |
465 |
return unres_tn; |
481 |
|
} |
482 |
|
|
483 |
2430 |
TypeNode SygusGrammarNorm::normalizeSygusRec(TypeNode tn) |
484 |
|
{ |
485 |
2430 |
if (!tn.isDatatype()) |
486 |
|
{ |
487 |
|
// Might not be a sygus datatype, e.g. if the input grammar had the |
488 |
|
// any constant constructor. |
489 |
|
return tn; |
490 |
|
} |
491 |
|
/* Collect all operators for normalization */ |
492 |
2430 |
const DType& dt = tn.getDType(); |
493 |
2430 |
if (!dt.isSygus()) |
494 |
|
{ |
495 |
|
// datatype but not sygus datatype case |
496 |
|
return tn; |
497 |
|
} |
498 |
4860 |
std::vector<unsigned> op_pos(dt.getNumConstructors()); |
499 |
2430 |
std::iota(op_pos.begin(), op_pos.end(), 0); |
500 |
2430 |
return normalizeSygusRec(tn, dt, op_pos); |
501 |
|
} |
502 |
|
|
503 |
205 |
TypeNode SygusGrammarNorm::normalizeSygusType(TypeNode tn, Node sygus_vars) |
504 |
|
{ |
505 |
|
/* Normalize all types in tn */ |
506 |
205 |
d_sygus_vars = sygus_vars; |
507 |
205 |
normalizeSygusRec(tn); |
508 |
|
/* Resolve created types */ |
509 |
205 |
Assert(!d_dt_all.empty() && !d_unres_t_all.empty()); |
510 |
205 |
if (Trace.isOn("sygus-grammar-normalize-build")) |
511 |
|
{ |
512 |
|
Trace("sygus-grammar-normalize-build") |
513 |
|
<< "making mutual datatyes with datatypes \n"; |
514 |
|
for (unsigned i = 0, size = d_dt_all.size(); i < size; ++i) |
515 |
|
{ |
516 |
|
Trace("sygus-grammar-normalize-build") << d_dt_all[i]; |
517 |
|
} |
518 |
|
Trace("sygus-grammar-normalize-build") << " and unresolved types\n"; |
519 |
|
for (const TypeNode& unres_t : d_unres_t_all) |
520 |
|
{ |
521 |
|
Trace("sygus-grammar-normalize-build") << unres_t << " "; |
522 |
|
} |
523 |
|
Trace("sygus-grammar-normalize-build") << "\n"; |
524 |
|
} |
525 |
205 |
Assert(d_dt_all.size() == d_unres_t_all.size()); |
526 |
|
std::vector<TypeNode> types = NodeManager::currentNM()->mkMutualDatatypeTypes( |
527 |
410 |
d_dt_all, d_unres_t_all, NodeManager::DATATYPE_FLAG_PLACEHOLDER); |
528 |
205 |
Assert(types.size() == d_dt_all.size()); |
529 |
|
/* Clear accumulators */ |
530 |
205 |
d_dt_all.clear(); |
531 |
205 |
d_unres_t_all.clear(); |
532 |
|
/* By construction the normalized type node will be the last one considered */ |
533 |
410 |
return types.back(); |
534 |
|
} |
535 |
|
|
536 |
|
} // namespace quantifiers |
537 |
|
} // namespace theory |
538 |
29505 |
} // namespace cvc5 |