GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/term_database_sygus.cpp Lines: 446 515 86.6 %
Date: 2021-11-07 Branches: 784 1879 41.7 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Andres Noetzli, Mathias Preiner
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 term database sygus class.
14
 */
15
16
#include "theory/quantifiers/sygus/term_database_sygus.h"
17
18
#include <sstream>
19
20
#include "base/check.h"
21
#include "expr/dtype_cons.h"
22
#include "expr/skolem_manager.h"
23
#include "expr/sygus_datatype.h"
24
#include "options/base_options.h"
25
#include "options/datatypes_options.h"
26
#include "options/quantifiers_options.h"
27
#include "printer/printer.h"
28
#include "theory/datatypes/sygus_datatype_utils.h"
29
#include "theory/quantifiers/quantifiers_attributes.h"
30
#include "theory/quantifiers/quantifiers_inference_manager.h"
31
#include "theory/quantifiers/quantifiers_state.h"
32
#include "theory/quantifiers/term_util.h"
33
#include "theory/rewriter.h"
34
35
using namespace cvc5::kind;
36
37
namespace cvc5 {
38
namespace theory {
39
namespace quantifiers {
40
41
std::ostream& operator<<(std::ostream& os, EnumeratorRole r)
42
{
43
  switch (r)
44
  {
45
    case ROLE_ENUM_POOL: os << "POOL"; break;
46
    case ROLE_ENUM_SINGLE_SOLUTION: os << "SINGLE_SOLUTION"; break;
47
    case ROLE_ENUM_MULTI_SOLUTION: os << "MULTI_SOLUTION"; break;
48
    case ROLE_ENUM_CONSTRAINED: os << "CONSTRAINED"; break;
49
    default: os << "enum_" << static_cast<unsigned>(r); break;
50
  }
51
  return os;
52
}
53
54
1900
TermDbSygus::TermDbSygus(Env& env, QuantifiersState& qs)
55
    : EnvObj(env),
56
      d_qstate(qs),
57
1900
      d_syexp(new SygusExplain(this)),
58
1900
      d_funDefEval(new FunDefEvaluator(env)),
59
5700
      d_eval_unfold(new SygusEvalUnfold(env, this))
60
{
61
1900
  d_true = NodeManager::currentNM()->mkConst( true );
62
1900
  d_false = NodeManager::currentNM()->mkConst( false );
63
1900
}
64
65
1900
void TermDbSygus::finishInit(QuantifiersInferenceManager* qim) { d_qim = qim; }
66
67
bool TermDbSygus::reset( Theory::Effort e ) {
68
  return true;
69
}
70
71
306570
TNode TermDbSygus::getFreeVar( TypeNode tn, int i, bool useSygusType ) {
72
306570
  unsigned sindex = 0;
73
613140
  TypeNode vtn = tn;
74
613140
  TypeNode builtinType = tn;
75
306570
  if (tn.isDatatype())
76
  {
77
300618
    const DType& dt = tn.getDType();
78
300618
    if (!dt.getSygusType().isNull())
79
    {
80
300618
      builtinType = dt.getSygusType();
81
300618
      if (useSygusType)
82
      {
83
24695
        vtn = builtinType;
84
24695
        sindex = 1;
85
      }
86
    }
87
  }
88
306570
  NodeManager* nm = NodeManager::currentNM();
89
330300
  while( i>=(int)d_fv[sindex][tn].size() ){
90
23730
    std::stringstream ss;
91
11865
    if( tn.isDatatype() ){
92
6742
      const DType& dt = tn.getDType();
93
6742
      ss << "fv_" << dt.getName() << "_" << i;
94
    }else{
95
5123
      ss << "fv_" << tn << "_" << i;
96
    }
97
11865
    Assert(!vtn.isNull());
98
23730
    Node v = nm->mkBoundVar(ss.str(), vtn);
99
    // store its id, which is unique per builtin type, regardless of how it is
100
    // otherwise cached.
101
11865
    d_fvId[v] = d_fvTypeIdCounter[builtinType];
102
11865
    d_fvTypeIdCounter[builtinType]++;
103
23730
    Trace("sygus-db-debug") << "Free variable id " << v << " = " << d_fvId[v]
104
11865
                            << ", " << builtinType << std::endl;
105
11865
    d_fv[sindex][tn].push_back( v );
106
  }
107
613140
  return d_fv[sindex][tn][i];
108
}
109
110
177074
TNode TermDbSygus::getFreeVarInc( TypeNode tn, std::map< TypeNode, int >& var_count, bool useSygusType ) {
111
177074
  std::map< TypeNode, int >::iterator it = var_count.find( tn );
112
177074
  if( it==var_count.end() ){
113
63517
    var_count[tn] = 1;
114
63517
    return getFreeVar( tn, 0, useSygusType );
115
  }else{
116
113557
    int index = it->second;
117
113557
    var_count[tn]++;
118
113557
    return getFreeVar( tn, index, useSygusType );
119
  }
120
}
121
122
5741
bool TermDbSygus::isFreeVar(Node n) const
123
{
124
5741
  return d_fvId.find(n) != d_fvId.end();
125
}
126
5717
size_t TermDbSygus::getFreeVarId(Node n) const
127
{
128
5717
  std::map<Node, size_t>::const_iterator it = d_fvId.find(n);
129
5717
  if (it == d_fvId.end())
130
  {
131
    Assert(false) << "TermDbSygus::isFreeVar: " << n
132
                  << " is not a cached free variable.";
133
    return 0;
134
  }
135
5717
  return it->second;
136
}
137
138
24
bool TermDbSygus::hasFreeVar( Node n, std::map< Node, bool >& visited ){
139
24
  if( visited.find( n )==visited.end() ){
140
24
    visited[n] = true;
141
24
    if( isFreeVar( n ) ){
142
20
      return true;
143
    }
144
4
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
145
      if( hasFreeVar( n[i], visited ) ){
146
        return true;
147
      }
148
    }
149
  }
150
4
  return false;
151
}
152
153
24
bool TermDbSygus::hasFreeVar( Node n ) {
154
48
  std::map< Node, bool > visited;
155
48
  return hasFreeVar( n, visited );
156
}
157
158
47
Node TermDbSygus::getProxyVariable(TypeNode tn, Node c)
159
{
160
47
  Assert(tn.isDatatype());
161
47
  Assert(tn.getDType().isSygus());
162
47
  Assert(tn.getDType().getSygusType().isComparableTo(c.getType()));
163
164
47
  std::map<Node, Node>::iterator it = d_proxy_vars[tn].find(c);
165
47
  if (it == d_proxy_vars[tn].end())
166
  {
167
40
    SygusTypeInfo& ti = getTypeInfo(tn);
168
40
    int anyC = ti.getAnyConstantConsNum();
169
40
    NodeManager* nm = NodeManager::currentNM();
170
80
    Node k;
171
40
    if (anyC == -1)
172
    {
173
      SkolemManager* sm = nm->getSkolemManager();
174
      k = sm->mkDummySkolem("sy", tn, "sygus proxy");
175
      SygusPrintProxyAttribute spa;
176
      k.setAttribute(spa, c);
177
    }
178
    else
179
    {
180
40
      const DType& dt = tn.getDType();
181
40
      k = nm->mkNode(APPLY_CONSTRUCTOR, dt[anyC].getConstructor(), c);
182
    }
183
40
    d_proxy_vars[tn][c] = k;
184
40
    return k;
185
  }
186
7
  return it->second;
187
}
188
189
587518
Node TermDbSygus::mkGeneric(const DType& dt,
190
                            unsigned c,
191
                            std::map<TypeNode, int>& var_count,
192
                            std::map<int, Node>& pre,
193
                            bool doBetaRed)
194
{
195
587518
  Assert(c < dt.getNumConstructors());
196
587518
  Assert(dt.isSygus());
197
587518
  Assert(!dt[c].getSygusOp().isNull());
198
1175036
  std::vector< Node > children;
199
1175036
  Trace("sygus-db-debug") << "mkGeneric " << dt.getName() << " " << c << "..."
200
587518
                          << std::endl;
201
1377126
  for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
202
  {
203
1579216
    Node a;
204
789608
    std::map< int, Node >::iterator it = pre.find( i );
205
789608
    if( it!=pre.end() ){
206
766704
      a = it->second;
207
766704
      Trace("sygus-db-debug") << "From pre: " << a << std::endl;
208
    }else{
209
45808
      TypeNode tna = dt[c].getArgType(i);
210
22904
      a = getFreeVarInc( tna, var_count, true );
211
    }
212
1579216
    Trace("sygus-db-debug")
213
789608
        << "  child " << i << " : " << a << " : " << a.getType() << std::endl;
214
789608
    Assert(!a.isNull());
215
789608
    children.push_back( a );
216
  }
217
587518
  Node ret = datatypes::utils::mkSygusTerm(dt, c, children, doBetaRed);
218
587518
  Trace("sygus-db-debug") << "mkGeneric returns " << ret << std::endl;
219
1175036
  return ret;
220
}
221
222
587518
Node TermDbSygus::mkGeneric(const DType& dt,
223
                            int c,
224
                            std::map<int, Node>& pre,
225
                            bool doBetaRed)
226
{
227
1175036
  std::map<TypeNode, int> var_count;
228
1175036
  return mkGeneric(dt, c, var_count, pre, doBetaRed);
229
}
230
231
18243
Node TermDbSygus::mkGeneric(const DType& dt, int c, bool doBetaRed)
232
{
233
36486
  std::map<int, Node> pre;
234
36486
  return mkGeneric(dt, c, pre, doBetaRed);
235
}
236
237
struct CanonizeBuiltinAttributeId
238
{
239
};
240
using CanonizeBuiltinAttribute =
241
    expr::Attribute<CanonizeBuiltinAttributeId, Node>;
242
243
Node TermDbSygus::canonizeBuiltin(Node n)
244
{
245
  std::map<TypeNode, int> var_count;
246
  return canonizeBuiltin(n, var_count);
247
}
248
249
88104
Node TermDbSygus::canonizeBuiltin(Node n, std::map<TypeNode, int>& var_count)
250
{
251
  // has it already been computed?
252
88104
  if (var_count.empty() && n.hasAttribute(CanonizeBuiltinAttribute()))
253
  {
254
144104
    Node ret = n.getAttribute(CanonizeBuiltinAttribute());
255
72052
    Trace("sygus-db-canon") << "cached " << n << " : " << ret << "\n";
256
72052
    return ret;
257
  }
258
16052
  Trace("sygus-db-canon") << "  CanonizeBuiltin : compute for " << n << "\n";
259
32104
  Node ret = n;
260
  // it is symbolic if it represents "any constant"
261
16052
  if (n.getKind() == APPLY_SELECTOR_TOTAL)
262
  {
263
1858
    ret = getFreeVarInc(n[0].getType(), var_count, true);
264
  }
265
14194
  else if (n.getKind() != APPLY_CONSTRUCTOR)
266
  {
267
    ret = n;
268
  }
269
  else
270
  {
271
14194
    Assert(n.getKind() == APPLY_CONSTRUCTOR);
272
14194
    bool childChanged = false;
273
28388
    std::vector<Node> children;
274
14194
    children.push_back(n.getOperator());
275
37398
    for (unsigned j = 0, size = n.getNumChildren(); j < size; ++j)
276
    {
277
46408
      Node child = canonizeBuiltin(n[j], var_count);
278
23204
      children.push_back(child);
279
23204
      childChanged = childChanged || child != n[j];
280
    }
281
14194
    if (childChanged)
282
    {
283
2691
      ret = NodeManager::currentNM()->mkNode(APPLY_CONSTRUCTOR, children);
284
    }
285
  }
286
  // cache if we had a fresh variable count
287
16052
  if (var_count.empty())
288
  {
289
11283
    n.setAttribute(CanonizeBuiltinAttribute(), ret);
290
  }
291
32104
  Trace("sygus-db-canon") << "  ...normalized " << n << " --> " << ret
292
16052
                          << std::endl;
293
16052
  Assert(ret.getType().isComparableTo(n.getType()));
294
16052
  return ret;
295
}
296
297
struct SygusToBuiltinAttributeId
298
{
299
};
300
typedef expr::Attribute<SygusToBuiltinAttributeId, Node>
301
    SygusToBuiltinAttribute;
302
303
88093
Node TermDbSygus::sygusToBuiltin(Node n, TypeNode tn)
304
{
305
88093
  if (n.isConst())
306
  {
307
    // if its a constant, we use the datatype utility version
308
58893
    return datatypes::utils::sygusToBuiltin(n);
309
  }
310
29200
  Assert(n.getType().isComparableTo(tn));
311
29200
  if (!tn.isDatatype())
312
  {
313
143
    return n;
314
  }
315
  // has it already been computed?
316
29057
  if (n.hasAttribute(SygusToBuiltinAttribute()))
317
  {
318
12105
    return n.getAttribute(SygusToBuiltinAttribute());
319
  }
320
33904
  Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n
321
16952
                          << ", type = " << tn << std::endl;
322
16952
  const DType& dt = tn.getDType();
323
16952
  if (!dt.isSygus())
324
  {
325
    return n;
326
  }
327
16952
  if (n.getKind() == APPLY_CONSTRUCTOR)
328
  {
329
11235
    unsigned i = datatypes::utils::indexOf(n.getOperator());
330
11235
    Assert(n.getNumChildren() == dt[i].getNumArgs());
331
22470
    std::map<int, Node> pre;
332
34039
    for (unsigned j = 0, size = n.getNumChildren(); j < size; j++)
333
    {
334
22804
      pre[j] = sygusToBuiltin(n[j], dt[i].getArgType(j));
335
45608
      Trace("sygus-db-debug")
336
22804
          << "sygus to builtin " << n[j] << " is " << pre[j] << std::endl;
337
    }
338
22470
    Node ret = mkGeneric(dt, i, pre);
339
22470
    Trace("sygus-db-debug")
340
11235
        << "SygusToBuiltin : Generic is " << ret << std::endl;
341
    // cache
342
11235
    n.setAttribute(SygusToBuiltinAttribute(), ret);
343
11235
    return ret;
344
  }
345
5717
  if (n.hasAttribute(SygusPrintProxyAttribute()))
346
  {
347
    // this variable was associated by an attribute to a builtin node
348
    return n.getAttribute(SygusPrintProxyAttribute());
349
  }
350
5717
  Assert(isFreeVar(n));
351
  // map to builtin variable type
352
5717
  size_t fv_num = getFreeVarId(n);
353
5717
  Assert(!dt.getSygusType().isNull());
354
11434
  TypeNode vtn = dt.getSygusType();
355
11434
  Node ret = getFreeVar(vtn, fv_num);
356
11434
  Trace("sygus-db-debug") << "SygusToBuiltin: variable for " << n << " is "
357
5717
                          << ret << ", fv_num=" << fv_num << std::endl;
358
5717
  return ret;
359
}
360
361
21753
bool TermDbSygus::registerSygusType(TypeNode tn)
362
{
363
21753
  std::map<TypeNode, bool>::iterator it = d_registerStatus.find(tn);
364
21753
  if (it != d_registerStatus.end())
365
  {
366
    // already registered
367
18691
    return it->second;
368
  }
369
3062
  d_registerStatus[tn] = false;
370
  // it must be a sygus datatype
371
3062
  if (!tn.isDatatype())
372
  {
373
55
    return false;
374
  }
375
3007
  const DType& dt = tn.getDType();
376
3007
  if (!dt.isSygus())
377
  {
378
    return false;
379
  }
380
3007
  d_registerStatus[tn] = true;
381
3007
  SygusTypeInfo& sti = d_tinfo[tn];
382
3007
  sti.initialize(this, tn);
383
3007
  return true;
384
}
385
386
688
void TermDbSygus::registerEnumerator(Node e,
387
                                     Node f,
388
                                     SynthConjecture* conj,
389
                                     EnumeratorRole erole)
390
{
391
688
  if (d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end())
392
  {
393
    // already registered
394
    return;
395
  }
396
688
  Trace("sygus-db") << "Register enumerator : " << e << std::endl;
397
  // register its type
398
1376
  TypeNode et = e.getType();
399
688
  registerSygusType(et);
400
688
  d_enum_to_conjecture[e] = conj;
401
688
  d_enum_to_synth_fun[e] = f;
402
688
  NodeManager* nm = NodeManager::currentNM();
403
404
1376
  Trace("sygus-db") << "  registering symmetry breaking clauses..."
405
688
                    << std::endl;
406
  // depending on if we are using symbolic constructors, introduce symmetry
407
  // breaking lemma templates for each relevant subtype of the grammar
408
688
  SygusTypeInfo& eti = getTypeInfo(et);
409
1376
  std::vector<TypeNode> sf_types;
410
688
  eti.getSubfieldTypes(sf_types);
411
  // for each type of subfield type of this enumerator
412
2144
  for (unsigned i = 0, ntypes = sf_types.size(); i < ntypes; i++)
413
  {
414
2912
    std::vector<unsigned> rm_indices;
415
2912
    TypeNode stn = sf_types[i];
416
1456
    Assert(stn.isDatatype());
417
1456
    SygusTypeInfo& sti = getTypeInfo(stn);
418
1456
    const DType& dt = stn.getDType();
419
1456
    int anyC = sti.getAnyConstantConsNum();
420
10527
    for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
421
    {
422
9071
      bool isAnyC = static_cast<int>(j) == anyC;
423
9071
      if (anyC != -1 && !isAnyC)
424
      {
425
        // if we are using the any constant constructor, do not use any
426
        // concrete constant
427
562
        Node c_op = sti.getConsNumConst(j);
428
281
        if (!c_op.isNull())
429
        {
430
61
          rm_indices.push_back(j);
431
        }
432
      }
433
    }
434
1517
    for (unsigned& rindex : rm_indices)
435
    {
436
      // make the apply-constructor corresponding to an application of the
437
      // constant or "any constant" constructor
438
      // we call getInstCons since in the case of any constant constructors, it
439
      // is necessary to generate a term of the form any_constant( x.0 ) for a
440
      // fresh variable x.0.
441
122
      Node fv = getFreeVar(stn, 0);
442
122
      Node exc_val = datatypes::utils::getInstCons(fv, dt, rindex);
443
      // should not include the constuctor in any subterm
444
122
      Node x = getFreeVar(stn, 0);
445
122
      Trace("sygus-db") << "Construct symmetry breaking lemma from " << x
446
61
                        << " == " << exc_val << std::endl;
447
122
      Node lem = getExplain()->getExplanationForEquality(x, exc_val);
448
61
      lem = lem.negate();
449
122
      Trace("cegqi-lemma")
450
61
          << "Cegqi::Lemma : exclude symbolic cons lemma (template) : " << lem
451
61
          << std::endl;
452
      // the size of the subterm we are blocking is the weight of the
453
      // constructor (usually zero)
454
61
      registerSymBreakLemma(e, lem, stn, dt[rindex].getWeight());
455
    }
456
  }
457
688
  Trace("sygus-db") << "  ...finished" << std::endl;
458
459
  // determine if we are actively-generated
460
688
  bool isActiveGen = false;
461
688
  if (options::sygusActiveGenMode() != options::SygusActiveGenMode::NONE)
462
  {
463
680
    if (erole == ROLE_ENUM_MULTI_SOLUTION || erole == ROLE_ENUM_CONSTRAINED)
464
    {
465
      // If the enumerator is a solution for a conjecture with multiple
466
      // functions, we do not use active generation. If we did, we would have to
467
      // generate a "product" of two actively-generated enumerators. That is,
468
      // given a conjecture with two functions-to-synthesize with enumerators
469
      // e_f and e_g, and if these enumerators generated:
470
      // e_f -> t1, ..., tn
471
      // e_g -> s1, ..., sm
472
      // The sygus module in charge of this conjecture would expect
473
      // constructCandidates calls of the form
474
      //   (e_f,e_g) -> (ti, sj)
475
      // for each i,j. We instead use passive enumeration in this case.
476
      //
477
      // If the enumerator is constrained, it cannot be actively generated.
478
    }
479
376
    else if (erole == ROLE_ENUM_POOL)
480
    {
481
      // If the enumerator is used for generating a pool of values, we always
482
      // use active generation.
483
110
      isActiveGen = true;
484
    }
485
266
    else if (erole == ROLE_ENUM_SINGLE_SOLUTION)
486
    {
487
      // If the enumerator is the single function-to-synthesize, if auto is
488
      // enabled, we infer whether it is better to enable active generation.
489
266
      if (options::sygusActiveGenMode() == options::SygusActiveGenMode::AUTO)
490
      {
491
        // We use active generation if the grammar of the enumerator does not
492
        // have ITE and does not have Boolean connectives. Experimentally, it
493
        // is better to use passive generation for these cases since it enables
494
        // useful search space pruning techniques, e.g. evaluation unfolding,
495
        // conjecture-specific symmetry breaking. Also, if sygus-stream is
496
        // enabled, we always use active generation, since the use cases of
497
        // sygus stream are to find many solutions to an easy problem, where
498
        // the bottleneck often becomes the large number of "exclude the current
499
        // solution" clauses.
500
508
        if (options::sygusStream()
501
254
            || (!eti.hasIte() && !eti.hasBoolConnective()))
502
        {
503
86
          isActiveGen = true;
504
        }
505
      }
506
      else
507
      {
508
12
        isActiveGen = true;
509
      }
510
    }
511
    else
512
    {
513
      Unreachable() << "Unknown enumerator mode in registerEnumerator";
514
    }
515
  }
516
1376
  Trace("sygus-db") << "isActiveGen for " << e << ", role = " << erole
517
688
                    << " returned " << isActiveGen << std::endl;
518
  // Currently, actively-generated enumerators are either basic or variable
519
  // agnostic.
520
  bool isVarAgnostic = isActiveGen
521
688
                       && options::sygusActiveGenMode()
522
688
                              == options::SygusActiveGenMode::VAR_AGNOSTIC;
523
688
  d_enum_var_agnostic[e] = isVarAgnostic;
524
688
  if (isVarAgnostic)
525
  {
526
    // requires variable subclasses
527
2
    eti.initializeVarSubclasses();
528
    // If no subclass has more than one variable, do not use variable agnostic
529
    // enumeration
530
2
    bool useVarAgnostic = !eti.isSubclassVarTrivial();
531
2
    if (!useVarAgnostic)
532
    {
533
      Trace("sygus-db")
534
          << "...disabling variable agnostic for " << e
535
          << " since it has no subclass with more than one variable."
536
          << std::endl;
537
      d_enum_var_agnostic[e] = false;
538
      isActiveGen = false;
539
    }
540
  }
541
688
  d_enum_active_gen[e] = isActiveGen;
542
688
  d_enum_basic[e] = isActiveGen && !isVarAgnostic;
543
544
  // We make an active guard if we will be explicitly blocking solutions for
545
  // the enumerator. This is the case if the role of the enumerator is to
546
  // populate a pool of terms, or (some cases) of when it is actively generated.
547
688
  if (isActiveGen || erole == ROLE_ENUM_POOL)
548
  {
549
212
    SkolemManager* sm = nm->getSkolemManager();
550
    // make the guard
551
424
    Node ag = sm->mkDummySkolem("eG", nm->booleanType());
552
    // must ensure it is a literal immediately here
553
212
    ag = d_qstate.getValuation().ensureLiteral(ag);
554
    // must ensure that it is asserted as a literal before we begin solving
555
424
    Node lem = nm->mkNode(OR, ag, ag.negate());
556
212
    d_qim->requirePhase(ag, true);
557
212
    d_qim->lemma(lem, InferenceId::QUANTIFIERS_SYGUS_ENUM_ACTIVE_GUARD_SPLIT);
558
212
    d_enum_to_active_guard[e] = ag;
559
  }
560
}
561
562
71299
bool TermDbSygus::isEnumerator(Node e) const
563
{
564
71299
  return d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end();
565
}
566
567
657
SynthConjecture* TermDbSygus::getConjectureForEnumerator(Node e) const
568
{
569
  std::map<Node, SynthConjecture*>::const_iterator itm =
570
657
      d_enum_to_conjecture.find(e);
571
657
  if (itm != d_enum_to_conjecture.end()) {
572
657
    return itm->second;
573
  }
574
  return nullptr;
575
}
576
577
573
Node TermDbSygus::getSynthFunForEnumerator(Node e) const
578
{
579
573
  std::map<Node, Node>::const_iterator itsf = d_enum_to_synth_fun.find(e);
580
573
  if (itsf != d_enum_to_synth_fun.end())
581
  {
582
527
    return itsf->second;
583
  }
584
46
  return Node::null();
585
}
586
587
67953
Node TermDbSygus::getActiveGuardForEnumerator(Node e) const
588
{
589
67953
  std::map<Node, Node>::const_iterator itag = d_enum_to_active_guard.find(e);
590
67953
  if (itag != d_enum_to_active_guard.end()) {
591
51408
    return itag->second;
592
  }
593
16545
  return Node::null();
594
}
595
596
10036
bool TermDbSygus::usingSymbolicConsForEnumerator(Node e) const
597
{
598
10036
  std::map<Node, bool>::const_iterator itus = d_enum_to_using_sym_cons.find(e);
599
10036
  if (itus != d_enum_to_using_sym_cons.end())
600
  {
601
    return itus->second;
602
  }
603
10036
  return false;
604
}
605
606
26907
bool TermDbSygus::isVariableAgnosticEnumerator(Node e) const
607
{
608
26907
  std::map<Node, bool>::const_iterator itus = d_enum_var_agnostic.find(e);
609
26907
  if (itus != d_enum_var_agnostic.end())
610
  {
611
26907
    return itus->second;
612
  }
613
  return false;
614
}
615
616
448
bool TermDbSygus::isBasicEnumerator(Node e) const
617
{
618
448
  std::map<Node, bool>::const_iterator itus = d_enum_basic.find(e);
619
448
  if (itus != d_enum_basic.end())
620
  {
621
448
    return itus->second;
622
  }
623
  return false;
624
}
625
626
85659
bool TermDbSygus::isPassiveEnumerator(Node e) const
627
{
628
85659
  std::map<Node, bool>::const_iterator itus = d_enum_active_gen.find(e);
629
85659
  if (itus != d_enum_active_gen.end())
630
  {
631
84233
    return !itus->second;
632
  }
633
1426
  return true;
634
}
635
636
11914
void TermDbSygus::getEnumerators(std::vector<Node>& mts)
637
{
638
16780
  for (std::map<Node, SynthConjecture*>::iterator itm =
639
11914
           d_enum_to_conjecture.begin();
640
28694
       itm != d_enum_to_conjecture.end();
641
       ++itm)
642
  {
643
16780
    mts.push_back( itm->first );
644
  }
645
11914
}
646
647
124
void TermDbSygus::registerSymBreakLemma(
648
    Node e, Node lem, TypeNode tn, unsigned sz, bool isTempl)
649
{
650
124
  d_enum_to_sb_lemmas[e].push_back(lem);
651
124
  d_sb_lemma_to_type[lem] = tn;
652
124
  d_sb_lemma_to_size[lem] = sz;
653
124
  d_sb_lemma_to_isTempl[lem] = isTempl;
654
124
}
655
656
11914
bool TermDbSygus::hasSymBreakLemmas(std::vector<Node>& enums) const
657
{
658
11914
  if (!d_enum_to_sb_lemmas.empty())
659
  {
660
617
    for (std::pair<const Node, std::vector<Node> > sb : d_enum_to_sb_lemmas)
661
    {
662
319
      enums.push_back(sb.first);
663
    }
664
298
    return true;
665
  }
666
11616
  return false;
667
}
668
669
267
void TermDbSygus::getSymBreakLemmas(Node e, std::vector<Node>& lemmas) const
670
{
671
  std::map<Node, std::vector<Node> >::const_iterator itsb =
672
267
      d_enum_to_sb_lemmas.find(e);
673
267
  if (itsb != d_enum_to_sb_lemmas.end())
674
  {
675
86
    lemmas.insert(lemmas.end(), itsb->second.begin(), itsb->second.end());
676
  }
677
267
}
678
679
14
TypeNode TermDbSygus::getTypeForSymBreakLemma(Node lem) const
680
{
681
14
  std::map<Node, TypeNode>::const_iterator it = d_sb_lemma_to_type.find(lem);
682
14
  Assert(it != d_sb_lemma_to_type.end());
683
14
  return it->second;
684
}
685
14
unsigned TermDbSygus::getSizeForSymBreakLemma(Node lem) const
686
{
687
14
  std::map<Node, unsigned>::const_iterator it = d_sb_lemma_to_size.find(lem);
688
14
  Assert(it != d_sb_lemma_to_size.end());
689
14
  return it->second;
690
}
691
692
124
bool TermDbSygus::isSymBreakLemmaTemplate(Node lem) const
693
{
694
124
  std::map<Node, bool>::const_iterator it = d_sb_lemma_to_isTempl.find(lem);
695
124
  Assert(it != d_sb_lemma_to_isTempl.end());
696
124
  return it->second;
697
}
698
699
6
void TermDbSygus::clearSymBreakLemmas(Node e) { d_enum_to_sb_lemmas.erase(e); }
700
701
208881
bool TermDbSygus::isRegistered(TypeNode tn) const
702
{
703
208881
  return d_tinfo.find(tn) != d_tinfo.end();
704
}
705
706
11504
TypeNode TermDbSygus::sygusToBuiltinType( TypeNode tn ) {
707
11504
  std::map<TypeNode, SygusTypeInfo>::iterator it = d_tinfo.find(tn);
708
11504
  Assert(it != d_tinfo.end());
709
11504
  return it->second.getBuiltinType();
710
}
711
712
16401
void TermDbSygus::toStreamSygus(const char* c, Node n)
713
{
714
16401
  if (Trace.isOn(c))
715
  {
716
    std::stringstream ss;
717
    toStreamSygus(ss, n);
718
    Trace(c) << ss.str();
719
  }
720
16401
}
721
722
300
void TermDbSygus::toStreamSygus(std::ostream& out, Node n)
723
{
724
300
  if (n.isNull())
725
  {
726
    out << n;
727
    return;
728
  }
729
  // use external conversion
730
300
  out << datatypes::utils::sygusToBuiltin(n, true);
731
}
732
733
299211
SygusTypeInfo& TermDbSygus::getTypeInfo(TypeNode tn)
734
{
735
299211
  AlwaysAssert(d_tinfo.find(tn) != d_tinfo.end());
736
299211
  return d_tinfo[tn];
737
}
738
739
373136
Node TermDbSygus::rewriteNode(Node n) const
740
{
741
746272
  Node res;
742
373136
  if (options().quantifiers.sygusExtRew)
743
  {
744
373064
    res = extendedRewrite(n);
745
  }
746
  else
747
  {
748
72
    res = rewrite(n);
749
  }
750
373136
  if (res.isConst())
751
  {
752
    // constant, we are done
753
234573
    return res;
754
  }
755
138563
  if (options::sygusRecFun())
756
  {
757
137729
    if (d_funDefEval->hasDefinitions())
758
    {
759
      // If recursive functions are enabled, then we use the recursive function
760
      // evaluation utility.
761
2316
      Node fres = d_funDefEval->evaluateDefinitions(res);
762
1678
      if (!fres.isNull())
763
      {
764
1040
        return fres;
765
      }
766
      // It may have failed, in which case there are undefined symbols in res or
767
      // we reached the limit of evaluations. In this case, we revert to the
768
      // result of rewriting in the return statement below.
769
    }
770
  }
771
137523
  return res;
772
}
773
774
1816
unsigned TermDbSygus::getSelectorWeight(TypeNode tn, Node sel)
775
{
776
  std::map<TypeNode, std::map<Node, unsigned> >::iterator itsw =
777
1816
      d_sel_weight.find(tn);
778
1816
  if (itsw == d_sel_weight.end())
779
  {
780
361
    d_sel_weight[tn].clear();
781
361
    itsw = d_sel_weight.find(tn);
782
361
    const DType& dt = tn.getDType();
783
722
    Trace("sygus-db") << "Compute selector weights for " << dt.getName()
784
361
                      << std::endl;
785
2143
    for (unsigned i = 0, size = dt.getNumConstructors(); i < size; i++)
786
    {
787
1782
      unsigned cw = dt[i].getWeight();
788
3894
      for (unsigned j = 0, size2 = dt[i].getNumArgs(); j < size2; j++)
789
      {
790
4224
        Node csel = dt[i].getSelectorInternal(tn, j);
791
2112
        std::map<Node, unsigned>::iterator its = itsw->second.find(csel);
792
2112
        if (its == itsw->second.end() || cw < its->second)
793
        {
794
1230
          d_sel_weight[tn][csel] = cw;
795
1230
          Trace("sygus-db") << "  w(" << csel << ") <= " << cw << std::endl;
796
        }
797
      }
798
    }
799
  }
800
1816
  Assert(itsw->second.find(sel) != itsw->second.end());
801
1816
  return itsw->second[sel];
802
}
803
804
727785
TypeNode TermDbSygus::getArgType(const DTypeConstructor& c, unsigned i) const
805
{
806
727785
  Assert(i < c.getNumArgs());
807
727785
  return c.getArgType(i);
808
}
809
810
8
bool TermDbSygus::isTypeMatch(const DTypeConstructor& c1,
811
                              const DTypeConstructor& c2)
812
{
813
8
  if( c1.getNumArgs()!=c2.getNumArgs() ){
814
    return false;
815
  }else{
816
24
    for( unsigned i=0; i<c1.getNumArgs(); i++ ){
817
16
      if( getArgType( c1, i )!=getArgType( c2, i ) ){
818
        return false;
819
      }
820
    }
821
8
    return true;
822
  }
823
}
824
825
bool TermDbSygus::isSymbolicConsApp(Node n) const
826
{
827
  if (n.getKind() != APPLY_CONSTRUCTOR)
828
  {
829
    return false;
830
  }
831
  TypeNode tn = n.getType();
832
  Assert(tn.isDatatype());
833
  const DType& dt = tn.getDType();
834
  Assert(dt.isSygus());
835
  unsigned cindex = datatypes::utils::indexOf(n.getOperator());
836
  Node sygusOp = dt[cindex].getSygusOp();
837
  // it is symbolic if it represents "any constant"
838
  return sygusOp.getAttribute(SygusAnyConstAttribute());
839
}
840
841
3593
bool TermDbSygus::canConstructKind(TypeNode tn,
842
                                   Kind k,
843
                                   std::vector<TypeNode>& argts,
844
                                   bool aggr)
845
{
846
3593
  Assert(isRegistered(tn));
847
3593
  SygusTypeInfo& ti = getTypeInfo(tn);
848
3593
  int c = ti.getKindConsNum(k);
849
3593
  const DType& dt = tn.getDType();
850
3593
  if (c != -1)
851
  {
852
9802
    for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
853
    {
854
6538
      argts.push_back(dt[c].getArgType(i));
855
    }
856
3264
    return true;
857
  }
858
329
  if (!options::sygusSymBreakAgg())
859
  {
860
    return false;
861
  }
862
329
  if (sygusToBuiltinType(tn).isBoolean())
863
  {
864
323
    if (k == ITE)
865
    {
866
      // ite( b1, b2, b3 ) <---- and( or( ~b1, b2 ), or( b1, b3 ) )
867
288
      std::vector<TypeNode> conj_types;
868
252
      if (canConstructKind(tn, AND, conj_types, true) && conj_types.size() == 2)
869
      {
870
228
        bool success = true;
871
684
        std::vector<TypeNode> disj_types[2];
872
660
        for (unsigned cc = 0; cc < 2; cc++)
873
        {
874
1332
          if (!canConstructKind(conj_types[cc], OR, disj_types[cc], true)
875
1332
              || disj_types[cc].size() != 2)
876
          {
877
12
            success = false;
878
12
            break;
879
          }
880
        }
881
228
        if (success)
882
        {
883
216
          for (unsigned r = 0; r < 2; r++)
884
          {
885
216
            for (unsigned d = 0, size = disj_types[r].size(); d < size; d++)
886
            {
887
216
              TypeNode dtn = disj_types[r][d];
888
              // must have negation that occurs in the other conjunct
889
216
              std::vector<TypeNode> ntypes;
890
216
              if (canConstructKind(dtn, NOT, ntypes) && ntypes.size() == 1)
891
              {
892
216
                TypeNode ntn = ntypes[0];
893
216
                for (unsigned dd = 0, inner_size = disj_types[1 - r].size();
894
216
                     dd < inner_size;
895
                     dd++)
896
                {
897
216
                  if (disj_types[1 - r][dd] == ntn)
898
                  {
899
216
                    argts.push_back(ntn);
900
216
                    argts.push_back(disj_types[r][d]);
901
216
                    argts.push_back(disj_types[1 - r][1 - dd]);
902
216
                    if (Trace.isOn("sygus-cons-kind"))
903
                    {
904
                      Trace("sygus-cons-kind")
905
                          << "Can construct kind " << k << " in " << tn
906
                          << " via child types:" << std::endl;
907
                      for (unsigned i = 0; i < 3; i++)
908
                      {
909
                        Trace("sygus-cons-kind")
910
                            << "  " << argts[i] << std::endl;
911
                      }
912
                    }
913
216
                    return true;
914
                  }
915
                }
916
              }
917
            }
918
          }
919
        }
920
      }
921
    }
922
  }
923
  // could try aggressive inferences here, such as
924
  // (and b1 b2) <---- (not (or (not b1) (not b2)))
925
  // (or b1 b2)  <---- (not (and (not b1) (not b2)))
926
113
  return false;
927
}
928
929
41914
bool TermDbSygus::involvesDivByZero( Node n, std::map< Node, bool >& visited ){
930
41914
  if( visited.find( n )==visited.end() ){
931
39123
    visited[n] = true;
932
39123
    Kind k = n.getKind();
933
39123
    if( k==DIVISION || k==DIVISION_TOTAL || k==INTS_DIVISION || k==INTS_DIVISION_TOTAL ||
934
39123
        k==INTS_MODULUS || k==INTS_MODULUS_TOTAL ){
935
48
      if( n[1].isConst() ){
936
24
        if (n[1] == TermUtil::mkTypeValue(n[1].getType(), 0))
937
        {
938
          return true;
939
        }
940
      }else{
941
        // if it has free variables it might be a non-zero constant
942
24
        if( !hasFreeVar( n[1] ) ){
943
4
          return true;
944
        }
945
      }
946
    }
947
69171
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
948
30056
      if( involvesDivByZero( n[i], visited ) ){
949
4
        return true;
950
      }
951
    }
952
  }
953
41906
  return false;
954
}
955
956
11858
bool TermDbSygus::involvesDivByZero( Node n ) {
957
23716
  std::map< Node, bool > visited;
958
23716
  return involvesDivByZero( n, visited );
959
}
960
961
4874
Node TermDbSygus::getAnchor( Node n ) {
962
4874
  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
963
2352
    return getAnchor( n[0] );
964
  }else{
965
2522
    return n;
966
  }
967
}
968
969
unsigned TermDbSygus::getAnchorDepth( Node n ) {
970
  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
971
    return 1+getAnchorDepth( n[0] );
972
  }else{
973
    return 0;
974
  }
975
}
976
977
198760
Node TermDbSygus::evaluateBuiltin(TypeNode tn,
978
                                  Node bn,
979
                                  const std::vector<Node>& args,
980
                                  bool tryEval)
981
{
982
198760
  if (args.empty())
983
  {
984
476
    return rewrite(bn);
985
  }
986
198284
  Assert(isRegistered(tn));
987
198284
  SygusTypeInfo& ti = getTypeInfo(tn);
988
198284
  const std::vector<Node>& varlist = ti.getVarList();
989
198284
  Assert(varlist.size() == args.size());
990
991
396568
  Node res;
992
198284
  if (tryEval && options::sygusEvalOpt())
993
  {
994
    // Try evaluating, which is much faster than substitution+rewriting.
995
    // This may fail if there is a subterm of bn under the
996
    // substitution that is not constant, or if an operator in bn is not
997
    // supported by the evaluator
998
198284
    res = evaluate(bn, varlist, args);
999
  }
1000
198284
  if (res.isNull())
1001
  {
1002
    // must do substitution
1003
    res =
1004
        bn.substitute(varlist.begin(), varlist.end(), args.begin(), args.end());
1005
  }
1006
  // Call the rewrite node function, which may involve recursive function
1007
  // evaluation.
1008
198284
  return rewriteNode(res);
1009
}
1010
1011
1009
bool TermDbSygus::isEvaluationPoint(Node n) const
1012
{
1013
1009
  if (n.getKind() != DT_SYGUS_EVAL)
1014
  {
1015
464
    return false;
1016
  }
1017
545
  if (!n[0].isVar())
1018
  {
1019
    return false;
1020
  }
1021
2057
  for (unsigned i = 1, nchild = n.getNumChildren(); i < nchild; i++)
1022
  {
1023
1532
    if (!n[i].isConst())
1024
    {
1025
20
      return false;
1026
    }
1027
  }
1028
525
  return true;
1029
}
1030
1031
}  // namespace quantifiers
1032
}  // namespace theory
1033
31137
}  // namespace cvc5