GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/sygus_grammar_cons.cpp Lines: 798 909 87.8 %
Date: 2021-11-07 Branches: 1470 3488 42.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Haniel Barbosa, Aina Niemetz
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 constructing inductive datatypes that
14
 * correspond to grammars that encode syntactic restrictions for SyGuS.
15
 */
16
#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
17
18
#include <sstream>
19
#include <stack>
20
21
#include "expr/ascription_type.h"
22
#include "expr/dtype_cons.h"
23
#include "expr/node_algorithm.h"
24
#include "options/base_options.h"
25
#include "options/quantifiers_options.h"
26
#include "theory/bv/theory_bv_utils.h"
27
#include "theory/datatypes/sygus_datatype_utils.h"
28
#include "theory/quantifiers/sygus/sygus_grammar_norm.h"
29
#include "theory/quantifiers/sygus/sygus_process_conj.h"
30
#include "theory/quantifiers/sygus/sygus_utils.h"
31
#include "theory/quantifiers/sygus/synth_conjecture.h"
32
#include "theory/quantifiers/sygus/term_database_sygus.h"
33
#include "theory/quantifiers/term_util.h"
34
#include "theory/rewriter.h"
35
#include "theory/strings/word.h"
36
#include "util/floatingpoint.h"
37
#include "util/string.h"
38
#include "printer/smt2/smt2_printer.h"
39
40
using namespace cvc5::kind;
41
42
namespace cvc5 {
43
namespace theory {
44
namespace quantifiers {
45
46
1900
CegGrammarConstructor::CegGrammarConstructor(Env& env,
47
                                             TermDbSygus* tds,
48
1900
                                             SynthConjecture* p)
49
1900
    : EnvObj(env), d_tds(tds), d_parent(p), d_is_syntax_restricted(false)
50
{
51
1900
}
52
53
121
bool CegGrammarConstructor::hasSyntaxRestrictions(Node q)
54
{
55
121
  Assert(q.getKind() == FORALL);
56
177
  for (const Node& f : q[0])
57
  {
58
177
    TypeNode tn = SygusUtils::getSygusTypeForSynthFun(f);
59
121
    if (tn.isDatatype() && tn.getDType().isSygus())
60
    {
61
65
      return true;
62
    }
63
  }
64
56
  return false;
65
}
66
67
540
void CegGrammarConstructor::collectTerms(
68
    Node n, std::map<TypeNode, std::unordered_set<Node>>& consts)
69
{
70
540
  NodeManager * nm = NodeManager::currentNM();
71
1080
  std::unordered_map<TNode, bool> visited;
72
540
  std::unordered_map<TNode, bool>::iterator it;
73
1080
  std::stack<TNode> visit;
74
1080
  TNode cur;
75
540
  visit.push(n);
76
31097
  do {
77
31637
    cur = visit.top();
78
31637
    visit.pop();
79
31637
    it = visited.find(cur);
80
31637
    if (it == visited.end()) {
81
18082
      visited[cur] = true;
82
      // is this a constant?
83
18082
      if( cur.isConst() ){
84
5948
        TypeNode tn = cur.getType();
85
5948
        Node c = cur;
86
2974
        if( tn.isReal() ){
87
1119
          c = nm->mkConst( c.getConst<Rational>().abs() );
88
        }
89
2974
        consts[tn].insert(c);
90
2974
        if (tn.isInteger())
91
        {
92
2198
          TypeNode rtype = nm->realType();
93
1099
          consts[rtype].insert(c);
94
        }
95
      }
96
      // recurse
97
49179
      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
98
31097
        visit.push(cur[i]);
99
      }
100
    }
101
31637
  } while (!visit.empty());
102
540
}
103
104
542
Node CegGrammarConstructor::process(Node q,
105
                                    const std::map<Node, Node>& templates,
106
                                    const std::map<Node, Node>& templates_arg)
107
{
108
  // convert to deep embedding and finalize single invocation here
109
  // now, construct the grammar
110
1084
  Trace("cegqi") << "SynthConjecture : convert to deep embedding..."
111
542
                 << std::endl;
112
1084
  std::map<TypeNode, std::unordered_set<Node>> extra_cons;
113
542
  if( options::sygusAddConstGrammar() ){
114
540
    Trace("cegqi") << "SynthConjecture : collect constants..." << std::endl;
115
540
    collectTerms( q[1], extra_cons );
116
  }
117
1084
  std::map<TypeNode, std::unordered_set<Node>> exc_cons;
118
1084
  std::map<TypeNode, std::unordered_set<Node>> inc_cons;
119
120
542
  NodeManager* nm = NodeManager::currentNM();
121
122
1084
  std::vector< Node > ebvl;
123
1464
  for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
124
1844
    Node sf = q[0][i];
125
    // if non-null, v encodes the syntactic restrictions (via an inductive
126
    // datatype) on sf from the input.
127
1844
    Node v = sf.getAttribute(SygusSynthGrammarAttribute());
128
1844
    TypeNode preGrammarType;
129
922
    if (!v.isNull())
130
    {
131
339
      preGrammarType = v.getType();
132
    }
133
    else
134
    {
135
      // otherwise, the grammar is the default for the range of the function
136
583
      preGrammarType = sf.getType();
137
583
      if (preGrammarType.isFunction())
138
      {
139
452
        preGrammarType = preGrammarType.getRangeType();
140
      }
141
    }
142
143
    // the actual sygus datatype we will use (normalized below)
144
1844
    TypeNode tn;
145
1844
    std::stringstream ss;
146
922
    ss << sf;
147
1844
    Node sfvl;
148
922
    if (preGrammarType.isDatatype() && preGrammarType.getDType().isSygus())
149
    {
150
339
      sfvl = preGrammarType.getDType().getSygusVarList();
151
339
      tn = preGrammarType;
152
      // normalize type, if user-provided
153
678
      SygusGrammarNorm sygus_norm(d_tds);
154
339
      tn = sygus_norm.normalizeSygusType(tn, sfvl);
155
    }else{
156
583
      sfvl = SygusUtils::getSygusArgumentListForSynthFun(sf);
157
      // check which arguments are irrelevant
158
1166
      std::unordered_set<unsigned> arg_irrelevant;
159
583
      d_parent->getProcess()->getIrrelevantArgs(sf, arg_irrelevant);
160
1166
      std::unordered_set<Node> term_irlv;
161
      // convert to term
162
651
      for (const unsigned& arg : arg_irrelevant)
163
      {
164
68
        Assert(arg < sfvl.getNumChildren());
165
68
        term_irlv.insert(sfvl[arg]);
166
      }
167
168
      // make the default grammar
169
583
      tn = mkSygusDefaultType(preGrammarType,
170
                              sfvl,
171
1166
                              ss.str(),
172
                              extra_cons,
173
                              exc_cons,
174
                              inc_cons,
175
                              term_irlv);
176
      // print the grammar
177
583
      if (isOutputOn(OutputTag::SYGUS_GRAMMAR))
178
      {
179
2
        output(OutputTag::SYGUS_GRAMMAR)
180
4
            << "(sygus-grammar " << ss.str()
181
6
            << printer::smt2::Smt2Printer::sygusGrammarString(tn) << ")"
182
2
            << std::endl;
183
      }
184
    }
185
    // sfvl may be null for constant synthesis functions
186
1844
    Trace("cegqi-debug") << "...sygus var list associated with " << sf << " is "
187
922
                         << sfvl << std::endl;
188
189
922
    std::map<Node, Node>::const_iterator itt = templates.find(sf);
190
922
    if( itt!=templates.end() ){
191
92
      Node templ = itt->second;
192
46
      std::map<Node, Node>::const_iterator itta = templates_arg.find(sf);
193
46
      Assert(itta != templates_arg.end());
194
92
      TNode templ_arg = itta->second;
195
46
      Assert(!templ_arg.isNull());
196
      // if there is a template for this argument, make a sygus type on top of it
197
46
      if( options::sygusTemplEmbedGrammar() ){
198
        Trace("cegqi-debug") << "Template for " << sf << " is : " << templ
199
                             << " with arg " << templ_arg << std::endl;
200
        Trace("cegqi-debug") << "  embed this template as a grammar..." << std::endl;
201
        tn = mkSygusTemplateType( templ, templ_arg, tn, sfvl, ss.str() );
202
      }
203
    }
204
205
    // ev is the first-order variable corresponding to this synth fun
206
1844
    std::stringstream ssf;
207
922
    ssf << "f" << sf;
208
1844
    Node ev = nm->mkBoundVar(ssf.str(), tn);
209
922
    ebvl.push_back(ev);
210
1844
    Trace("cegqi") << "...embedding synth fun : " << sf << " -> " << ev
211
922
                   << std::endl;
212
  }
213
1084
  return process(q, templates, templates_arg, ebvl);
214
}
215
216
542
Node CegGrammarConstructor::process(Node q,
217
                                    const std::map<Node, Node>& templates,
218
                                    const std::map<Node, Node>& templates_arg,
219
                                    const std::vector<Node>& ebvl)
220
{
221
542
  Assert(q[0].getNumChildren() == ebvl.size());
222
542
  Assert(d_synth_fun_vars.empty());
223
224
542
  NodeManager* nm = NodeManager::currentNM();
225
226
1084
  std::vector<Node> qchildren;
227
1084
  Node qbody_subs = q[1];
228
1464
  for (unsigned i = 0, size = q[0].getNumChildren(); i < size; i++)
229
  {
230
1844
    Node sf = q[0][i];
231
922
    d_synth_fun_vars[sf] = ebvl[i];
232
1844
    Node sfvl = SygusUtils::getSygusArgumentListForSynthFun(sf);
233
1844
    TypeNode tn = ebvl[i].getType();
234
    // check if there is a template
235
922
    std::map<Node, Node>::const_iterator itt = templates.find(sf);
236
922
    if (itt != templates.end())
237
    {
238
92
      Node templ = itt->second;
239
46
      std::map<Node, Node>::const_iterator itta = templates_arg.find(sf);
240
46
      Assert(itta != templates_arg.end());
241
92
      TNode templ_arg = itta->second;
242
46
      Assert(!templ_arg.isNull());
243
      // if there is a template for this argument, make a sygus type on top of
244
      // it
245
46
      if (!options().quantifiers.sygusTemplEmbedGrammar)
246
      {
247
        // otherwise, apply it as a preprocessing pass
248
92
        Trace("cegqi-debug") << "Template for " << sf << " is : " << templ
249
46
                             << " with arg " << templ_arg << std::endl;
250
46
        Trace("cegqi-debug") << "  apply this template as a substituion during preprocess..." << std::endl;
251
92
        std::vector< Node > schildren;
252
92
        std::vector< Node > largs;
253
320
        for( unsigned j=0; j<sfvl.getNumChildren(); j++ ){
254
274
          schildren.push_back( sfvl[j] );
255
274
          largs.push_back(nm->mkBoundVar(sfvl[j].getType()));
256
        }
257
92
        std::vector< Node > subsfn_children;
258
46
        subsfn_children.push_back( sf );
259
46
        subsfn_children.insert( subsfn_children.end(), schildren.begin(), schildren.end() );
260
92
        Node subsfn = nm->mkNode(kind::APPLY_UF, subsfn_children);
261
92
        TNode subsf = subsfn;
262
46
        Trace("cegqi-debug") << "  substitute arg : " << templ_arg << " -> " << subsf << std::endl;
263
46
        templ = templ.substitute( templ_arg, subsf );
264
        // substitute lambda arguments
265
46
        templ = templ.substitute( schildren.begin(), schildren.end(), largs.begin(), largs.end() );
266
        Node subsn =
267
92
            nm->mkNode(kind::LAMBDA, nm->mkNode(BOUND_VAR_LIST, largs), templ);
268
92
        TNode var = sf;
269
92
        TNode subs = subsn;
270
46
        Trace("cegqi-debug") << "  substitute : " << var << " -> " << subs << std::endl;
271
46
        qbody_subs = qbody_subs.substitute( var, subs );
272
46
        Trace("cegqi-debug") << "  body is now : " << qbody_subs << std::endl;
273
      }
274
    }
275
922
    d_tds->registerSygusType(tn);
276
922
    Assert(tn.isDatatype());
277
922
    const DType& dt = tn.getDType();
278
922
    Assert(dt.isSygus());
279
922
    if( !dt.getSygusAllowAll() ){
280
330
      d_is_syntax_restricted = true;
281
    }
282
  }
283
542
  qchildren.push_back(nm->mkNode(kind::BOUND_VAR_LIST, ebvl));
284
542
  if( qbody_subs!=q[1] ){
285
46
    Trace("cegqi") << "...rewriting : " << qbody_subs << std::endl;
286
46
    qbody_subs = rewrite(qbody_subs);
287
46
    Trace("cegqi") << "...got : " << qbody_subs << std::endl;
288
  }
289
542
  qchildren.push_back(convertToEmbedding(qbody_subs));
290
542
  if( q.getNumChildren()==3 ){
291
542
    qchildren.push_back( q[2] );
292
  }
293
1084
  return nm->mkNode(kind::FORALL, qchildren);
294
}
295
296
584
Node CegGrammarConstructor::convertToEmbedding(Node n)
297
{
298
584
  NodeManager* nm = NodeManager::currentNM();
299
1168
  std::unordered_map<TNode, Node> visited;
300
584
  std::unordered_map<TNode, Node>::iterator it;
301
1168
  std::stack<TNode> visit;
302
1168
  TNode cur;
303
584
  visit.push(n);
304
51975
  do {
305
52559
    cur = visit.top();
306
52559
    visit.pop();
307
52559
    it = visited.find(cur);
308
52559
    if (it == visited.end()) {
309
19083
      visited[cur] = Node::null();
310
19083
      visit.push(cur);
311
51975
      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
312
32892
        visit.push(cur[i]);
313
      }
314
33476
    } else if (it->second.isNull()) {
315
38166
      Node ret = cur;
316
19083
      Kind ret_k = cur.getKind();
317
38166
      Node op;
318
19083
      bool childChanged = false;
319
38166
      std::vector<Node> children;
320
      // get the potential operator
321
19083
      if( cur.getNumChildren()>0 ){
322
14589
        if( cur.getKind()==kind::APPLY_UF ){
323
1642
          op = cur.getOperator();
324
        }
325
      }else{
326
4494
        op = cur;
327
      }
328
      // is the operator a synth function?
329
19083
      bool makeEvalFun = false;
330
19083
      if( !op.isNull() ){
331
6136
        std::map<Node, Node>::iterator its = d_synth_fun_vars.find(op);
332
6136
        if (its != d_synth_fun_vars.end())
333
        {
334
1723
          children.push_back( its->second );
335
1723
          makeEvalFun = true;
336
        }
337
      }
338
19083
      if (!makeEvalFun)
339
      {
340
        // otherwise, we apply the previous operator
341
17360
        if( cur.getMetaKind() == kind::metakind::PARAMETERIZED ){
342
466
          children.push_back( cur.getOperator() );
343
        }
344
      }
345
51975
      for (unsigned i = 0; i < cur.getNumChildren(); i++) {
346
32892
        it = visited.find(cur[i]);
347
32892
        Assert(it != visited.end());
348
32892
        Assert(!it->second.isNull());
349
32892
        childChanged = childChanged || cur[i] != it->second;
350
32892
        children.push_back(it->second);
351
      }
352
19083
      if (makeEvalFun)
353
      {
354
1723
        if (!cur.getType().isFunction())
355
        {
356
          // will make into an application of an evaluation function
357
1706
          ret = nm->mkNode(DT_SYGUS_EVAL, children);
358
        }
359
        else
360
        {
361
17
          Assert(children.size() == 1);
362
34
          Node ef = children[0];
363
          // Otherwise, we are using the function-to-synthesize itself in a
364
          // higher-order setting. We must return the lambda term:
365
          //   lambda x1...xn. (DT_SYGUS_EVAL ef x1 ... xn)
366
          // where ef is the first order variable for the
367
          // function-to-synthesize.
368
17
          SygusTypeInfo& ti = d_tds->getTypeInfo(ef.getType());
369
17
          const std::vector<Node>& vars = ti.getVarList();
370
17
          Assert(!vars.empty());
371
34
          std::vector<Node> vs;
372
40
          for (const Node& v : vars)
373
          {
374
23
            vs.push_back(nm->mkBoundVar(v.getType()));
375
          }
376
34
          Node lvl = nm->mkNode(BOUND_VAR_LIST, vs);
377
34
          std::vector<Node> eargs;
378
17
          eargs.push_back(ef);
379
17
          eargs.insert(eargs.end(), vs.begin(), vs.end());
380
17
          ret = nm->mkNode(LAMBDA, lvl, nm->mkNode(DT_SYGUS_EVAL, eargs));
381
        }
382
      }
383
17360
      else if (childChanged)
384
      {
385
7257
        ret = nm->mkNode(ret_k, children);
386
      }
387
19083
      visited[cur] = ret;
388
    }
389
52559
  } while (!visit.empty());
390
584
  Assert(visited.find(n) != visited.end());
391
584
  Assert(!visited.find(n)->second.isNull());
392
1168
  return visited[n];
393
}
394
395
1543
TypeNode CegGrammarConstructor::mkUnresolvedType(const std::string& name,
396
                                                 std::set<TypeNode>& unres)
397
{
398
  TypeNode unresolved = NodeManager::currentNM()->mkSort(
399
1543
      name, NodeManager::SORT_FLAG_PLACEHOLDER);
400
1543
  unres.insert(unresolved);
401
1543
  return unresolved;
402
}
403
404
1499
void CegGrammarConstructor::mkSygusConstantsForType(TypeNode type,
405
                                                    std::vector<Node>& ops)
406
{
407
1499
  NodeManager* nm = NodeManager::currentNM();
408
1499
  if (type.isReal())
409
  {
410
609
    ops.push_back(nm->mkConst(Rational(0)));
411
609
    ops.push_back(nm->mkConst(Rational(1)));
412
  }
413
890
  else if (type.isBitVector())
414
  {
415
41
    unsigned size = type.getBitVectorSize();
416
41
    ops.push_back(bv::utils::mkZero(size));
417
41
    ops.push_back(bv::utils::mkOne(size));
418
  }
419
849
  else if (type.isBoolean())
420
  {
421
737
    ops.push_back(nm->mkConst(true));
422
737
    ops.push_back(nm->mkConst(false));
423
  }
424
112
  else if (type.isStringLike())
425
  {
426
33
    ops.push_back(strings::Word::mkEmptyWord(type));
427
33
    if (type.isString())  // string-only
428
    {
429
      // Dummy character "A". This is not necessary for sequences which
430
      // have the generic constructor seq.unit.
431
33
      ops.push_back(nm->mkConst(String("A")));
432
    }
433
  }
434
79
  else if (type.isArray() || type.isSet())
435
  {
436
    // generate constant array over the first element of the constituent type
437
56
    Node c = type.mkGroundTerm();
438
    // note that c should never contain an uninterpreted constant
439
28
    Assert(!expr::hasSubtermKind(UNINTERPRETED_CONSTANT, c));
440
28
    ops.push_back(c);
441
  }
442
51
  else if (type.isRoundingMode())
443
  {
444
    ops.push_back(nm->mkConst(RoundingMode::ROUND_NEAREST_TIES_TO_AWAY));
445
    ops.push_back(nm->mkConst(RoundingMode::ROUND_NEAREST_TIES_TO_EVEN));
446
    ops.push_back(nm->mkConst(RoundingMode::ROUND_TOWARD_NEGATIVE));
447
    ops.push_back(nm->mkConst(RoundingMode::ROUND_TOWARD_POSITIVE));
448
    ops.push_back(nm->mkConst(RoundingMode::ROUND_TOWARD_ZERO));
449
  }
450
51
  else if (type.isFloatingPoint())
451
  {
452
    FloatingPointSize fp_size(type.getFloatingPointExponentSize(),
453
                              type.getFloatingPointSignificandSize());
454
    ops.push_back(nm->mkConst(FloatingPoint::makeNaN(fp_size)));
455
    ops.push_back(nm->mkConst(FloatingPoint::makeInf(fp_size, true)));
456
    ops.push_back(nm->mkConst(FloatingPoint::makeInf(fp_size, false)));
457
    ops.push_back(nm->mkConst(FloatingPoint::makeZero(fp_size, true)));
458
    ops.push_back(nm->mkConst(FloatingPoint::makeZero(fp_size, false)));
459
    ops.push_back(nm->mkConst(FloatingPoint::makeMinSubnormal(fp_size, true)));
460
    ops.push_back(nm->mkConst(FloatingPoint::makeMinSubnormal(fp_size, false)));
461
    ops.push_back(nm->mkConst(FloatingPoint::makeMaxSubnormal(fp_size, true)));
462
    ops.push_back(nm->mkConst(FloatingPoint::makeMaxSubnormal(fp_size, false)));
463
    ops.push_back(nm->mkConst(FloatingPoint::makeMinNormal(fp_size, true)));
464
    ops.push_back(nm->mkConst(FloatingPoint::makeMinNormal(fp_size, false)));
465
    ops.push_back(nm->mkConst(FloatingPoint::makeMaxNormal(fp_size, true)));
466
    ops.push_back(nm->mkConst(FloatingPoint::makeMaxNormal(fp_size, false)));
467
  }
468
1499
}
469
470
2494
void CegGrammarConstructor::collectSygusGrammarTypesFor(
471
    TypeNode range, std::vector<TypeNode>& types)
472
{
473
2494
  if( !range.isBoolean() ){
474
2057
    if( std::find( types.begin(), types.end(), range )==types.end() ){
475
911
      Trace("sygus-grammar-def") << "...will make grammar for " << range << std::endl;
476
911
      types.push_back( range );
477
911
      if( range.isDatatype() ){
478
43
        const DType& dt = range.getDType();
479
96
        for (unsigned i = 0, size = dt.getNumConstructors(); i < size; ++i)
480
        {
481
          // get the specialized constructor type, which accounts for
482
          // parametric datatypes
483
106
          TypeNode ctn = dt[i].getSpecializedConstructorType(range);
484
106
          std::vector<TypeNode> argTypes = ctn.getArgTypes();
485
139
          for (size_t j = 0, nargs = argTypes.size(); j < nargs; ++j)
486
          {
487
86
            collectSygusGrammarTypesFor(argTypes[j], types);
488
          }
489
        }
490
      }
491
868
      else if (range.isArray())
492
      {
493
        // add index and constituent type
494
24
        collectSygusGrammarTypesFor(range.getArrayIndexType(), types);
495
24
        collectSygusGrammarTypesFor(range.getArrayConstituentType(), types);
496
      }
497
844
      else if (range.isSet())
498
      {
499
12
        collectSygusGrammarTypesFor(range.getSetElementType(), types);
500
      }
501
832
      else if (range.isStringLike())
502
      {
503
        // theory of strings shares the integer type
504
94
        TypeNode intType = NodeManager::currentNM()->integerType();
505
47
        collectSygusGrammarTypesFor(intType,types);
506
47
        if (range.isSequence())
507
        {
508
          collectSygusGrammarTypesFor(range.getSequenceElementType(), types);
509
        }
510
      }
511
785
      else if (range.isFunction())
512
      {
513
60
        std::vector<TypeNode> atypes = range.getArgTypes();
514
64
        for (unsigned i = 0, ntypes = atypes.size(); i < ntypes; i++)
515
        {
516
34
          collectSygusGrammarTypesFor(atypes[i], types);
517
        }
518
30
        collectSygusGrammarTypesFor(range.getRangeType(), types);
519
      }
520
755
      else if (range.isFloatingPoint())
521
      {
522
        // FP also includes RoundingMode type
523
        TypeNode rmType = NodeManager::currentNM()->roundingModeType();
524
        collectSygusGrammarTypesFor(rmType, types);
525
      }
526
    }
527
  }
528
2494
}
529
530
127
bool CegGrammarConstructor::isHandledType(TypeNode t)
531
{
532
254
  std::vector<TypeNode> types;
533
127
  collectSygusGrammarTypesFor(t, types);
534
276
  for (const TypeNode& tn : types)
535
  {
536
151
    if (tn.isSort() || tn.isFloatingPoint())
537
    {
538
2
      return false;
539
    }
540
  }
541
125
  return true;
542
}
543
544
8
Node CegGrammarConstructor::createLambdaWithZeroArg(
545
    Kind k, TypeNode bArgType)
546
{
547
8
  NodeManager* nm = NodeManager::currentNM();
548
16
  std::vector<Node> opLArgs;
549
  // get the builtin type
550
8
  opLArgs.push_back(nm->mkBoundVar(bArgType));
551
  // build zarg
552
16
  Node zarg;
553
8
  Assert(bArgType.isReal() || bArgType.isBitVector());
554
8
  if (bArgType.isReal())
555
  {
556
8
    zarg = nm->mkConst(Rational(0));
557
  }
558
  else
559
  {
560
    unsigned size = bArgType.getBitVectorSize();
561
    zarg = bv::utils::mkZero(size);
562
  }
563
16
  Node body = nm->mkNode(k, zarg, opLArgs.back());
564
  // create operator
565
8
  Node op = nm->mkNode(LAMBDA, nm->mkNode(BOUND_VAR_LIST, opLArgs), body);
566
8
  Trace("sygus-grammar-def") << "\t...building lambda op " << op << "\n";
567
16
  return op;
568
}
569
570
724
void CegGrammarConstructor::mkSygusDefaultGrammar(
571
    TypeNode range,
572
    Node bvl,
573
    const std::string& fun,
574
    std::map<TypeNode, std::unordered_set<Node>>& extra_cons,
575
    std::map<TypeNode, std::unordered_set<Node>>& exclude_cons,
576
    const std::map<TypeNode, std::unordered_set<Node>>& include_cons,
577
    std::unordered_set<Node>& term_irrelevant,
578
    std::vector<SygusDatatypeGenerator>& sdts,
579
    std::set<TypeNode>& unres)
580
{
581
724
  NodeManager* nm = NodeManager::currentNM();
582
1448
  Trace("sygus-grammar-def") << "Construct default grammar for " << fun << " "
583
724
                             << range << std::endl;
584
  // collect the variables
585
1448
  std::vector<Node> sygus_vars;
586
724
  if (!bvl.isNull())
587
  {
588
1915
    for (unsigned i = 0, size = bvl.getNumChildren(); i < size; ++i)
589
    {
590
1454
      if (term_irrelevant.find(bvl[i]) == term_irrelevant.end())
591
      {
592
1386
        sygus_vars.push_back(bvl[i]);
593
      }
594
      else
595
      {
596
136
        Trace("sygus-grammar-def")
597
136
            << "...synth var " << bvl[i] << " has been marked irrelevant."
598
68
            << std::endl;
599
      }
600
    }
601
  }
602
  // index of top datatype, i.e. the datatype for the range type
603
724
  int startIndex = -1;
604
1448
  std::map<TypeNode, TypeNode> sygus_to_builtin;
605
606
1448
  std::vector<TypeNode> types;
607
  // Collect connected types for each of the variables.
608
2110
  for (unsigned i = 0, size = sygus_vars.size(); i < size; ++i)
609
  {
610
2772
    TypeNode tni = sygus_vars[i].getType();
611
1386
    collectSygusGrammarTypesFor(tni, types);
612
  }
613
  // collect connected types to range
614
724
  collectSygusGrammarTypesFor(range, types);
615
616
  // create placeholder for boolean type (kept apart since not collected)
617
618
  // create placeholders for collected types
619
1448
  std::vector<TypeNode> unres_types;
620
1448
  std::map<TypeNode, TypeNode> type_to_unres;
621
724
  std::map<TypeNode, std::unordered_set<Node>>::const_iterator itc;
622
  // maps types to the index of its "any term" grammar construction
623
1448
  std::map<TypeNode, std::pair<unsigned, bool>> typeToGAnyTerm;
624
724
  options::SygusGrammarConsMode sgcm = options::sygusGrammarConsMode();
625
1484
  for (unsigned i = 0, size = types.size(); i < size; ++i)
626
  {
627
1520
    std::stringstream ss;
628
760
    ss << fun << "_" << types[i];
629
1520
    std::string dname = ss.str();
630
760
    sdts.push_back(SygusDatatypeGenerator(dname));
631
760
    itc = exclude_cons.find(types[i]);
632
760
    if (itc != exclude_cons.end())
633
    {
634
      sdts.back().d_exclude_cons = itc->second;
635
    }
636
760
    itc = include_cons.find(types[i]);
637
760
    if (itc != include_cons.end())
638
    {
639
3
      sdts.back().d_include_cons = itc->second;
640
    }
641
    //make unresolved type
642
1520
    TypeNode unres_t = mkUnresolvedType(dname, unres);
643
760
    unres_types.push_back(unres_t);
644
760
    type_to_unres[types[i]] = unres_t;
645
760
    sygus_to_builtin[unres_t] = types[i];
646
  }
647
  // make Boolean type
648
1448
  std::stringstream ssb;
649
724
  ssb << fun << "_Bool";
650
1448
  std::string dbname = ssb.str();
651
724
  sdts.push_back(SygusDatatypeGenerator(dbname));
652
724
  unsigned boolIndex = types.size();
653
1448
  TypeNode bool_type = nm->booleanType();
654
1448
  TypeNode unres_bt = mkUnresolvedType(ssb.str(), unres);
655
724
  types.push_back(bool_type);
656
724
  unres_types.push_back(unres_bt);
657
724
  type_to_unres[bool_type] = unres_bt;
658
724
  sygus_to_builtin[unres_bt] = bool_type;
659
660
  // We ensure an ordering on types such that parametric types are processed
661
  // before their consitituents. Since parametric types were added before their
662
  // arguments in collectSygusGrammarTypesFor above, we will construct the
663
  // sygus grammars by iterating on types in reverse order. This ensures
664
  // that we know all constructors coming from other types (e.g. select(A,i))
665
  // by the time we process the type. We start with types.size()-2, since
666
  // we construct the grammar for the Boolean type last.
667
1484
  for (int i = (types.size() - 2); i >= 0; --i)
668
  {
669
1520
    Trace("sygus-grammar-def") << "Make grammar for " << types[i] << " "
670
760
                               << unres_types[i] << std::endl;
671
1520
    TypeNode unres_t = unres_types[i];
672
760
    options::SygusGrammarConsMode tsgcm = sgcm;
673
760
    if (tsgcm == options::SygusGrammarConsMode::ANY_TERM
674
752
        || tsgcm == options::SygusGrammarConsMode::ANY_TERM_CONCISE)
675
    {
676
      // If the type does not support any term, we do any constant instead.
677
      // We also fall back on any constant construction if the type has no
678
      // constructors at this point (e.g. it simply encodes all constants).
679
12
      if (!types[i].isReal())
680
      {
681
4
        tsgcm = options::SygusGrammarConsMode::ANY_CONST;
682
      }
683
      else
684
      {
685
        // Add a placeholder for the "any term" version of this datatype, to be
686
        // constructed later.
687
16
        std::stringstream ssat;
688
8
        ssat << sdts[i].d_sdt.getName() << "_any_term";
689
8
        sdts.push_back(SygusDatatypeGenerator(ssat.str()));
690
16
        TypeNode unresAnyTerm = mkUnresolvedType(ssat.str(), unres);
691
8
        unres_types.push_back(unresAnyTerm);
692
        // set tracking information for later addition at boolean type.
693
8
        std::pair<unsigned, bool> p(sdts.size() - 1, false);
694
8
        typeToGAnyTerm[types[i]] = p;
695
      }
696
    }
697
1520
    Trace("sygus-grammar-def")
698
760
        << "Grammar constructor mode for this type is " << tsgcm << std::endl;
699
    //add variables
700
2432
    for (const Node& sv : sygus_vars)
701
    {
702
3344
      TypeNode svt = sv.getType();
703
1672
      if (svt == types[i])
704
      {
705
2328
        std::stringstream ss;
706
1164
        ss << sv;
707
2328
        Trace("sygus-grammar-def")
708
1164
            << "...add for variable " << ss.str() << std::endl;
709
2328
        std::vector<TypeNode> cargsEmpty;
710
1164
        sdts[i].addConstructor(sv, ss.str(), cargsEmpty);
711
      }
712
508
      else if (svt.isFunction() && svt.getRangeType() == types[i])
713
      {
714
        // We add an APPLY_UF for all function whose return type is this type
715
        // whose argument types are the other sygus types we are constructing.
716
12
        std::vector<TypeNode> argTypes = svt.getArgTypes();
717
12
        std::vector<TypeNode> stypes;
718
12
        for (unsigned k = 0, ntypes = argTypes.size(); k < ntypes; k++)
719
        {
720
          unsigned index =
721
6
              std::distance(types.begin(),
722
12
                            std::find(types.begin(), types.end(), argTypes[k]));
723
6
          stypes.push_back(unres_types[index]);
724
        }
725
12
        std::stringstream ss;
726
6
        ss << "apply_" << sv;
727
6
        sdts[i].addConstructor(sv, ss.str(), stypes);
728
      }
729
    }
730
    //add constants
731
1520
    std::vector<Node> consts;
732
760
    mkSygusConstantsForType(types[i], consts);
733
760
    if (tsgcm == options::SygusGrammarConsMode::ANY_CONST)
734
    {
735
      // Use the any constant constructor. Notice that for types that don't
736
      // have constants (e.g. uninterpreted or function types), we don't add
737
      // this constructor.
738
10
      if (!consts.empty())
739
      {
740
10
        sdts[i].d_sdt.addAnyConstantConstructor(types[i]);
741
      }
742
    }
743
    else
744
    {
745
      std::map<TypeNode, std::unordered_set<Node>>::iterator itec =
746
750
          extra_cons.find(types[i]);
747
750
      if (itec != extra_cons.end())
748
      {
749
2348
        for (std::unordered_set<Node>::iterator set_it = itec->second.begin();
750
2348
             set_it != itec->second.end();
751
             ++set_it)
752
        {
753
1755
          if (std::find(consts.begin(), consts.end(), *set_it) == consts.end())
754
          {
755
781
            consts.push_back(*set_it);
756
          }
757
        }
758
      }
759
2903
      for (unsigned j = 0, size_j = consts.size(); j < size_j; ++j)
760
      {
761
4306
        std::stringstream ss;
762
2153
        ss << consts[j];
763
4306
        Trace("sygus-grammar-def")
764
2153
            << "...add for constant " << ss.str() << std::endl;
765
4306
        std::vector<TypeNode> cargsEmpty;
766
2153
        sdts[i].addConstructor(consts[j], ss.str(), cargsEmpty);
767
      }
768
    }
769
770
760
    if (types[i].isReal())
771
    {
772
      // Add PLUS, MINUS
773
609
      Kind kinds[2] = {PLUS, MINUS};
774
1827
      for (const Kind kind : kinds)
775
      {
776
1218
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
777
2436
        std::vector<TypeNode> cargsOp;
778
1218
        cargsOp.push_back(unres_t);
779
1218
        cargsOp.push_back(unres_t);
780
1218
        sdts[i].addConstructor(kind, cargsOp);
781
      }
782
609
      if (!types[i].isInteger())
783
      {
784
86
        Trace("sygus-grammar-def")
785
43
            << "  ...create auxiliary Positive Integers grammar\n";
786
        // Creating type for positive integers. Notice we can't use the any
787
        // constant constructor here, since it admits zero.
788
86
        std::stringstream ss;
789
43
        ss << fun << "_PosInt";
790
86
        std::string pos_int_name = ss.str();
791
        // make unresolved type
792
86
        TypeNode unresPosInt = mkUnresolvedType(pos_int_name, unres);
793
43
        unres_types.push_back(unresPosInt);
794
        // make data type for positive constant integers
795
43
        sdts.push_back(SygusDatatypeGenerator(pos_int_name));
796
        /* Add operator 1 */
797
43
        Trace("sygus-grammar-def") << "\t...add for 1 to Pos_Int\n";
798
86
        std::vector<TypeNode> cargsEmpty;
799
43
        sdts.back().addConstructor(nm->mkConst(Rational(1)), "1", cargsEmpty);
800
        /* Add operator PLUS */
801
43
        Kind kind = PLUS;
802
43
        Trace("sygus-grammar-def") << "\t...add for PLUS to Pos_Int\n";
803
86
        std::vector<TypeNode> cargsPlus;
804
43
        cargsPlus.push_back(unresPosInt);
805
43
        cargsPlus.push_back(unresPosInt);
806
43
        sdts.back().addConstructor(kind, cargsPlus);
807
43
        sdts.back().d_sdt.initializeDatatype(types[i], bvl, true, true);
808
86
        Trace("sygus-grammar-def")
809
43
            << "  ...built datatype " << sdts.back().d_sdt.getDatatype() << " ";
810
        /* Adding division at root */
811
43
        kind = DIVISION;
812
43
        Trace("sygus-grammar-def") << "\t...add for " << kind << std::endl;
813
86
        std::vector<TypeNode> cargsDiv;
814
43
        cargsDiv.push_back(unres_t);
815
43
        cargsDiv.push_back(unresPosInt);
816
43
        sdts[i].addConstructor(kind, cargsDiv);
817
      }
818
    }
819
151
    else if (types[i].isBitVector())
820
    {
821
      // unary ops
822
82
      std::vector<Kind> un_kinds = {BITVECTOR_NOT, BITVECTOR_NEG};
823
82
      std::vector<TypeNode> cargsUnary;
824
41
      cargsUnary.push_back(unres_t);
825
123
      for (const Kind kind : un_kinds)
826
      {
827
82
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
828
82
        sdts[i].addConstructor(kind, cargsUnary);
829
      }
830
      // binary ops
831
      std::vector<Kind> bin_kinds = {BITVECTOR_AND,
832
                                     BITVECTOR_OR,
833
                                     BITVECTOR_XOR,
834
                                     BITVECTOR_ADD,
835
                                     BITVECTOR_SUB,
836
                                     BITVECTOR_MULT,
837
                                     BITVECTOR_UDIV,
838
                                     BITVECTOR_UREM,
839
                                     BITVECTOR_SDIV,
840
                                     BITVECTOR_SREM,
841
                                     BITVECTOR_SHL,
842
                                     BITVECTOR_LSHR,
843
82
                                     BITVECTOR_ASHR};
844
82
      std::vector<TypeNode> cargsBinary;
845
41
      cargsBinary.push_back(unres_t);
846
41
      cargsBinary.push_back(unres_t);
847
574
      for (const Kind kind : bin_kinds)
848
      {
849
533
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
850
533
        sdts[i].addConstructor(kind, cargsBinary);
851
      }
852
    }
853
110
    else if (types[i].isFloatingPoint())
854
    {
855
      // unary ops
856
      std::vector<Kind> unary_kinds = {
857
          FLOATINGPOINT_ABS,
858
          FLOATINGPOINT_NEG,
859
      };
860
      std::vector<TypeNode> cargs = {unres_t};
861
      for (const Kind kind : unary_kinds)
862
      {
863
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
864
        sdts[i].addConstructor(kind, cargs);
865
      }
866
      // binary ops
867
      {
868
        const Kind kind = FLOATINGPOINT_REM;
869
        cargs.push_back(unres_t);
870
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
871
        sdts[i].addConstructor(kind, cargs);
872
      }
873
      // binary ops with RM
874
      std::vector<Kind> binary_rm_kinds = {
875
          FLOATINGPOINT_SQRT,
876
          FLOATINGPOINT_RTI,
877
      };
878
      TypeNode rmType = nm->roundingModeType();
879
      Assert(std::find(types.begin(), types.end(), rmType) != types.end());
880
      TypeNode unres_rm_t = type_to_unres[rmType];
881
      std::vector<TypeNode> cargs_rm = {unres_rm_t, unres_t};
882
      for (const Kind kind : binary_rm_kinds)
883
      {
884
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
885
        sdts[i].addConstructor(kind, cargs_rm);
886
      }
887
      // ternary ops with RM
888
      std::vector<Kind> ternary_rm_kinds = {
889
          FLOATINGPOINT_ADD,
890
          FLOATINGPOINT_SUB,
891
          FLOATINGPOINT_MULT,
892
          FLOATINGPOINT_DIV,
893
      };
894
      cargs_rm.push_back(unres_t);
895
      for (const Kind kind : ternary_rm_kinds)
896
      {
897
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
898
        sdts[i].addConstructor(kind, cargs_rm);
899
      }
900
      // quaternary ops
901
      {
902
        cargs_rm.push_back(unres_t);
903
        const Kind kind = FLOATINGPOINT_FMA;
904
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
905
        sdts[i].addConstructor(kind, cargs_rm);
906
      }
907
    }
908
110
    else if (types[i].isStringLike())
909
    {
910
      // concatenation
911
66
      std::vector<TypeNode> cargsBinary;
912
33
      cargsBinary.push_back(unres_t);
913
33
      cargsBinary.push_back(unres_t);
914
33
      sdts[i].addConstructor(STRING_CONCAT, cargsBinary);
915
      // length
916
66
      TypeNode intType = nm->integerType();
917
33
      Assert(std::find(types.begin(), types.end(), intType) != types.end());
918
33
      unsigned i_intType = std::distance(
919
          types.begin(),
920
          std::find(types.begin(),
921
                    types.end(),
922
33
                    intType));
923
66
      std::vector<TypeNode> cargsLen;
924
33
      cargsLen.push_back(unres_t);
925
33
      sdts[i_intType].addConstructor(STRING_LENGTH, cargsLen);
926
33
      if (types[i].isSequence())
927
      {
928
        TypeNode etype = types[i].getSequenceElementType();
929
        // retrieve element unresolved type
930
        Assert(type_to_unres.find(etype) != type_to_unres.end());
931
        TypeNode unresElemType = type_to_unres[etype];
932
933
        Trace("sygus-grammar-def") << "...add for seq.unit" << std::endl;
934
        std::vector<TypeNode> cargsSeqUnit;
935
        cargsSeqUnit.push_back(unresElemType);
936
        sdts[i].addConstructor(SEQ_UNIT, cargsSeqUnit);
937
      }
938
    }
939
77
    else if (types[i].isArray())
940
    {
941
36
      Trace("sygus-grammar-def")
942
18
          << "...building for array type " << types[i] << "\n";
943
36
      TypeNode indexType = types[i].getArrayIndexType();
944
36
      TypeNode elemType = types[i].getArrayConstituentType();
945
36
      Trace("sygus-grammar-def")
946
18
          << "......finding unres type for index type " << indexType << "\n";
947
      // retrieve index and constituent unresolved types
948
18
      Assert(type_to_unres.find(indexType) != type_to_unres.end());
949
36
      TypeNode unres_indexType = type_to_unres[indexType];
950
18
      Assert(std::find(types.begin(), types.end(), elemType) != types.end());
951
      // must get this index since we add to sdt[i_constituentType] below.
952
18
      unsigned i_constituentType = std::distance(
953
18
          types.begin(), std::find(types.begin(), types.end(), elemType));
954
36
      TypeNode unres_constituentType = unres_types[i_constituentType];
955
      // add (store ArrayType IndexType ConstituentType)
956
18
      Trace("sygus-grammar-def") << "...add for STORE\n";
957
958
36
      std::vector<TypeNode> cargsStore;
959
18
      cargsStore.push_back(unres_t);
960
18
      cargsStore.push_back(unres_indexType);
961
18
      cargsStore.push_back(unres_constituentType);
962
18
      sdts[i].addConstructor(STORE, cargsStore);
963
      // add to constituent type : (select ArrayType IndexType)
964
36
      Trace("sygus-grammar-def") << "...add select for constituent type"
965
18
                                 << unres_constituentType << "\n";
966
36
      std::vector<TypeNode> cargsSelect;
967
18
      cargsSelect.push_back(unres_t);
968
18
      cargsSelect.push_back(unres_indexType);
969
18
      sdts[i_constituentType].addConstructor(SELECT, cargsSelect);
970
    }
971
59
    else if (types[i].isSet())
972
    {
973
16
      TypeNode etype = types[i].getSetElementType();
974
      // retrieve element unresolved type
975
8
      Assert(type_to_unres.find(etype) != type_to_unres.end());
976
16
      TypeNode unresElemType = type_to_unres[etype];
977
978
      // add for singleton
979
8
      Trace("sygus-grammar-def") << "...add for singleton" << std::endl;
980
16
      std::vector<TypeNode> cargsSingleton;
981
8
      cargsSingleton.push_back(unresElemType);
982
983
      // lambda x . (singleton (singleton_op T) x) where T = x.getType()
984
16
      Node x = nm->mkBoundVar(etype);
985
16
      Node vars = nm->mkNode(BOUND_VAR_LIST, x);
986
16
      Node singleton = nm->mkSingleton(etype, x);
987
16
      Node lambda = nm->mkNode(LAMBDA,vars, singleton);
988
8
      sdts[i].addConstructor(lambda, "singleton", cargsSingleton);
989
990
      // add for union, difference, intersection
991
16
      std::vector<Kind> bin_kinds = {UNION, INTERSECTION, SETMINUS};
992
16
      std::vector<TypeNode> cargsBinary;
993
8
      cargsBinary.push_back(unres_t);
994
8
      cargsBinary.push_back(unres_t);
995
32
      for (const Kind kind : bin_kinds)
996
      {
997
24
        Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
998
24
        sdts[i].addConstructor(kind, cargsBinary);
999
      }
1000
    }
1001
51
    else if (types[i].isDatatype())
1002
    {
1003
43
      Trace("sygus-grammar-def") << "...add for constructors" << std::endl;
1004
43
      const DType& dt = types[i].getDType();
1005
96
      for (unsigned l = 0, size_l = dt.getNumConstructors(); l < size_l; ++l)
1006
      {
1007
53
        Trace("sygus-grammar-def") << "...for " << dt[l].getName() << std::endl;
1008
106
        Node cop = dt[l].getConstructor();
1009
106
        TypeNode tspec = dt[l].getSpecializedConstructorType(types[i]);
1010
        // must specialize if a parametric datatype
1011
53
        if (dt.isParametric())
1012
        {
1013
12
          cop = nm->mkNode(
1014
8
              APPLY_TYPE_ASCRIPTION, nm->mkConst(AscriptionType(tspec)), cop);
1015
        }
1016
53
        if (dt[l].getNumArgs() == 0)
1017
        {
1018
          // Nullary constructors are interpreted as terms, not operators.
1019
          // Thus, we apply them to no arguments here.
1020
10
          cop = nm->mkNode(APPLY_CONSTRUCTOR, cop);
1021
        }
1022
106
        std::vector<TypeNode> cargsCons;
1023
53
        Trace("sygus-grammar-def") << "...add for selectors" << std::endl;
1024
        // iterate over the arguments of the specialized constructor type,
1025
        // which accounts for parametric datatypes
1026
106
        std::vector<TypeNode> tsargs = tspec.getArgTypes();
1027
106
        TypeNode selDomain = type_to_unres[types[i]];
1028
139
        for (unsigned j = 0, size_j = tsargs.size(); j < size_j; ++j)
1029
        {
1030
172
          Trace("sygus-grammar-def")
1031
86
              << "...for " << dt[l][j].getName() << std::endl;
1032
172
          TypeNode crange = tsargs[j];
1033
86
          Assert(type_to_unres.find(crange) != type_to_unres.end());
1034
86
          cargsCons.push_back(type_to_unres[crange]);
1035
          // add to the selector type the selector operator
1036
1037
86
          Assert(std::find(types.begin(), types.end(), crange) != types.end());
1038
86
          unsigned i_selType = std::distance(
1039
86
              types.begin(), std::find(types.begin(), types.end(), crange));
1040
172
          std::vector<TypeNode> cargsSel;
1041
86
          cargsSel.push_back(selDomain);
1042
172
          Node sel = dt[l][j].getSelector();
1043
86
          sdts[i_selType].addConstructor(sel, dt[l][j].getName(), cargsSel);
1044
        }
1045
53
        sdts[i].addConstructor(cop, dt[l].getName(), cargsCons);
1046
      }
1047
    }
1048
22
    else if (types[i].isSort() || types[i].isFunction()
1049
8
             || types[i].isRoundingMode())
1050
    {
1051
      // do nothing
1052
    }
1053
    else
1054
    {
1055
      Warning()
1056
          << "Warning: No implementation for default Sygus grammar of type "
1057
          << types[i] << std::endl;
1058
    }
1059
1060
760
    if (sdts[i].d_sdt.getNumConstructors() == 0)
1061
    {
1062
      // if there are not constructors yet by this point, which can happen,
1063
      // e.g. for unimplemented types that have no variables in the argument
1064
      // list of the function-to-synthesize, create a fresh ground term
1065
      sdts[i].addConstructor(types[i].mkGroundTerm(), "", {});
1066
    }
1067
1068
    // always add ITE
1069
760
    Kind k = ITE;
1070
760
    Trace("sygus-grammar-def") << "...add for " << k << std::endl;
1071
1520
    std::vector<TypeNode> cargsIte;
1072
760
    cargsIte.push_back(unres_bt);
1073
760
    cargsIte.push_back(unres_t);
1074
760
    cargsIte.push_back(unres_t);
1075
760
    sdts[i].addConstructor(k, cargsIte);
1076
  }
1077
724
  std::map<TypeNode, std::pair<unsigned, bool>>::iterator itgat;
1078
  // initialize the datatypes (except for the last one, reserved for Bool)
1079
1484
  for (unsigned i = 0, size = types.size() - 1; i < size; ++i)
1080
  {
1081
760
    sdts[i].d_sdt.initializeDatatype(types[i], bvl, true, true);
1082
1520
    Trace("sygus-grammar-def")
1083
760
        << "...built datatype " << sdts[i].d_sdt.getDatatype() << " ";
1084
    //set start index if applicable
1085
760
    if( types[i]==range ){
1086
549
      startIndex = i;
1087
    }
1088
760
    itgat = typeToGAnyTerm.find(types[i]);
1089
760
    if (itgat == typeToGAnyTerm.end())
1090
    {
1091
      // no any term datatype, we are done
1092
752
      continue;
1093
    }
1094
8
    unsigned iat = itgat->second.first;
1095
16
    Trace("sygus-grammar-def")
1096
8
        << "Build any-term datatype for " << types[i] << "..." << std::endl;
1097
1098
    // for now, only real has any term construction
1099
8
    Assert(types[i].isReal());
1100
    // We have initialized the given type sdts[i], which should now contain
1101
    // a constructor for each relevant arithmetic term/variable. We now
1102
    // construct a sygus datatype of one of the following two forms.
1103
    //
1104
    // (1) The "sum of monomials" grammar:
1105
    //   I -> C*x1 | ... | C*xn | C | I + I | ite( B, I, I )
1106
    //   C -> any_constant
1107
    // where x1, ..., xn are the arithmetic terms/variables (non-arithmetic
1108
    // builtin operators) terms we have considered thus far.
1109
    //
1110
    // (2) The "polynomial" grammar:
1111
    //   I -> C*x1 + ... + C*xn + C | ite( B, I, I )
1112
    //   C -> any_constant
1113
    //
1114
    // The advantage of the first is that it allows for sums of terms
1115
    // constructible from other theories that share sorts with arithmetic, e.g.
1116
    //   c1*str.len(x) + c2*str.len(y)
1117
    // The advantage of the second is that there are fewer constructors, and
1118
    // hence may be more efficient.
1119
1120
    // Before proceeding, we build the any constant datatype
1121
16
    Trace("sygus-grammar-def")
1122
8
        << "Build any-constant datatype for " << types[i] << std::endl;
1123
16
    std::stringstream ss;
1124
8
    ss << fun << "_AnyConst";
1125
    // Make sygus datatype for any constant.
1126
16
    TypeNode unresAnyConst = mkUnresolvedType(ss.str(), unres);
1127
8
    unres_types.push_back(unresAnyConst);
1128
8
    sdts.push_back(SygusDatatypeGenerator(ss.str()));
1129
8
    sdts.back().d_sdt.addAnyConstantConstructor(types[i]);
1130
8
    sdts.back().d_sdt.initializeDatatype(types[i], bvl, true, true);
1131
1132
    // Now get the reference to the sygus datatype at position i (important that
1133
    // this comes after the modification to sdts above, which may modify
1134
    // the references).
1135
8
    const SygusDatatype& sdti = sdts[i].d_sdt;
1136
    // whether we will use the polynomial grammar
1137
8
    bool polynomialGrammar =
1138
        sgcm == options::SygusGrammarConsMode::ANY_TERM_CONCISE;
1139
    // A set of constructor indices that will be used in the overall sum we
1140
    // are constructing; indices of constructors corresponding to builtin
1141
    // arithmetic operators will be excluded from this set.
1142
16
    std::set<unsigned> useConstructor;
1143
16
    Trace("sygus-grammar-def")
1144
16
        << "Look at operators, num = " << sdti.getNumConstructors() << "..."
1145
8
        << std::endl;
1146
108
    for (unsigned k = 0, ncons = sdti.getNumConstructors(); k < ncons; k++)
1147
    {
1148
100
      const SygusDatatypeConstructor& sdc = sdti.getConstructor(k);
1149
200
      Node sop = sdc.d_op;
1150
100
      bool isBuiltinArithOp = (sop.getKind() == CONST_RATIONAL);
1151
100
      bool hasExternalType = false;
1152
112
      for (unsigned j = 0, nargs = sdc.d_argTypes.size(); j < nargs; j++)
1153
      {
1154
        // Since we are accessing the fields of the sygus datatype, this
1155
        // already corresponds to the correct sygus datatype type.
1156
50
        TypeNode atype = sdc.d_argTypes[j];
1157
38
        if (atype == unres_types[i])
1158
        {
1159
          // It is recursive, thus is (likely) a builtin arithmetic operator
1160
          // as constructed above. It may also be an operator from another
1161
          // theory that has both an arithmetic return type and an arithmetic
1162
          // argument (e.g. str.indexof). In either case, we ignore it for the
1163
          // sake of well-foundedness.
1164
26
          isBuiltinArithOp = true;
1165
26
          break;
1166
        }
1167
12
        else if (atype != unres_bt)
1168
        {
1169
          // It is an external type. This is the case of an operator of another
1170
          // theory whose return type is arithmetic, e.g. select.
1171
4
          hasExternalType = true;
1172
        }
1173
      }
1174
100
      if (!isBuiltinArithOp)
1175
      {
1176
12
        useConstructor.insert(k);
1177
12
        if (hasExternalType)
1178
        {
1179
          // If we have an external term in the sum, e.g. select(A,i), we
1180
          // cannot use a fixed polynomial template. As mentioned above, we
1181
          // cannot use a polynomial grammar when external terms (those built
1182
          // from the symbols of other theories) are involved.
1183
8
          Trace("sygus-grammar-def")
1184
4
              << "Cannot use polynomial grammar due to " << sop << std::endl;
1185
4
          polynomialGrammar = false;
1186
        }
1187
      }
1188
    }
1189
16
    Trace("sygus-grammar-def")
1190
16
        << "Done look at operators, num = " << sdti.getNumConstructors()
1191
8
        << "..." << std::endl;
1192
    // we have now decided whether we will use sum-of-monomials or polynomial
1193
    // Now, extract the terms and set up the polynomial
1194
16
    std::vector<Node> sumChildren;
1195
16
    std::vector<TypeNode> cargsAnyTerm;
1196
16
    std::vector<Node> lambdaVars;
1197
108
    for (unsigned k = 0, ncons = sdti.getNumConstructors(); k < ncons; k++)
1198
    {
1199
100
      Trace("sygus-grammar-def") << "Process #" << k << std::endl;
1200
188
      if (useConstructor.find(k) == useConstructor.end())
1201
      {
1202
88
        Trace("sygus-grammar-def") << "Skip variable #" << k << std::endl;
1203
        // builtin operator, as computed above, we skip
1204
88
        continue;
1205
      }
1206
12
      const SygusDatatypeConstructor& sdc = sdti.getConstructor(k);
1207
24
      Node sop = sdc.d_op;
1208
24
      Trace("sygus-grammar-def")
1209
12
          << "Monomial variable: #" << k << ": " << sop << std::endl;
1210
12
      unsigned nargs = sdc.d_argTypes.size();
1211
24
      std::vector<TypeNode> opCArgs;
1212
24
      std::vector<Node> opLArgs;
1213
12
      if (nargs > 0)
1214
      {
1215
        // Take its arguments. For example, if we are building a polynomial
1216
        // over str.len(s), then our any term constructor would include an
1217
        // argument of string type, e.g.:
1218
        //   (lambda s : String, c1, c2 : Int. c1*len(s) + c2)
1219
8
        for (unsigned j = 0; j < nargs; j++)
1220
        {
1221
          // this is already corresponds to the correct sygus datatype type
1222
8
          TypeNode atype = sdc.d_argTypes[j];
1223
4
          opCArgs.push_back(atype);
1224
          // get the builtin type
1225
8
          TypeNode btype = sygus_to_builtin[atype];
1226
4
          opLArgs.push_back(nm->mkBoundVar(btype));
1227
        }
1228
        // Do beta reduction on the operator so that its arguments match the
1229
        // fresh variables of the lambda (op) we are constructing below.
1230
4
        sop = datatypes::utils::mkSygusTerm(sop, opLArgs);
1231
4
        sop = Rewriter::rewrite(sop);
1232
      }
1233
12
      opCArgs.push_back(unresAnyConst);
1234
24
      Node coeff = nm->mkBoundVar(types[i]);
1235
12
      opLArgs.push_back(coeff);
1236
24
      Node monomial = nm->mkNode(MULT, coeff, sop);
1237
12
      if (polynomialGrammar)
1238
      {
1239
        // add the monomial c*t to the sum
1240
8
        sumChildren.push_back(monomial);
1241
8
        lambdaVars.insert(lambdaVars.end(), opLArgs.begin(), opLArgs.end());
1242
8
        cargsAnyTerm.insert(cargsAnyTerm.end(), opCArgs.begin(), opCArgs.end());
1243
      }
1244
      else
1245
      {
1246
        Node op =
1247
8
            nm->mkNode(LAMBDA, nm->mkNode(BOUND_VAR_LIST, opLArgs), monomial);
1248
        // add it as a constructor
1249
8
        std::stringstream ssop;
1250
4
        ssop << "monomial_" << sdc.d_name;
1251
        // we use 0 as the weight, since this constructor should be seen as
1252
        // a generalization of a non-Boolean variable (which has weight 0).
1253
        // This ensures that e.g. ( c1*x >= 0 ) has the same weight as
1254
        // ( x >= 0 ).
1255
4
        sdts[iat].d_sdt.addConstructor(op, ssop.str(), opCArgs, 0);
1256
      }
1257
    }
1258
8
    if (polynomialGrammar)
1259
    {
1260
      // add the constant
1261
8
      Node coeff = nm->mkBoundVar(types[i]);
1262
4
      lambdaVars.push_back(coeff);
1263
4
      sumChildren.push_back(coeff);
1264
4
      cargsAnyTerm.push_back(unresAnyConst);
1265
      // make the sygus operator lambda X. c1*t1 + ... + cn*tn + c
1266
4
      Assert(sumChildren.size() > 1);
1267
8
      Node ops = nm->mkNode(PLUS, sumChildren);
1268
8
      Node op = nm->mkNode(LAMBDA, nm->mkNode(BOUND_VAR_LIST, lambdaVars), ops);
1269
4
      Trace("sygus-grammar-def") << "any term operator is " << op << std::endl;
1270
      // make the any term datatype, add to back
1271
      // do not consider the exclusion criteria of the generator
1272
      // we use 0 as the weight, since this constructor should be seen as
1273
      // a simultaneous generalization of set of non-Boolean variables.
1274
      // This ensures that ( c1*x + c2*y >= 0 ) has the same weight as
1275
      // e.g. ( x >= 0 ) or ( y >= 0 ).
1276
4
      sdts[iat].d_sdt.addConstructor(op, "polynomial", cargsAnyTerm, 0);
1277
      // mark that predicates should be of the form (= pol 0) and (<= pol 0)
1278
4
      itgat->second.second = true;
1279
    }
1280
    else
1281
    {
1282
      // add the any constant constructor as a separate constructor
1283
4
      sdts[iat].d_sdt.addAnyConstantConstructor(types[i]);
1284
      // add plus
1285
8
      std::vector<TypeNode> cargsPlus;
1286
4
      cargsPlus.push_back(unres_types[iat]);
1287
4
      cargsPlus.push_back(unres_types[iat]);
1288
4
      sdts[iat].d_sdt.addConstructor(PLUS, cargsPlus);
1289
    }
1290
    // add the ITE, regardless of sum-of-monomials vs polynomial
1291
16
    std::vector<TypeNode> cargsIte;
1292
8
    cargsIte.push_back(unres_bt);
1293
8
    cargsIte.push_back(unres_types[iat]);
1294
8
    cargsIte.push_back(unres_types[iat]);
1295
8
    sdts[iat].d_sdt.addConstructor(ITE, cargsIte);
1296
8
    sdts[iat].d_sdt.initializeDatatype(types[i], bvl, true, true);
1297
16
    Trace("sygus-grammar-def")
1298
8
        << "...built datatype " << sdts[iat].d_sdt.getDatatype() << std::endl;
1299
    // if the type is range, use it as the default type
1300
8
    if (types[i] == range)
1301
    {
1302
8
      startIndex = iat;
1303
    }
1304
  }
1305
  //------ make Boolean type
1306
724
  SygusDatatypeGenerator& sdtBool = sdts[boolIndex];
1307
724
  Trace("sygus-grammar-def") << "Make grammar for " << bool_type << std::endl;
1308
  //add variables
1309
2110
  for (unsigned i = 0, size = sygus_vars.size(); i < size; ++i)
1310
  {
1311
1386
    if( sygus_vars[i].getType().isBoolean() ){
1312
444
      std::stringstream ss;
1313
222
      ss << sygus_vars[i];
1314
222
      Trace("sygus-grammar-def") << "...add for variable " << ss.str() << std::endl;
1315
444
      std::vector<TypeNode> cargsEmpty;
1316
      // make boolean variables weight as non-nullary constructors
1317
222
      sdtBool.addConstructor(sygus_vars[i], ss.str(), cargsEmpty, 1);
1318
    }
1319
  }
1320
  // add constants
1321
1448
  std::vector<Node> consts;
1322
724
  mkSygusConstantsForType(bool_type, consts);
1323
2172
  for (unsigned i = 0, size = consts.size(); i < size; ++i)
1324
  {
1325
2896
    std::stringstream ss;
1326
1448
    ss << consts[i];
1327
2896
    Trace("sygus-grammar-def") << "...add for constant " << ss.str()
1328
1448
                               << std::endl;
1329
2896
    std::vector<TypeNode> cargsEmpty;
1330
1448
    sdtBool.addConstructor(consts[i], ss.str(), cargsEmpty);
1331
  }
1332
  // add predicates for non-Boolean types
1333
1484
  for (unsigned i = 0, size = types.size() - 1; i < size; ++i)
1334
  {
1335
760
    if (!types[i].isFirstClass())
1336
    {
1337
      continue;
1338
    }
1339
760
    unsigned iuse = i;
1340
760
    bool zarg = false;
1341
    // use the any-term type if it exists and a zero argument if it is a
1342
    // polynomial grammar
1343
760
    itgat = typeToGAnyTerm.find(types[i]);
1344
760
    if (itgat != typeToGAnyTerm.end())
1345
    {
1346
8
      iuse = itgat->second.first;
1347
8
      zarg = itgat->second.second;
1348
16
      Trace("sygus-grammar-def")
1349
8
          << "...unres type " << unres_types[i] << " became "
1350
16
          << (!zarg ? "polynomial " : "") << "unres anyterm type "
1351
8
          << unres_types[iuse] << "\n";
1352
    }
1353
760
    Trace("sygus-grammar-def") << "...add predicates for " << types[i] << std::endl;
1354
    //add equality per type
1355
760
    Kind k = EQUAL;
1356
760
    Trace("sygus-grammar-def") << "...add for " << k << std::endl;
1357
1520
    std::stringstream ss;
1358
1520
    std::vector<TypeNode> cargs;
1359
760
    cargs.push_back(unres_types[iuse]);
1360
    // if polynomial grammar, generate (= anyterm 0) and (<= anyterm 0) as the
1361
    // predicates
1362
760
    if (zarg)
1363
    {
1364
8
      Node op = createLambdaWithZeroArg(k, types[i]);
1365
4
      ss << "eq_" << types[i];
1366
4
      sdtBool.addConstructor(op, ss.str(), cargs);
1367
    }
1368
    else
1369
    {
1370
756
      ss << kindToString(k) << "_" << types[i];
1371
756
      cargs.push_back(unres_types[iuse]);
1372
756
      sdtBool.addConstructor(nm->operatorOf(k), ss.str(), cargs);
1373
756
      cargs.pop_back();
1374
    }
1375
    // type specific predicates
1376
1520
    std::stringstream ssop;
1377
760
    if (types[i].isReal())
1378
    {
1379
609
      Kind kind = LEQ;
1380
609
      Trace("sygus-grammar-def") << "...add for " << k << std::endl;
1381
609
      if (zarg)
1382
      {
1383
8
        Node op = createLambdaWithZeroArg(kind, types[i]);
1384
4
        ssop << "leq_" << types[i];
1385
4
        sdtBool.addConstructor(op, ssop.str(), cargs);
1386
      }
1387
      else
1388
      {
1389
605
        cargs.push_back(unres_types[iuse]);
1390
605
        sdtBool.addConstructor(kind, cargs);
1391
      }
1392
    }
1393
151
    else if (types[i].isBitVector())
1394
    {
1395
41
      Kind kind = BITVECTOR_ULT;
1396
41
      Trace("sygus-grammar-def") << "...add for " << k << std::endl;
1397
41
      if (zarg)
1398
      {
1399
        Node op = createLambdaWithZeroArg(kind, types[i]);
1400
        ssop << "leq_" << types[i];
1401
        sdtBool.addConstructor(op, ssop.str(), cargs);
1402
      }
1403
      else
1404
      {
1405
41
        cargs.push_back(unres_types[iuse]);
1406
41
        sdtBool.addConstructor(kind, cargs);
1407
      }
1408
    }
1409
110
    else if (types[i].isFloatingPoint())
1410
    {
1411
      Trace("sygus-grammar-def") << "...add FP predicates" << std::endl;
1412
      std::vector<Kind> fp_unary_predicates = {FLOATINGPOINT_ISN,
1413
                                               FLOATINGPOINT_ISSN,
1414
                                               FLOATINGPOINT_ISZ,
1415
                                               FLOATINGPOINT_ISINF,
1416
                                               FLOATINGPOINT_ISNAN,
1417
                                               FLOATINGPOINT_ISNEG,
1418
                                               FLOATINGPOINT_ISPOS};
1419
      for (const Kind kind : fp_unary_predicates)
1420
      {
1421
        sdtBool.addConstructor(kind, cargs);
1422
      }
1423
      std::vector<Kind> fp_binary_predicates = {FLOATINGPOINT_LEQ,
1424
                                                FLOATINGPOINT_LT};
1425
      cargs.push_back(unres_types[iuse]);
1426
      for (const Kind kind : fp_binary_predicates)
1427
      {
1428
        sdtBool.addConstructor(kind, cargs);
1429
      }
1430
    }
1431
110
    else if (types[i].isDatatype())
1432
    {
1433
      //add for testers
1434
43
      Trace("sygus-grammar-def") << "...add for testers" << std::endl;
1435
43
      const DType& dt = types[i].getDType();
1436
86
      std::vector<TypeNode> cargsTester;
1437
43
      cargsTester.push_back(unres_types[iuse]);
1438
96
      for (unsigned kind = 0, size_k = dt.getNumConstructors(); kind < size_k;
1439
           ++kind)
1440
      {
1441
106
        Trace("sygus-grammar-def")
1442
53
            << "...for " << dt[kind].getTester() << std::endl;
1443
106
        std::stringstream sst;
1444
53
        sst << dt[kind].getTester();
1445
53
        sdtBool.addConstructor(dt[kind].getTester(), sst.str(), cargsTester);
1446
      }
1447
    }
1448
67
    else if (types[i].isSet())
1449
    {
1450
      // add for member
1451
16
      TypeNode etype = types[i].getSetElementType();
1452
8
      Assert(type_to_unres.find(etype) != type_to_unres.end());
1453
16
      TypeNode unresElemType = type_to_unres[etype];
1454
16
      std::vector<TypeNode> cargsMember;
1455
8
      cargsMember.push_back(unresElemType);
1456
8
      cargsMember.push_back(unres_types[iuse]);
1457
8
      Trace("sygus-grammar-def") << "...for MEMBER" << std::endl;
1458
8
      sdtBool.addConstructor(MEMBER, cargsMember);
1459
    }
1460
  }
1461
  // add Boolean connectives, if not in a degenerate case of (recursively)
1462
  // having only constant constructors
1463
1448
  Trace("sygus-grammar-def")
1464
724
      << "...add Boolean connectives for unres type " << unres_bt << std::endl;
1465
724
  if (sdtBool.d_sdt.getNumConstructors() > consts.size())
1466
  {
1467
3235
    for (unsigned i = 0; i < 4; i++)
1468
    {
1469
2588
      Kind k = i == 0 ? NOT : (i == 1 ? AND : (i == 2 ? OR : ITE));
1470
      // TODO #1935 ITEs are added to Boolean grammars so that we can infer
1471
      // unification strategies. We can do away with this if we can infer
1472
      // unification strategies from and/or/not
1473
2588
      if (k == ITE && options::sygusUnifPi() == options::SygusUnifPiMode::NONE)
1474
      {
1475
637
        continue;
1476
      }
1477
1951
      Trace("sygus-grammar-def") << "...add for " << k << std::endl;
1478
3902
      std::vector<TypeNode> cargs;
1479
1951
      cargs.push_back(unres_bt);
1480
1951
      if (k != NOT)
1481
      {
1482
1304
        cargs.push_back(unres_bt);
1483
1304
        if (k == ITE)
1484
        {
1485
10
          cargs.push_back(unres_bt);
1486
        }
1487
      }
1488
1951
      sdtBool.addConstructor(k, cargs);
1489
    }
1490
  }
1491
724
  if (range == bool_type)
1492
  {
1493
175
    startIndex = boolIndex;
1494
  }
1495
724
  sdtBool.d_sdt.initializeDatatype(bool_type, bvl, true, true);
1496
1448
  Trace("sygus-grammar-def")
1497
724
      << "...built datatype for Bool " << sdtBool.d_sdt.getDatatype() << " ";
1498
724
  Trace("sygus-grammar-def") << "...finished make default grammar for " << fun << " " << range << std::endl;
1499
  // make first datatype be the top level datatype
1500
724
  if( startIndex>0 ){
1501
248
    SygusDatatypeGenerator tmp_dt = sdts[0];
1502
124
    sdts[0] = sdts[startIndex];
1503
124
    sdts[startIndex] = tmp_dt;
1504
  }
1505
724
}
1506
1507
724
TypeNode CegGrammarConstructor::mkSygusDefaultType(
1508
    TypeNode range,
1509
    Node bvl,
1510
    const std::string& fun,
1511
    std::map<TypeNode, std::unordered_set<Node>>& extra_cons,
1512
    std::map<TypeNode, std::unordered_set<Node>>& exclude_cons,
1513
    std::map<TypeNode, std::unordered_set<Node>>& include_cons,
1514
    std::unordered_set<Node>& term_irrelevant)
1515
{
1516
724
  Trace("sygus-grammar-def") << "*** Make sygus default type " << range << ", make datatypes..." << std::endl;
1517
1280
  for (std::map<TypeNode, std::unordered_set<Node>>::iterator it =
1518
724
           extra_cons.begin();
1519
2004
       it != extra_cons.end();
1520
       ++it)
1521
  {
1522
1280
    Trace("sygus-grammar-def") << "    ...using " << it->second.size() << " extra constants for " << it->first << std::endl;
1523
  }
1524
1448
  std::set<TypeNode> unres;
1525
1448
  std::vector<SygusDatatypeGenerator> sdts;
1526
724
  mkSygusDefaultGrammar(range,
1527
                        bvl,
1528
                        fun,
1529
                        extra_cons,
1530
                        exclude_cons,
1531
                        include_cons,
1532
                        term_irrelevant,
1533
                        sdts,
1534
                        unres);
1535
  // extract the datatypes from the sygus datatype generator objects
1536
1448
  std::vector<DType> datatypes;
1537
2267
  for (unsigned i = 0, ndts = sdts.size(); i < ndts; i++)
1538
  {
1539
1543
    datatypes.push_back(sdts[i].d_sdt.getDatatype());
1540
  }
1541
724
  Trace("sygus-grammar-def")  << "...made " << datatypes.size() << " datatypes, now make mutual datatype types..." << std::endl;
1542
724
  Assert(!datatypes.empty());
1543
  std::vector<TypeNode> types = NodeManager::currentNM()->mkMutualDatatypeTypes(
1544
1448
      datatypes, unres, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
1545
724
  Trace("sygus-grammar-def") << "...finished" << std::endl;
1546
724
  Assert(types.size() == datatypes.size());
1547
1448
  return types[0];
1548
}
1549
1550
TypeNode CegGrammarConstructor::mkSygusTemplateTypeRec( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl,
1551
                                              const std::string& fun, unsigned& tcount ) {
1552
  if( templ==templ_arg ){
1553
    //Assert( templ_arg.getType()==sygusToBuiltinType( templ_arg_sygus_type ) );
1554
    return templ_arg_sygus_type;
1555
  }else{
1556
    tcount++;
1557
    std::set<TypeNode> unres;
1558
    std::vector<SygusDatatype> sdts;
1559
    std::stringstream ssd;
1560
    ssd << fun << "_templ_" << tcount;
1561
    std::string dbname = ssd.str();
1562
    sdts.push_back(SygusDatatype(dbname));
1563
    Node op;
1564
    std::vector<TypeNode> argTypes;
1565
    if( templ.getNumChildren()==0 ){
1566
      // TODO : can short circuit to this case when !TermUtil::containsTerm( templ, templ_arg )
1567
      op = templ;
1568
    }else{
1569
      Assert(templ.hasOperator());
1570
      op = templ.getOperator();
1571
      // make constructor taking arguments types from children
1572
      for( unsigned i=0; i<templ.getNumChildren(); i++ ){
1573
        //recursion depth bound by the depth of SyGuS template expressions (low)
1574
        TypeNode tnc = mkSygusTemplateTypeRec( templ[i], templ_arg, templ_arg_sygus_type, bvl, fun, tcount );
1575
        argTypes.push_back(tnc);
1576
      }
1577
    }
1578
    std::stringstream ssdc;
1579
    ssdc << fun << "_templ_cons_" << tcount;
1580
    // we have a single sygus constructor that encodes the template
1581
    sdts.back().addConstructor(op, ssdc.str(), argTypes);
1582
    sdts.back().initializeDatatype(templ.getType(), bvl, true, true);
1583
    // extract the datatypes from the sygus datatype objects
1584
    std::vector<DType> datatypes;
1585
    for (unsigned i = 0, ndts = sdts.size(); i < ndts; i++)
1586
    {
1587
      datatypes.push_back(sdts[i].getDatatype());
1588
    }
1589
    std::vector<TypeNode> types =
1590
        NodeManager::currentNM()->mkMutualDatatypeTypes(
1591
            datatypes, unres, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
1592
    Assert(types.size() == 1);
1593
    return types[0];
1594
  }
1595
}
1596
1597
TypeNode CegGrammarConstructor::mkSygusTemplateType( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl,
1598
                                                     const std::string& fun ) {
1599
  unsigned tcount = 0;
1600
  return mkSygusTemplateTypeRec( templ, templ_arg, templ_arg_sygus_type, bvl, fun, tcount );
1601
}
1602
1603
1543
CegGrammarConstructor::SygusDatatypeGenerator::SygusDatatypeGenerator(
1604
1543
    const std::string& name)
1605
1543
    : d_sdt(name)
1606
{
1607
1543
}
1608
11410
void CegGrammarConstructor::SygusDatatypeGenerator::addConstructor(
1609
    Node op,
1610
    const std::string& name,
1611
    const std::vector<TypeNode>& consTypes,
1612
    int weight)
1613
{
1614
11410
  if (shouldInclude(op))
1615
  {
1616
11369
    d_sdt.addConstructor(op, name, consTypes, weight);
1617
  }
1618
11410
}
1619
5410
void CegGrammarConstructor::SygusDatatypeGenerator::addConstructor(
1620
    Kind k,
1621
    const std::vector<TypeNode>& consTypes,
1622
    int weight)
1623
{
1624
5410
  NodeManager* nm = NodeManager::currentNM();
1625
5410
  addConstructor(nm->operatorOf(k), kindToString(k), consTypes, weight);
1626
5410
}
1627
11410
bool CegGrammarConstructor::SygusDatatypeGenerator::shouldInclude(Node op) const
1628
{
1629
11410
  if (d_exclude_cons.find(op) != d_exclude_cons.end())
1630
  {
1631
    return false;
1632
  }
1633
11410
  if (!d_include_cons.empty())
1634
  {
1635
    // special case, variables and terms of certain types are always included
1636
60
    if (!op.isVar() && op.getType().getKind() == TYPE_CONSTANT)
1637
    {
1638
48
      if (d_include_cons.find(op) == d_include_cons.end())
1639
      {
1640
41
        return false;
1641
      }
1642
    }
1643
  }
1644
11369
  return true;
1645
}
1646
1647
}  // namespace quantifiers
1648
}  // namespace theory
1649
31137
}  // namespace cvc5