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