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