GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/datatypes/sygus_extension.cpp Lines: 866 1009 85.8 %
Date: 2021-09-29 Branches: 2002 4932 40.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Mathias Preiner, Aina Niemetz
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 the sygus extension of the theory of datatypes.
14
 */
15
16
#include "theory/datatypes/sygus_extension.h"
17
18
#include "expr/dtype.h"
19
#include "expr/dtype_cons.h"
20
#include "expr/node_manager.h"
21
#include "expr/skolem_manager.h"
22
#include "expr/sygus_datatype.h"
23
#include "options/base_options.h"
24
#include "options/datatypes_options.h"
25
#include "options/quantifiers_options.h"
26
#include "printer/printer.h"
27
#include "smt/logic_exception.h"
28
#include "theory/datatypes/inference_manager.h"
29
#include "theory/datatypes/sygus_datatype_utils.h"
30
#include "theory/datatypes/theory_datatypes_utils.h"
31
#include "theory/quantifiers/sygus/sygus_explain.h"
32
#include "theory/quantifiers/sygus/synth_conjecture.h"
33
#include "theory/quantifiers/sygus/term_database_sygus.h"
34
#include "theory/quantifiers/term_util.h"
35
#include "theory/rewriter.h"
36
#include "theory/theory_model.h"
37
#include "theory/theory_state.h"
38
#include "util/rational.h"
39
40
using namespace cvc5;
41
using namespace cvc5::kind;
42
using namespace cvc5::context;
43
using namespace cvc5::theory;
44
using namespace cvc5::theory::datatypes;
45
46
1193
SygusExtension::SygusExtension(Env& env,
47
                               TheoryState& s,
48
                               InferenceManager& im,
49
1193
                               quantifiers::TermDbSygus* tds)
50
    : EnvObj(env),
51
      d_state(s),
52
      d_im(im),
53
      d_tds(tds),
54
      d_ssb(tds),
55
      d_testers(context()),
56
      d_testers_exp(context()),
57
      d_active_terms(context()),
58
1193
      d_currTermSize(context())
59
{
60
1193
  d_zero = NodeManager::currentNM()->mkConst(Rational(0));
61
1193
  d_true = NodeManager::currentNM()->mkConst(true);
62
1193
}
63
64
2382
SygusExtension::~SygusExtension() {
65
66
2382
}
67
68
/** add tester */
69
305829
void SygusExtension::assertTester(int tindex, TNode n, Node exp)
70
{
71
305829
  registerTerm(n);
72
  // check if this is a relevant (sygus) term
73
305829
  if( d_term_to_anchor.find( n )!=d_term_to_anchor.end() ){
74
284053
    Trace("sygus-sb-debug2") << "Sygus : process tester : " << exp << std::endl;
75
    // if not already active (may have duplicate calls for the same tester)
76
284053
    if( d_active_terms.find( n )==d_active_terms.end() ) {
77
254216
      d_testers[n] = tindex;
78
254216
      d_testers_exp[n] = exp;
79
80
      // check if parent is active
81
254216
      bool do_add = true;
82
254216
      if( options::sygusSymBreakLazy() ){
83
254208
        if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
84
235664
          NodeSet::const_iterator it = d_active_terms.find( n[0] );
85
235664
          if( it==d_active_terms.end() ){
86
143302
            do_add = false;
87
          }else{
88
            //this must be a proper selector
89
92362
            IntMap::const_iterator itt = d_testers.find( n[0] );
90
92362
            Assert(itt != d_testers.end());
91
92362
            int ptindex = (*itt).second;
92
184724
            TypeNode ptn = n[0].getType();
93
92362
            const DType& pdt = ptn.getDType();
94
            int sindex_in_parent =
95
92362
                pdt[ptindex].getSelectorIndexInternal(n.getOperator());
96
            // the tester is irrelevant in this branch
97
92362
            if( sindex_in_parent==-1 ){
98
51568
              do_add = false;
99
            }
100
          }
101
        }
102
      }
103
254216
      if( do_add ){
104
59346
        assertTesterInternal(tindex, n, exp);
105
      }else{
106
194870
        Trace("sygus-sb-debug2") << "...ignore inactive tester : " << exp << std::endl;
107
      }
108
    }else{
109
29837
      Trace("sygus-sb-debug2") << "...ignore repeated tester : " << exp << std::endl;
110
    }
111
  }else{
112
21776
    Trace("sygus-sb-debug2") << "...ignore non-sygus tester : " << exp << std::endl;
113
  }
114
305829
}
115
116
1971550
void SygusExtension::assertFact(Node n, bool polarity)
117
{
118
1971550
  if (n.getKind() == kind::DT_SYGUS_BOUND)
119
  {
120
17174
    Node m = n[0];
121
8587
    Trace("sygus-fair") << "Have sygus bound : " << n << ", polarity=" << polarity << " on measure " << m << std::endl;
122
8587
    registerMeasureTerm( m );
123
8587
    if (options::sygusFair() == options::SygusFairMode::DT_SIZE)
124
    {
125
      std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator its =
126
8584
          d_szinfo.find(m);
127
8584
      Assert(its != d_szinfo.end());
128
17168
      Node mt = its->second->getOrMkMeasureValue();
129
      //it relates the measure term to arithmetic
130
17168
      Node blem = n.eqNode( NodeManager::currentNM()->mkNode( kind::LEQ, mt, n[1] ) );
131
8584
      d_im.lemma(blem, InferenceId::DATATYPES_SYGUS_FAIR_SIZE);
132
    }
133
8587
    if( polarity ){
134
6206
      uint64_t s = n[1].getConst<Rational>().getNumerator().toUnsignedInt();
135
6206
      notifySearchSize(m, s, n);
136
    }
137
1962963
  }else if( n.getKind() == kind::DT_HEIGHT_BOUND || n.getKind()==DT_SIZE_BOUND ){
138
    //reduce to arithmetic TODO ?
139
140
  }
141
1971550
}
142
143
219
Node SygusExtension::getTermOrderPredicate( Node n1, Node n2 ) {
144
219
  NodeManager* nm = NodeManager::currentNM();
145
438
  std::vector< Node > comm_disj;
146
  // size of left is greater than or equal to the size of right
147
  Node szGeq =
148
219
      nm->mkNode(GEQ, nm->mkNode(DT_SIZE, n1), nm->mkNode(DT_SIZE, n2));
149
438
  return szGeq;
150
}
151
152
307218
void SygusExtension::registerTerm(Node n)
153
{
154
307218
  if( d_is_top_level.find( n )==d_is_top_level.end() ){
155
1816
    d_is_top_level[n] = false;
156
3632
    TypeNode tn = n.getType();
157
1816
    unsigned d = 0;
158
1816
    bool is_top_level = false;
159
1816
    bool success = false;
160
1816
    if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
161
1389
      registerTerm(n[0]);
162
1389
      std::unordered_map<Node, Node>::iterator it = d_term_to_anchor.find(n[0]);
163
1389
      if( it!=d_term_to_anchor.end() ) {
164
1331
        d_term_to_anchor[n] = it->second;
165
        unsigned sel_weight =
166
1331
            d_tds->getSelectorWeight(n[0].getType(), n.getOperator());
167
1331
        d = d_term_to_depth[n[0]] + sel_weight;
168
1331
        is_top_level = computeTopLevel( tn, n[0] );
169
1331
        success = true;
170
      }
171
427
    }else if( n.isVar() ){
172
409
      registerSizeTerm(n);
173
409
      if( d_register_st[n] ){
174
358
        d_term_to_anchor[n] = n;
175
358
        d_anchor_to_conj[n] = d_tds->getConjectureForEnumerator(n);
176
        // this assertion fails if we have a sygus term in the search that is unmeasured
177
358
        d = 0;
178
358
        is_top_level = true;
179
358
        success = true;
180
      }
181
    }
182
1816
    if( success ){
183
3378
      Trace("sygus-sb-debug")
184
1689
          << "Register : " << n << ", depth : " << d
185
1689
          << ", top level = " << is_top_level
186
1689
          << ", type = " << tn.getDType().getName() << std::endl;
187
1689
      d_term_to_depth[n] = d;
188
1689
      d_is_top_level[n] = is_top_level;
189
1689
      registerSearchTerm(tn, d, n, is_top_level);
190
    }else{
191
127
      Trace("sygus-sb-debug2") << "Term " << n << " is not part of sygus search." << std::endl;
192
    }
193
  }
194
307218
}
195
196
1834
bool SygusExtension::computeTopLevel( TypeNode tn, Node n ){
197
1834
  if( n.getType()==tn ){
198
899
    return false;
199
935
  }else if( n.getKind()==kind::APPLY_SELECTOR_TOTAL ){
200
503
    return computeTopLevel( tn, n[0] );
201
  }else{
202
432
    return true;
203
  }
204
}
205
206
65793
void SygusExtension::assertTesterInternal(int tindex, TNode n, Node exp)
207
{
208
131586
  TypeNode ntn = n.getType();
209
65793
  if (!ntn.isDatatype())
210
  {
211
    // nothing to do for non-datatype types
212
    return;
213
  }
214
65793
  const DType& dt = ntn.getDType();
215
65793
  if (!dt.isSygus())
216
  {
217
    // nothing to do for non-sygus-datatype type
218
    return;
219
  }
220
65793
  d_active_terms.insert(n);
221
131586
  Trace("sygus-sb-debug2") << "Sygus : activate term : " << n << " : " << exp
222
65793
                           << std::endl;
223
224
  // get the search size for this
225
65793
  Assert(d_term_to_anchor.find(n) != d_term_to_anchor.end());
226
131586
  Node a = d_term_to_anchor[n];
227
65793
  Assert(d_anchor_to_measure_term.find(a) != d_anchor_to_measure_term.end());
228
131586
  Node m = d_anchor_to_measure_term[a];
229
  std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator itsz =
230
65793
      d_szinfo.find(m);
231
65793
  Assert(itsz != d_szinfo.end());
232
65793
  unsigned ssz = itsz->second->d_curr_search_size;
233
234
65793
  if (options::sygusFair() == options::SygusFairMode::DIRECT)
235
  {
236
3
    if( dt[tindex].getNumArgs()>0 ){
237
      quantifiers::SygusTypeInfo& nti = d_tds->getTypeInfo(ntn);
238
      // consider lower bounds for size of types
239
      unsigned lb_add = nti.getMinConsTermSize(tindex);
240
      unsigned lb_rem = n == a ? 0 : nti.getMinTermSize();
241
      Assert(lb_add >= lb_rem);
242
      d_currTermSize[a].set( d_currTermSize[a].get() + ( lb_add - lb_rem ) );
243
    }
244
3
    if( (unsigned)d_currTermSize[a].get()>ssz ){
245
      if( Trace.isOn("sygus-sb-fair") ){
246
        std::map< TypeNode, int > var_count;
247
        Node templ = getCurrentTemplate( a, var_count );
248
        Trace("sygus-sb-fair") << "FAIRNESS : we have " <<  d_currTermSize[a].get() << " at search size " << ssz << ", template is " << templ << std::endl;
249
      }
250
      // conflict
251
      std::vector< Node > conflict;
252
      for( NodeSet::const_iterator its = d_active_terms.begin(); its != d_active_terms.end(); ++its ){
253
        Node x = *its;
254
        Node xa = d_term_to_anchor[x];
255
        if( xa==a ){
256
          IntMap::const_iterator ittv = d_testers.find( x );
257
          Assert(ittv != d_testers.end());
258
          int tidx = (*ittv).second;
259
          const DType& dti = x.getType().getDType();
260
          if (dti[tidx].getNumArgs() > 0)
261
          {
262
            NodeMap::const_iterator itt = d_testers_exp.find( x );
263
            Assert(itt != d_testers_exp.end());
264
            conflict.push_back( (*itt).second );
265
          }
266
        }
267
      }
268
      Assert(conflict.size() == (unsigned)d_currTermSize[a].get());
269
      Assert(itsz->second->d_search_size_exp.find(ssz)
270
             != itsz->second->d_search_size_exp.end());
271
      conflict.push_back( itsz->second->d_search_size_exp[ssz] );
272
      Node conf = NodeManager::currentNM()->mkNode( kind::AND, conflict );
273
      Trace("sygus-sb-fair") << "Conflict is : " << conf << std::endl;
274
      Node confn = conf.negate();
275
      d_im.lemma(confn, InferenceId::DATATYPES_SYGUS_FAIR_SIZE_CONFLICT);
276
      return;
277
    }
278
  }
279
280
  // now, add all applicable symmetry breaking lemmas for this term
281
65793
  Assert(d_term_to_depth.find(n) != d_term_to_depth.end());
282
65793
  unsigned d = d_term_to_depth[n];
283
65793
  Trace("sygus-sb-fair-debug") << "Tester " << exp << " is for depth " << d << " term in search size " << ssz << std::endl;
284
  //Assert( d<=ssz );
285
65793
  if( options::sygusSymBreakLazy() ){
286
    // dynamic symmetry breaking
287
65785
    addSymBreakLemmasFor(ntn, n, d);
288
  }
289
290
65793
  Trace("sygus-sb-debug") << "Get simple symmetry breaking predicates...\n";
291
65793
  unsigned max_depth = ssz>=d ? ssz-d : 0;
292
65793
  unsigned min_depth = d_simple_proc[exp];
293
65793
  NodeManager* nm = NodeManager::currentNM();
294
65793
  if( min_depth<=max_depth ){
295
11000
    TNode x = getFreeVar( ntn );
296
11000
    std::vector<std::pair<Node, InferenceId>> sbLemmas;
297
    // symmetry breaking lemmas requiring predicate elimination
298
11000
    std::map<Node, bool> sb_elim_pred;
299
5500
    bool usingSymCons = d_tds->usingSymbolicConsForEnumerator(m);
300
5500
    bool isVarAgnostic = d_tds->isVariableAgnosticEnumerator(m);
301
14560
    for (unsigned ds = 0; ds <= max_depth; ds++)
302
    {
303
      // static conjecture-independent symmetry breaking
304
9060
      Trace("sygus-sb-debug") << "  simple symmetry breaking...\n";
305
      Node ipred = getSimpleSymBreakPred(
306
18120
          m, ntn, tindex, ds, usingSymCons, isVarAgnostic);
307
9060
      if (!ipred.isNull())
308
      {
309
6519
        sbLemmas.emplace_back(ipred,
310
13038
                              InferenceId::DATATYPES_SYGUS_SIMPLE_SYM_BREAK);
311
6519
        if (ds == 0 && isVarAgnostic)
312
        {
313
3
          sb_elim_pred[ipred] = true;
314
        }
315
      }
316
      // static conjecture-dependent symmetry breaking
317
18120
      Trace("sygus-sb-debug")
318
9060
          << "  conjecture-dependent symmetry breaking...\n";
319
      std::map<Node, quantifiers::SynthConjecture*>::iterator itc =
320
9060
          d_anchor_to_conj.find(a);
321
9060
      if (itc != d_anchor_to_conj.end())
322
      {
323
9060
        quantifiers::SynthConjecture* conj = itc->second;
324
9060
        if (conj)
325
        {
326
          Node dpred =
327
17826
              conj->getSymmetryBreakingPredicate(x, a, ntn, tindex, ds);
328
8913
          if (!dpred.isNull())
329
          {
330
            sbLemmas.emplace_back(dpred,
331
                                  InferenceId::DATATYPES_SYGUS_CDEP_SYM_BREAK);
332
          }
333
        }
334
      }
335
    }
336
337
    // add the above symmetry breaking predicates to lemmas
338
11000
    std::unordered_map<TNode, TNode> cache;
339
11000
    Node rlv = getRelevancyCondition(n);
340
12019
    for (std::pair<Node, InferenceId>& sbl : sbLemmas)
341
    {
342
13038
      Node slem = sbl.first;
343
13038
      Node sslem = slem.substitute(x, n, cache);
344
      // if we require predicate elimination
345
6519
      if (sb_elim_pred.find(slem) != sb_elim_pred.end())
346
      {
347
6
        Trace("sygus-sb-tp") << "Eliminate traversal predicates: start "
348
3
                             << sslem << std::endl;
349
3
        sslem = eliminateTraversalPredicates(sslem);
350
6
        Trace("sygus-sb-tp") << "Eliminate traversal predicates: finish "
351
3
                             << sslem << std::endl;
352
      }
353
6519
      if (!rlv.isNull())
354
      {
355
4063
        sslem = nm->mkNode(OR, rlv, sslem);
356
      }
357
6519
      d_im.lemma(sslem, sbl.second);
358
    }
359
  }
360
65793
  d_simple_proc[exp] = max_depth + 1;
361
362
  // now activate the children those testers were previously asserted in this
363
  // context and are awaiting activation, if they exist.
364
65793
  if( options::sygusSymBreakLazy() ){
365
65785
    Trace("sygus-sb-debug") << "Do lazy symmetry breaking...\n";
366
116643
    for( unsigned j=0; j<dt[tindex].getNumArgs(); j++ ){
367
      Node sel = nm->mkNode(
368
101716
          APPLY_SELECTOR_TOTAL, dt[tindex].getSelectorInternal(ntn, j), n);
369
50858
      Trace("sygus-sb-debug2") << "  activate child sel : " << sel << std::endl;
370
50858
      Assert(d_active_terms.find(sel) == d_active_terms.end());
371
50858
      IntMap::const_iterator itt = d_testers.find( sel );
372
50858
      if( itt != d_testers.end() ){
373
6447
        Assert(d_testers_exp.find(sel) != d_testers_exp.end());
374
6447
        assertTesterInternal((*itt).second, sel, d_testers_exp[sel]);
375
      }
376
    }
377
65785
    Trace("sygus-sb-debug") << "...finished" << std::endl;
378
  }
379
}
380
381
73971
Node SygusExtension::getRelevancyCondition( Node n ) {
382
73971
  if (!options::sygusSymBreakRlv())
383
  {
384
6
    return Node::null();
385
  }
386
73965
  std::map< Node, Node >::iterator itr = d_rlv_cond.find( n );
387
73965
  if( itr==d_rlv_cond.end() ){
388
2500
    Node cond;
389
1250
    if (n.getKind() == APPLY_SELECTOR_TOTAL)
390
    {
391
1788
      TypeNode ntn = n[0].getType();
392
894
      const DType& dt = ntn.getDType();
393
1788
      Node sel = n.getOperator();
394
894
      if( options::dtSharedSelectors() ){
395
1312
        std::vector< Node > disj;
396
656
        bool excl = false;
397
3805
        for( unsigned i=0; i<dt.getNumConstructors(); i++ ){
398
3149
          int sindexi = dt[i].getSelectorIndexInternal(sel);
399
3149
          if (sindexi != -1)
400
          {
401
1342
            disj.push_back(utils::mkTester(n[0], i, dt).negate());
402
          }
403
          else
404
          {
405
1807
            excl = true;
406
          }
407
        }
408
656
        Assert(!disj.empty());
409
656
        if( excl ){
410
509
          cond = disj.size() == 1 ? disj[0] : NodeManager::currentNM()->mkNode(
411
                                                  kind::AND, disj);
412
        }
413
      }else{
414
238
        int sindex = utils::cindexOf(sel);
415
238
        Assert(sindex != -1);
416
238
        cond = utils::mkTester(n[0], sindex, dt).negate();
417
      }
418
1788
      Node c1 = getRelevancyCondition( n[0] );
419
894
      if( cond.isNull() ){
420
147
        cond = c1;
421
747
      }else if( !c1.isNull() ){
422
428
        cond = NodeManager::currentNM()->mkNode(kind::OR, cond, c1);
423
      }
424
    }
425
1250
    Trace("sygus-sb-debug2") << "Relevancy condition for " << n << " is " << cond << std::endl;
426
1250
    d_rlv_cond[n] = cond;
427
1250
    return cond;
428
  }else{
429
72715
    return itr->second;
430
  }
431
}
432
433
23
Node SygusExtension::getTraversalPredicate(TypeNode tn, Node n, bool isPre)
434
{
435
23
  unsigned index = isPre ? 0 : 1;
436
23
  std::map<Node, Node>::iterator itt = d_traversal_pred[index][tn].find(n);
437
23
  if (itt != d_traversal_pred[index][tn].end())
438
  {
439
19
    return itt->second;
440
  }
441
4
  NodeManager* nm = NodeManager::currentNM();
442
4
  SkolemManager* sm = nm->getSkolemManager();
443
8
  std::vector<TypeNode> types;
444
4
  types.push_back(tn);
445
8
  TypeNode ptn = nm->mkPredicateType(types);
446
8
  Node pred = sm->mkDummySkolem(isPre ? "pre" : "post", ptn);
447
4
  d_traversal_pred[index][tn][n] = pred;
448
4
  return pred;
449
}
450
451
4
Node SygusExtension::eliminateTraversalPredicates(Node n)
452
{
453
4
  NodeManager* nm = NodeManager::currentNM();
454
4
  SkolemManager* sm = nm->getSkolemManager();
455
8
  std::unordered_map<TNode, Node> visited;
456
4
  std::unordered_map<TNode, Node>::iterator it;
457
4
  std::map<Node, Node>::iterator ittb;
458
8
  std::vector<TNode> visit;
459
8
  TNode cur;
460
4
  visit.push_back(n);
461
110
  do
462
  {
463
114
    cur = visit.back();
464
114
    visit.pop_back();
465
114
    it = visited.find(cur);
466
467
114
    if (it == visited.end())
468
    {
469
64
      if (cur.getKind() == APPLY_UF)
470
      {
471
20
        Assert(cur.getType().isBoolean());
472
20
        Assert(cur.getNumChildren() == 1
473
               && (cur[0].isVar() || cur[0].getKind() == APPLY_SELECTOR_TOTAL));
474
20
        ittb = d_traversal_bool.find(cur);
475
40
        Node ret;
476
20
        if (ittb == d_traversal_bool.end())
477
        {
478
24
          std::stringstream ss;
479
12
          ss << "v_" << cur;
480
12
          ret = sm->mkDummySkolem(ss.str(), cur.getType());
481
12
          d_traversal_bool[cur] = ret;
482
        }
483
        else
484
        {
485
8
          ret = ittb->second;
486
        }
487
20
        visited[cur] = ret;
488
      }
489
      else
490
      {
491
44
        visited[cur] = Node::null();
492
44
        visit.push_back(cur);
493
110
        for (const Node& cn : cur)
494
        {
495
66
          visit.push_back(cn);
496
        }
497
      }
498
    }
499
50
    else if (it->second.isNull())
500
    {
501
88
      Node ret = cur;
502
44
      bool childChanged = false;
503
88
      std::vector<Node> children;
504
44
      if (cur.getMetaKind() == metakind::PARAMETERIZED)
505
      {
506
5
        children.push_back(cur.getOperator());
507
      }
508
110
      for (const Node& cn : cur)
509
      {
510
66
        it = visited.find(cn);
511
66
        Assert(it != visited.end());
512
66
        Assert(!it->second.isNull());
513
66
        childChanged = childChanged || cn != it->second;
514
66
        children.push_back(it->second);
515
      }
516
44
      if (childChanged)
517
      {
518
19
        ret = nm->mkNode(cur.getKind(), children);
519
      }
520
44
      visited[cur] = ret;
521
    }
522
114
  } while (!visit.empty());
523
4
  Assert(visited.find(n) != visited.end());
524
4
  Assert(!visited.find(n)->second.isNull());
525
8
  return visited[n];
526
}
527
528
9060
Node SygusExtension::getSimpleSymBreakPred(Node e,
529
                                             TypeNode tn,
530
                                             int tindex,
531
                                             unsigned depth,
532
                                             bool usingSymCons,
533
                                             bool isVarAgnostic)
534
{
535
  // Compute the tuple of expressions we hash the predicate for.
536
537
  // The hash value in d_simple_sb_pred for the given options
538
9060
  unsigned optHashVal = usingSymCons ? 1 : 0;
539
9060
  if (isVarAgnostic && depth == 0)
540
  {
541
    // variable agnostic symmetry breaking only applies at depth 0
542
3
    optHashVal = optHashVal + 2;
543
  }
544
  else
545
  {
546
    // enumerator is only specific to variable agnostic symmetry breaking
547
9057
    e = Node::null();
548
  }
549
  std::map<unsigned, Node>& ssbCache =
550
9060
      d_simple_sb_pred[e][tn][tindex][optHashVal];
551
9060
  std::map<unsigned, Node>::iterator it = ssbCache.find(depth);
552
9060
  if (it != ssbCache.end())
553
  {
554
6356
    return it->second;
555
  }
556
  // this function is only called on sygus datatype types
557
2704
  Assert(tn.isDatatype());
558
2704
  NodeManager* nm = NodeManager::currentNM();
559
5408
  Node n = getFreeVar(tn);
560
2704
  const DType& dt = tn.getDType();
561
2704
  Assert(dt.isSygus());
562
2704
  Assert(tindex >= 0 && tindex < static_cast<int>(dt.getNumConstructors()));
563
564
5408
  Trace("sygus-sb-simple-debug")
565
5408
      << "Simple symmetry breaking for " << dt.getName() << ", constructor "
566
2704
      << dt[tindex].getName() << ", at depth " << depth << std::endl;
567
568
2704
  quantifiers::SygusTypeInfo& ti = d_tds->getTypeInfo(tn);
569
  // get the sygus operator
570
5408
  Node sop = dt[tindex].getSygusOp();
571
  // get the kind of the constructor operator
572
2704
  Kind nk = ti.getConsNumKind(tindex);
573
  // is this the any-constant constructor?
574
2704
  bool isAnyConstant = sop.getAttribute(SygusAnyConstAttribute());
575
576
  // conjunctive conclusion of lemma
577
5408
  std::vector<Node> sbp_conj;
578
579
  // the number of (sygus) arguments
580
  // Notice if this is an any-constant constructor, its child is not a
581
  // sygus child, hence we set to 0 here.
582
2704
  unsigned dt_index_nargs = isAnyConstant ? 0 : dt[tindex].getNumArgs();
583
584
  // builtin type
585
5408
  TypeNode tnb = dt.getSygusType();
586
  // get children
587
5408
  std::vector<Node> children;
588
5565
  for (unsigned j = 0; j < dt_index_nargs; j++)
589
  {
590
    Node sel = nm->mkNode(
591
5722
        APPLY_SELECTOR_TOTAL, dt[tindex].getSelectorInternal(tn, j), n);
592
2861
    Assert(sel.getType().isDatatype());
593
2861
    children.push_back(sel);
594
  }
595
596
2704
  if (depth == 0)
597
  {
598
1586
    Trace("sygus-sb-simple-debug") << "  Size..." << std::endl;
599
    // fairness
600
3172
    if (options::sygusFair() == options::SygusFairMode::DT_SIZE
601
1586
        && !isAnyConstant)
602
    {
603
3122
      Node szl = nm->mkNode(DT_SIZE, n);
604
3122
      Node szr = nm->mkNode(DT_SIZE, utils::getInstCons(n, dt, tindex));
605
1561
      szr = rewrite(szr);
606
1561
      sbp_conj.push_back(szl.eqNode(szr));
607
    }
608
1586
    if (isVarAgnostic)
609
    {
610
      // Enforce symmetry breaking lemma template for each x_i:
611
      // template z.
612
      //   is-x_i( z ) => pre_{x_{i-1}}( z )
613
      //   for args a = 1...n
614
      //      // pre-definition
615
      //      pre_{x_i}( z.a ) = a=0 ? pre_{x_i}( z ) : post_{x_i}( z.{a-1} )
616
      //   post_{x_i}( z ) = post_{x_i}( z.n ) OR is-x_i( z )
617
618
      // Notice that we are constructing a symmetry breaking template
619
      // under the condition that is-C( z ) holds in this method, where C
620
      // is the tindex^{th} constructor of dt. Thus, is-x_i( z ) is either
621
      // true or false below.
622
623
6
      Node svl = dt.getSygusVarList();
624
      // for each variable
625
3
      Assert(!e.isNull());
626
6
      TypeNode etn = e.getType();
627
      // for each variable in the sygus type
628
9
      for (const Node& var : svl)
629
      {
630
6
        quantifiers::SygusTypeInfo& eti = d_tds->getTypeInfo(etn);
631
6
        unsigned sc = eti.getSubclassForVar(var);
632
6
        if (eti.getNumSubclassVars(sc) == 1)
633
        {
634
          // unique variable in singleton subclass, skip
635
          continue;
636
        }
637
        // Compute the "predecessor" variable in the subclass of var.
638
12
        Node predVar;
639
6
        unsigned scindex = 0;
640
6
        if (eti.getIndexInSubclassForVar(var, scindex))
641
        {
642
6
          if (scindex > 0)
643
          {
644
3
            predVar = eti.getVarSubclassIndex(sc, scindex - 1);
645
          }
646
        }
647
12
        Node preParentOp = getTraversalPredicate(tn, var, true);
648
12
        Node preParent = nm->mkNode(APPLY_UF, preParentOp, n);
649
12
        Node prev = preParent;
650
        // for each child
651
10
        for (const Node& child : children)
652
        {
653
8
          TypeNode ctn = child.getType();
654
          // my pre is equal to the previous
655
8
          Node preCurrOp = getTraversalPredicate(ctn, var, true);
656
8
          Node preCurr = nm->mkNode(APPLY_UF, preCurrOp, child);
657
          // definition of pre, for each argument
658
4
          sbp_conj.push_back(preCurr.eqNode(prev));
659
8
          Node postCurrOp = getTraversalPredicate(ctn, var, false);
660
4
          prev = nm->mkNode(APPLY_UF, postCurrOp, child);
661
        }
662
12
        Node postParent = getTraversalPredicate(tn, var, false);
663
12
        Node finish = nm->mkNode(APPLY_UF, postParent, n);
664
        // check if we are constructing the symmetry breaking predicate for the
665
        // variable in question. If so, is-{x_i}( z ) is true.
666
6
        int varCn = ti.getOpConsNum(var);
667
6
        if (varCn == static_cast<int>(tindex))
668
        {
669
          // the post value is true
670
2
          prev = d_true;
671
          // requirement : If I am the variable, I must have seen
672
          // the variable before this one in its type class.
673
2
          if (!predVar.isNull())
674
          {
675
2
            Node preParentPredVarOp = getTraversalPredicate(tn, predVar, true);
676
2
            Node preParentPredVar = nm->mkNode(APPLY_UF, preParentPredVarOp, n);
677
1
            sbp_conj.push_back(preParentPredVar);
678
          }
679
        }
680
        // definition of post
681
6
        sbp_conj.push_back(finish.eqNode(prev));
682
      }
683
    }
684
  }
685
686
  // if we are the "any constant" constructor, we do no symmetry breaking
687
  // only do simple symmetry breaking up to depth 2
688
2704
  bool doSymBreak = options::sygusSymBreak();
689
2704
  if (isAnyConstant || depth > 2)
690
  {
691
257
    doSymBreak = false;
692
  }
693
  // symmetry breaking
694
2704
  if (doSymBreak)
695
  {
696
    // direct solving for children
697
    //   for instance, we may want to insist that the LHS of MINUS is 0
698
2410
    Trace("sygus-sb-simple-debug") << "  Solve children..." << std::endl;
699
4820
    std::map<unsigned, unsigned> children_solved;
700
4949
    for (unsigned j = 0; j < dt_index_nargs; j++)
701
    {
702
2539
      int i = d_ssb.solveForArgument(tn, tindex, j);
703
2539
      if (i >= 0)
704
      {
705
        children_solved[j] = i;
706
        TypeNode ctn = children[j].getType();
707
        const DType& cdt = ctn.getDType();
708
        Assert(i < static_cast<int>(cdt.getNumConstructors()));
709
        sbp_conj.push_back(utils::mkTester(children[j], i, cdt));
710
      }
711
    }
712
713
    // depth 1 symmetry breaking : talks about direct children
714
2410
    if (depth == 1)
715
    {
716
618
      if (nk != UNDEFINED_KIND)
717
      {
718
720
        Trace("sygus-sb-simple-debug")
719
360
            << "  Equality reasoning about children..." << std::endl;
720
        // commutative operators
721
360
        if (quantifiers::TermUtil::isComm(nk))
722
        {
723
358
          if (children.size() == 2
724
358
              && children[0].getType() == children[1].getType())
725
          {
726
346
            Node order_pred = getTermOrderPredicate(children[0], children[1]);
727
173
            sbp_conj.push_back(order_pred);
728
          }
729
        }
730
        // operators whose arguments are non-additive (e.g. should be different)
731
720
        std::vector<unsigned> deq_child[2];
732
360
        if (children.size() == 2 && children[0].getType() == tn)
733
        {
734
153
          bool argDeq = false;
735
153
          if (quantifiers::TermUtil::isNonAdditive(nk))
736
          {
737
50
            argDeq = true;
738
          }
739
          else
740
          {
741
            // other cases of rewriting x k x -> x'
742
206
            Node req_const;
743
103
            if (nk == GT || nk == LT || nk == XOR || nk == MINUS
744
72
                || nk == BITVECTOR_SUB || nk == BITVECTOR_XOR
745
71
                || nk == BITVECTOR_UREM)
746
            {
747
              // must have the zero element
748
33
              req_const = quantifiers::TermUtil::mkTypeValue(tnb, 0);
749
            }
750
70
            else if (nk == EQUAL || nk == LEQ || nk == GEQ
751
70
                     || nk == BITVECTOR_XNOR)
752
            {
753
              req_const = quantifiers::TermUtil::mkTypeMaxValue(tnb);
754
            }
755
            // cannot do division since we have to consider when both are zero
756
103
            if (!req_const.isNull())
757
            {
758
33
              if (ti.hasConst(req_const))
759
              {
760
27
                argDeq = true;
761
              }
762
            }
763
          }
764
153
          if (argDeq)
765
          {
766
77
            deq_child[0].push_back(0);
767
77
            deq_child[1].push_back(1);
768
          }
769
        }
770
360
        if (nk == ITE || nk == STRING_REPLACE || nk == STRING_REPLACE_ALL)
771
        {
772
37
          deq_child[0].push_back(1);
773
37
          deq_child[1].push_back(2);
774
        }
775
360
        if (nk == STRING_REPLACE || nk == STRING_REPLACE_ALL)
776
        {
777
          deq_child[0].push_back(0);
778
          deq_child[1].push_back(1);
779
        }
780
        // this code adds simple symmetry breaking predicates of the form
781
        // d.i != d.j, for example if we are considering an ITE constructor,
782
        // we enforce that d.1 != d.2 since otherwise the ITE can be
783
        // simplified.
784
474
        for (unsigned i = 0, size = deq_child[0].size(); i < size; i++)
785
        {
786
114
          unsigned c1 = deq_child[0][i];
787
114
          unsigned c2 = deq_child[1][i];
788
228
          TypeNode tnc = children[c1].getType();
789
          // we may only apply this symmetry breaking scheme (which introduces
790
          // disequalities) if the types are infinite.
791
114
          if (tnc == children[c2].getType() && !d_state.isFiniteType(tnc))
792
          {
793
228
            Node sym_lem_deq = children[c1].eqNode(children[c2]).negate();
794
            // notice that this symmetry breaking still allows for
795
            //   ite( C, any_constant(x), any_constant(y) )
796
            // since any_constant takes a builtin argument.
797
114
            sbp_conj.push_back(sym_lem_deq);
798
          }
799
        }
800
801
720
        Trace("sygus-sb-simple-debug") << "  Redundant operators..."
802
360
                                       << std::endl;
803
        // singular arguments (e.g. 0 for mult)
804
        // redundant arguments (e.g. 0 for plus, 1 for mult)
805
        // right-associativity
806
        // simple rewrites
807
        // explanation of why not all children of this are constant
808
720
        std::vector<Node> exp_not_all_const;
809
        // is the above explanation valid? This is set to false if
810
        // one child does not have a constant, hence making the explanation
811
        // false.
812
360
        bool exp_not_all_const_valid = dt_index_nargs > 0;
813
        // does the parent have an any constant constructor?
814
        bool usingAnyConstCons =
815
360
            usingSymCons && (ti.getAnyConstantConsNum() != -1);
816
1084
        for (unsigned j = 0; j < dt_index_nargs; j++)
817
        {
818
1448
          Node nc = children[j];
819
          // if not already solved
820
724
          if (children_solved.find(j) != children_solved.end())
821
          {
822
            continue;
823
          }
824
1448
          TypeNode tnc = nc.getType();
825
724
          quantifiers::SygusTypeInfo& cti = d_tds->getTypeInfo(tnc);
826
724
          int anyc_cons_num = cti.getAnyConstantConsNum();
827
724
          const DType& cdt = tnc.getDType();
828
1448
          std::vector<Node> exp_const;
829
5308
          for (unsigned k = 0, ncons = cdt.getNumConstructors(); k < ncons; k++)
830
          {
831
4584
            Kind nck = cti.getConsNumKind(k);
832
4584
            bool red = false;
833
9168
            Node tester = utils::mkTester(nc, k, cdt);
834
            // check if the argument is redundant
835
4584
            if (static_cast<int>(k) == anyc_cons_num)
836
            {
837
48
              exp_const.push_back(tester);
838
            }
839
4536
            else if (nck != UNDEFINED_KIND)
840
            {
841
4968
              Trace("sygus-sb-simple-debug") << "  argument " << j << " " << k
842
2484
                                             << " is : " << nck << std::endl;
843
2484
              red = !d_ssb.considerArgKind(tnc, tn, nck, nk, j);
844
            }
845
            else
846
            {
847
4104
              Node cc = cti.getConsNumConst(k);
848
2052
              if (!cc.isNull())
849
              {
850
2366
                Trace("sygus-sb-simple-debug")
851
1183
                    << "  argument " << j << " " << k << " is constant : " << cc
852
1183
                    << std::endl;
853
1183
                red = !d_ssb.considerConst(tnc, tn, cc, nk, j);
854
1183
                if (usingAnyConstCons)
855
                {
856
                  // we only consider concrete constant constructors
857
                  // of children if we have the "any constant" constructor
858
                  // otherwise, we would disallow solutions for grammars
859
                  // like the following:
860
                  //   A -> B+B
861
                  //   B -> 4 | 8 | 100
862
                  // where A allows all constants but is not using the
863
                  // any constant constructor.
864
                  exp_const.push_back(tester);
865
                }
866
              }
867
              else
868
              {
869
                // defined function?
870
              }
871
            }
872
4584
            if (red)
873
            {
874
1078
              Trace("sygus-sb-simple-debug") << "  ...redundant." << std::endl;
875
1078
              sbp_conj.push_back(tester.negate());
876
            }
877
          }
878
724
          if (exp_const.empty())
879
          {
880
676
            exp_not_all_const_valid = false;
881
          }
882
          else
883
          {
884
96
            Node ecn = exp_const.size() == 1 ? exp_const[0]
885
144
                                             : nm->mkNode(OR, exp_const);
886
48
            exp_not_all_const.push_back(ecn.negate());
887
          }
888
        }
889
        // explicitly handle constants and "any constant" constructors
890
        // if this type admits any constant, then at least one of my
891
        // children must not be a constant or the "any constant" constructor
892
360
        if (dt.getSygusAllowConst() && exp_not_all_const_valid)
893
        {
894
18
          Assert(!exp_not_all_const.empty());
895
18
          Node expaan = exp_not_all_const.size() == 1
896
1
                            ? exp_not_all_const[0]
897
37
                            : nm->mkNode(OR, exp_not_all_const);
898
36
          Trace("sygus-sb-simple-debug")
899
18
              << "Ensure not all constant: " << expaan << std::endl;
900
18
          sbp_conj.push_back(expaan);
901
        }
902
      }
903
      else
904
      {
905
        // defined function?
906
      }
907
    }
908
1792
    else if (depth == 2)
909
    {
910
      // commutative operators
911
612
      if (quantifiers::TermUtil::isComm(nk) && children.size() == 2
912
612
          && children[0].getType() == tn && children[1].getType() == tn)
913
      {
914
        // chainable
915
        Node child11 = nm->mkNode(APPLY_SELECTOR_TOTAL,
916
92
                                  dt[tindex].getSelectorInternal(tn, 1),
917
184
                                  children[0]);
918
46
        Assert(child11.getType() == children[1].getType());
919
        Node order_pred_trans =
920
            nm->mkNode(OR,
921
92
                       utils::mkTester(children[0], tindex, dt).negate(),
922
184
                       getTermOrderPredicate(child11, children[1]));
923
46
        sbp_conj.push_back(order_pred_trans);
924
      }
925
    }
926
  }
927
928
5408
  Node sb_pred;
929
2704
  if (!sbp_conj.empty())
930
  {
931
1923
    sb_pred =
932
3846
        sbp_conj.size() == 1 ? sbp_conj[0] : nm->mkNode(kind::AND, sbp_conj);
933
3846
    Trace("sygus-sb-simple")
934
1923
        << "Simple predicate for " << tn << " index " << tindex << " (" << nk
935
1923
        << ") at depth " << depth << " : " << std::endl;
936
1923
    Trace("sygus-sb-simple") << "   " << sb_pred << std::endl;
937
1923
    sb_pred = nm->mkNode(OR, utils::mkTester(n, tindex, dt).negate(), sb_pred);
938
  }
939
2704
  d_simple_sb_pred[e][tn][tindex][optHashVal][depth] = sb_pred;
940
2704
  return sb_pred;
941
}
942
943
59016
TNode SygusExtension::getFreeVar( TypeNode tn ) {
944
59016
  return d_tds->getFreeVar(tn, 0);
945
}
946
947
1689
void SygusExtension::registerSearchTerm(TypeNode tn,
948
                                        unsigned d,
949
                                        Node n,
950
                                        bool topLevel)
951
{
952
  //register this term
953
1689
  std::unordered_map<Node, Node>::iterator ita = d_term_to_anchor.find(n);
954
1689
  Assert(ita != d_term_to_anchor.end());
955
3378
  Node a = ita->second;
956
1689
  Assert(!a.isNull());
957
1689
  SearchCache& sca = d_cache[a];
958
5067
  if (std::find(
959
1689
          sca.d_search_terms[tn][d].begin(), sca.d_search_terms[tn][d].end(), n)
960
5067
      == sca.d_search_terms[tn][d].end())
961
  {
962
1689
    Trace("sygus-sb-debug") << "  register search term : " << n << " at depth " << d << ", type=" << tn << ", tl=" << topLevel << std::endl;
963
1689
    sca.d_search_terms[tn][d].push_back(n);
964
1689
    if( !options::sygusSymBreakLazy() ){
965
2
      addSymBreakLemmasFor(tn, n, d);
966
    }
967
  }
968
1689
}
969
970
27853
Node SygusExtension::registerSearchValue(Node a,
971
                                           Node n,
972
                                           Node nv,
973
                                           unsigned d,
974
                                           bool isVarAgnostic,
975
                                           bool doSym)
976
{
977
27853
  Assert(n.getType().isComparableTo(nv.getType()));
978
55706
  TypeNode tn = n.getType();
979
27853
  if (!tn.isDatatype())
980
  {
981
    // don't register non-datatype terms, instead we return the
982
    // selector chain n.
983
469
    return n;
984
  }
985
27384
  const DType& dt = tn.getDType();
986
27384
  if (!dt.isSygus())
987
  {
988
    // don't register non-sygus-datatype terms
989
    return n;
990
  }
991
27384
  Assert(nv.getKind() == APPLY_CONSTRUCTOR);
992
27384
  NodeManager* nm = NodeManager::currentNM();
993
  // we call the body of this function in a bottom-up fashion
994
  // this ensures that the "abstraction" of the model value is available
995
27384
  if( nv.getNumChildren()>0 ){
996
10266
    unsigned cindex = utils::indexOf(nv.getOperator());
997
20224
    std::vector<Node> rcons_children;
998
10266
    rcons_children.push_back(nv.getOperator());
999
10266
    bool childrenChanged = false;
1000
29729
    for (unsigned i = 0, nchild = nv.getNumChildren(); i < nchild; i++)
1001
    {
1002
      Node sel = nm->mkNode(
1003
39234
          APPLY_SELECTOR_TOTAL, dt[cindex].getSelectorInternal(tn, i), n);
1004
      Node nvc = registerSearchValue(a,
1005
                                     sel,
1006
                                     nv[i],
1007
                                     d + 1,
1008
                                     isVarAgnostic,
1009
39234
                                     doSym && (!isVarAgnostic || i == 0));
1010
19771
      if (nvc.isNull())
1011
      {
1012
308
        return Node::null();
1013
      }
1014
19463
      rcons_children.push_back(nvc);
1015
19463
      childrenChanged = childrenChanged || nvc != nv[i];
1016
    }
1017
    // reconstruct the value, which may be a skeleton
1018
9958
    if (childrenChanged)
1019
    {
1020
843
      nv = nm->mkNode(APPLY_CONSTRUCTOR, rcons_children);
1021
    }
1022
  }
1023
27076
  if (!doSym)
1024
  {
1025
    return nv;
1026
  }
1027
27076
  Trace("sygus-sb-debug2") << "Registering search value " << n << " -> " << nv << std::endl;
1028
54152
  std::map<TypeNode, int> var_count;
1029
54152
  Node cnv = d_tds->canonizeBuiltin(nv, var_count);
1030
27076
  Trace("sygus-sb-debug") << "  ...canonized value is " << cnv << std::endl;
1031
27076
  SearchCache& sca = d_cache[a];
1032
  // must do this for all nodes, regardless of top-level
1033
27076
  if (sca.d_search_val_proc.find(cnv) == sca.d_search_val_proc.end())
1034
  {
1035
4782
    sca.d_search_val_proc.insert(cnv);
1036
    // get the root (for PBE symmetry breaking)
1037
4782
    Assert(d_anchor_to_conj.find(a) != d_anchor_to_conj.end());
1038
4782
    quantifiers::SynthConjecture* aconj = d_anchor_to_conj[a];
1039
9564
    Trace("sygus-sb-debug") << "  ...register search value " << cnv
1040
4782
                            << ", type=" << tn << std::endl;
1041
7921
    Node bv = d_tds->sygusToBuiltin(cnv, tn);
1042
4782
    Trace("sygus-sb-debug") << "  ......builtin is " << bv << std::endl;
1043
7921
    Node bvr = extendedRewrite(bv);
1044
4782
    Trace("sygus-sb-debug") << "  ......search value rewrites to " << bvr << std::endl;
1045
4782
    Trace("dt-sygus") << "  * DT builtin : " << n << " -> " << bvr << std::endl;
1046
4782
    unsigned sz = utils::getSygusTermSize(nv);
1047
4782
    if( d_tds->involvesDivByZero( bvr ) ){
1048
2
      quantifiers::DivByZeroSygusInvarianceTest dbzet;
1049
2
      Trace("sygus-sb-mexp-debug") << "Minimize explanation for div-by-zero in "
1050
1
                                   << bv << std::endl;
1051
1
      registerSymBreakLemmaForValue(a, nv, dbzet, Node::null(), var_count);
1052
1
      return Node::null();
1053
    }else{
1054
4781
      std::unordered_map<Node, Node>& scasv = sca.d_search_val[tn];
1055
4781
      std::unordered_map<Node, unsigned>& scasvs = sca.d_search_val_sz[tn];
1056
4781
      std::unordered_map<Node, Node>::iterator itsv = scasv.find(bvr);
1057
7920
      Node bad_val_bvr;
1058
4781
      bool by_examples = false;
1059
4781
      if (itsv == scasv.end())
1060
      {
1061
        // Is it equivalent under examples?
1062
6298
        Node bvr_equiv;
1063
3149
        if (aconj != nullptr && options::sygusSymBreakPbe())
1064
        {
1065
          // If the enumerator has examples, see if it is equivalent up to its
1066
          // examples with a previous term.
1067
3035
          quantifiers::ExampleEvalCache* eec = aconj->getExampleEvalCache(a);
1068
3035
          if (eec != nullptr)
1069
          {
1070
433
            bvr_equiv = eec->addSearchVal(tn, bvr);
1071
          }
1072
        }
1073
3149
        if( !bvr_equiv.isNull() ){
1074
433
          if( bvr_equiv!=bvr ){
1075
15
            Trace("sygus-sb-debug") << "......adding search val for " << bvr << " returned " << bvr_equiv << std::endl;
1076
15
            Assert(scasv.find(bvr_equiv) != scasv.end());
1077
30
            Trace("sygus-sb-debug")
1078
15
                << "......search value was " << scasv[bvr_equiv] << std::endl;
1079
15
            if( Trace.isOn("sygus-sb-exc") ){
1080
              Node prev = d_tds->sygusToBuiltin(scasv[bvr_equiv], tn);
1081
              Trace("sygus-sb-exc") << "  ......programs " << prev << " and " << bv << " are equivalent up to examples." << std::endl;
1082
            }
1083
15
            bad_val_bvr = bvr_equiv;
1084
15
            by_examples = true;
1085
          }
1086
        }
1087
        //store rewritten values, regardless of whether it will be considered
1088
3149
        scasv[bvr] = nv;
1089
3149
        scasvs[bvr] = sz;
1090
      }
1091
      else
1092
      {
1093
1632
        bad_val_bvr = bvr;
1094
1632
        if( Trace.isOn("sygus-sb-exc") ){
1095
          Node prev_bv = d_tds->sygusToBuiltin( itsv->second, tn );
1096
          Trace("sygus-sb-exc") << "  ......programs " << prev_bv << " and " << bv << " rewrite to " << bvr << "." << std::endl;
1097
        }
1098
      }
1099
1100
4781
      if (options::sygusRewVerify())
1101
      {
1102
7
        if (bv != bvr)
1103
        {
1104
          // add to the sampler database object
1105
          std::map<TypeNode, std::unique_ptr<quantifiers::SygusSampler>>& smap =
1106
1
              d_sampler[a];
1107
          std::map<TypeNode,
1108
                   std::unique_ptr<quantifiers::SygusSampler>>::iterator its =
1109
1
              smap.find(tn);
1110
1
          if (its == smap.end())
1111
          {
1112
1
            smap[tn].reset(new quantifiers::SygusSampler(d_env));
1113
2
            smap[tn]->initializeSygus(
1114
1
                d_tds, nv, options::sygusSamples(), false);
1115
1
            its = d_sampler[a].find(tn);
1116
          }
1117
          // check equivalent
1118
1
          its->second->checkEquivalent(bv, bvr, *options().base.out);
1119
        }
1120
      }
1121
1122
4781
      if( !bad_val_bvr.isNull() ){
1123
1652
        Node bad_val = nv;
1124
1652
        Node bad_val_o = scasv[bad_val_bvr];
1125
1647
        Assert(scasvs.find(bad_val_bvr) != scasvs.end());
1126
1647
        unsigned prev_sz = scasvs[bad_val_bvr];
1127
1647
        bool doFlip = (prev_sz > sz);
1128
1647
        if (doFlip)
1129
        {
1130
          //swap : the excluded value is the previous
1131
5
          scasvs[bad_val_bvr] = sz;
1132
5
          bad_val = scasv[bad_val_bvr];
1133
5
          bad_val_o = nv;
1134
5
          if (Trace.isOn("sygus-sb-exc"))
1135
          {
1136
            Trace("sygus-sb-exc") << "Flip : exclude ";
1137
            quantifiers::TermDbSygus::toStreamSygus("sygus-sb-exc", bad_val);
1138
            Trace("sygus-sb-exc") << " instead of ";
1139
            quantifiers::TermDbSygus::toStreamSygus("sygus-sb-exc", bad_val_o);
1140
            Trace("sygus-sb-exc") << ", since its size is " << sz << " < "
1141
                                  << prev_sz << std::endl;
1142
          }
1143
5
          sz = prev_sz;
1144
        }
1145
1647
        if( Trace.isOn("sygus-sb-exc") ){
1146
          Node bad_val_bv = d_tds->sygusToBuiltin( bad_val, tn );
1147
          Trace("sygus-sb-exc") << "  ........exclude : " << bad_val_bv;
1148
          if( by_examples ){
1149
            Trace("sygus-sb-exc") << " (by examples)";
1150
          }
1151
          Trace("sygus-sb-exc") << std::endl;
1152
        }
1153
1647
        Assert(utils::getSygusTermSize(bad_val) == sz);
1154
1155
        // generalize the explanation for why the analog of bad_val
1156
        // is equivalent to bvr
1157
1652
        quantifiers::EquivSygusInvarianceTest eset;
1158
1647
        eset.init(d_tds, tn, aconj, a, bvr);
1159
1160
1647
        Trace("sygus-sb-mexp-debug") << "Minimize explanation for eval[" << d_tds->sygusToBuiltin( bad_val ) << "] = " << bvr << std::endl;
1161
1647
        registerSymBreakLemmaForValue(a, bad_val, eset, bad_val_o, var_count);
1162
1163
        // other generalization criteria go here
1164
1165
        // If the exclusion was flipped, we are excluding a previous value
1166
        // instead of the current one. Hence, the current value is a legal
1167
        // value that we will consider.
1168
1647
        if (!doFlip)
1169
        {
1170
1642
          return Node::null();
1171
        }
1172
      }
1173
    }
1174
  }
1175
25433
  return nv;
1176
}
1177
1178
1648
void SygusExtension::registerSymBreakLemmaForValue(
1179
    Node a,
1180
    Node val,
1181
    quantifiers::SygusInvarianceTest& et,
1182
    Node valr,
1183
    std::map<TypeNode, int>& var_count)
1184
{
1185
3296
  TypeNode tn = val.getType();
1186
3296
  Node x = getFreeVar(tn);
1187
1648
  unsigned sz = utils::getSygusTermSize(val);
1188
3296
  std::vector<Node> exp;
1189
1648
  d_tds->getExplain()->getExplanationFor(x, val, exp, et, valr, var_count, sz);
1190
  Node lem =
1191
3296
      exp.size() == 1 ? exp[0] : NodeManager::currentNM()->mkNode(AND, exp);
1192
1648
  lem = lem.negate();
1193
3296
  Trace("sygus-sb-exc") << "  ........exc lemma is " << lem << ", size = " << sz
1194
1648
                        << std::endl;
1195
1648
  registerSymBreakLemma(tn, lem, sz, a);
1196
1648
}
1197
1198
1657
void SygusExtension::registerSymBreakLemma(TypeNode tn,
1199
                                           Node lem,
1200
                                           unsigned sz,
1201
                                           Node a)
1202
{
1203
  // lem holds for all terms of type tn, and is applicable to terms of size sz
1204
3314
  Trace("sygus-sb-debug") << "  register sym break lemma : " << lem
1205
1657
                          << std::endl;
1206
1657
  Trace("sygus-sb-debug") << "     anchor : " << a << std::endl;
1207
1657
  Trace("sygus-sb-debug") << "     type : " << tn << std::endl;
1208
1657
  Trace("sygus-sb-debug") << "     size : " << sz << std::endl;
1209
1657
  Assert(!a.isNull());
1210
1657
  SearchCache& sca = d_cache[a];
1211
1657
  sca.d_sbLemmas[tn][sz].push_back(lem);
1212
3314
  TNode x = getFreeVar( tn );
1213
1657
  unsigned csz = getSearchSizeForAnchor( a );
1214
1657
  int max_depth = ((int)csz)-((int)sz);
1215
1657
  NodeManager* nm = NodeManager::currentNM();
1216
3832
  for( int d=0; d<=max_depth; d++ ){
1217
    std::map<unsigned, std::vector<Node>>::iterator itt =
1218
2175
        sca.d_search_terms[tn].find(d);
1219
2175
    if (itt != sca.d_search_terms[tn].end())
1220
    {
1221
3707
      for (const Node& t : itt->second)
1222
      {
1223
3996
        if (!options::sygusSymBreakLazy()
1224
1998
            || d_active_terms.find(t) != d_active_terms.end())
1225
        {
1226
3580
          Node slem = lem.substitute(x, t);
1227
3580
          Node rlv = getRelevancyCondition(t);
1228
1790
          if (!rlv.isNull())
1229
          {
1230
290
            slem = nm->mkNode(OR, rlv, slem);
1231
          }
1232
1790
          d_im.lemma(slem, InferenceId::DATATYPES_SYGUS_SYM_BREAK);
1233
        }
1234
      }
1235
    }
1236
  }
1237
1657
}
1238
1239
65787
void SygusExtension::addSymBreakLemmasFor(TypeNode tn, TNode t, unsigned d)
1240
{
1241
65787
  Assert(d_term_to_anchor.find(t) != d_term_to_anchor.end());
1242
131574
  Node a = d_term_to_anchor[t];
1243
65787
  addSymBreakLemmasFor(tn, t, d, a);
1244
65787
}
1245
1246
65787
void SygusExtension::addSymBreakLemmasFor(TypeNode tn,
1247
                                          TNode t,
1248
                                          unsigned d,
1249
                                          Node a)
1250
{
1251
65787
  Assert(t.getType() == tn);
1252
65787
  Assert(!a.isNull());
1253
131574
  Trace("sygus-sb-debug2") << "add sym break lemmas for " << t << " " << d
1254
65787
                           << " " << a << std::endl;
1255
65787
  SearchCache& sca = d_cache[a];
1256
  std::map<TypeNode, std::map<uint64_t, std::vector<Node>>>::iterator its =
1257
65787
      sca.d_sbLemmas.find(tn);
1258
131574
  Node rlv = getRelevancyCondition(t);
1259
65787
  NodeManager* nm = NodeManager::currentNM();
1260
65787
  if (its != sca.d_sbLemmas.end())
1261
  {
1262
94874
    TNode x = getFreeVar( tn );
1263
    //get symmetry breaking lemmas for this term
1264
47437
    unsigned csz = getSearchSizeForAnchor( a );
1265
47437
    uint64_t max_sz = d > csz ? 0 : (csz - d);
1266
94874
    Trace("sygus-sb-debug2")
1267
47437
        << "add lemmas up to size " << max_sz << ", which is (search_size) "
1268
47437
        << csz << " - (depth) " << d << std::endl;
1269
94874
    std::unordered_map<TNode, TNode> cache;
1270
145191
    for (std::pair<const uint64_t, std::vector<Node>>& sbls : its->second)
1271
    {
1272
97754
      if (sbls.first <= max_sz)
1273
      {
1274
422287
        for (const Node& lem : sbls.second)
1275
        {
1276
733288
          Node slem = lem.substitute(x, t, cache);
1277
          // add the relevancy condition for t
1278
366644
          if (!rlv.isNull())
1279
          {
1280
188755
            slem = nm->mkNode(OR, rlv, slem);
1281
          }
1282
366644
          d_im.lemma(slem, InferenceId::DATATYPES_SYGUS_SYM_BREAK);
1283
        }
1284
      }
1285
    }
1286
  }
1287
65787
  Trace("sygus-sb-debug2") << "...finished." << std::endl;
1288
65787
}
1289
1290
23073
void SygusExtension::preRegisterTerm(TNode n)
1291
{
1292
23073
  if( n.isVar() ){
1293
1148
    Trace("sygus-sb-debug") << "Pre-register variable : " << n << std::endl;
1294
1148
    registerSizeTerm(n);
1295
  }
1296
23073
}
1297
1298
1837
void SygusExtension::registerSizeTerm(Node e)
1299
{
1300
1837
  if (d_register_st.find(e) != d_register_st.end())
1301
  {
1302
    // already registered
1303
2601
    return;
1304
  }
1305
1073
  TypeNode etn = e.getType();
1306
713
  if (!etn.isDatatype())
1307
  {
1308
    // not a datatype term
1309
31
    d_register_st[e] = false;
1310
31
    return;
1311
  }
1312
682
  const DType& dt = etn.getDType();
1313
682
  if (!dt.isSygus())
1314
  {
1315
    // not a sygus datatype term
1316
160
    d_register_st[e] = false;
1317
160
    return;
1318
  }
1319
522
  if (!d_tds->isEnumerator(e))
1320
  {
1321
    // not sure if it is a size term or not (may be registered later?)
1322
162
    return;
1323
  }
1324
360
  d_register_st[e] = true;
1325
720
  Node ag = d_tds->getActiveGuardForEnumerator(e);
1326
360
  if (!ag.isNull())
1327
  {
1328
118
    d_anchor_to_active_guard[e] = ag;
1329
    std::map<Node, std::unique_ptr<DecisionStrategy>>::iterator itaas =
1330
118
        d_anchor_to_ag_strategy.find(e);
1331
118
    if (itaas == d_anchor_to_ag_strategy.end())
1332
    {
1333
354
      d_anchor_to_ag_strategy[e].reset(new DecisionStrategySingleton(
1334
236
          d_env, "sygus_enum_active", ag, d_state.getValuation()));
1335
    }
1336
236
    d_im.getDecisionManager()->registerStrategy(
1337
        DecisionManager::STRAT_DT_SYGUS_ENUM_ACTIVE,
1338
118
        d_anchor_to_ag_strategy[e].get());
1339
  }
1340
720
  Node m;
1341
360
  if (!ag.isNull())
1342
  {
1343
    // if it has an active guard (it is an enumerator), use itself as measure
1344
    // term. This will enforce fairness on it independently.
1345
118
    m = e;
1346
  }
1347
  else
1348
  {
1349
    // otherwise we enforce fairness in a unified way for all
1350
242
    if (d_generic_measure_term.isNull())
1351
    {
1352
      // choose e as master for all future terms
1353
133
      d_generic_measure_term = e;
1354
    }
1355
242
    m = d_generic_measure_term;
1356
  }
1357
720
  Trace("sygus-sb") << "Sygus : register size term : " << e << " with measure "
1358
360
                    << m << std::endl;
1359
360
  registerMeasureTerm(m);
1360
360
  d_szinfo[m]->d_anchors.push_back(e);
1361
360
  d_anchor_to_measure_term[e] = m;
1362
360
  NodeManager* nm = NodeManager::currentNM();
1363
360
  if (options::sygusFair() == options::SygusFairMode::DT_SIZE)
1364
  {
1365
    // update constraints on the measure term
1366
714
    Node slem;
1367
357
    if (options::sygusFairMax())
1368
    {
1369
714
      Node ds = nm->mkNode(DT_SIZE, e);
1370
357
      slem = nm->mkNode(LEQ, ds, d_szinfo[m]->getOrMkMeasureValue());
1371
    }else{
1372
      Node mt = d_szinfo[m]->getOrMkActiveMeasureValue();
1373
      Node newMt = d_szinfo[m]->getOrMkActiveMeasureValue(true);
1374
      Node ds = nm->mkNode(DT_SIZE, e);
1375
      slem = mt.eqNode(nm->mkNode(PLUS, newMt, ds));
1376
    }
1377
357
    Trace("sygus-sb") << "...size lemma : " << slem << std::endl;
1378
357
    d_im.lemma(slem, InferenceId::DATATYPES_SYGUS_MT_BOUND);
1379
  }
1380
360
  if (d_tds->isVariableAgnosticEnumerator(e))
1381
  {
1382
    // if it is variable agnostic, enforce top-level constraint that says no
1383
    // variables occur pre-traversal at top-level
1384
2
    Node varList = dt.getSygusVarList();
1385
2
    std::vector<Node> constraints;
1386
1
    quantifiers::SygusTypeInfo& eti = d_tds->getTypeInfo(etn);
1387
3
    for (const Node& v : varList)
1388
    {
1389
2
      unsigned sc = eti.getSubclassForVar(v);
1390
      // no symmetry breaking occurs for variables in singleton subclasses
1391
2
      if (eti.getNumSubclassVars(sc) > 1)
1392
      {
1393
4
        Node preRootOp = getTraversalPredicate(etn, v, true);
1394
4
        Node preRoot = nm->mkNode(APPLY_UF, preRootOp, e);
1395
2
        constraints.push_back(preRoot.negate());
1396
      }
1397
    }
1398
1
    if (!constraints.empty())
1399
    {
1400
1
      Node preNoVar = constraints.size() == 1 ? constraints[0]
1401
2
                                              : nm->mkNode(AND, constraints);
1402
2
      Node preNoVarProc = eliminateTraversalPredicates(preNoVar);
1403
1
      Trace("sygus-sb") << "...variable order : " << preNoVarProc << std::endl;
1404
2
      Trace("sygus-sb-tp") << "...variable order : " << preNoVarProc
1405
1
                           << std::endl;
1406
1
      d_im.lemma(preNoVarProc, InferenceId::DATATYPES_SYGUS_VAR_AGNOSTIC);
1407
    }
1408
  }
1409
}
1410
1411
8947
void SygusExtension::registerMeasureTerm( Node m ) {
1412
  std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator it =
1413
8947
      d_szinfo.find(m);
1414
8947
  if( it==d_szinfo.end() ){
1415
251
    Trace("sygus-sb") << "Sygus : register measure term : " << m << std::endl;
1416
251
    d_szinfo[m].reset(new SygusSizeDecisionStrategy(d_env, d_im, m, d_state));
1417
    // register this as a decision strategy
1418
502
    d_im.getDecisionManager()->registerStrategy(
1419
251
        DecisionManager::STRAT_DT_SYGUS_ENUM_SIZE, d_szinfo[m].get());
1420
  }
1421
8947
}
1422
1423
6206
void SygusExtension::notifySearchSize(TNode m, uint64_t s, Node exp)
1424
{
1425
  std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator its =
1426
6206
      d_szinfo.find(m);
1427
6206
  Assert(its != d_szinfo.end());
1428
6206
  if( its->second->d_search_size.find( s )==its->second->d_search_size.end() ){
1429
459
    its->second->d_search_size[s] = true;
1430
459
    its->second->d_search_size_exp[s] = exp;
1431
459
    Assert(s == 0
1432
           || its->second->d_search_size.find(s - 1)
1433
                  != its->second->d_search_size.end());
1434
459
    Trace("sygus-fair") << "SygusExtension:: now considering term measure : " << s << " for " << m << std::endl;
1435
459
    Assert(s >= its->second->d_curr_search_size);
1436
875
    while( s>its->second->d_curr_search_size ){
1437
208
      incrementCurrentSearchSize(m);
1438
    }
1439
459
    Trace("sygus-fair") << "...finish increment for term measure : " << s << std::endl;
1440
  }
1441
6206
}
1442
1443
unsigned SygusExtension::getSearchSizeFor( Node n ) {
1444
  Trace("sygus-sb-debug2") << "get search size for term : " << n << std::endl;
1445
  std::unordered_map<Node, Node>::iterator ita = d_term_to_anchor.find(n);
1446
  Assert(ita != d_term_to_anchor.end());
1447
  return getSearchSizeForAnchor( ita->second );
1448
}
1449
1450
57173
unsigned SygusExtension::getSearchSizeForAnchor( Node a ) {
1451
57173
  Trace("sygus-sb-debug2") << "get search size for anchor : " << a << std::endl;
1452
57173
  std::map< Node, Node >::iterator it = d_anchor_to_measure_term.find( a );
1453
57173
  Assert(it != d_anchor_to_measure_term.end());
1454
57173
  return getSearchSizeForMeasureTerm(it->second);
1455
}
1456
1457
57173
unsigned SygusExtension::getSearchSizeForMeasureTerm(Node m)
1458
{
1459
57173
  Trace("sygus-sb-debug2") << "get search size for measure : " << m << std::endl;
1460
  std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator its =
1461
57173
      d_szinfo.find(m);
1462
57173
  Assert(its != d_szinfo.end());
1463
57173
  return its->second->d_curr_search_size;
1464
}
1465
1466
208
void SygusExtension::incrementCurrentSearchSize(TNode m)
1467
{
1468
  std::map<Node, std::unique_ptr<SygusSizeDecisionStrategy>>::iterator itsz =
1469
208
      d_szinfo.find(m);
1470
208
  Assert(itsz != d_szinfo.end());
1471
208
  itsz->second->d_curr_search_size++;
1472
208
  Trace("sygus-fair") << "  register search size " << itsz->second->d_curr_search_size << " for " << m << std::endl;
1473
208
  NodeManager* nm = NodeManager::currentNM();
1474
496
  for( std::map< Node, SearchCache >::iterator itc = d_cache.begin(); itc != d_cache.end(); ++itc ){
1475
576
    Node a = itc->first;
1476
288
    Trace("sygus-fair-debug") << "  look at anchor " << a << "..." << std::endl;
1477
    // check whether a is bounded by m
1478
288
    Assert(d_anchor_to_measure_term.find(a) != d_anchor_to_measure_term.end());
1479
288
    if( d_anchor_to_measure_term[a]==m ){
1480
70
      for (std::pair<const TypeNode, std::map<uint64_t, std::vector<Node>>>&
1481
285
               sbl : itc->second.d_sbLemmas)
1482
      {
1483
140
        TypeNode tn = sbl.first;
1484
140
        TNode x = getFreeVar( tn );
1485
163
        for (std::pair<const uint64_t, std::vector<Node>>& s : sbl.second)
1486
        {
1487
93
          unsigned sz = s.first;
1488
93
          int new_depth = ((int)itsz->second->d_curr_search_size) - ((int)sz);
1489
93
          std::map< unsigned, std::vector< Node > >::iterator itt = itc->second.d_search_terms[tn].find( new_depth );
1490
93
          if( itt!=itc->second.d_search_terms[tn].end() ){
1491
315
            for (const Node& t : itt->second)
1492
            {
1493
488
              if (!options::sygusSymBreakLazy()
1494
244
                  || (d_active_terms.find(t) != d_active_terms.end()
1495
                      && !s.second.empty()))
1496
              {
1497
                Node rlv = getRelevancyCondition(t);
1498
                std::unordered_map<TNode, TNode> cache;
1499
                for (const Node& lem : s.second)
1500
                {
1501
                  Node slem = lem.substitute(x, t, cache);
1502
                  if (!rlv.isNull())
1503
                  {
1504
                    slem = nm->mkNode(OR, rlv, slem);
1505
                  }
1506
                  d_im.lemma(slem, InferenceId::DATATYPES_SYGUS_SYM_BREAK);
1507
                }
1508
              }
1509
            }
1510
          }
1511
        }
1512
      }
1513
    }
1514
  }
1515
208
}
1516
1517
5379
void SygusExtension::check()
1518
{
1519
5379
  Trace("sygus-sb") << "SygusExtension::check" << std::endl;
1520
1521
  // reset the count of lemmas sent
1522
5379
  d_im.reset();
1523
1524
  // check for externally registered symmetry breaking lemmas
1525
10554
  std::vector<Node> anchors;
1526
5379
  if (d_tds->hasSymBreakLemmas(anchors))
1527
  {
1528
384
    for (const Node& a : anchors)
1529
    {
1530
      // is this a registered enumerator?
1531
198
      if (d_register_st.find(a) != d_register_st.end())
1532
      {
1533
        // symmetry breaking lemmas should only be for enumerators
1534
147
        Assert(d_register_st[a]);
1535
        // If this is a non-basic enumerator, process its symmetry breaking
1536
        // clauses. Since this class is not responsible for basic enumerators,
1537
        // their symmetry breaking clauses are ignored.
1538
147
        if (!d_tds->isBasicEnumerator(a))
1539
        {
1540
8
          std::vector<Node> sbl;
1541
4
          d_tds->getSymBreakLemmas(a, sbl);
1542
13
          for (const Node& lem : sbl)
1543
          {
1544
9
            if (d_tds->isSymBreakLemmaTemplate(lem))
1545
            {
1546
              // register the lemma template
1547
18
              TypeNode tn = d_tds->getTypeForSymBreakLemma(lem);
1548
9
              unsigned sz = d_tds->getSizeForSymBreakLemma(lem);
1549
9
              registerSymBreakLemma(tn, lem, sz, a);
1550
            }
1551
            else
1552
            {
1553
              Trace("dt-sygus-debug")
1554
                  << "DT sym break lemma : " << lem << std::endl;
1555
              // it is a normal lemma
1556
              d_im.lemma(lem, InferenceId::DATATYPES_SYGUS_ENUM_SYM_BREAK);
1557
            }
1558
          }
1559
4
          d_tds->clearSymBreakLemmas(a);
1560
        }
1561
      }
1562
    }
1563
186
    if (d_im.hasSentLemma())
1564
    {
1565
      return;
1566
    }
1567
  }
1568
1569
  // register search values, add symmetry breaking lemmas if applicable
1570
10554
  std::vector<Node> es;
1571
5379
  d_tds->getEnumerators(es);
1572
5379
  bool needsRecheck = false;
1573
  // for each enumerator registered to d_tds
1574
14029
  for (Node& prog : es)
1575
  {
1576
8650
    if (d_register_st.find(prog) == d_register_st.end())
1577
    {
1578
      // not yet registered, do so now
1579
280
      registerSizeTerm(prog);
1580
280
      needsRecheck = true;
1581
    }
1582
    else
1583
    {
1584
16740
      Trace("dt-sygus-debug") << "Checking model value of " << prog << "..."
1585
8370
                              << std::endl;
1586
8370
      Assert(prog.getType().isDatatype());
1587
16740
      Node progv = d_state.getValuation().getModel()->getValue(prog);
1588
8370
      if (Trace.isOn("dt-sygus"))
1589
      {
1590
        Trace("dt-sygus") << "* DT model : " << prog << " -> ";
1591
        std::stringstream ss;
1592
        quantifiers::TermDbSygus::toStreamSygus(ss, progv);
1593
        Trace("dt-sygus") << ss.str() << std::endl;
1594
      }
1595
      // first check that the value progv for prog is what we expected
1596
8370
      bool isExc = true;
1597
8370
      if (checkValue(prog, progv, 0))
1598
      {
1599
8082
        isExc = false;
1600
        //debugging : ensure fairness was properly handled
1601
8082
        if (options::sygusFair() == options::SygusFairMode::DT_SIZE)
1602
        {
1603
16158
          Node prog_sz = NodeManager::currentNM()->mkNode( kind::DT_SIZE, prog );
1604
16158
          Node prog_szv = d_state.getValuation().getModel()->getValue(prog_sz);
1605
16158
          Node progv_sz = NodeManager::currentNM()->mkNode( kind::DT_SIZE, progv );
1606
1607
8079
          Trace("sygus-sb") << "  Mv[" << prog << "] = " << progv << ", size = " << prog_szv << std::endl;
1608
8079
          if( prog_szv.getConst<Rational>().getNumerator().toUnsignedInt() > getSearchSizeForAnchor( prog ) ){
1609
            AlwaysAssert(false);
1610
            Node szlem = NodeManager::currentNM()->mkNode( kind::OR, prog.eqNode( progv ).negate(),
1611
                                                                     prog_sz.eqNode( progv_sz ) );
1612
            Trace("sygus-sb-warn") << "SygusSymBreak : WARNING : adding size correction : " << szlem << std::endl;
1613
            d_im.lemma(szlem, InferenceId::DATATYPES_SYGUS_SIZE_CORRECTION);
1614
            isExc = true;
1615
          }
1616
        }
1617
1618
        // register the search value ( prog -> progv ), this may invoke symmetry
1619
        // breaking
1620
8082
        if (!isExc && options::sygusSymBreakDynamic())
1621
        {
1622
8082
          bool isVarAgnostic = d_tds->isVariableAgnosticEnumerator(prog);
1623
          // check that it is unique up to theory-specific rewriting and
1624
          // conjecture-specific symmetry breaking.
1625
          Node rsv =
1626
16164
              registerSearchValue(prog, prog, progv, 0, isVarAgnostic, true);
1627
8082
          if (rsv.isNull())
1628
          {
1629
1643
            isExc = true;
1630
1643
            Trace("sygus-sb") << "  SygusExtension::check: ...added new symmetry breaking lemma for " << prog << "." << std::endl;
1631
          }
1632
          else
1633
          {
1634
6439
            Trace("dt-sygus") << "  ...success." << std::endl;
1635
          }
1636
        }
1637
      }
1638
      SygusSymBreakOkAttribute ssbo;
1639
8370
      prog.setAttribute(ssbo, !isExc);
1640
    }
1641
  }
1642
5379
  Trace("sygus-sb") << "SygusExtension::check: finished." << std::endl;
1643
5379
  if (needsRecheck)
1644
  {
1645
204
    Trace("sygus-sb") << " SygusExtension::rechecking..." << std::endl;
1646
204
    return check();
1647
  }
1648
1649
5175
  if (Trace.isOn("sygus-engine") && !d_szinfo.empty())
1650
  {
1651
    if (d_im.hasSentLemma())
1652
    {
1653
      Trace("sygus-engine") << "*** Sygus : passed datatypes check. term size(s) : ";
1654
      for (std::pair<const Node, std::unique_ptr<SygusSizeDecisionStrategy>>&
1655
               p : d_szinfo)
1656
      {
1657
        SygusSizeDecisionStrategy* s = p.second.get();
1658
        Trace("sygus-engine") << s->d_curr_search_size << " ";
1659
      }
1660
      Trace("sygus-engine") << std::endl;
1661
    }
1662
    else
1663
    {
1664
      Trace("sygus-engine")
1665
          << "*** Sygus : produced symmetry breaking lemmas" << std::endl;
1666
    }
1667
  }
1668
}
1669
1670
28724
bool SygusExtension::checkValue(Node n, TNode vn, int ind)
1671
{
1672
28724
  if (vn.getKind() != kind::APPLY_CONSTRUCTOR)
1673
  {
1674
    // all datatype terms should be constant here
1675
477
    Assert(!vn.getType().isDatatype());
1676
477
    return true;
1677
  }
1678
28247
  NodeManager* nm = NodeManager::currentNM();
1679
28247
  if (Trace.isOn("sygus-sb-check-value"))
1680
  {
1681
    Node prog_sz = nm->mkNode(DT_SIZE, n);
1682
    Node prog_szv = d_state.getValuation().getModel()->getValue(prog_sz);
1683
    for( int i=0; i<ind; i++ ){
1684
      Trace("sygus-sb-check-value") << "  ";
1685
    }
1686
    Trace("sygus-sb-check-value") << n << " : " << vn << " : " << prog_szv
1687
                                  << std::endl;
1688
  }
1689
56494
  TypeNode tn = n.getType();
1690
28247
  const DType& dt = tn.getDType();
1691
1692
  // ensure that the expected size bound is met
1693
28247
  int cindex = utils::indexOf(vn.getOperator());
1694
56494
  Node tst = utils::mkTester(n, cindex, dt);
1695
28247
  bool hastst = d_state.getEqualityEngine()->hasTerm(tst);
1696
56494
  Node tstrep;
1697
28247
  if (hastst)
1698
  {
1699
27959
    tstrep = d_state.getEqualityEngine()->getRepresentative(tst);
1700
  }
1701
28247
  if (!hastst || tstrep != d_true)
1702
  {
1703
576
    Trace("sygus-check-value") << "- has tester : " << tst << " : "
1704
288
                               << (hastst ? "true" : "false");
1705
288
    Trace("sygus-check-value") << ", value=" << tstrep << std::endl;
1706
288
    if( !hastst ){
1707
      // This should not happen generally, it is caused by a sygus term not
1708
      // being assigned a tester.
1709
576
      Node split = utils::mkSplit(n, dt);
1710
576
      Trace("sygus-sb") << "  SygusExtension::check: ...WARNING: considered "
1711
288
                           "missing split for "
1712
288
                        << n << "." << std::endl;
1713
288
      Assert(!split.isNull());
1714
288
      d_im.lemma(split, InferenceId::DATATYPES_SYGUS_VALUE_CORRECTION);
1715
288
      return false;
1716
    }
1717
  }
1718
48302
  for( unsigned i=0; i<vn.getNumChildren(); i++ ){
1719
    Node sel = nm->mkNode(
1720
40697
        APPLY_SELECTOR_TOTAL, dt[cindex].getSelectorInternal(tn, i), n);
1721
20354
    if (!checkValue(sel, vn[i], ind + 1))
1722
    {
1723
11
      return false;
1724
    }
1725
  }
1726
27948
  return true;
1727
}
1728
1729
Node SygusExtension::getCurrentTemplate( Node n, std::map< TypeNode, int >& var_count ) {
1730
  if( d_active_terms.find( n )!=d_active_terms.end() ){
1731
    TypeNode tn = n.getType();
1732
    IntMap::const_iterator it = d_testers.find( n );
1733
    Assert(it != d_testers.end());
1734
    const DType& dt = tn.getDType();
1735
    int tindex = (*it).second;
1736
    Assert(tindex >= 0);
1737
    Assert(tindex < (int)dt.getNumConstructors());
1738
    std::vector< Node > children;
1739
    children.push_back(dt[tindex].getConstructor());
1740
    for( unsigned i=0; i<dt[tindex].getNumArgs(); i++ ){
1741
      Node sel = NodeManager::currentNM()->mkNode(
1742
          APPLY_SELECTOR_TOTAL, dt[tindex].getSelectorInternal(tn, i), n);
1743
      Node cc = getCurrentTemplate( sel, var_count );
1744
      children.push_back( cc );
1745
    }
1746
    return NodeManager::currentNM()->mkNode( kind::APPLY_CONSTRUCTOR, children );
1747
  }else{
1748
    return d_tds->getFreeVarInc( n.getType(), var_count );
1749
  }
1750
}
1751
1752
251
SygusExtension::SygusSizeDecisionStrategy::SygusSizeDecisionStrategy(
1753
251
    Env& env, InferenceManager& im, Node t, TheoryState& s)
1754
251
    : DecisionStrategyFmf(env, s.getValuation()),
1755
      d_this(t),
1756
      d_curr_search_size(0),
1757
502
      d_im(im)
1758
{
1759
251
}
1760
1761
8941
Node SygusExtension::SygusSizeDecisionStrategy::getOrMkMeasureValue()
1762
{
1763
8941
  if (d_measure_value.isNull())
1764
  {
1765
248
    NodeManager* nm = NodeManager::currentNM();
1766
248
    SkolemManager* sm = nm->getSkolemManager();
1767
248
    d_measure_value = sm->mkDummySkolem("mt", nm->integerType());
1768
    Node mtlem =
1769
496
        nm->mkNode(kind::GEQ, d_measure_value, nm->mkConst(Rational(0)));
1770
248
    d_im.lemma(mtlem, InferenceId::DATATYPES_SYGUS_MT_POS);
1771
  }
1772
8941
  return d_measure_value;
1773
}
1774
1775
Node SygusExtension::SygusSizeDecisionStrategy::getOrMkActiveMeasureValue(
1776
    bool mkNew)
1777
{
1778
  if (mkNew)
1779
  {
1780
    NodeManager* nm = NodeManager::currentNM();
1781
    SkolemManager* sm = nm->getSkolemManager();
1782
    Node new_mt = sm->mkDummySkolem("mt", nm->integerType());
1783
    Node mtlem = nm->mkNode(kind::GEQ, new_mt, nm->mkConst(Rational(0)));
1784
    d_measure_value_active = new_mt;
1785
    d_im.lemma(mtlem, InferenceId::DATATYPES_SYGUS_MT_POS);
1786
  }
1787
  else if (d_measure_value_active.isNull())
1788
  {
1789
    d_measure_value_active = getOrMkMeasureValue();
1790
  }
1791
  return d_measure_value_active;
1792
}
1793
1794
461
Node SygusExtension::SygusSizeDecisionStrategy::mkLiteral(unsigned s)
1795
{
1796
461
  if (options::sygusFair() == options::SygusFairMode::NONE)
1797
  {
1798
    return Node::null();
1799
  }
1800
922
  if (options::sygusAbortSize() != -1
1801
461
      && static_cast<int>(s) > options::sygusAbortSize())
1802
  {
1803
4
    std::stringstream ss;
1804
2
    ss << "Maximum term size (" << options::sygusAbortSize()
1805
2
       << ") for enumerative SyGuS exceeded.";
1806
2
    throw LogicException(ss.str());
1807
  }
1808
459
  Assert(!d_this.isNull());
1809
459
  NodeManager* nm = NodeManager::currentNM();
1810
918
  Trace("sygus-engine") << "******* Sygus : allocate size literal " << s
1811
459
                        << " for " << d_this << std::endl;
1812
459
  return nm->mkNode(DT_SYGUS_BOUND, d_this, nm->mkConst(Rational(s)));
1813
}
1814
1815
int SygusExtension::getGuardStatus( Node g ) {
1816
  bool value;
1817
  if (d_state.getValuation().hasSatValue(g, value))
1818
  {
1819
    if( value ){
1820
      return 1;
1821
    }else{
1822
      return -1;
1823
    }
1824
  }else{
1825
    return 0;
1826
  }
1827
22746
}
1828