GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/cegis.cpp Lines: 323 344 93.9 %
Date: 2021-08-01 Branches: 611 1298 47.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Haniel Barbosa, 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 cegis.
14
 */
15
16
#include "theory/quantifiers/sygus/cegis.h"
17
18
#include "expr/node_algorithm.h"
19
#include "options/base_options.h"
20
#include "options/quantifiers_options.h"
21
#include "printer/printer.h"
22
#include "theory/quantifiers/sygus/example_min_eval.h"
23
#include "theory/quantifiers/sygus/synth_conjecture.h"
24
#include "theory/quantifiers/sygus/term_database_sygus.h"
25
#include "theory/rewriter.h"
26
27
using namespace std;
28
using namespace cvc5::kind;
29
using namespace cvc5::context;
30
31
namespace cvc5 {
32
namespace theory {
33
namespace quantifiers {
34
35
3453
Cegis::Cegis(QuantifiersInferenceManager& qim,
36
             TermDbSygus* tds,
37
3453
             SynthConjecture* p)
38
    : SygusModule(qim, tds, p),
39
3453
      d_eval_unfold(tds->getEvalUnfold()),
40
6906
      d_usingSymCons(false)
41
{
42
3453
}
43
44
198
bool Cegis::initialize(Node conj,
45
                       Node n,
46
                       const std::vector<Node>& candidates,
47
                       std::vector<Node>& lemmas)
48
{
49
198
  d_base_body = n;
50
198
  if (d_base_body.getKind() == NOT && d_base_body[0].getKind() == FORALL)
51
  {
52
828
    for (const Node& v : d_base_body[0][0])
53
    {
54
695
      d_base_vars.push_back(v);
55
    }
56
133
    d_base_body = d_base_body[0][1];
57
  }
58
59
  // assign the cegis sampler if applicable
60
3851
  if (options::cegisSample() != options::CegisSampleMode::NONE)
61
  {
62
10
    Trace("cegis-sample") << "Initialize sampler for " << d_base_body << "..."
63
5
                          << std::endl;
64
10
    TypeNode bt = d_base_body.getType();
65
5
    d_cegis_sampler.initialize(bt, d_base_vars, options::sygusSamples());
66
  }
67
198
  return processInitialize(conj, n, candidates, lemmas);
68
}
69
70
185
bool Cegis::processInitialize(Node conj,
71
                              Node n,
72
                              const std::vector<Node>& candidates,
73
                              std::vector<Node>& lemmas)
74
{
75
185
  Trace("cegis") << "Initialize cegis..." << std::endl;
76
185
  unsigned csize = candidates.size();
77
  // The role of enumerators is to be either the single solution or part of
78
  // a solution involving multiple enumerators.
79
185
  EnumeratorRole erole =
80
185
      csize == 1 ? ROLE_ENUM_SINGLE_SOLUTION : ROLE_ENUM_MULTI_SOLUTION;
81
  // initialize an enumerator for each candidate
82
426
  for (unsigned i = 0; i < csize; i++)
83
  {
84
241
    Trace("cegis") << "...register enumerator " << candidates[i];
85
    // We use symbolic constants if we are doing repair constants or if the
86
    // grammar construction was not simple.
87
482
    if (options::sygusRepairConst()
88
907
        || options::sygusGrammarConsMode()
89
               != options::SygusGrammarConsMode::SIMPLE)
90
    {
91
24
      TypeNode ctn = candidates[i].getType();
92
12
      d_tds->registerSygusType(ctn);
93
12
      SygusTypeInfo& cti = d_tds->getTypeInfo(ctn);
94
12
      if (cti.hasSubtermSymbolicCons())
95
      {
96
        // remember that we are using symbolic constructors
97
12
        d_usingSymCons = true;
98
12
        Trace("cegis") << " (using symbolic constructors)";
99
      }
100
    }
101
241
    Trace("cegis") << std::endl;
102
241
    d_tds->registerEnumerator(candidates[i], candidates[i], d_parent, erole);
103
  }
104
185
  return true;
105
}
106
107
34989
void Cegis::getTermList(const std::vector<Node>& candidates,
108
                        std::vector<Node>& enums)
109
{
110
34989
  enums.insert(enums.end(), candidates.begin(), candidates.end());
111
34989
}
112
113
16280
bool Cegis::addEvalLemmas(const std::vector<Node>& candidates,
114
                          const std::vector<Node>& candidate_values,
115
                          std::vector<Node>& lems)
116
{
117
  // First, decide if this call will apply "conjecture-specific refinement".
118
  // In other words, in some settings, the following method will identify and
119
  // block a class of solutions {candidates -> S} that generalizes the current
120
  // one (given by {candidates -> candidate_values}), such that for each
121
  // candidate_values' in S, we have that {candidates -> candidate_values'} is
122
  // also not a solution for the given conjecture. We may not
123
  // apply this form of refinement if any (relevant) enumerator in candidates is
124
  // "actively generated" (see TermDbSygs::isPassiveEnumerator), since its
125
  // model values are themselves interpreted as classes of solutions.
126
16280
  bool doGen = true;
127
24912
  for (const Node& v : candidates)
128
  {
129
    // if it is relevant to refinement
130
21092
    if (d_refinement_lemma_vars.find(v) != d_refinement_lemma_vars.end())
131
    {
132
18787
      if (!d_tds->isPassiveEnumerator(v))
133
      {
134
12460
        doGen = false;
135
12460
        break;
136
      }
137
    }
138
  }
139
16280
  NodeManager* nm = NodeManager::currentNM();
140
16280
  bool addedEvalLemmas = false;
141
  // Refinement evaluation should not be done for grammars with symbolic
142
  // constructors.
143
16280
  if (!d_usingSymCons)
144
  {
145
32366
    Trace("sygus-engine") << "  *** Do refinement lemma evaluation"
146
32366
                          << (doGen ? " with conjecture-specific refinement"
147
16183
                                    : "")
148
16183
                          << "..." << std::endl;
149
    // see if any refinement lemma is refuted by evaluation
150
16183
    if (doGen)
151
    {
152
7450
      std::vector<Node> cre_lems;
153
3725
      getRefinementEvalLemmas(candidates, candidate_values, cre_lems);
154
3725
      if (!cre_lems.empty())
155
      {
156
1822
        lems.insert(lems.end(), cre_lems.begin(), cre_lems.end());
157
1822
        addedEvalLemmas = true;
158
1822
        if (Trace.isOn("cegqi-lemma"))
159
        {
160
          for (const Node& lem : cre_lems)
161
          {
162
            Trace("cegqi-lemma")
163
                << "Cegqi::Lemma : ref evaluation : " << lem << std::endl;
164
          }
165
        }
166
        /* we could, but do not return here. experimentally, it is better to
167
          add the lemmas below as well, in parallel. */
168
      }
169
    }
170
    else
171
    {
172
      // just check whether the refinement lemmas are satisfied, fail if not
173
12458
      if (checkRefinementEvalLemmas(candidates, candidate_values))
174
      {
175
24244
        Trace("sygus-engine") << "...(actively enumerated) candidate failed "
176
12122
                                 "refinement lemma evaluation."
177
12122
                              << std::endl;
178
12122
        return true;
179
      }
180
    }
181
  }
182
  // we only do evaluation unfolding for passive enumerators
183
368060
  bool doEvalUnfold = (doGen && options::sygusEvalUnfold()) || d_usingSymCons;
184
4158
  if (doEvalUnfold)
185
  {
186
3822
    Trace("sygus-engine") << "  *** Do evaluation unfolding..." << std::endl;
187
7644
    std::vector<Node> eager_terms, eager_vals, eager_exps;
188
12456
    for (unsigned i = 0, size = candidates.size(); i < size; ++i)
189
    {
190
17268
      Trace("cegqi-debug") << "  register " << candidates[i] << " -> "
191
8634
                           << candidate_values[i] << std::endl;
192
17268
      d_eval_unfold->registerModelValue(candidates[i],
193
8634
                                        candidate_values[i],
194
                                        eager_terms,
195
                                        eager_vals,
196
                                        eager_exps);
197
    }
198
7644
    Trace("cegqi-debug") << "...produced " << eager_terms.size()
199
3822
                         << " evaluation unfold lemmas.\n";
200
15440
    for (unsigned i = 0, size = eager_terms.size(); i < size; ++i)
201
    {
202
      Node lem = nm->mkNode(
203
23236
          OR, eager_exps[i].negate(), eager_terms[i].eqNode(eager_vals[i]));
204
11618
      lems.push_back(lem);
205
11618
      addedEvalLemmas = true;
206
23236
      Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation unfold : " << lem
207
11618
                           << std::endl;
208
    }
209
  }
210
4158
  return addedEvalLemmas;
211
}
212
213
65
Node Cegis::getRefinementLemmaFormula()
214
{
215
130
  std::vector<Node> conj;
216
65
  conj.insert(
217
130
      conj.end(), d_refinement_lemmas.begin(), d_refinement_lemmas.end());
218
  // get the propagated values
219
230
  for (unsigned i = 0, nprops = d_rl_eval_hds.size(); i < nprops; i++)
220
  {
221
165
    conj.push_back(d_rl_eval_hds[i].eqNode(d_rl_vals[i]));
222
  }
223
  // make the formula
224
65
  NodeManager* nm = NodeManager::currentNM();
225
65
  Node ret;
226
65
  if (conj.empty())
227
  {
228
1
    ret = nm->mkConst(true);
229
  }
230
  else
231
  {
232
64
    ret = conj.size() == 1 ? conj[0] : nm->mkNode(AND, conj);
233
  }
234
130
  return ret;
235
}
236
237
16350
bool Cegis::constructCandidates(const std::vector<Node>& enums,
238
                                const std::vector<Node>& enum_values,
239
                                const std::vector<Node>& candidates,
240
                                std::vector<Node>& candidate_values,
241
                                std::vector<Node>& lems)
242
{
243
16350
  if (Trace.isOn("cegis"))
244
  {
245
    Trace("cegis") << "  Enumerators :\n";
246
    for (unsigned i = 0, size = enums.size(); i < size; ++i)
247
    {
248
      Trace("cegis") << "    " << enums[i] << " -> ";
249
      TermDbSygus::toStreamSygus("cegis", enum_values[i]);
250
      Trace("cegis") << "\n";
251
    }
252
  }
253
  // if we are using grammar-based repair
254
16350
  if (d_usingSymCons && options::sygusRepairConst())
255
  {
256
110
    SygusRepairConst* src = d_parent->getRepairConst();
257
110
    Assert(src != nullptr);
258
    // check if any enum_values have symbolic terms that must be repaired
259
110
    bool mustRepair = false;
260
150
    for (const Node& c : enum_values)
261
    {
262
110
      if (SygusRepairConst::mustRepair(c))
263
      {
264
70
        mustRepair = true;
265
70
        break;
266
      }
267
    }
268
110
    Trace("cegis") << "...must repair is: " << mustRepair << std::endl;
269
    // if the solution contains a subterm that must be repaired
270
110
    if (mustRepair)
271
    {
272
140
      std::vector<Node> fail_cvs = enum_values;
273
70
      Assert(candidates.size() == fail_cvs.size());
274
      // try to solve entire problem?
275
70
      if (src->repairSolution(candidates, fail_cvs, candidate_values))
276
      {
277
5
        return true;
278
      }
279
130
      Node rl = getRefinementLemmaFormula();
280
      // try to solve for the refinement lemmas only
281
      bool ret =
282
65
          src->repairSolution(rl, candidates, fail_cvs, candidate_values);
283
      // Even if ret is true, we will exclude the skeleton as well; this means
284
      // that we have one chance to repair each skeleton. It is possible however
285
      // that we might want to repair the same skeleton multiple times.
286
130
      std::vector<Node> exp;
287
130
      for (unsigned i = 0, size = enums.size(); i < size; i++)
288
      {
289
195
        d_tds->getExplain()->getExplanationForEquality(
290
130
            enums[i], enum_values[i], exp);
291
      }
292
65
      Assert(!exp.empty());
293
65
      NodeManager* nm = NodeManager::currentNM();
294
130
      Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp);
295
      // must guard it
296
65
      expn = nm->mkNode(OR, d_parent->getGuard().negate(), expn.negate());
297
65
      lems.push_back(expn);
298
65
      return ret;
299
    }
300
  }
301
302
  // evaluate on refinement lemmas
303
16280
  bool addedEvalLemmas = addEvalLemmas(enums, enum_values, lems);
304
305
  // try to construct candidates
306
16280
  if (!processConstructCandidates(enums,
307
                                  enum_values,
308
                                  candidates,
309
                                  candidate_values,
310
16280
                                  !addedEvalLemmas,
311
16280
                                  lems))
312
  {
313
14546
    return false;
314
  }
315
316
1734
  if (options::cegisSample() != options::CegisSampleMode::NONE && lems.empty())
317
  {
318
    // if we didn't add a lemma, trying sampling to add a refinement lemma
319
    // that immediately refutes the candidate we just constructed
320
21
    if (sampleAddRefinementLemma(candidates, candidate_values, lems))
321
    {
322
6
      candidate_values.clear();
323
      // restart (should be guaranteed to add evaluation lemmas on this call)
324
      return constructCandidates(
325
6
          enums, enum_values, candidates, candidate_values, lems);
326
    }
327
  }
328
1728
  return true;
329
}
330
331
15875
bool Cegis::processConstructCandidates(const std::vector<Node>& enums,
332
                                       const std::vector<Node>& enum_values,
333
                                       const std::vector<Node>& candidates,
334
                                       std::vector<Node>& candidate_values,
335
                                       bool satisfiedRl,
336
                                       std::vector<Node>& lems)
337
{
338
15875
  if (satisfiedRl)
339
  {
340
1702
    candidate_values.insert(
341
3404
        candidate_values.end(), enum_values.begin(), enum_values.end());
342
1702
    return true;
343
  }
344
14173
  return false;
345
}
346
347
429
void Cegis::addRefinementLemma(Node lem)
348
{
349
429
  Trace("cegis-rl") << "Cegis::addRefinementLemma: " << lem << std::endl;
350
429
  d_refinement_lemmas.push_back(lem);
351
  // apply existing substitution
352
858
  Node slem = lem;
353
429
  if (!d_rl_eval_hds.empty())
354
  {
355
151
    slem = lem.substitute(d_rl_eval_hds.begin(),
356
                          d_rl_eval_hds.end(),
357
                          d_rl_vals.begin(),
358
                          d_rl_vals.end());
359
  }
360
  // rewrite with extended rewriter
361
429
  slem = d_tds->getExtRewriter()->extendedRewrite(slem);
362
  // collect all variables in slem
363
429
  expr::getSymbols(slem, d_refinement_lemma_vars);
364
858
  std::vector<Node> waiting;
365
429
  waiting.push_back(lem);
366
429
  unsigned wcounter = 0;
367
  // while we are not done adding lemmas
368
1683
  while (wcounter < waiting.size())
369
  {
370
    // add the conjunct, possibly propagating
371
627
    addRefinementLemmaConjunct(wcounter, waiting);
372
627
    wcounter++;
373
  }
374
429
}
375
376
627
void Cegis::addRefinementLemmaConjunct(unsigned wcounter,
377
                                       std::vector<Node>& waiting)
378
{
379
1124
  Node lem = waiting[wcounter];
380
627
  lem = Rewriter::rewrite(lem);
381
  // apply substitution and rewrite if applicable
382
627
  if (lem.isConst())
383
  {
384
5
    if (!lem.getConst<bool>())
385
    {
386
      // conjecture is infeasible
387
    }
388
    else
389
    {
390
3
      return;
391
    }
392
  }
393
  // break into conjunctions
394
624
  if (lem.getKind() == AND)
395
  {
396
265
    for (const Node& lc : lem)
397
    {
398
194
      waiting.push_back(lc);
399
    }
400
71
    return;
401
  }
402
  // does this correspond to a substitution?
403
553
  NodeManager* nm = NodeManager::currentNM();
404
1050
  TNode term;
405
1050
  TNode val;
406
553
  if (lem.getKind() == EQUAL)
407
  {
408
556
    for (unsigned i = 0; i < 2; i++)
409
    {
410
413
      if (lem[i].isConst() && d_tds->isEvaluationPoint(lem[1 - i]))
411
      {
412
64
        term = lem[1 - i];
413
64
        val = lem[i];
414
64
        break;
415
      }
416
    }
417
  }
418
  else
419
  {
420
346
    term = lem.getKind() == NOT ? lem[0] : lem;
421
    // predicate case: the conjunct is a (negated) evaluation point
422
346
    if (d_tds->isEvaluationPoint(term))
423
    {
424
157
      val = nm->mkConst(lem.getKind() != NOT);
425
    }
426
  }
427
553
  if (!val.isNull())
428
  {
429
221
    if (d_refinement_lemma_unit.find(lem) != d_refinement_lemma_unit.end())
430
    {
431
      // already added
432
56
      return;
433
    }
434
330
    Trace("cegis-rl") << "* cegis-rl: propagate: " << term << " -> " << val
435
165
                      << std::endl;
436
165
    d_rl_eval_hds.push_back(term);
437
165
    d_rl_vals.push_back(val);
438
165
    d_refinement_lemma_unit.insert(lem);
439
440
    // apply to waiting lemmas beyond this one
441
200
    for (unsigned i = wcounter + 1, size = waiting.size(); i < size; i++)
442
    {
443
35
      waiting[i] = waiting[i].substitute(term, val);
444
    }
445
    // apply to all existing refinement lemmas
446
330
    std::vector<Node> to_rem;
447
187
    for (const Node& rl : d_refinement_lemma_conj)
448
    {
449
44
      Node srl = rl.substitute(term, val);
450
22
      if (srl != rl)
451
      {
452
8
        Trace("cegis-rl") << "* cegis-rl: replace: " << rl << " -> " << srl
453
4
                          << std::endl;
454
4
        waiting.push_back(srl);
455
4
        to_rem.push_back(rl);
456
      }
457
    }
458
169
    for (const Node& tr : to_rem)
459
    {
460
4
      d_refinement_lemma_conj.erase(tr);
461
    }
462
  }
463
  else
464
  {
465
332
    if (Trace.isOn("cegis-rl"))
466
    {
467
      if (d_refinement_lemma_conj.find(lem) == d_refinement_lemma_conj.end())
468
      {
469
        Trace("cegis-rl") << "cegis-rl: add: " << lem << std::endl;
470
      }
471
    }
472
332
    d_refinement_lemma_conj.insert(lem);
473
  }
474
}
475
476
402
void Cegis::registerRefinementLemma(const std::vector<Node>& vars,
477
                                    Node lem,
478
                                    std::vector<Node>& lems)
479
{
480
402
  addRefinementLemma(lem);
481
  // Make the refinement lemma and add it to lems.
482
  // This lemma is guarded by the parent's guard, which has the semantics
483
  // "this conjecture has a solution", hence this lemma states:
484
  // if the parent conjecture has a solution, it satisfies the specification
485
  // for the given concrete point.
486
  Node rlem =
487
804
      NodeManager::currentNM()->mkNode(OR, d_parent->getGuard().negate(), lem);
488
402
  lems.push_back(rlem);
489
402
}
490
491
164
bool Cegis::usingRepairConst() { return true; }
492
3725
bool Cegis::getRefinementEvalLemmas(const std::vector<Node>& vs,
493
                                    const std::vector<Node>& ms,
494
                                    std::vector<Node>& lems)
495
{
496
7450
  Trace("sygus-cref-eval") << "Cref eval : conjecture has "
497
7450
                           << d_refinement_lemma_unit.size() << " unit and "
498
7450
                           << d_refinement_lemma_conj.size()
499
3725
                           << " non-unit refinement lemma conjunctions."
500
3725
                           << std::endl;
501
3725
  Assert(vs.size() == ms.size());
502
503
3725
  NodeManager* nm = NodeManager::currentNM();
504
505
7450
  Node nfalse = nm->mkConst(false);
506
7450
  Node neg_guard = d_parent->getGuard().negate();
507
3725
  bool ret = false;
508
509
8688
  for (unsigned r = 0; r < 2; r++)
510
  {
511
6785
    std::unordered_set<Node>& rlemmas =
512
        r == 0 ? d_refinement_lemma_unit : d_refinement_lemma_conj;
513
22750
    for (const Node& lem : rlemmas)
514
    {
515
15965
      Assert(!lem.isNull());
516
31930
      std::map<Node, Node> visited;
517
31930
      std::map<Node, std::vector<Node> > exp;
518
31930
      EvalSygusInvarianceTest vsit;
519
31930
      Trace("sygus-cref-eval") << "Check refinement lemma conjunct " << lem
520
15965
                               << " against current model." << std::endl;
521
31930
      Trace("sygus-cref-eval2") << "Check refinement lemma conjunct " << lem
522
15965
                                << " against current model." << std::endl;
523
31930
      Node cre_lem;
524
31930
      Node lemcs = lem.substitute(vs.begin(), vs.end(), ms.begin(), ms.end());
525
31930
      Trace("sygus-cref-eval2")
526
15965
          << "...under substitution it is : " << lemcs << std::endl;
527
31930
      Node lemcsu = vsit.doEvaluateWithUnfolding(d_tds, lemcs);
528
31930
      Trace("sygus-cref-eval2")
529
15965
          << "...after unfolding is : " << lemcsu << std::endl;
530
15965
      if (lemcsu.isConst() && !lemcsu.getConst<bool>())
531
      {
532
4602
        ret = true;
533
9204
        std::vector<Node> msu;
534
9204
        std::vector<Node> mexp;
535
4602
        msu.insert(msu.end(), ms.begin(), ms.end());
536
9204
        std::map<TypeNode, int> var_count;
537
12798
        for (unsigned k = 0; k < vs.size(); k++)
538
        {
539
8196
          vsit.setUpdatedTerm(msu[k]);
540
8196
          msu[k] = vs[k];
541
          // substitute for everything except this
542
          Node sconj =
543
16392
              lem.substitute(vs.begin(), vs.end(), msu.begin(), msu.end());
544
8196
          vsit.init(sconj, vs[k], nfalse);
545
          // get minimal explanation for this
546
16392
          Node ut = vsit.getUpdatedTerm();
547
16392
          Trace("sygus-cref-eval2-debug")
548
8196
              << "  compute min explain of : " << vs[k] << " = " << ut
549
8196
              << std::endl;
550
16392
          d_tds->getExplain()->getExplanationFor(
551
8196
              vs[k], ut, mexp, vsit, var_count, false);
552
8196
          Trace("sygus-cref-eval2-debug") << "exp now: " << mexp << std::endl;
553
8196
          msu[k] = vsit.getUpdatedTerm();
554
16392
          Trace("sygus-cref-eval2-debug")
555
8196
              << "updated term : " << msu[k] << std::endl;
556
        }
557
4602
        if (!mexp.empty())
558
        {
559
9204
          Node en = mexp.size() == 1 ? mexp[0] : nm->mkNode(kind::AND, mexp);
560
4602
          cre_lem = nm->mkNode(kind::OR, en.negate(), neg_guard);
561
        }
562
        else
563
        {
564
          cre_lem = neg_guard;
565
        }
566
4602
        if (std::find(lems.begin(), lems.end(), cre_lem) == lems.end())
567
        {
568
4708
          Trace("sygus-cref-eval") << "...produced lemma : " << cre_lem
569
2354
                                   << std::endl;
570
2354
          lems.push_back(cre_lem);
571
        }
572
      }
573
    }
574
6785
    if (!lems.empty())
575
    {
576
1822
      break;
577
    }
578
  }
579
7450
  return ret;
580
}
581
582
12458
bool Cegis::checkRefinementEvalLemmas(const std::vector<Node>& vs,
583
                                      const std::vector<Node>& ms)
584
{
585
  // Maybe we already evaluated some terms in refinement lemmas.
586
  // In particular, the example eval cache for f may have some evaluations
587
  // cached, which we add to evalVisited and pass to the evaluator below.
588
24916
  std::unordered_map<Node, Node> evalVisited;
589
12458
  ExampleInfer* ei = d_parent->getExampleInfer();
590
24916
  for (unsigned i = 0, vsize = vs.size(); i < vsize; i++)
591
  {
592
24916
    Node f = vs[i];
593
12458
    ExampleEvalCache* eec = d_parent->getExampleEvalCache(f);
594
12458
    if (eec != nullptr)
595
    {
596
      // get the results we obtained through the example evaluation utility
597
4436
      std::vector<Node> vsProc;
598
4436
      std::vector<Node> msProc;
599
4436
      Node bmsi = d_tds->sygusToBuiltin(ms[i]);
600
2218
      ei->getExampleTerms(f, vsProc);
601
2218
      eec->evaluateVec(bmsi, msProc);
602
2218
      Assert(vsProc.size() == msProc.size());
603
23030
      for (unsigned j = 0, psize = vsProc.size(); j < psize; j++)
604
      {
605
20812
        evalVisited[vsProc[j]] = msProc[j];
606
20812
        Assert(vsProc[j].getType().isComparableTo(msProc[j].getType()));
607
      }
608
    }
609
  }
610
611
12458
  Evaluator* eval = d_tds->getEvaluator();
612
15227
  for (unsigned r = 0; r < 2; r++)
613
  {
614
14891
    std::unordered_set<Node>& rlemmas =
615
        r == 0 ? d_refinement_lemma_unit : d_refinement_lemma_conj;
616
19409
    for (const Node& lem : rlemmas)
617
    {
618
      // We may have computed the evaluation of some function applications
619
      // via example-based symmetry breaking, stored in evalVisited.
620
21158
      Node lemcsu = eval->eval(lem, vs, ms, evalVisited);
621
16640
      if (lemcsu.isConst() && !lemcsu.getConst<bool>())
622
      {
623
12122
        return true;
624
      }
625
    }
626
  }
627
336
  return false;
628
}
629
630
21
bool Cegis::sampleAddRefinementLemma(const std::vector<Node>& candidates,
631
                                     const std::vector<Node>& vals,
632
                                     std::vector<Node>& lems)
633
{
634
21
  Trace("sygus-engine") << "  *** Do sample add refinement..." << std::endl;
635
21
  if (Trace.isOn("cegis-sample"))
636
  {
637
    Trace("cegis-sample") << "Check sampling for candidate solution"
638
                          << std::endl;
639
    for (unsigned i = 0, size = vals.size(); i < size; i++)
640
    {
641
      Trace("cegis-sample") << "  " << candidates[i] << " -> " << vals[i]
642
                            << std::endl;
643
    }
644
  }
645
21
  Assert(vals.size() == candidates.size());
646
  Node sbody = d_base_body.substitute(
647
42
      candidates.begin(), candidates.end(), vals.begin(), vals.end());
648
21
  Trace("cegis-sample-debug2") << "Sample " << sbody << std::endl;
649
  // do eager rewriting
650
21
  sbody = Rewriter::rewrite(sbody);
651
21
  Trace("cegis-sample") << "Sample (after rewriting): " << sbody << std::endl;
652
653
21
  NodeManager* nm = NodeManager::currentNM();
654
14634
  for (unsigned i = 0, size = d_cegis_sampler.getNumSamplePoints(); i < size;
655
       i++)
656
  {
657
14619
    if (d_cegis_sample_refine.find(i) == d_cegis_sample_refine.end())
658
    {
659
29208
      Node ev = d_cegis_sampler.evaluate(sbody, i);
660
29214
      Trace("cegis-sample-debug") << "...evaluate point #" << i << " to " << ev
661
14607
                                  << std::endl;
662
14607
      Assert(ev.isConst());
663
14607
      Assert(ev.getType().isBoolean());
664
14607
      if (!ev.getConst<bool>())
665
      {
666
6
        Trace("cegis-sample-debug") << "...false for point #" << i << std::endl;
667
        // mark this as a CEGIS point (no longer sampled)
668
6
        d_cegis_sample_refine.insert(i);
669
6
        std::vector<Node> pt;
670
6
        d_cegis_sampler.getSamplePoint(i, pt);
671
6
        Assert(d_base_vars.size() == pt.size());
672
        Node rlem = d_base_body.substitute(
673
6
            d_base_vars.begin(), d_base_vars.end(), pt.begin(), pt.end());
674
6
        rlem = Rewriter::rewrite(rlem);
675
18
        if (std::find(
676
6
                d_refinement_lemmas.begin(), d_refinement_lemmas.end(), rlem)
677
18
            == d_refinement_lemmas.end())
678
        {
679
6
          if (Trace.isOn("cegis-sample"))
680
          {
681
            Trace("cegis-sample") << "   false for point #" << i << " : ";
682
            for (const Node& cn : pt)
683
            {
684
              Trace("cegis-sample") << cn << " ";
685
            }
686
            Trace("cegis-sample") << std::endl;
687
          }
688
6
          Trace("sygus-engine") << "  *** Refine by sampling" << std::endl;
689
6
          addRefinementLemma(rlem);
690
          // if trust, we are not interested in sending out refinement lemmas
691
6
          if (options::cegisSample() != options::CegisSampleMode::TRUST)
692
          {
693
6
            Node lem = nm->mkNode(OR, d_parent->getGuard().negate(), rlem);
694
3
            lems.push_back(lem);
695
          }
696
6
          return true;
697
        }
698
        else
699
        {
700
          Trace("cegis-sample-debug") << "...duplicate." << std::endl;
701
        }
702
      }
703
    }
704
  }
705
15
  return false;
706
}
707
708
}  // namespace quantifiers
709
}  // namespace theory
710
29280
}  // namespace cvc5