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