GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/quantifiers/sygus/synth_engine.cpp Lines: 120 126 95.2 %
Date: 2021-08-14 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
1151
SynthEngine::SynthEngine(QuantifiersState& qs,
30
                         QuantifiersInferenceManager& qim,
31
                         QuantifiersRegistry& qr,
32
1151
                         TermRegistry& tr)
33
1151
    : QuantifiersModule(qs, qim, qr, tr), d_conj(nullptr), d_sqp()
34
{
35
2302
  d_conjs.push_back(std::unique_ptr<SynthConjecture>(
36
1151
      new SynthConjecture(qs, qim, qr, tr, d_statistics)));
37
1151
  d_conj = d_conjs.back().get();
38
1151
}
39
40
2302
SynthEngine::~SynthEngine() {}
41
42
1126
void SynthEngine::presolve()
43
{
44
1126
  Trace("sygus-engine") << "SynthEngine::presolve" << std::endl;
45
2252
  for (unsigned i = 0, size = d_conjs.size(); i < size; i++)
46
  {
47
1126
    d_conjs[i]->presolve();
48
  }
49
1126
  Trace("sygus-engine") << "SynthEngine::presolve finished" << std::endl;
50
1126
}
51
52
12186
bool SynthEngine::needsCheck(Theory::Effort e)
53
{
54
12186
  return e >= Theory::EFFORT_LAST_CALL;
55
}
56
57
5249
QuantifiersModule::QEffort SynthEngine::needsModel(Theory::Effort e)
58
{
59
5249
  return QEFFORT_MODEL;
60
}
61
62
17310
void SynthEngine::check(Theory::Effort e, QEffort quant_e)
63
{
64
  // are we at the proper effort level?
65
17310
  if (quant_e != QEFFORT_MODEL)
66
  {
67
24742
    return;
68
  }
69
70
  // if we are waiting to assign the conjecture, do it now
71
4941
  bool assigned = !d_waiting_conj.empty();
72
4955
  while (!d_waiting_conj.empty())
73
  {
74
14
    Node q = d_waiting_conj.back();
75
7
    d_waiting_conj.pop_back();
76
14
    Trace("sygus-engine") << "--- Conjecture waiting to assign: " << q
77
7
                          << std::endl;
78
7
    assignConjecture(q);
79
  }
80
4941
  if (assigned)
81
  {
82
    // assign conjecture always uses the output channel, either by reducing a
83
    // quantified formula to another, or adding initial lemmas during
84
    // SynthConjecture::assign. Thus, we return here and re-check.
85
4
    return;
86
  }
87
88
9874
  Trace("sygus-engine") << "---Counterexample Guided Instantiation Engine---"
89
4937
                        << std::endl;
90
4937
  Trace("sygus-engine-debug") << std::endl;
91
4937
  Valuation& valuation = d_qstate.getValuation();
92
9874
  std::vector<SynthConjecture*> activeCheckConj;
93
9874
  for (unsigned i = 0, size = d_conjs.size(); i < size; i++)
94
  {
95
4937
    SynthConjecture* sc = d_conjs[i].get();
96
4937
    bool active = false;
97
    bool value;
98
4937
    if (valuation.hasSatValue(sc->getConjecture(), value))
99
    {
100
4916
      active = value;
101
    }
102
    else
103
    {
104
42
      Trace("sygus-engine-debug") << "...no value for quantified formula."
105
21
                                  << std::endl;
106
    }
107
9874
    Trace("sygus-engine-debug")
108
4937
        << "Current conjecture status : active : " << active << std::endl;
109
4937
    if (active && sc->needsCheck())
110
    {
111
4908
      activeCheckConj.push_back(sc);
112
    }
113
  }
114
9874
  std::vector<SynthConjecture*> acnext;
115
34298
  do
116
  {
117
78470
    Trace("sygus-engine-debug") << "Checking " << activeCheckConj.size()
118
39235
                                << " active conjectures..." << std::endl;
119
78432
    for (unsigned i = 0, size = activeCheckConj.size(); i < size; i++)
120
    {
121
39206
      SynthConjecture* sc = activeCheckConj[i];
122
39206
      if (!checkConjecture(sc))
123
      {
124
34548
        if (!sc->needsRefinement())
125
        {
126
34548
          acnext.push_back(sc);
127
        }
128
      }
129
    }
130
39226
    activeCheckConj.clear();
131
39226
    activeCheckConj = acnext;
132
39226
    acnext.clear();
133
39226
  } while (!activeCheckConj.empty() && !d_qstate.getValuation().needCheck());
134
9856
  Trace("sygus-engine")
135
4928
      << "Finished Counterexample Guided Instantiation engine." << std::endl;
136
}
137
138
334
void SynthEngine::assignConjecture(Node q)
139
{
140
334
  Trace("sygus-engine") << "SynthEngine::assignConjecture " << q << std::endl;
141
334
  if (options::sygusQePreproc())
142
  {
143
11
    Node lem = d_sqp.preprocess(q);
144
7
    if (!lem.isNull())
145
    {
146
6
      Trace("cegqi-lemma") << "Cegqi::Lemma : qe-preprocess : " << lem
147
3
                           << std::endl;
148
3
      d_qim.lemma(lem, InferenceId::QUANTIFIERS_SYGUS_QE_PREPROC);
149
      // we've reduced the original to a preprocessed version, return
150
3
      return;
151
    }
152
  }
153
  // allocate a new synthesis conjecture if not assigned
154
331
  if (d_conjs.back()->isAssigned())
155
  {
156
    d_conjs.push_back(std::unique_ptr<SynthConjecture>(
157
        new SynthConjecture(d_qstate, d_qim, d_qreg, d_treg, d_statistics)));
158
  }
159
331
  d_conjs.back()->assign(q);
160
}
161
162
738
void SynthEngine::checkOwnership(Node q)
163
{
164
  // take ownership of quantified formulas with sygus attribute, and function
165
  // definitions when options::sygusRecFun is true.
166
738
  QuantAttributes& qa = d_qreg.getQuantAttributes();
167
738
  if (qa.isSygus(q) || (qa.isFunDef(q) && options::sygusRecFun()))
168
  {
169
369
    d_qreg.setOwner(q, this, 2);
170
  }
171
738
}
172
173
738
void SynthEngine::registerQuantifier(Node q)
174
{
175
1476
  Trace("cegqi-debug") << "SynthEngine: Register quantifier : " << q
176
738
                       << std::endl;
177
738
  if (d_qreg.getOwner(q) != this)
178
  {
179
369
    return;
180
  }
181
369
  if (d_qreg.getQuantAttributes().isFunDef(q))
182
  {
183
33
    Assert(options::sygusRecFun());
184
    // If it is a recursive function definition, add it to the function
185
    // definition evaluator class.
186
33
    Trace("cegqi") << "Registering function definition : " << q << "\n";
187
33
    FunDefEvaluator* fde = d_treg.getTermDatabaseSygus()->getFunDefEvaluator();
188
33
    fde->assertDefinition(q);
189
33
    return;
190
  }
191
336
  Trace("cegqi") << "Register conjecture : " << q << std::endl;
192
336
  if (options::sygusQePreproc())
193
  {
194
9
    d_waiting_conj.push_back(q);
195
  }
196
  else
197
  {
198
    // assign it now
199
327
    assignConjecture(q);
200
  }
201
}
202
203
39206
bool SynthEngine::checkConjecture(SynthConjecture* conj)
204
{
205
39206
  if (Trace.isOn("sygus-engine-debug"))
206
  {
207
    conj->debugPrint("sygus-engine-debug");
208
    Trace("sygus-engine-debug") << std::endl;
209
  }
210
211
39206
  if (!conj->needsRefinement())
212
  {
213
39198
    Trace("sygus-engine-debug") << "Do conjecture check..." << std::endl;
214
78396
    Trace("sygus-engine-debug")
215
39198
        << "  *** Check candidate phase..." << std::endl;
216
39198
    size_t prevPending = d_qim.numPendingLemmas();
217
39198
    bool ret = conj->doCheck();
218
    // if we added a lemma, return true
219
39189
    if (d_qim.numPendingLemmas() > prevPending)
220
    {
221
5052
      Trace("sygus-engine-debug")
222
2526
          << "  ...check for counterexample." << std::endl;
223
2526
      return true;
224
    }
225
36663
    if (!conj->needsRefinement())
226
    {
227
36248
      return ret;
228
    }
229
    // otherwise, immediately go to refine candidate
230
  }
231
423
  Trace("sygus-engine-debug") << "  *** Refine candidate phase..." << std::endl;
232
423
  return conj->doRefine();
233
}
234
235
257
bool SynthEngine::getSynthSolutions(
236
    std::map<Node, std::map<Node, Node> >& sol_map)
237
{
238
257
  bool ret = true;
239
514
  for (unsigned i = 0, size = d_conjs.size(); i < size; i++)
240
  {
241
257
    if (d_conjs[i]->isAssigned())
242
    {
243
253
      if (!d_conjs[i]->getSynthSolutions(sol_map))
244
      {
245
        // if one conjecture fails, we fail overall
246
        ret = false;
247
        break;
248
      }
249
    }
250
  }
251
257
  return ret;
252
}
253
254
2354
void SynthEngine::preregisterAssertion(Node n)
255
{
256
  // check if it sygus conjecture
257
2354
  if (QuantAttributes::checkSygusConjecture(n))
258
  {
259
    // this is a sygus conjecture
260
333
    Trace("cegqi") << "Preregister sygus conjecture : " << n << std::endl;
261
333
    d_conj->preregisterConjecture(n);
262
  }
263
2354
}
264
265
}  // namespace quantifiers
266
}  // namespace theory
267
29340
}  // namespace cvc5