GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/term_database_sygus.cpp Lines: 447 516 86.6 %
Date: 2021-09-17 Branches: 785 1881 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
1233
TermDbSygus::TermDbSygus(Env& env, QuantifiersState& qs)
55
    : EnvObj(env),
56
      d_qstate(qs),
57
1233
      d_syexp(new SygusExplain(this)),
58
1233
      d_eval(new Evaluator),
59
1233
      d_funDefEval(new FunDefEvaluator),
60
4932
      d_eval_unfold(new SygusEvalUnfold(this))
61
{
62
1233
  d_true = NodeManager::currentNM()->mkConst( true );
63
1233
  d_false = NodeManager::currentNM()->mkConst( false );
64
1233
}
65
66
1233
void TermDbSygus::finishInit(QuantifiersInferenceManager* qim) { d_qim = qim; }
67
68
bool TermDbSygus::reset( Theory::Effort e ) {
69
  return true;
70
}
71
72
136940
TNode TermDbSygus::getFreeVar( TypeNode tn, int i, bool useSygusType ) {
73
136940
  unsigned sindex = 0;
74
273880
  TypeNode vtn = tn;
75
273880
  TypeNode builtinType = tn;
76
136940
  if (tn.isDatatype())
77
  {
78
134251
    const DType& dt = tn.getDType();
79
134251
    if (!dt.getSygusType().isNull())
80
    {
81
134251
      builtinType = dt.getSygusType();
82
134251
      if (useSygusType)
83
      {
84
16432
        vtn = builtinType;
85
16432
        sindex = 1;
86
      }
87
    }
88
  }
89
136940
  NodeManager* nm = NodeManager::currentNM();
90
151282
  while( i>=(int)d_fv[sindex][tn].size() ){
91
14342
    std::stringstream ss;
92
7171
    if( tn.isDatatype() ){
93
4368
      const DType& dt = tn.getDType();
94
4368
      ss << "fv_" << dt.getName() << "_" << i;
95
    }else{
96
2803
      ss << "fv_" << tn << "_" << i;
97
    }
98
7171
    Assert(!vtn.isNull());
99
14342
    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
7171
    d_fvId[v] = d_fvTypeIdCounter[builtinType];
103
7171
    d_fvTypeIdCounter[builtinType]++;
104
14342
    Trace("sygus-db-debug") << "Free variable id " << v << " = " << d_fvId[v]
105
7171
                            << ", " << builtinType << std::endl;
106
7171
    d_fv[sindex][tn].push_back( v );
107
  }
108
273880
  return d_fv[sindex][tn][i];
109
}
110
111
74822
TNode TermDbSygus::getFreeVarInc( TypeNode tn, std::map< TypeNode, int >& var_count, bool useSygusType ) {
112
74822
  std::map< TypeNode, int >::iterator it = var_count.find( tn );
113
74822
  if( it==var_count.end() ){
114
30015
    var_count[tn] = 1;
115
30015
    return getFreeVar( tn, 0, useSygusType );
116
  }else{
117
44807
    int index = it->second;
118
44807
    var_count[tn]++;
119
44807
    return getFreeVar( tn, index, useSygusType );
120
  }
121
}
122
123
2526
bool TermDbSygus::isFreeVar(Node n) const
124
{
125
2526
  return d_fvId.find(n) != d_fvId.end();
126
}
127
2514
size_t TermDbSygus::getFreeVarId(Node n) const
128
{
129
2514
  std::map<Node, size_t>::const_iterator it = d_fvId.find(n);
130
2514
  if (it == d_fvId.end())
131
  {
132
    Assert(false) << "TermDbSygus::isFreeVar: " << n
133
                  << " is not a cached free variable.";
134
    return 0;
135
  }
136
2514
  return it->second;
137
}
138
139
12
bool TermDbSygus::hasFreeVar( Node n, std::map< Node, bool >& visited ){
140
12
  if( visited.find( n )==visited.end() ){
141
12
    visited[n] = true;
142
12
    if( isFreeVar( n ) ){
143
10
      return true;
144
    }
145
2
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
146
      if( hasFreeVar( n[i], visited ) ){
147
        return true;
148
      }
149
    }
150
  }
151
2
  return false;
152
}
153
154
12
bool TermDbSygus::hasFreeVar( Node n ) {
155
24
  std::map< Node, bool > visited;
156
24
  return hasFreeVar( n, visited );
157
}
158
159
21
Node TermDbSygus::getProxyVariable(TypeNode tn, Node c)
160
{
161
21
  Assert(tn.isDatatype());
162
21
  Assert(tn.getDType().isSygus());
163
21
  Assert(tn.getDType().getSygusType().isComparableTo(c.getType()));
164
165
21
  std::map<Node, Node>::iterator it = d_proxy_vars[tn].find(c);
166
21
  if (it == d_proxy_vars[tn].end())
167
  {
168
16
    SygusTypeInfo& ti = getTypeInfo(tn);
169
16
    int anyC = ti.getAnyConstantConsNum();
170
16
    NodeManager* nm = NodeManager::currentNM();
171
32
    Node k;
172
16
    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
16
      const DType& dt = tn.getDType();
182
16
      k = nm->mkNode(APPLY_CONSTRUCTOR, dt[anyC].getConstructor(), c);
183
    }
184
16
    d_proxy_vars[tn][c] = k;
185
16
    return k;
186
  }
187
5
  return it->second;
188
}
189
190
391373
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
391373
  Assert(c < dt.getNumConstructors());
197
391373
  Assert(dt.isSygus());
198
391373
  Assert(!dt[c].getSygusOp().isNull());
199
782746
  std::vector< Node > children;
200
782746
  Trace("sygus-db-debug") << "mkGeneric " << dt.getName() << " " << c << "..."
201
391373
                          << std::endl;
202
870844
  for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
203
  {
204
958942
    Node a;
205
479471
    std::map< int, Node >::iterator it = pre.find( i );
206
479471
    if( it!=pre.end() ){
207
464115
      a = it->second;
208
464115
      Trace("sygus-db-debug") << "From pre: " << a << std::endl;
209
    }else{
210
30712
      TypeNode tna = dt[c].getArgType(i);
211
15356
      a = getFreeVarInc( tna, var_count, true );
212
    }
213
958942
    Trace("sygus-db-debug")
214
479471
        << "  child " << i << " : " << a << " : " << a.getType() << std::endl;
215
479471
    Assert(!a.isNull());
216
479471
    children.push_back( a );
217
  }
218
391373
  Node ret = datatypes::utils::mkSygusTerm(dt, c, children, doBetaRed);
219
391373
  Trace("sygus-db-debug") << "mkGeneric returns " << ret << std::endl;
220
782746
  return ret;
221
}
222
223
391373
Node TermDbSygus::mkGeneric(const DType& dt,
224
                            int c,
225
                            std::map<int, Node>& pre,
226
                            bool doBetaRed)
227
{
228
782746
  std::map<TypeNode, int> var_count;
229
782746
  return mkGeneric(dt, c, var_count, pre, doBetaRed);
230
}
231
232
11838
Node TermDbSygus::mkGeneric(const DType& dt, int c, bool doBetaRed)
233
{
234
23676
  std::map<int, Node> pre;
235
23676
  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
37376
Node TermDbSygus::canonizeBuiltin(Node n, std::map<TypeNode, int>& var_count)
251
{
252
  // has it already been computed?
253
37376
  if (var_count.empty() && n.hasAttribute(CanonizeBuiltinAttribute()))
254
  {
255
59688
    Node ret = n.getAttribute(CanonizeBuiltinAttribute());
256
29844
    Trace("sygus-db-canon") << "cached " << n << " : " << ret << "\n";
257
29844
    return ret;
258
  }
259
7532
  Trace("sygus-db-canon") << "  CanonizeBuiltin : compute for " << n << "\n";
260
15064
  Node ret = n;
261
  // it is symbolic if it represents "any constant"
262
7532
  if (n.getKind() == APPLY_SELECTOR_TOTAL)
263
  {
264
1120
    ret = getFreeVarInc(n[0].getType(), var_count, true);
265
  }
266
6412
  else if (n.getKind() != APPLY_CONSTRUCTOR)
267
  {
268
    ret = n;
269
  }
270
  else
271
  {
272
6412
    Assert(n.getKind() == APPLY_CONSTRUCTOR);
273
6412
    bool childChanged = false;
274
12824
    std::vector<Node> children;
275
6412
    children.push_back(n.getOperator());
276
16131
    for (unsigned j = 0, size = n.getNumChildren(); j < size; ++j)
277
    {
278
19438
      Node child = canonizeBuiltin(n[j], var_count);
279
9719
      children.push_back(child);
280
9719
      childChanged = childChanged || child != n[j];
281
    }
282
6412
    if (childChanged)
283
    {
284
1637
      ret = NodeManager::currentNM()->mkNode(APPLY_CONSTRUCTOR, children);
285
    }
286
  }
287
  // cache if we had a fresh variable count
288
7532
  if (var_count.empty())
289
  {
290
4647
    n.setAttribute(CanonizeBuiltinAttribute(), ret);
291
  }
292
15064
  Trace("sygus-db-canon") << "  ...normalized " << n << " --> " << ret
293
7532
                          << std::endl;
294
7532
  Assert(ret.getType().isComparableTo(n.getType()));
295
7532
  return ret;
296
}
297
298
struct SygusToBuiltinAttributeId
299
{
300
};
301
typedef expr::Attribute<SygusToBuiltinAttributeId, Node>
302
    SygusToBuiltinAttribute;
303
304
38715
Node TermDbSygus::sygusToBuiltin(Node n, TypeNode tn)
305
{
306
38715
  if (n.isConst())
307
  {
308
    // if its a constant, we use the datatype utility version
309
27553
    return datatypes::utils::sygusToBuiltin(n);
310
  }
311
11162
  Assert(n.getType().isComparableTo(tn));
312
11162
  if (!tn.isDatatype())
313
  {
314
79
    return n;
315
  }
316
  // has it already been computed?
317
11083
  if (n.hasAttribute(SygusToBuiltinAttribute()))
318
  {
319
4090
    return n.getAttribute(SygusToBuiltinAttribute());
320
  }
321
13986
  Trace("sygus-db-debug") << "SygusToBuiltin : compute for " << n
322
6993
                          << ", type = " << tn << std::endl;
323
6993
  const DType& dt = tn.getDType();
324
6993
  if (!dt.isSygus())
325
  {
326
    return n;
327
  }
328
6993
  if (n.getKind() == APPLY_CONSTRUCTOR)
329
  {
330
4479
    unsigned i = datatypes::utils::indexOf(n.getOperator());
331
4479
    Assert(n.getNumChildren() == dt[i].getNumArgs());
332
8958
    std::map<int, Node> pre;
333
13724
    for (unsigned j = 0, size = n.getNumChildren(); j < size; j++)
334
    {
335
9245
      pre[j] = sygusToBuiltin(n[j], dt[i].getArgType(j));
336
18490
      Trace("sygus-db-debug")
337
9245
          << "sygus to builtin " << n[j] << " is " << pre[j] << std::endl;
338
    }
339
8958
    Node ret = mkGeneric(dt, i, pre);
340
8958
    Trace("sygus-db-debug")
341
4479
        << "SygusToBuiltin : Generic is " << ret << std::endl;
342
    // cache
343
4479
    n.setAttribute(SygusToBuiltinAttribute(), ret);
344
4479
    return ret;
345
  }
346
2514
  if (n.hasAttribute(SygusPrintProxyAttribute()))
347
  {
348
    // this variable was associated by an attribute to a builtin node
349
    return n.getAttribute(SygusPrintProxyAttribute());
350
  }
351
2514
  Assert(isFreeVar(n));
352
  // map to builtin variable type
353
2514
  size_t fv_num = getFreeVarId(n);
354
2514
  Assert(!dt.getSygusType().isNull());
355
5028
  TypeNode vtn = dt.getSygusType();
356
5028
  Node ret = getFreeVar(vtn, fv_num);
357
5028
  Trace("sygus-db-debug") << "SygusToBuiltin: variable for " << n << " is "
358
2514
                          << ret << ", fv_num=" << fv_num << std::endl;
359
2514
  return ret;
360
}
361
362
14639
bool TermDbSygus::registerSygusType(TypeNode tn)
363
{
364
14639
  std::map<TypeNode, bool>::iterator it = d_registerStatus.find(tn);
365
14639
  if (it != d_registerStatus.end())
366
  {
367
    // already registered
368
12644
    return it->second;
369
  }
370
1995
  d_registerStatus[tn] = false;
371
  // it must be a sygus datatype
372
1995
  if (!tn.isDatatype())
373
  {
374
36
    return false;
375
  }
376
1959
  const DType& dt = tn.getDType();
377
1959
  if (!dt.isSygus())
378
  {
379
    return false;
380
  }
381
1959
  d_registerStatus[tn] = true;
382
1959
  SygusTypeInfo& sti = d_tinfo[tn];
383
1959
  sti.initialize(this, tn);
384
1959
  return true;
385
}
386
387
477
void TermDbSygus::registerEnumerator(Node e,
388
                                     Node f,
389
                                     SynthConjecture* conj,
390
                                     EnumeratorRole erole)
391
{
392
477
  if (d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end())
393
  {
394
    // already registered
395
    return;
396
  }
397
477
  Trace("sygus-db") << "Register enumerator : " << e << std::endl;
398
  // register its type
399
954
  TypeNode et = e.getType();
400
477
  registerSygusType(et);
401
477
  d_enum_to_conjecture[e] = conj;
402
477
  d_enum_to_synth_fun[e] = f;
403
477
  NodeManager* nm = NodeManager::currentNM();
404
405
954
  Trace("sygus-db") << "  registering symmetry breaking clauses..."
406
477
                    << 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
477
  SygusTypeInfo& eti = getTypeInfo(et);
410
954
  std::vector<TypeNode> sf_types;
411
477
  eti.getSubfieldTypes(sf_types);
412
  // for each type of subfield type of this enumerator
413
1492
  for (unsigned i = 0, ntypes = sf_types.size(); i < ntypes; i++)
414
  {
415
2030
    std::vector<unsigned> rm_indices;
416
2030
    TypeNode stn = sf_types[i];
417
1015
    Assert(stn.isDatatype());
418
1015
    SygusTypeInfo& sti = getTypeInfo(stn);
419
1015
    const DType& dt = stn.getDType();
420
1015
    int anyC = sti.getAnyConstantConsNum();
421
7353
    for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
422
    {
423
6338
      bool isAnyC = static_cast<int>(j) == anyC;
424
6338
      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
1058
    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
477
  Trace("sygus-db") << "  ...finished" << std::endl;
459
460
  // determine if we are actively-generated
461
477
  bool isActiveGen = false;
462
477
  if (options::sygusActiveGenMode() != options::SygusActiveGenMode::NONE)
463
  {
464
473
    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
213
    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
152
    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
152
      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
286
        if (options::sygusStream()
502
143
            || (!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
954
  Trace("sygus-db") << "isActiveGen for " << e << ", role = " << erole
518
477
                    << " returned " << isActiveGen << std::endl;
519
  // Currently, actively-generated enumerators are either basic or variable
520
  // agnostic.
521
  bool isVarAgnostic = isActiveGen
522
477
                       && options::sygusActiveGenMode()
523
477
                              == options::SygusActiveGenMode::VAR_AGNOSTIC;
524
477
  d_enum_var_agnostic[e] = isVarAgnostic;
525
477
  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
477
  d_enum_active_gen[e] = isActiveGen;
543
477
  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
477
  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
46426
bool TermDbSygus::isEnumerator(Node e) const
564
{
565
46426
  return d_enum_to_conjecture.find(e) != d_enum_to_conjecture.end();
566
}
567
568
447
SynthConjecture* TermDbSygus::getConjectureForEnumerator(Node e) const
569
{
570
  std::map<Node, SynthConjecture*>::const_iterator itm =
571
447
      d_enum_to_conjecture.find(e);
572
447
  if (itm != d_enum_to_conjecture.end()) {
573
447
    return itm->second;
574
  }
575
  return nullptr;
576
}
577
578
332
Node TermDbSygus::getSynthFunForEnumerator(Node e) const
579
{
580
332
  std::map<Node, Node>::const_iterator itsf = d_enum_to_synth_fun.find(e);
581
332
  if (itsf != d_enum_to_synth_fun.end())
582
  {
583
306
    return itsf->second;
584
  }
585
26
  return Node::null();
586
}
587
588
44618
Node TermDbSygus::getActiveGuardForEnumerator(Node e) const
589
{
590
44618
  std::map<Node, Node>::const_iterator itag = d_enum_to_active_guard.find(e);
591
44618
  if (itag != d_enum_to_active_guard.end()) {
592
35397
    return itag->second;
593
  }
594
9221
  return Node::null();
595
}
596
597
5713
bool TermDbSygus::usingSymbolicConsForEnumerator(Node e) const
598
{
599
5713
  std::map<Node, bool>::const_iterator itus = d_enum_to_using_sym_cons.find(e);
600
5713
  if (itus != d_enum_to_using_sym_cons.end())
601
  {
602
    return itus->second;
603
  }
604
5713
  return false;
605
}
606
607
15072
bool TermDbSygus::isVariableAgnosticEnumerator(Node e) const
608
{
609
15072
  std::map<Node, bool>::const_iterator itus = d_enum_var_agnostic.find(e);
610
15072
  if (itus != d_enum_var_agnostic.end())
611
  {
612
15072
    return itus->second;
613
  }
614
  return false;
615
}
616
617
266
bool TermDbSygus::isBasicEnumerator(Node e) const
618
{
619
266
  std::map<Node, bool>::const_iterator itus = d_enum_basic.find(e);
620
266
  if (itus != d_enum_basic.end())
621
  {
622
266
    return itus->second;
623
  }
624
  return false;
625
}
626
627
59190
bool TermDbSygus::isPassiveEnumerator(Node e) const
628
{
629
59190
  std::map<Node, bool>::const_iterator itus = d_enum_active_gen.find(e);
630
59190
  if (itus != d_enum_active_gen.end())
631
  {
632
57907
    return !itus->second;
633
  }
634
1283
  return true;
635
}
636
637
5522
void TermDbSygus::getEnumerators(std::vector<Node>& mts)
638
{
639
9245
  for (std::map<Node, SynthConjecture*>::iterator itm =
640
5522
           d_enum_to_conjecture.begin();
641
14767
       itm != d_enum_to_conjecture.end();
642
       ++itm)
643
  {
644
9245
    mts.push_back( itm->first );
645
  }
646
5522
}
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
5522
bool TermDbSygus::hasSymBreakLemmas(std::vector<Node>& enums) const
658
{
659
5522
  if (!d_enum_to_sb_lemmas.empty())
660
  {
661
384
    for (std::pair<const Node, std::vector<Node> > sb : d_enum_to_sb_lemmas)
662
    {
663
198
      enums.push_back(sb.first);
664
    }
665
186
    return true;
666
  }
667
5336
  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
119899
bool TermDbSygus::isRegistered(TypeNode tn) const
703
{
704
119899
  return d_tinfo.find(tn) != d_tinfo.end();
705
}
706
707
6664
TypeNode TermDbSygus::sygusToBuiltinType( TypeNode tn ) {
708
6664
  std::map<TypeNode, SygusTypeInfo>::iterator it = d_tinfo.find(tn);
709
6664
  Assert(it != d_tinfo.end());
710
6664
  return it->second.getBuiltinType();
711
}
712
713
8402
void TermDbSygus::toStreamSygus(const char* c, Node n)
714
{
715
8402
  if (Trace.isOn(c))
716
  {
717
    std::stringstream ss;
718
    toStreamSygus(ss, n);
719
    Trace(c) << ss.str();
720
  }
721
8402
}
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
170334
SygusTypeInfo& TermDbSygus::getTypeInfo(TypeNode tn)
735
{
736
170334
  AlwaysAssert(d_tinfo.find(tn) != d_tinfo.end());
737
170334
  return d_tinfo[tn];
738
}
739
740
176058
Node TermDbSygus::rewriteNode(Node n) const
741
{
742
352116
  Node res;
743
176058
  if (options().quantifiers.sygusExtRew)
744
  {
745
173962
    res = extendedRewrite(n);
746
  }
747
  else
748
  {
749
2096
    res = rewrite(n);
750
  }
751
176058
  if (res.isConst())
752
  {
753
    // constant, we are done
754
126448
    return res;
755
  }
756
49610
  if (options::sygusRecFun())
757
  {
758
48776
    if (d_funDefEval->hasDefinitions())
759
    {
760
      // If recursive functions are enabled, then we use the recursive function
761
      // evaluation utility.
762
1345
      Node fres = d_funDefEval->evaluate(res);
763
975
      if (!fres.isNull())
764
      {
765
605
        return fres;
766
      }
767
      // It may have failed, in which case there are undefined symbols in res or
768
      // we reached the limit of evaluations. In this case, we revert to the
769
      // result of rewriting in the return statement below.
770
    }
771
  }
772
49005
  return res;
773
}
774
775
1331
unsigned TermDbSygus::getSelectorWeight(TypeNode tn, Node sel)
776
{
777
  std::map<TypeNode, std::map<Node, unsigned> >::iterator itsw =
778
1331
      d_sel_weight.find(tn);
779
1331
  if (itsw == d_sel_weight.end())
780
  {
781
203
    d_sel_weight[tn].clear();
782
203
    itsw = d_sel_weight.find(tn);
783
203
    const DType& dt = tn.getDType();
784
406
    Trace("sygus-db") << "Compute selector weights for " << dt.getName()
785
203
                      << std::endl;
786
1152
    for (unsigned i = 0, size = dt.getNumConstructors(); i < size; i++)
787
    {
788
949
      unsigned cw = dt[i].getWeight();
789
2109
      for (unsigned j = 0, size2 = dt[i].getNumArgs(); j < size2; j++)
790
      {
791
2320
        Node csel = dt[i].getSelectorInternal(tn, j);
792
1160
        std::map<Node, unsigned>::iterator its = itsw->second.find(csel);
793
1160
        if (its == itsw->second.end() || cw < its->second)
794
        {
795
724
          d_sel_weight[tn][csel] = cw;
796
724
          Trace("sygus-db") << "  w(" << csel << ") <= " << cw << std::endl;
797
        }
798
      }
799
    }
800
  }
801
1331
  Assert(itsw->second.find(sel) != itsw->second.end());
802
1331
  return itsw->second[sel];
803
}
804
805
449429
TypeNode TermDbSygus::getArgType(const DTypeConstructor& c, unsigned i) const
806
{
807
449429
  Assert(i < c.getNumArgs());
808
449429
  return c.getArgType(i);
809
}
810
811
4
bool TermDbSygus::isTypeMatch(const DTypeConstructor& c1,
812
                              const DTypeConstructor& c2)
813
{
814
4
  if( c1.getNumArgs()!=c2.getNumArgs() ){
815
    return false;
816
  }else{
817
12
    for( unsigned i=0; i<c1.getNumArgs(); i++ ){
818
8
      if( getArgType( c1, i )!=getArgType( c2, i ) ){
819
        return false;
820
      }
821
    }
822
4
    return true;
823
  }
824
}
825
826
bool TermDbSygus::isSymbolicConsApp(Node n) const
827
{
828
  if (n.getKind() != APPLY_CONSTRUCTOR)
829
  {
830
    return false;
831
  }
832
  TypeNode tn = n.getType();
833
  Assert(tn.isDatatype());
834
  const DType& dt = tn.getDType();
835
  Assert(dt.isSygus());
836
  unsigned cindex = datatypes::utils::indexOf(n.getOperator());
837
  Node sygusOp = dt[cindex].getSygusOp();
838
  // it is symbolic if it represents "any constant"
839
  return sygusOp.getAttribute(SygusAnyConstAttribute());
840
}
841
842
2084
bool TermDbSygus::canConstructKind(TypeNode tn,
843
                                   Kind k,
844
                                   std::vector<TypeNode>& argts,
845
                                   bool aggr)
846
{
847
2084
  Assert(isRegistered(tn));
848
2084
  SygusTypeInfo& ti = getTypeInfo(tn);
849
2084
  int c = ti.getKindConsNum(k);
850
2084
  const DType& dt = tn.getDType();
851
2084
  if (c != -1)
852
  {
853
5712
    for (unsigned i = 0, nargs = dt[c].getNumArgs(); i < nargs; i++)
854
    {
855
3809
      argts.push_back(dt[c].getArgType(i));
856
    }
857
1903
    return true;
858
  }
859
181
  if (!options::sygusSymBreakAgg())
860
  {
861
    return false;
862
  }
863
181
  if (sygusToBuiltinType(tn).isBoolean())
864
  {
865
178
    if (k == ITE)
866
    {
867
      // ite( b1, b2, b3 ) <---- and( or( ~b1, b2 ), or( b1, b3 ) )
868
160
      std::vector<TypeNode> conj_types;
869
142
      if (canConstructKind(tn, AND, conj_types, true) && conj_types.size() == 2)
870
      {
871
130
        bool success = true;
872
390
        std::vector<TypeNode> disj_types[2];
873
378
        for (unsigned cc = 0; cc < 2; cc++)
874
        {
875
762
          if (!canConstructKind(conj_types[cc], OR, disj_types[cc], true)
876
762
              || disj_types[cc].size() != 2)
877
          {
878
6
            success = false;
879
6
            break;
880
          }
881
        }
882
130
        if (success)
883
        {
884
124
          for (unsigned r = 0; r < 2; r++)
885
          {
886
124
            for (unsigned d = 0, size = disj_types[r].size(); d < size; d++)
887
            {
888
124
              TypeNode dtn = disj_types[r][d];
889
              // must have negation that occurs in the other conjunct
890
124
              std::vector<TypeNode> ntypes;
891
124
              if (canConstructKind(dtn, NOT, ntypes) && ntypes.size() == 1)
892
              {
893
124
                TypeNode ntn = ntypes[0];
894
124
                for (unsigned dd = 0, inner_size = disj_types[1 - r].size();
895
124
                     dd < inner_size;
896
                     dd++)
897
                {
898
124
                  if (disj_types[1 - r][dd] == ntn)
899
                  {
900
124
                    argts.push_back(ntn);
901
124
                    argts.push_back(disj_types[r][d]);
902
124
                    argts.push_back(disj_types[1 - r][1 - dd]);
903
124
                    if (Trace.isOn("sygus-cons-kind"))
904
                    {
905
                      Trace("sygus-cons-kind")
906
                          << "Can construct kind " << k << " in " << tn
907
                          << " via child types:" << std::endl;
908
                      for (unsigned i = 0; i < 3; i++)
909
                      {
910
                        Trace("sygus-cons-kind")
911
                            << "  " << argts[i] << std::endl;
912
                      }
913
                    }
914
124
                    return true;
915
                  }
916
                }
917
              }
918
            }
919
          }
920
        }
921
      }
922
    }
923
  }
924
  // could try aggressive inferences here, such as
925
  // (and b1 b2) <---- (not (or (not b1) (not b2)))
926
  // (or b1 b2)  <---- (not (and (not b1) (not b2)))
927
57
  return false;
928
}
929
930
17209
bool TermDbSygus::involvesDivByZero( Node n, std::map< Node, bool >& visited ){
931
17209
  if( visited.find( n )==visited.end() ){
932
16072
    visited[n] = true;
933
16072
    Kind k = n.getKind();
934
16072
    if( k==DIVISION || k==DIVISION_TOTAL || k==INTS_DIVISION || k==INTS_DIVISION_TOTAL ||
935
16072
        k==INTS_MODULUS || k==INTS_MODULUS_TOTAL ){
936
24
      if( n[1].isConst() ){
937
12
        if (n[1] == TermUtil::mkTypeValue(n[1].getType(), 0))
938
        {
939
          return true;
940
        }
941
      }else{
942
        // if it has free variables it might be a non-zero constant
943
12
        if( !hasFreeVar( n[1] ) ){
944
2
          return true;
945
        }
946
      }
947
    }
948
28303
    for( unsigned i=0; i<n.getNumChildren(); i++ ){
949
12235
      if( involvesDivByZero( n[i], visited ) ){
950
2
        return true;
951
      }
952
    }
953
  }
954
17205
  return false;
955
}
956
957
4974
bool TermDbSygus::involvesDivByZero( Node n ) {
958
9948
  std::map< Node, bool > visited;
959
9948
  return involvesDivByZero( n, visited );
960
}
961
962
2275
Node TermDbSygus::getAnchor( Node n ) {
963
2275
  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
964
1019
    return getAnchor( n[0] );
965
  }else{
966
1256
    return n;
967
  }
968
}
969
970
unsigned TermDbSygus::getAnchorDepth( Node n ) {
971
  if( n.getKind()==APPLY_SELECTOR_TOTAL ){
972
    return 1+getAnchorDepth( n[0] );
973
  }else{
974
    return 0;
975
  }
976
}
977
978
113694
Node TermDbSygus::evaluateBuiltin(TypeNode tn,
979
                                  Node bn,
980
                                  const std::vector<Node>& args,
981
                                  bool tryEval)
982
{
983
113694
  if (args.empty())
984
  {
985
432
    return Rewriter::rewrite( bn );
986
  }
987
113262
  Assert(isRegistered(tn));
988
113262
  SygusTypeInfo& ti = getTypeInfo(tn);
989
113262
  const std::vector<Node>& varlist = ti.getVarList();
990
113262
  Assert(varlist.size() == args.size());
991
992
226524
  Node res;
993
113262
  if (tryEval && options::sygusEvalOpt())
994
  {
995
    // Try evaluating, which is much faster than substitution+rewriting.
996
    // This may fail if there is a subterm of bn under the
997
    // substitution that is not constant, or if an operator in bn is not
998
    // supported by the evaluator
999
113262
    res = d_eval->eval(bn, varlist, args);
1000
  }
1001
113262
  if (res.isNull())
1002
  {
1003
    // must do substitution
1004
    res =
1005
        bn.substitute(varlist.begin(), varlist.end(), args.begin(), args.end());
1006
  }
1007
  // Call the rewrite node function, which may involve recursive function
1008
  // evaluation.
1009
113262
  return rewriteNode(res);
1010
}
1011
1012
525
bool TermDbSygus::isEvaluationPoint(Node n) const
1013
{
1014
525
  if (n.getKind() != DT_SYGUS_EVAL)
1015
  {
1016
238
    return false;
1017
  }
1018
287
  if (!n[0].isVar())
1019
  {
1020
    return false;
1021
  }
1022
1122
  for (unsigned i = 1, nchild = n.getNumChildren(); i < nchild; i++)
1023
  {
1024
845
    if (!n[i].isConst())
1025
    {
1026
10
      return false;
1027
    }
1028
  }
1029
277
  return true;
1030
}
1031
1032
}  // namespace quantifiers
1033
}  // namespace theory
1034
29577
}  // namespace cvc5