GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/term_database_sygus.cpp Lines: 479 554 86.5 %
Date: 2021-05-22 Branches: 865 2051 42.2 %

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