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