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