GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/term_database_sygus.cpp Lines: 468 543 86.2 %
Date: 2021-08-06 Branches: 852 2009 42.4 %

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