GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/cegis.cpp Lines: 323 344 93.9 %
Date: 2021-05-22 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
4587
Cegis::Cegis(QuantifiersInferenceManager& qim,
36
             TermDbSygus* tds,
37
4587
             SynthConjecture* p)
38
    : SygusModule(qim, tds, p),
39
4587
      d_eval_unfold(tds->getEvalUnfold()),
40
9174
      d_usingSymCons(false)
41
{
42
4587
}
43
44
191
bool Cegis::initialize(Node conj,
45
                       Node n,
46
                       const std::vector<Node>& candidates,
47
                       std::vector<Node>& lemmas)
48
{
49
191
  d_base_body = n;
50
191
  if (d_base_body.getKind() == NOT && d_base_body[0].getKind() == FORALL)
51
  {
52
694
    for (const Node& v : d_base_body[0][0])
53
    {
54
567
      d_base_vars.push_back(v);
55
    }
56
127
    d_base_body = d_base_body[0][1];
57
  }
58
59
  // assign the cegis sampler if applicable
60
3772
  if (options::cegisSample() != options::CegisSampleMode::NONE)
61
  {
62
6
    Trace("cegis-sample") << "Initialize sampler for " << d_base_body << "..."
63
3
                          << std::endl;
64
6
    TypeNode bt = d_base_body.getType();
65
3
    d_cegis_sampler.initialize(bt, d_base_vars, options::sygusSamples());
66
  }
67
191
  return processInitialize(conj, n, candidates, lemmas);
68
}
69
70
180
bool Cegis::processInitialize(Node conj,
71
                              Node n,
72
                              const std::vector<Node>& candidates,
73
                              std::vector<Node>& lemmas)
74
{
75
180
  Trace("cegis") << "Initialize cegis..." << std::endl;
76
180
  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
180
  EnumeratorRole erole =
80
180
      csize == 1 ? ROLE_ENUM_SINGLE_SOLUTION : ROLE_ENUM_MULTI_SOLUTION;
81
  // initialize an enumerator for each candidate
82
416
  for (unsigned i = 0; i < csize; i++)
83
  {
84
236
    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
472
    if (options::sygusRepairConst()
88
901
        || 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
236
    Trace("cegis") << std::endl;
102
236
    d_tds->registerEnumerator(candidates[i], candidates[i], d_parent, erole);
103
  }
104
180
  return true;
105
}
106
107
34732
void Cegis::getTermList(const std::vector<Node>& candidates,
108
                        std::vector<Node>& enums)
109
{
110
34732
  enums.insert(enums.end(), candidates.begin(), candidates.end());
111
34732
}
112
113
15958
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
15958
  bool doGen = true;
127
22165
  for (const Node& v : candidates)
128
  {
129
    // if it is relevant to refinement
130
18667
    if (d_refinement_lemma_vars.find(v) != d_refinement_lemma_vars.end())
131
    {
132
16733
      if (!d_tds->isPassiveEnumerator(v))
133
      {
134
12460
        doGen = false;
135
12460
        break;
136
      }
137
    }
138
  }
139
15958
  NodeManager* nm = NodeManager::currentNM();
140
15958
  bool addedEvalLemmas = false;
141
  // Refinement evaluation should not be done for grammars with symbolic
142
  // constructors.
143
15958
  if (!d_usingSymCons)
144
  {
145
31706
    Trace("sygus-engine") << "  *** Do refinement lemma evaluation"
146
31706
                          << (doGen ? " with conjecture-specific refinement"
147
15853
                                    : "")
148
15853
                          << "..." << std::endl;
149
    // see if any refinement lemma is refuted by evaluation
150
15853
    if (doGen)
151
    {
152
6790
      std::vector<Node> cre_lems;
153
3395
      getRefinementEvalLemmas(candidates, candidate_values, cre_lems);
154
3395
      if (!cre_lems.empty())
155
      {
156
1644
        lems.insert(lems.end(), cre_lems.begin(), cre_lems.end());
157
1644
        addedEvalLemmas = true;
158
1644
        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
24234
        Trace("sygus-engine") << "...(actively enumerated) candidate failed "
176
12117
                                 "refinement lemma evaluation."
177
12117
                              << std::endl;
178
12117
        return true;
179
      }
180
    }
181
  }
182
  // we only do evaluation unfolding for passive enumerators
183
357383
  bool doEvalUnfold = (doGen && options::sygusEvalUnfold()) || d_usingSymCons;
184
3841
  if (doEvalUnfold)
185
  {
186
3500
    Trace("sygus-engine") << "  *** Do evaluation unfolding..." << std::endl;
187
7000
    std::vector<Node> eager_terms, eager_vals, eager_exps;
188
9709
    for (unsigned i = 0, size = candidates.size(); i < size; ++i)
189
    {
190
12418
      Trace("cegqi-debug") << "  register " << candidates[i] << " -> "
191
6209
                           << candidate_values[i] << std::endl;
192
12418
      d_eval_unfold->registerModelValue(candidates[i],
193
6209
                                        candidate_values[i],
194
                                        eager_terms,
195
                                        eager_vals,
196
                                        eager_exps);
197
    }
198
7000
    Trace("cegqi-debug") << "...produced " << eager_terms.size()
199
3500
                         << " evaluation unfold lemmas.\n";
200
14403
    for (unsigned i = 0, size = eager_terms.size(); i < size; ++i)
201
    {
202
      Node lem = nm->mkNode(
203
21806
          OR, eager_exps[i].negate(), eager_terms[i].eqNode(eager_vals[i]));
204
10903
      lems.push_back(lem);
205
10903
      addedEvalLemmas = true;
206
21806
      Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation unfold : " << lem
207
10903
                           << std::endl;
208
    }
209
  }
210
3841
  return addedEvalLemmas;
211
}
212
213
72
Node Cegis::getRefinementLemmaFormula()
214
{
215
144
  std::vector<Node> conj;
216
72
  conj.insert(
217
144
      conj.end(), d_refinement_lemmas.begin(), d_refinement_lemmas.end());
218
  // get the propagated values
219
254
  for (unsigned i = 0, nprops = d_rl_eval_hds.size(); i < nprops; i++)
220
  {
221
182
    conj.push_back(d_rl_eval_hds[i].eqNode(d_rl_vals[i]));
222
  }
223
  // make the formula
224
72
  NodeManager* nm = NodeManager::currentNM();
225
72
  Node ret;
226
72
  if (conj.empty())
227
  {
228
1
    ret = nm->mkConst(true);
229
  }
230
  else
231
  {
232
71
    ret = conj.size() == 1 ? conj[0] : nm->mkNode(AND, conj);
233
  }
234
144
  return ret;
235
}
236
237
16035
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
16035
  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
16035
  if (d_usingSymCons && options::sygusRepairConst())
255
  {
256
125
    SygusRepairConst* src = d_parent->getRepairConst();
257
125
    Assert(src != nullptr);
258
    // check if any enum_values have symbolic terms that must be repaired
259
125
    bool mustRepair = false;
260
173
    for (const Node& c : enum_values)
261
    {
262
125
      if (SygusRepairConst::mustRepair(c))
263
      {
264
77
        mustRepair = true;
265
77
        break;
266
      }
267
    }
268
125
    Trace("cegis") << "...must repair is: " << mustRepair << std::endl;
269
    // if the solution contains a subterm that must be repaired
270
125
    if (mustRepair)
271
    {
272
154
      std::vector<Node> fail_cvs = enum_values;
273
77
      Assert(candidates.size() == fail_cvs.size());
274
      // try to solve entire problem?
275
77
      if (src->repairSolution(candidates, fail_cvs, candidate_values))
276
      {
277
5
        return true;
278
      }
279
144
      Node rl = getRefinementLemmaFormula();
280
      // try to solve for the refinement lemmas only
281
      bool ret =
282
72
          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
144
      std::vector<Node> exp;
287
144
      for (unsigned i = 0, size = enums.size(); i < size; i++)
288
      {
289
216
        d_tds->getExplain()->getExplanationForEquality(
290
144
            enums[i], enum_values[i], exp);
291
      }
292
72
      Assert(!exp.empty());
293
72
      NodeManager* nm = NodeManager::currentNM();
294
144
      Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp);
295
      // must guard it
296
72
      expn = nm->mkNode(OR, d_parent->getGuard().negate(), expn.negate());
297
72
      lems.push_back(expn);
298
72
      return ret;
299
    }
300
  }
301
302
  // evaluate on refinement lemmas
303
15958
  bool addedEvalLemmas = addEvalLemmas(enums, enum_values, lems);
304
305
  // try to construct candidates
306
15958
  if (!processConstructCandidates(enums,
307
                                  enum_values,
308
                                  candidates,
309
                                  candidate_values,
310
15958
                                  !addedEvalLemmas,
311
15958
                                  lems))
312
  {
313
14256
    return false;
314
  }
315
316
1702
  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
9
    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
1696
  return true;
329
}
330
331
15658
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
15658
  if (satisfiedRl)
339
  {
340
1681
    candidate_values.insert(
341
3362
        candidate_values.end(), enum_values.begin(), enum_values.end());
342
1681
    return true;
343
  }
344
13977
  return false;
345
}
346
347
415
void Cegis::addRefinementLemma(Node lem)
348
{
349
415
  Trace("cegis-rl") << "Cegis::addRefinementLemma: " << lem << std::endl;
350
415
  d_refinement_lemmas.push_back(lem);
351
  // apply existing substitution
352
830
  Node slem = lem;
353
415
  if (!d_rl_eval_hds.empty())
354
  {
355
143
    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
415
  slem = d_tds->getExtRewriter()->extendedRewrite(slem);
362
  // collect all variables in slem
363
415
  expr::getSymbols(slem, d_refinement_lemma_vars);
364
830
  std::vector<Node> waiting;
365
415
  waiting.push_back(lem);
366
415
  unsigned wcounter = 0;
367
  // while we are not done adding lemmas
368
1583
  while (wcounter < waiting.size())
369
  {
370
    // add the conjunct, possibly propagating
371
584
    addRefinementLemmaConjunct(wcounter, waiting);
372
584
    wcounter++;
373
  }
374
415
}
375
376
584
void Cegis::addRefinementLemmaConjunct(unsigned wcounter,
377
                                       std::vector<Node>& waiting)
378
{
379
1055
  Node lem = waiting[wcounter];
380
584
  lem = Rewriter::rewrite(lem);
381
  // apply substitution and rewrite if applicable
382
584
  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
581
  if (lem.getKind() == AND)
395
  {
396
224
    for (const Node& lc : lem)
397
    {
398
165
      waiting.push_back(lc);
399
    }
400
59
    return;
401
  }
402
  // does this correspond to a substitution?
403
522
  NodeManager* nm = NodeManager::currentNM();
404
993
  TNode term;
405
993
  TNode val;
406
522
  if (lem.getKind() == EQUAL)
407
  {
408
565
    for (unsigned i = 0; i < 2; i++)
409
    {
410
419
      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
312
    term = lem.getKind() == NOT ? lem[0] : lem;
421
    // predicate case: the conjunct is a (negated) evaluation point
422
312
    if (d_tds->isEvaluationPoint(term))
423
    {
424
150
      val = nm->mkConst(lem.getKind() != NOT);
425
    }
426
  }
427
522
  if (!val.isNull())
428
  {
429
214
    if (d_refinement_lemma_unit.find(lem) != d_refinement_lemma_unit.end())
430
    {
431
      // already added
432
51
      return;
433
    }
434
326
    Trace("cegis-rl") << "* cegis-rl: propagate: " << term << " -> " << val
435
163
                      << std::endl;
436
163
    d_rl_eval_hds.push_back(term);
437
163
    d_rl_vals.push_back(val);
438
163
    d_refinement_lemma_unit.insert(lem);
439
440
    // apply to waiting lemmas beyond this one
441
195
    for (unsigned i = wcounter + 1, size = waiting.size(); i < size; i++)
442
    {
443
32
      waiting[i] = waiting[i].substitute(term, val);
444
    }
445
    // apply to all existing refinement lemmas
446
326
    std::vector<Node> to_rem;
447
182
    for (const Node& rl : d_refinement_lemma_conj)
448
    {
449
38
      Node srl = rl.substitute(term, val);
450
19
      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
167
    for (const Node& tr : to_rem)
459
    {
460
4
      d_refinement_lemma_conj.erase(tr);
461
    }
462
  }
463
  else
464
  {
465
308
    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
308
    d_refinement_lemma_conj.insert(lem);
473
  }
474
}
475
476
398
void Cegis::registerRefinementLemma(const std::vector<Node>& vars,
477
                                    Node lem,
478
                                    std::vector<Node>& lems)
479
{
480
398
  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
796
      NodeManager::currentNM()->mkNode(OR, d_parent->getGuard().negate(), lem);
488
398
  lems.push_back(rlem);
489
398
}
490
491
186
bool Cegis::usingRepairConst() { return true; }
492
3395
bool Cegis::getRefinementEvalLemmas(const std::vector<Node>& vs,
493
                                    const std::vector<Node>& ms,
494
                                    std::vector<Node>& lems)
495
{
496
6790
  Trace("sygus-cref-eval") << "Cref eval : conjecture has "
497
6790
                           << d_refinement_lemma_unit.size() << " unit and "
498
6790
                           << d_refinement_lemma_conj.size()
499
3395
                           << " non-unit refinement lemma conjunctions."
500
3395
                           << std::endl;
501
3395
  Assert(vs.size() == ms.size());
502
503
3395
  NodeManager* nm = NodeManager::currentNM();
504
505
6790
  Node nfalse = nm->mkConst(false);
506
6790
  Node neg_guard = d_parent->getGuard().negate();
507
3395
  bool ret = false;
508
509
7958
  for (unsigned r = 0; r < 2; r++)
510
  {
511
6207
    std::unordered_set<Node>& rlemmas =
512
        r == 0 ? d_refinement_lemma_unit : d_refinement_lemma_conj;
513
17829
    for (const Node& lem : rlemmas)
514
    {
515
11622
      Assert(!lem.isNull());
516
23244
      std::map<Node, Node> visited;
517
23244
      std::map<Node, std::vector<Node> > exp;
518
23244
      EvalSygusInvarianceTest vsit;
519
23244
      Trace("sygus-cref-eval") << "Check refinement lemma conjunct " << lem
520
11622
                               << " against current model." << std::endl;
521
23244
      Trace("sygus-cref-eval2") << "Check refinement lemma conjunct " << lem
522
11622
                                << " against current model." << std::endl;
523
23244
      Node cre_lem;
524
23244
      Node lemcs = lem.substitute(vs.begin(), vs.end(), ms.begin(), ms.end());
525
23244
      Trace("sygus-cref-eval2")
526
11622
          << "...under substitution it is : " << lemcs << std::endl;
527
23244
      Node lemcsu = vsit.doEvaluateWithUnfolding(d_tds, lemcs);
528
23244
      Trace("sygus-cref-eval2")
529
11622
          << "...after unfolding is : " << lemcsu << std::endl;
530
11622
      if (lemcsu.isConst() && !lemcsu.getConst<bool>())
531
      {
532
3988
        ret = true;
533
7976
        std::vector<Node> msu;
534
7976
        std::vector<Node> mexp;
535
3988
        msu.insert(msu.end(), ms.begin(), ms.end());
536
7976
        std::map<TypeNode, int> var_count;
537
11106
        for (unsigned k = 0; k < vs.size(); k++)
538
        {
539
7118
          vsit.setUpdatedTerm(msu[k]);
540
7118
          msu[k] = vs[k];
541
          // substitute for everything except this
542
          Node sconj =
543
14236
              lem.substitute(vs.begin(), vs.end(), msu.begin(), msu.end());
544
7118
          vsit.init(sconj, vs[k], nfalse);
545
          // get minimal explanation for this
546
14236
          Node ut = vsit.getUpdatedTerm();
547
14236
          Trace("sygus-cref-eval2-debug")
548
7118
              << "  compute min explain of : " << vs[k] << " = " << ut
549
7118
              << std::endl;
550
14236
          d_tds->getExplain()->getExplanationFor(
551
7118
              vs[k], ut, mexp, vsit, var_count, false);
552
7118
          Trace("sygus-cref-eval2-debug") << "exp now: " << mexp << std::endl;
553
7118
          msu[k] = vsit.getUpdatedTerm();
554
14236
          Trace("sygus-cref-eval2-debug")
555
7118
              << "updated term : " << msu[k] << std::endl;
556
        }
557
3988
        if (!mexp.empty())
558
        {
559
7976
          Node en = mexp.size() == 1 ? mexp[0] : nm->mkNode(kind::AND, mexp);
560
3988
          cre_lem = nm->mkNode(kind::OR, en.negate(), neg_guard);
561
        }
562
        else
563
        {
564
          cre_lem = neg_guard;
565
        }
566
3988
        if (std::find(lems.begin(), lems.end(), cre_lem) == lems.end())
567
        {
568
4410
          Trace("sygus-cref-eval") << "...produced lemma : " << cre_lem
569
2205
                                   << std::endl;
570
2205
          lems.push_back(cre_lem);
571
        }
572
      }
573
    }
574
6207
    if (!lems.empty())
575
    {
576
1644
      break;
577
    }
578
  }
579
6790
  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
15237
  for (unsigned r = 0; r < 2; r++)
613
  {
614
14896
    std::unordered_set<Node>& rlemmas =
615
        r == 0 ? d_refinement_lemma_unit : d_refinement_lemma_conj;
616
19457
    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
21239
      Node lemcsu = eval->eval(lem, vs, ms, evalVisited);
621
16678
      if (lemcsu.isConst() && !lemcsu.getConst<bool>())
622
      {
623
12117
        return true;
624
      }
625
    }
626
  }
627
341
  return false;
628
}
629
630
9
bool Cegis::sampleAddRefinementLemma(const std::vector<Node>& candidates,
631
                                     const std::vector<Node>& vals,
632
                                     std::vector<Node>& lems)
633
{
634
9
  Trace("sygus-engine") << "  *** Do sample add refinement..." << std::endl;
635
9
  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
9
  Assert(vals.size() == candidates.size());
646
  Node sbody = d_base_body.substitute(
647
18
      candidates.begin(), candidates.end(), vals.begin(), vals.end());
648
9
  Trace("cegis-sample-debug2") << "Sample " << sbody << std::endl;
649
  // do eager rewriting
650
9
  sbody = Rewriter::rewrite(sbody);
651
9
  Trace("cegis-sample") << "Sample (after rewriting): " << sbody << std::endl;
652
653
9
  NodeManager* nm = NodeManager::currentNM();
654
2622
  for (unsigned i = 0, size = d_cegis_sampler.getNumSamplePoints(); i < size;
655
       i++)
656
  {
657
2619
    if (d_cegis_sample_refine.find(i) == d_cegis_sample_refine.end())
658
    {
659
5208
      Node ev = d_cegis_sampler.evaluate(sbody, i);
660
5214
      Trace("cegis-sample-debug") << "...evaluate point #" << i << " to " << ev
661
2607
                                  << std::endl;
662
2607
      Assert(ev.isConst());
663
2607
      Assert(ev.getType().isBoolean());
664
2607
      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
3
  return false;
706
}
707
708
}  // namespace quantifiers
709
}  // namespace theory
710
28194
}  // namespace cvc5