GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/cegis.cpp Lines: 321 340 94.4 %
Date: 2021-09-29 Branches: 610 1284 47.5 %

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