GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/cegis.cpp Lines: 327 346 94.5 %
Date: 2021-11-07 Branches: 618 1294 47.8 %

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