GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/synth_engine.cpp Lines: 120 126 95.2 %
Date: 2021-09-18 Branches: 197 356 55.3 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Andrew Reynolds, Haniel Barbosa, Gereon Kremer
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 the quantifiers module for managing all approaches
14
 * to synthesis, in particular, those described in Reynolds et al CAV 2015.
15
 */
16
#include "theory/quantifiers/sygus/synth_engine.h"
17
18
#include "options/quantifiers_options.h"
19
#include "theory/quantifiers/quantifiers_attributes.h"
20
#include "theory/quantifiers/sygus/term_database_sygus.h"
21
#include "theory/quantifiers/term_registry.h"
22
23
using namespace cvc5::kind;
24
25
namespace cvc5 {
26
namespace theory {
27
namespace quantifiers {
28
29
1233
SynthEngine::SynthEngine(Env& env,
30
                         QuantifiersState& qs,
31
                         QuantifiersInferenceManager& qim,
32
                         QuantifiersRegistry& qr,
33
1233
                         TermRegistry& tr)
34
1233
    : QuantifiersModule(env, qs, qim, qr, tr), d_conj(nullptr), d_sqp(env)
35
{
36
2466
  d_conjs.push_back(std::unique_ptr<SynthConjecture>(
37
1233
      new SynthConjecture(env, qs, qim, qr, tr, d_statistics)));
38
1233
  d_conj = d_conjs.back().get();
39
1233
}
40
41
2462
SynthEngine::~SynthEngine() {}
42
43
1215
void SynthEngine::presolve()
44
{
45
1215
  Trace("sygus-engine") << "SynthEngine::presolve" << std::endl;
46
2430
  for (unsigned i = 0, size = d_conjs.size(); i < size; i++)
47
  {
48
1215
    d_conjs[i]->presolve();
49
  }
50
1215
  Trace("sygus-engine") << "SynthEngine::presolve finished" << std::endl;
51
1215
}
52
53
11716
bool SynthEngine::needsCheck(Theory::Effort e)
54
{
55
11716
  return e >= Theory::EFFORT_LAST_CALL;
56
}
57
58
4975
QuantifiersModule::QEffort SynthEngine::needsModel(Theory::Effort e)
59
{
60
4975
  return QEFFORT_MODEL;
61
}
62
63
16319
void SynthEngine::check(Theory::Effort e, QEffort quant_e)
64
{
65
  // are we at the proper effort level?
66
16319
  if (quant_e != QEFFORT_MODEL)
67
  {
68
23488
    return;
69
  }
70
71
  // if we are waiting to assign the conjecture, do it now
72
4577
  bool assigned = !d_waiting_conj.empty();
73
4591
  while (!d_waiting_conj.empty())
74
  {
75
14
    Node q = d_waiting_conj.back();
76
7
    d_waiting_conj.pop_back();
77
14
    Trace("sygus-engine") << "--- Conjecture waiting to assign: " << q
78
7
                          << std::endl;
79
7
    assignConjecture(q);
80
  }
81
4577
  if (assigned)
82
  {
83
    // assign conjecture always uses the output channel, either by reducing a
84
    // quantified formula to another, or adding initial lemmas during
85
    // SynthConjecture::assign. Thus, we return here and re-check.
86
4
    return;
87
  }
88
89
9146
  Trace("sygus-engine") << "---Counterexample Guided Instantiation Engine---"
90
4573
                        << std::endl;
91
4573
  Trace("sygus-engine-debug") << std::endl;
92
4573
  Valuation& valuation = d_qstate.getValuation();
93
9146
  std::vector<SynthConjecture*> activeCheckConj;
94
9146
  for (unsigned i = 0, size = d_conjs.size(); i < size; i++)
95
  {
96
4573
    SynthConjecture* sc = d_conjs[i].get();
97
4573
    bool active = false;
98
    bool value;
99
4573
    if (valuation.hasSatValue(sc->getConjecture(), value))
100
    {
101
4522
      active = value;
102
    }
103
    else
104
    {
105
102
      Trace("sygus-engine-debug") << "...no value for quantified formula."
106
51
                                  << std::endl;
107
    }
108
9146
    Trace("sygus-engine-debug")
109
4573
        << "Current conjecture status : active : " << active << std::endl;
110
4573
    if (active && sc->needsCheck())
111
    {
112
4514
      activeCheckConj.push_back(sc);
113
    }
114
  }
115
9146
  std::vector<SynthConjecture*> acnext;
116
34311
  do
117
  {
118
77768
    Trace("sygus-engine-debug") << "Checking " << activeCheckConj.size()
119
38884
                                << " active conjectures..." << std::endl;
120
77700
    for (unsigned i = 0, size = activeCheckConj.size(); i < size; i++)
121
    {
122
38825
      SynthConjecture* sc = activeCheckConj[i];
123
38825
      if (!checkConjecture(sc))
124
      {
125
34483
        if (!sc->needsRefinement())
126
        {
127
34483
          acnext.push_back(sc);
128
        }
129
      }
130
    }
131
38875
    activeCheckConj.clear();
132
38875
    activeCheckConj = acnext;
133
38875
    acnext.clear();
134
38875
  } while (!activeCheckConj.empty() && !d_qstate.getValuation().needCheck());
135
9128
  Trace("sygus-engine")
136
4564
      << "Finished Counterexample Guided Instantiation engine." << std::endl;
137
}
138
139
335
void SynthEngine::assignConjecture(Node q)
140
{
141
335
  Trace("sygus-engine") << "SynthEngine::assignConjecture " << q << std::endl;
142
335
  if (options::sygusQePreproc())
143
  {
144
11
    Node lem = d_sqp.preprocess(q);
145
7
    if (!lem.isNull())
146
    {
147
6
      Trace("cegqi-lemma") << "Cegqi::Lemma : qe-preprocess : " << lem
148
3
                           << std::endl;
149
3
      d_qim.lemma(lem, InferenceId::QUANTIFIERS_SYGUS_QE_PREPROC);
150
      // we've reduced the original to a preprocessed version, return
151
3
      return;
152
    }
153
  }
154
  // allocate a new synthesis conjecture if not assigned
155
332
  if (d_conjs.back()->isAssigned())
156
  {
157
    d_conjs.push_back(std::unique_ptr<SynthConjecture>(new SynthConjecture(
158
        d_env, d_qstate, d_qim, d_qreg, d_treg, d_statistics)));
159
  }
160
332
  d_conjs.back()->assign(q);
161
}
162
163
787
void SynthEngine::checkOwnership(Node q)
164
{
165
  // take ownership of quantified formulas with sygus attribute, and function
166
  // definitions when options::sygusRecFun is true.
167
787
  QuantAttributes& qa = d_qreg.getQuantAttributes();
168
787
  if (qa.isSygus(q) || (qa.isFunDef(q) && options::sygusRecFun()))
169
  {
170
370
    d_qreg.setOwner(q, this, 2);
171
  }
172
787
}
173
174
787
void SynthEngine::registerQuantifier(Node q)
175
{
176
1574
  Trace("cegqi-debug") << "SynthEngine: Register quantifier : " << q
177
787
                       << std::endl;
178
787
  if (d_qreg.getOwner(q) != this)
179
  {
180
417
    return;
181
  }
182
370
  if (d_qreg.getQuantAttributes().isFunDef(q))
183
  {
184
33
    Assert(options::sygusRecFun());
185
    // If it is a recursive function definition, add it to the function
186
    // definition evaluator class.
187
33
    Trace("cegqi") << "Registering function definition : " << q << "\n";
188
33
    FunDefEvaluator* fde = d_treg.getTermDatabaseSygus()->getFunDefEvaluator();
189
33
    fde->assertDefinition(q);
190
33
    return;
191
  }
192
337
  Trace("cegqi") << "Register conjecture : " << q << std::endl;
193
337
  if (options::sygusQePreproc())
194
  {
195
9
    d_waiting_conj.push_back(q);
196
  }
197
  else
198
  {
199
    // assign it now
200
328
    assignConjecture(q);
201
  }
202
}
203
204
38825
bool SynthEngine::checkConjecture(SynthConjecture* conj)
205
{
206
38825
  if (Trace.isOn("sygus-engine-debug"))
207
  {
208
    conj->debugPrint("sygus-engine-debug");
209
    Trace("sygus-engine-debug") << std::endl;
210
  }
211
212
38825
  if (!conj->needsRefinement())
213
  {
214
38817
    Trace("sygus-engine-debug") << "Do conjecture check..." << std::endl;
215
77634
    Trace("sygus-engine-debug")
216
38817
        << "  *** Check candidate phase..." << std::endl;
217
38817
    size_t prevPending = d_qim.numPendingLemmas();
218
38817
    bool ret = conj->doCheck();
219
    // if we added a lemma, return true
220
38808
    if (d_qim.numPendingLemmas() > prevPending)
221
    {
222
4622
      Trace("sygus-engine-debug")
223
2311
          << "  ...check for counterexample." << std::endl;
224
2311
      return true;
225
    }
226
36497
    if (!conj->needsRefinement())
227
    {
228
36103
      return ret;
229
    }
230
    // otherwise, immediately go to refine candidate
231
  }
232
402
  Trace("sygus-engine-debug") << "  *** Refine candidate phase..." << std::endl;
233
402
  return conj->doRefine();
234
}
235
236
259
bool SynthEngine::getSynthSolutions(
237
    std::map<Node, std::map<Node, Node> >& sol_map)
238
{
239
259
  bool ret = true;
240
518
  for (unsigned i = 0, size = d_conjs.size(); i < size; i++)
241
  {
242
259
    if (d_conjs[i]->isAssigned())
243
    {
244
255
      if (!d_conjs[i]->getSynthSolutions(sol_map))
245
      {
246
        // if one conjecture fails, we fail overall
247
        ret = false;
248
        break;
249
      }
250
    }
251
  }
252
259
  return ret;
253
}
254
255
2589
void SynthEngine::preregisterAssertion(Node n)
256
{
257
  // check if it sygus conjecture
258
2589
  if (QuantAttributes::checkSygusConjecture(n))
259
  {
260
    // this is a sygus conjecture
261
334
    Trace("cegqi") << "Preregister sygus conjecture : " << n << std::endl;
262
334
    d_conj->preregisterConjecture(n);
263
  }
264
2589
}
265
266
}  // namespace quantifiers
267
}  // namespace theory
268
29574
}  // namespace cvc5