GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/term_database_sygus.cpp Lines: 446 515 86.6 %
Date: 2021-09-29 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
1193
TermDbSygus::TermDbSygus(Env& env, QuantifiersState& qs)
55
    : EnvObj(env),
56
      d_qstate(qs),
57
1193
      d_syexp(new SygusExplain(this)),
58
1193
      d_funDefEval(new FunDefEvaluator(env)),
59
3579
      d_eval_unfold(new SygusEvalUnfold(this))
60
{
61
1193
  d_true = NodeManager::currentNM()->mkConst( true );
62
1193
  d_false = NodeManager::currentNM()->mkConst( false );
63
1193
}
64
65
1193
void TermDbSygus::finishInit(QuantifiersInferenceManager* qim) { d_qim = qim; }
66
67
bool TermDbSygus::reset( Theory::Effort e ) {
68
  return true;
69
}
70
71
135062
TNode TermDbSygus::getFreeVar( TypeNode tn, int i, bool useSygusType ) {
72
135062
  unsigned sindex = 0;
73
270124
  TypeNode vtn = tn;
74
270124
  TypeNode builtinType = tn;
75
135062
  if (tn.isDatatype())
76
  {
77
132373
    const DType& dt = tn.getDType();
78
132373
    if (!dt.getSygusType().isNull())
79
    {
80
132373
      builtinType = dt.getSygusType();
81
132373
      if (useSygusType)
82
      {
83
14980
        vtn = builtinType;
84
14980
        sindex = 1;
85
      }
86
    }
87
  }
88
135062
  NodeManager* nm = NodeManager::currentNM();
89
148470
  while( i>=(int)d_fv[sindex][tn].size() ){
90
13408
    std::stringstream ss;
91
6704
    if( tn.isDatatype() ){
92
3901
      const DType& dt = tn.getDType();
93
3901
      ss << "fv_" << dt.getName() << "_" << i;
94
    }else{
95
2803
      ss << "fv_" << tn << "_" << i;
96
    }
97
6704
    Assert(!vtn.isNull());
98
13408
    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
6704
    d_fvId[v] = d_fvTypeIdCounter[builtinType];
102
6704
    d_fvTypeIdCounter[builtinType]++;
103
13408
    Trace("sygus-db-debug") << "Free variable id " << v << " = " << d_fvId[v]
104
6704
                            << ", " << builtinType << std::endl;
105
6704
    d_fv[sindex][tn].push_back( v );
106
  }
107
270124
  return d_fv[sindex][tn][i];
108
}
109
110
73370
TNode TermDbSygus::getFreeVarInc( TypeNode tn, std::map< TypeNode, int >& var_count, bool useSygusType ) {
111
73370
  std::map< TypeNode, int >::iterator it = var_count.find( tn );
112
73370
  if( it==var_count.end() ){
113
29184
    var_count[tn] = 1;
114
29184
    return getFreeVar( tn, 0, useSygusType );
115
  }else{
116
44186
    int index = it->second;
117
44186
    var_count[tn]++;
118
44186
    return getFreeVar( tn, index, useSygusType );
119
  }
120
}
121
122
2526
bool TermDbSygus::isFreeVar(Node n) const
123
{
124
2526
  return d_fvId.find(n) != d_fvId.end();
125
}
126
2514
size_t TermDbSygus::getFreeVarId(Node n) const
127
{
128
2514
  std::map<Node, size_t>::const_iterator it = d_fvId.find(n);
129
2514
  if (it == d_fvId.end())
130
  {
131
    Assert(false) << "TermDbSygus::isFreeVar: " << n
132
                  << " is not a cached free variable.";
133
    return 0;
134
  }
135
2514
  return it->second;
136
}
137
138
12
bool TermDbSygus::hasFreeVar( Node n, std::map< Node, bool >& visited ){
139
12
  if( visited.find( n )==visited.end() ){
140
12
    visited[n] = true;
141
12
    if( isFreeVar( n ) ){
142
10
      return true;
143
    }
144
2
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
145
      if( hasFreeVar( n[i], visited ) ){
146
        return true;
147
      }
148
    }
149
  }
150
2
  return false;
151
}
152
153
12
bool TermDbSygus::hasFreeVar( Node n ) {
154
24
  std::map< Node, bool > visited;
155
24
  return hasFreeVar( n, visited );
156
}
157
158
21
Node TermDbSygus::getProxyVariable(TypeNode tn, Node c)
159
{
160
21
  Assert(tn.isDatatype());
161
21
  Assert(tn.getDType().isSygus());
162
21
  Assert(tn.getDType().getSygusType().isComparableTo(c.getType()));
163
164
21
  std::map<Node, Node>::iterator it = d_proxy_vars[tn].find(c);
165
21
  if (it == d_proxy_vars[tn].end())
166
  {
167
16
    SygusTypeInfo& ti = getTypeInfo(tn);
168
16
    int anyC = ti.getAnyConstantConsNum();
169
16
    NodeManager* nm = NodeManager::currentNM();
170
32
    Node k;
171
16
    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
16
      const DType& dt = tn.getDType();
181
16
      k = nm->mkNode(APPLY_CONSTRUCTOR, dt[anyC].getConstructor(), c);
182
    }
183
16
    d_proxy_vars[tn][c] = k;
184
16
    return k;
185
  }
186
5
  return it->second;
187
}
188
189
390062
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
390062
  Assert(c < dt.getNumConstructors());
196
390062
  Assert(dt.isSygus());
197
390062
  Assert(!dt[c].getSygusOp().isNull());
198
780124
  std::vector< Node > children;
199
780124
  Trace("sygus-db-debug") << "mkGeneric " << dt.getName() << " " << c << "..."
200
390062
                          << std::endl;
201
868081
  for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
202
  {
203
956038
    Node a;
204
478019
    std::map< int, Node >::iterator it = pre.find( i );
205
478019
    if( it!=pre.end() ){
206
464115
      a = it->second;
207
464115
      Trace("sygus-db-debug") << "From pre: " << a << std::endl;
208
    }else{
209
27808
      TypeNode tna = dt[c].getArgType(i);
210
13904
      a = getFreeVarInc( tna, var_count, true );
211
    }
212
956038
    Trace("sygus-db-debug")
213
478019
        << "  child " << i << " : " << a << " : " << a.getType() << std::endl;
214
478019
    Assert(!a.isNull());
215
478019
    children.push_back( a );
216
  }
217
390062
  Node ret = datatypes::utils::mkSygusTerm(dt, c, children, doBetaRed);
218
390062
  Trace("sygus-db-debug") << "mkGeneric returns " << ret << std::endl;
219
780124
  return ret;
220
}
221
222
390062
Node TermDbSygus::mkGeneric(const DType& dt,
223
                            int c,
224
                            std::map<int, Node>& pre,
225
                            bool doBetaRed)
226
{
227
780124
  std::map<TypeNode, int> var_count;
228
780124
  return mkGeneric(dt, c, var_count, pre, doBetaRed);
229
}
230
231
10527
Node TermDbSygus::mkGeneric(const DType& dt, int c, bool doBetaRed)
232
{
233
21054
  std::map<int, Node> pre;
234
21054
  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
36795
Node TermDbSygus::canonizeBuiltin(Node n, std::map<TypeNode, int>& var_count)
250
{
251
  // has it already been computed?
252
36795
  if (var_count.empty() && n.hasAttribute(CanonizeBuiltinAttribute()))
253
  {
254
58906
    Node ret = n.getAttribute(CanonizeBuiltinAttribute());
255
29453
    Trace("sygus-db-canon") << "cached " << n << " : " << ret << "\n";
256
29453
    return ret;
257
  }
258
7342
  Trace("sygus-db-canon") << "  CanonizeBuiltin : compute for " << n << "\n";
259
14684
  Node ret = n;
260
  // it is symbolic if it represents "any constant"
261
7342
  if (n.getKind() == APPLY_SELECTOR_TOTAL)
262
  {
263
1120
    ret = getFreeVarInc(n[0].getType(), var_count, true);
264
  }
265
6222
  else if (n.getKind() != APPLY_CONSTRUCTOR)
266
  {
267
    ret = n;
268
  }
269
  else
270
  {
271
6222
    Assert(n.getKind() == APPLY_CONSTRUCTOR);
272
6222
    bool childChanged = false;
273
12444
    std::vector<Node> children;
274
6222
    children.push_back(n.getOperator());
275
15941
    for (unsigned j = 0, size = n.getNumChildren(); j < size; ++j)
276
    {
277
19438
      Node child = canonizeBuiltin(n[j], var_count);
278
9719
      children.push_back(child);
279
9719
      childChanged = childChanged || child != n[j];
280
    }
281
6222
    if (childChanged)
282
    {
283
1637
      ret = NodeManager::currentNM()->mkNode(APPLY_CONSTRUCTOR, children);
284
    }
285
  }
286
  // cache if we had a fresh variable count
287
7342
  if (var_count.empty())
288
  {
289
4457
    n.setAttribute(CanonizeBuiltinAttribute(), ret);
290
  }
291
14684
  Trace("sygus-db-canon") << "  ...normalized " << n << " --> " << ret
292
7342
                          << std::endl;
293
7342
  Assert(ret.getType().isComparableTo(n.getType()));
294
7342
  return ret;
295
}
296
297
struct SygusToBuiltinAttributeId
298
{
299
};
300
typedef expr::Attribute<SygusToBuiltinAttributeId, Node>
301
    SygusToBuiltinAttribute;
302
303
38525
Node TermDbSygus::sygusToBuiltin(Node n, TypeNode tn)
304
{
305
38525
  if (n.isConst())
306
  {
307
    // if its a constant, we use the datatype utility version
308
27363
    return datatypes::utils::sygusToBuiltin(n);
309
  }
310
11162
  Assert(n.getType().isComparableTo(tn));
311
11162
  if (!tn.isDatatype())
312
  {
313
79
    return n;
314
  }
315
  // has it already been computed?
316
11083
  if (n.hasAttribute(SygusToBuiltinAttribute()))
317
  {
318
4090
    return n.getAttribute(SygusToBuiltinAttribute());
319
  }
320
13986
  Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n
321
6993
                          << ", type = " << tn << std::endl;
322
6993
  const DType& dt = tn.getDType();
323
6993
  if (!dt.isSygus())
324
  {
325
    return n;
326
  }
327
6993
  if (n.getKind() == APPLY_CONSTRUCTOR)
328
  {
329
4479
    unsigned i = datatypes::utils::indexOf(n.getOperator());
330
4479
    Assert(n.getNumChildren() == dt[i].getNumArgs());
331
8958
    std::map<int, Node> pre;
332
13724
    for (unsigned j = 0, size = n.getNumChildren(); j < size; j++)
333
    {
334
9245
      pre[j] = sygusToBuiltin(n[j], dt[i].getArgType(j));
335
18490
      Trace("sygus-db-debug")
336
9245
          << "sygus to builtin " << n[j] << " is " << pre[j] << std::endl;
337
    }
338
8958
    Node ret = mkGeneric(dt, i, pre);
339
8958
    Trace("sygus-db-debug")
340
4479
        << "SygusToBuiltin : Generic is " << ret << std::endl;
341
    // cache
342
4479
    n.setAttribute(SygusToBuiltinAttribute(), ret);
343
4479
    return ret;
344
  }
345
2514
  if (n.hasAttribute(SygusPrintProxyAttribute()))
346
  {
347
    // this variable was associated by an attribute to a builtin node
348
    return n.getAttribute(SygusPrintProxyAttribute());
349
  }
350
2514
  Assert(isFreeVar(n));
351
  // map to builtin variable type
352
2514
  size_t fv_num = getFreeVarId(n);
353
2514
  Assert(!dt.getSygusType().isNull());
354
5028
  TypeNode vtn = dt.getSygusType();
355
5028
  Node ret = getFreeVar(vtn, fv_num);
356
5028
  Trace("sygus-db-debug") << "SygusToBuiltin: variable for " << n << " is "
357
2514
                          << ret << ", fv_num=" << fv_num << std::endl;
358
2514
  return ret;
359
}
360
361
13068
bool TermDbSygus::registerSygusType(TypeNode tn)
362
{
363
13068
  std::map<TypeNode, bool>::iterator it = d_registerStatus.find(tn);
364
13068
  if (it != d_registerStatus.end())
365
  {
366
    // already registered
367
11290
    return it->second;
368
  }
369
1778
  d_registerStatus[tn] = false;
370
  // it must be a sygus datatype
371
1778
  if (!tn.isDatatype())
372
  {
373
36
    return false;
374
  }
375
1742
  const DType& dt = tn.getDType();
376
1742
  if (!dt.isSygus())
377
  {
378
    return false;
379
  }
380
1742
  d_registerStatus[tn] = true;
381
1742
  SygusTypeInfo& sti = d_tinfo[tn];
382
1742
  sti.initialize(this, tn);
383
1742
  return true;
384
}
385
386
384
void TermDbSygus::registerEnumerator(Node e,
387
                                     Node f,
388
                                     SynthConjecture* conj,
389
                                     EnumeratorRole erole)
390
{
391
384
  if (d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end())
392
  {
393
    // already registered
394
    return;
395
  }
396
384
  Trace("sygus-db") << "Register enumerator : " << e << std::endl;
397
  // register its type
398
768
  TypeNode et = e.getType();
399
384
  registerSygusType(et);
400
384
  d_enum_to_conjecture[e] = conj;
401
384
  d_enum_to_synth_fun[e] = f;
402
384
  NodeManager* nm = NodeManager::currentNM();
403
404
768
  Trace("sygus-db") << "  registering symmetry breaking clauses..."
405
384
                    << 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
384
  SygusTypeInfo& eti = getTypeInfo(et);
409
768
  std::vector<TypeNode> sf_types;
410
384
  eti.getSubfieldTypes(sf_types);
411
  // for each type of subfield type of this enumerator
412
1213
  for (unsigned i = 0, ntypes = sf_types.size(); i < ntypes; i++)
413
  {
414
1658
    std::vector<unsigned> rm_indices;
415
1658
    TypeNode stn = sf_types[i];
416
829
    Assert(stn.isDatatype());
417
829
    SygusTypeInfo& sti = getTypeInfo(stn);
418
829
    const DType& dt = stn.getDType();
419
829
    int anyC = sti.getAnyConstantConsNum();
420
5972
    for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
421
    {
422
5143
      bool isAnyC = static_cast<int>(j) == anyC;
423
5143
      if (anyC != -1 && !isAnyC)
424
      {
425
        // if we are using the any constant constructor, do not use any
426
        // concrete constant
427
420
        Node c_op = sti.getConsNumConst(j);
428
210
        if (!c_op.isNull())
429
        {
430
43
          rm_indices.push_back(j);
431
        }
432
      }
433
    }
434
872
    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
86
      Node fv = getFreeVar(stn, 0);
442
86
      Node exc_val = datatypes::utils::getInstCons(fv, dt, rindex);
443
      // should not include the constuctor in any subterm
444
86
      Node x = getFreeVar(stn, 0);
445
86
      Trace("sygus-db") << "Construct symmetry breaking lemma from " << x
446
43
                        << " == " << exc_val << std::endl;
447
86
      Node lem = getExplain()->getExplanationForEquality(x, exc_val);
448
43
      lem = lem.negate();
449
86
      Trace("cegqi-lemma")
450
43
          << "Cegqi::Lemma : exclude symbolic cons lemma (template) : " << lem
451
43
          << std::endl;
452
      // the size of the subterm we are blocking is the weight of the
453
      // constructor (usually zero)
454
43
      registerSymBreakLemma(e, lem, stn, dt[rindex].getWeight());
455
    }
456
  }
457
384
  Trace("sygus-db") << "  ...finished" << std::endl;
458
459
  // determine if we are actively-generated
460
384
  bool isActiveGen = false;
461
384
  if (options::sygusActiveGenMode() != options::SygusActiveGenMode::NONE)
462
  {
463
380
    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
212
    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
61
      isActiveGen = true;
484
    }
485
151
    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
151
      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
284
        if (options::sygusStream()
501
142
            || (!eti.hasIte() && !eti.hasBoolConnective()))
502
        {
503
47
          isActiveGen = true;
504
        }
505
      }
506
      else
507
      {
508
9
        isActiveGen = true;
509
      }
510
    }
511
    else
512
    {
513
      Unreachable() << "Unknown enumerator mode in registerEnumerator";
514
    }
515
  }
516
768
  Trace("sygus-db") << "isActiveGen for " << e << ", role = " << erole
517
384
                    << " returned " << isActiveGen << std::endl;
518
  // Currently, actively-generated enumerators are either basic or variable
519
  // agnostic.
520
  bool isVarAgnostic = isActiveGen
521
384
                       && options::sygusActiveGenMode()
522
384
                              == options::SygusActiveGenMode::VAR_AGNOSTIC;
523
384
  d_enum_var_agnostic[e] = isVarAgnostic;
524
384
  if (isVarAgnostic)
525
  {
526
    // requires variable subclasses
527
1
    eti.initializeVarSubclasses();
528
    // If no subclass has more than one variable, do not use variable agnostic
529
    // enumeration
530
1
    bool useVarAgnostic = !eti.isSubclassVarTrivial();
531
1
    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
384
  d_enum_active_gen[e] = isActiveGen;
542
384
  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
384
  if (isActiveGen || erole == ROLE_ENUM_POOL)
548
  {
549
119
    SkolemManager* sm = nm->getSkolemManager();
550
    // make the guard
551
238
    Node ag = sm->mkDummySkolem("eG", nm->booleanType());
552
    // must ensure it is a literal immediately here
553
119
    ag = d_qstate.getValuation().ensureLiteral(ag);
554
    // must ensure that it is asserted as a literal before we begin solving
555
238
    Node lem = nm->mkNode(OR, ag, ag.negate());
556
119
    d_qim->requirePhase(ag, true);
557
119
    d_qim->lemma(lem, InferenceId::QUANTIFIERS_SYGUS_ENUM_ACTIVE_GUARD_SPLIT);
558
119
    d_enum_to_active_guard[e] = ag;
559
  }
560
}
561
562
46319
bool TermDbSygus::isEnumerator(Node e) const
563
{
564
46319
  return d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end();
565
}
566
567
358
SynthConjecture* TermDbSygus::getConjectureForEnumerator(Node e) const
568
{
569
  std::map<Node, SynthConjecture*>::const_iterator itm =
570
358
      d_enum_to_conjecture.find(e);
571
358
  if (itm != d_enum_to_conjecture.end()) {
572
358
    return itm->second;
573
  }
574
  return nullptr;
575
}
576
577
325
Node TermDbSygus::getSynthFunForEnumerator(Node e) const
578
{
579
325
  std::map<Node, Node>::const_iterator itsf = d_enum_to_synth_fun.find(e);
580
325
  if (itsf != d_enum_to_synth_fun.end())
581
  {
582
299
    return itsf->second;
583
  }
584
26
  return Node::null();
585
}
586
587
44511
Node TermDbSygus::getActiveGuardForEnumerator(Node e) const
588
{
589
44511
  std::map<Node, Node>::const_iterator itag = d_enum_to_active_guard.find(e);
590
44511
  if (itag != d_enum_to_active_guard.end()) {
591
35397
    return itag->second;
592
  }
593
9114
  return Node::null();
594
}
595
596
5500
bool TermDbSygus::usingSymbolicConsForEnumerator(Node e) const
597
{
598
5500
  std::map<Node, bool>::const_iterator itus = d_enum_to_using_sym_cons.find(e);
599
5500
  if (itus != d_enum_to_using_sym_cons.end())
600
  {
601
    return itus->second;
602
  }
603
5500
  return false;
604
}
605
606
14179
bool TermDbSygus::isVariableAgnosticEnumerator(Node e) const
607
{
608
14179
  std::map<Node, bool>::const_iterator itus = d_enum_var_agnostic.find(e);
609
14179
  if (itus != d_enum_var_agnostic.end())
610
  {
611
14179
    return itus->second;
612
  }
613
  return false;
614
}
615
616
266
bool TermDbSygus::isBasicEnumerator(Node e) const
617
{
618
266
  std::map<Node, bool>::const_iterator itus = d_enum_basic.find(e);
619
266
  if (itus != d_enum_basic.end())
620
  {
621
266
    return itus->second;
622
  }
623
  return false;
624
}
625
626
59183
bool TermDbSygus::isPassiveEnumerator(Node e) const
627
{
628
59183
  std::map<Node, bool>::const_iterator itus = d_enum_active_gen.find(e);
629
59183
  if (itus != d_enum_active_gen.end())
630
  {
631
57900
    return !itus->second;
632
  }
633
1283
  return true;
634
}
635
636
5379
void TermDbSygus::getEnumerators(std::vector<Node>& mts)
637
{
638
8650
  for (std::map<Node, SynthConjecture*>::iterator itm =
639
5379
           d_enum_to_conjecture.begin();
640
14029
       itm != d_enum_to_conjecture.end();
641
       ++itm)
642
  {
643
8650
    mts.push_back( itm->first );
644
  }
645
5379
}
646
647
79
void TermDbSygus::registerSymBreakLemma(
648
    Node e, Node lem, TypeNode tn, unsigned sz, bool isTempl)
649
{
650
79
  d_enum_to_sb_lemmas[e].push_back(lem);
651
79
  d_sb_lemma_to_type[lem] = tn;
652
79
  d_sb_lemma_to_size[lem] = sz;
653
79
  d_sb_lemma_to_isTempl[lem] = isTempl;
654
79
}
655
656
5379
bool TermDbSygus::hasSymBreakLemmas(std::vector<Node>& enums) const
657
{
658
5379
  if (!d_enum_to_sb_lemmas.empty())
659
  {
660
384
    for (std::pair<const Node, std::vector<Node> > sb : d_enum_to_sb_lemmas)
661
    {
662
198
      enums.push_back(sb.first);
663
    }
664
186
    return true;
665
  }
666
5193
  return false;
667
}
668
669
171
void TermDbSygus::getSymBreakLemmas(Node e, std::vector<Node>& lemmas) const
670
{
671
  std::map<Node, std::vector<Node> >::const_iterator itsb =
672
171
      d_enum_to_sb_lemmas.find(e);
673
171
  if (itsb != d_enum_to_sb_lemmas.end())
674
  {
675
51
    lemmas.insert(lemmas.end(), itsb->second.begin(), itsb->second.end());
676
  }
677
171
}
678
679
9
TypeNode TermDbSygus::getTypeForSymBreakLemma(Node lem) const
680
{
681
9
  std::map<Node, TypeNode>::const_iterator it = d_sb_lemma_to_type.find(lem);
682
9
  Assert(it != d_sb_lemma_to_type.end());
683
9
  return it->second;
684
}
685
9
unsigned TermDbSygus::getSizeForSymBreakLemma(Node lem) const
686
{
687
9
  std::map<Node, unsigned>::const_iterator it = d_sb_lemma_to_size.find(lem);
688
9
  Assert(it != d_sb_lemma_to_size.end());
689
9
  return it->second;
690
}
691
692
79
bool TermDbSygus::isSymBreakLemmaTemplate(Node lem) const
693
{
694
79
  std::map<Node, bool>::const_iterator it = d_sb_lemma_to_isTempl.find(lem);
695
79
  Assert(it != d_sb_lemma_to_isTempl.end());
696
79
  return it->second;
697
}
698
699
4
void TermDbSygus::clearSymBreakLemmas(Node e) { d_enum_to_sb_lemmas.erase(e); }
700
701
119440
bool TermDbSygus::isRegistered(TypeNode tn) const
702
{
703
119440
  return d_tinfo.find(tn) != d_tinfo.end();
704
}
705
706
6664
TypeNode TermDbSygus::sygusToBuiltinType( TypeNode tn ) {
707
6664
  std::map<TypeNode, SygusTypeInfo>::iterator it = d_tinfo.find(tn);
708
6664
  Assert(it != d_tinfo.end());
709
6664
  return it->second.getBuiltinType();
710
}
711
712
8402
void TermDbSygus::toStreamSygus(const char* c, Node n)
713
{
714
8402
  if (Trace.isOn(c))
715
  {
716
    std::stringstream ss;
717
    toStreamSygus(ss, n);
718
    Trace(c) << ss.str();
719
  }
720
8402
}
721
722
210
void TermDbSygus::toStreamSygus(std::ostream& out, Node n)
723
{
724
210
  if (n.isNull())
725
  {
726
    out << n;
727
    return;
728
  }
729
  // use external conversion
730
210
  out << datatypes::utils::sygusToBuiltin(n, true);
731
}
732
733
167925
SygusTypeInfo& TermDbSygus::getTypeInfo(TypeNode tn)
734
{
735
167925
  AlwaysAssert(d_tinfo.find(tn) != d_tinfo.end());
736
167925
  return d_tinfo[tn];
737
}
738
739
176052
Node TermDbSygus::rewriteNode(Node n) const
740
{
741
352104
  Node res;
742
176052
  if (options().quantifiers.sygusExtRew)
743
  {
744
173956
    res = extendedRewrite(n);
745
  }
746
  else
747
  {
748
2096
    res = rewrite(n);
749
  }
750
176052
  if (res.isConst())
751
  {
752
    // constant, we are done
753
126447
    return res;
754
  }
755
49605
  if (options::sygusRecFun())
756
  {
757
48771
    if (d_funDefEval->hasDefinitions())
758
    {
759
      // If recursive functions are enabled, then we use the recursive function
760
      // evaluation utility.
761
1345
      Node fres = d_funDefEval->evaluateDefinitions(res);
762
975
      if (!fres.isNull())
763
      {
764
605
        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
49000
  return res;
772
}
773
774
1331
unsigned TermDbSygus::getSelectorWeight(TypeNode tn, Node sel)
775
{
776
  std::map<TypeNode, std::map<Node, unsigned> >::iterator itsw =
777
1331
      d_sel_weight.find(tn);
778
1331
  if (itsw == d_sel_weight.end())
779
  {
780
203
    d_sel_weight[tn].clear();
781
203
    itsw = d_sel_weight.find(tn);
782
203
    const DType& dt = tn.getDType();
783
406
    Trace("sygus-db") << "Compute selector weights for " << dt.getName()
784
203
                      << std::endl;
785
1152
    for (unsigned i = 0, size = dt.getNumConstructors(); i < size; i++)
786
    {
787
949
      unsigned cw = dt[i].getWeight();
788
2109
      for (unsigned j = 0, size2 = dt[i].getNumArgs(); j < size2; j++)
789
      {
790
2320
        Node csel = dt[i].getSelectorInternal(tn, j);
791
1160
        std::map<Node, unsigned>::iterator its = itsw->second.find(csel);
792
1160
        if (its == itsw->second.end() || cw < its->second)
793
        {
794
724
          d_sel_weight[tn][csel] = cw;
795
724
          Trace("sygus-db") << "  w(" << csel << ") <= " << cw << std::endl;
796
        }
797
      }
798
    }
799
  }
800
1331
  Assert(itsw->second.find(sel) != itsw->second.end());
801
1331
  return itsw->second[sel];
802
}
803
804
449429
TypeNode TermDbSygus::getArgType(const DTypeConstructor& c, unsigned i) const
805
{
806
449429
  Assert(i < c.getNumArgs());
807
449429
  return c.getArgType(i);
808
}
809
810
4
bool TermDbSygus::isTypeMatch(const DTypeConstructor& c1,
811
                              const DTypeConstructor& c2)
812
{
813
4
  if( c1.getNumArgs()!=c2.getNumArgs() ){
814
    return false;
815
  }else{
816
12
    for( unsigned i=0; i<c1.getNumArgs(); i++ ){
817
8
      if( getArgType( c1, i )!=getArgType( c2, i ) ){
818
        return false;
819
      }
820
    }
821
4
    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
2084
bool TermDbSygus::canConstructKind(TypeNode tn,
842
                                   Kind k,
843
                                   std::vector<TypeNode>& argts,
844
                                   bool aggr)
845
{
846
2084
  Assert(isRegistered(tn));
847
2084
  SygusTypeInfo& ti = getTypeInfo(tn);
848
2084
  int c = ti.getKindConsNum(k);
849
2084
  const DType& dt = tn.getDType();
850
2084
  if (c != -1)
851
  {
852
5712
    for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
853
    {
854
3809
      argts.push_back(dt[c].getArgType(i));
855
    }
856
1903
    return true;
857
  }
858
181
  if (!options::sygusSymBreakAgg())
859
  {
860
    return false;
861
  }
862
181
  if (sygusToBuiltinType(tn).isBoolean())
863
  {
864
178
    if (k == ITE)
865
    {
866
      // ite( b1, b2, b3 ) <---- and( or( ~b1, b2 ), or( b1, b3 ) )
867
160
      std::vector<TypeNode> conj_types;
868
142
      if (canConstructKind(tn, AND, conj_types, true) && conj_types.size() == 2)
869
      {
870
130
        bool success = true;
871
390
        std::vector<TypeNode> disj_types[2];
872
378
        for (unsigned cc = 0; cc < 2; cc++)
873
        {
874
762
          if (!canConstructKind(conj_types[cc], OR, disj_types[cc], true)
875
762
              || disj_types[cc].size() != 2)
876
          {
877
6
            success = false;
878
6
            break;
879
          }
880
        }
881
130
        if (success)
882
        {
883
124
          for (unsigned r = 0; r < 2; r++)
884
          {
885
124
            for (unsigned d = 0, size = disj_types[r].size(); d < size; d++)
886
            {
887
124
              TypeNode dtn = disj_types[r][d];
888
              // must have negation that occurs in the other conjunct
889
124
              std::vector<TypeNode> ntypes;
890
124
              if (canConstructKind(dtn, NOT, ntypes) && ntypes.size() == 1)
891
              {
892
124
                TypeNode ntn = ntypes[0];
893
124
                for (unsigned dd = 0, inner_size = disj_types[1 - r].size();
894
124
                     dd < inner_size;
895
                     dd++)
896
                {
897
124
                  if (disj_types[1 - r][dd] == ntn)
898
                  {
899
124
                    argts.push_back(ntn);
900
124
                    argts.push_back(disj_types[r][d]);
901
124
                    argts.push_back(disj_types[1 - r][1 - dd]);
902
124
                    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
124
                    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
57
  return false;
927
}
928
929
17019
bool TermDbSygus::involvesDivByZero( Node n, std::map< Node, bool >& visited ){
930
17019
  if( visited.find( n )==visited.end() ){
931
15882
    visited[n] = true;
932
15882
    Kind k = n.getKind();
933
15882
    if( k==DIVISION || k==DIVISION_TOTAL || k==INTS_DIVISION || k==INTS_DIVISION_TOTAL ||
934
15882
        k==INTS_MODULUS || k==INTS_MODULUS_TOTAL ){
935
24
      if( n[1].isConst() ){
936
12
        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
12
        if( !hasFreeVar( n[1] ) ){
943
2
          return true;
944
        }
945
      }
946
    }
947
28113
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
948
12235
      if( involvesDivByZero( n[i], visited ) ){
949
2
        return true;
950
      }
951
    }
952
  }
953
17015
  return false;
954
}
955
956
4784
bool TermDbSygus::involvesDivByZero( Node n ) {
957
9568
  std::map< Node, bool > visited;
958
9568
  return involvesDivByZero( n, visited );
959
}
960
961
2180
Node TermDbSygus::getAnchor( Node n ) {
962
2180
  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
963
1019
    return getAnchor( n[0] );
964
  }else{
965
1161
    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
113688
Node TermDbSygus::evaluateBuiltin(TypeNode tn,
978
                                  Node bn,
979
                                  const std::vector<Node>& args,
980
                                  bool tryEval)
981
{
982
113688
  if (args.empty())
983
  {
984
426
    return Rewriter::rewrite( bn );
985
  }
986
113262
  Assert(isRegistered(tn));
987
113262
  SygusTypeInfo& ti = getTypeInfo(tn);
988
113262
  const std::vector<Node>& varlist = ti.getVarList();
989
113262
  Assert(varlist.size() == args.size());
990
991
226524
  Node res;
992
113262
  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
113262
    res = evaluate(bn, varlist, args);
999
  }
1000
113262
  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
113262
  return rewriteNode(res);
1009
}
1010
1011
523
bool TermDbSygus::isEvaluationPoint(Node n) const
1012
{
1013
523
  if (n.getKind() != DT_SYGUS_EVAL)
1014
  {
1015
236
    return false;
1016
  }
1017
287
  if (!n[0].isVar())
1018
  {
1019
    return false;
1020
  }
1021
1122
  for (unsigned i = 1, nchild = n.getNumChildren(); i < nchild; i++)
1022
  {
1023
845
    if (!n[i].isConst())
1024
    {
1025
10
      return false;
1026
    }
1027
  }
1028
277
  return true;
1029
}
1030
1031
}  // namespace quantifiers
1032
}  // namespace theory
1033
22746
}  // namespace cvc5