GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/cegis.cpp Lines: 323 341 94.7 %
Date: 2021-08-17 Branches: 613 1284 47.7 %

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