1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, MikolasJanota, Aina Niemetz |
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 an enumerative instantiation strategy. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/inst_strategy_enumerative.h" |
17 |
|
|
18 |
|
#include "options/quantifiers_options.h" |
19 |
|
#include "theory/quantifiers/instantiate.h" |
20 |
|
#include "theory/quantifiers/relevant_domain.h" |
21 |
|
#include "theory/quantifiers/term_database.h" |
22 |
|
#include "theory/quantifiers/term_tuple_enumerator.h" |
23 |
|
#include "theory/quantifiers/term_util.h" |
24 |
|
|
25 |
|
using namespace cvc5::kind; |
26 |
|
using namespace cvc5::context; |
27 |
|
|
28 |
|
namespace cvc5 { |
29 |
|
namespace theory { |
30 |
|
namespace quantifiers { |
31 |
|
|
32 |
111 |
InstStrategyEnum::InstStrategyEnum(Env& env, |
33 |
|
QuantifiersState& qs, |
34 |
|
QuantifiersInferenceManager& qim, |
35 |
|
QuantifiersRegistry& qr, |
36 |
|
TermRegistry& tr, |
37 |
111 |
RelevantDomain* rd) |
38 |
111 |
: QuantifiersModule(env, qs, qim, qr, tr), d_rd(rd), d_fullSaturateLimit(-1) |
39 |
|
{ |
40 |
111 |
} |
41 |
111 |
void InstStrategyEnum::presolve() |
42 |
|
{ |
43 |
111 |
d_fullSaturateLimit = options::fullSaturateLimit(); |
44 |
111 |
} |
45 |
10442 |
bool InstStrategyEnum::needsCheck(Theory::Effort e) |
46 |
|
{ |
47 |
10442 |
if (d_fullSaturateLimit == 0) |
48 |
|
{ |
49 |
|
return false; |
50 |
|
} |
51 |
10442 |
if (options::fullSaturateInterleave()) |
52 |
|
{ |
53 |
|
// if interleaved, we run at the same time as E-matching |
54 |
|
if (d_qstate.getInstWhenNeedsCheck(e)) |
55 |
|
{ |
56 |
|
return true; |
57 |
|
} |
58 |
|
} |
59 |
10442 |
if (options::fullSaturateQuant()) |
60 |
|
{ |
61 |
10442 |
if (e >= Theory::EFFORT_LAST_CALL) |
62 |
|
{ |
63 |
428 |
return true; |
64 |
|
} |
65 |
|
} |
66 |
10014 |
return false; |
67 |
|
} |
68 |
|
|
69 |
1449 |
void InstStrategyEnum::reset_round(Theory::Effort e) {} |
70 |
1399 |
void InstStrategyEnum::check(Theory::Effort e, QEffort quant_e) |
71 |
|
{ |
72 |
1399 |
bool doCheck = false; |
73 |
1399 |
bool fullEffort = false; |
74 |
1399 |
if (d_fullSaturateLimit != 0) |
75 |
|
{ |
76 |
1399 |
if (options::fullSaturateInterleave()) |
77 |
|
{ |
78 |
|
// we only add when interleaved with other strategies |
79 |
|
doCheck = quant_e == QEFFORT_STANDARD && d_qim.hasPendingLemma(); |
80 |
|
} |
81 |
1399 |
if (options::fullSaturateQuant() && !doCheck) |
82 |
|
{ |
83 |
1399 |
if (!d_qstate.getValuation().needCheck()) |
84 |
|
{ |
85 |
865 |
doCheck = quant_e == QEFFORT_LAST_CALL; |
86 |
865 |
fullEffort = true; |
87 |
|
} |
88 |
|
} |
89 |
|
} |
90 |
1399 |
if (!doCheck) |
91 |
|
{ |
92 |
1260 |
return; |
93 |
|
} |
94 |
139 |
Assert(!d_qstate.isInConflict()); |
95 |
139 |
double clSet = 0; |
96 |
139 |
if (Trace.isOn("fs-engine")) |
97 |
|
{ |
98 |
|
clSet = double(clock()) / double(CLOCKS_PER_SEC); |
99 |
|
Trace("fs-engine") << "---Full Saturation Round, effort = " << e << "---" |
100 |
|
<< std::endl; |
101 |
|
} |
102 |
139 |
unsigned rstart = options::fullSaturateQuantRd() ? 0 : 1; |
103 |
139 |
unsigned rend = fullEffort ? 1 : rstart; |
104 |
139 |
unsigned addedLemmas = 0; |
105 |
|
// First try in relevant domain of all quantified formulas, if no |
106 |
|
// instantiations exist, try arbitrary ground terms. |
107 |
|
// Notice that this stratification of effort levels makes it so that some |
108 |
|
// quantified formulas may not be instantiated (if they have no instances |
109 |
|
// at effort level r=0 but another quantified formula does). We prefer |
110 |
|
// this stratification since effort level r=1 may be highly expensive in the |
111 |
|
// case where we have a quantified formula with many entailed instances. |
112 |
139 |
FirstOrderModel* fm = d_treg.getModel(); |
113 |
139 |
unsigned nquant = fm->getNumAssertedQuantifiers(); |
114 |
278 |
std::map<Node, bool> alreadyProc; |
115 |
395 |
for (unsigned r = rstart; r <= rend; r++) |
116 |
|
{ |
117 |
267 |
if (d_rd || r > 0) |
118 |
|
{ |
119 |
267 |
if (r == 0) |
120 |
|
{ |
121 |
139 |
Trace("inst-alg") << "-> Relevant domain instantiate..." << std::endl; |
122 |
139 |
Trace("inst-alg-debug") << "Compute relevant domain..." << std::endl; |
123 |
139 |
d_rd->compute(); |
124 |
139 |
Trace("inst-alg-debug") << "...finished" << std::endl; |
125 |
|
} |
126 |
|
else |
127 |
|
{ |
128 |
128 |
Trace("inst-alg") << "-> Ground term instantiate..." << std::endl; |
129 |
|
} |
130 |
2368 |
for (unsigned i = 0; i < nquant; i++) |
131 |
|
{ |
132 |
4202 |
Node q = fm->getAssertedQuantifier(i, true); |
133 |
6303 |
bool doProcess = d_qreg.hasOwnership(q, this) |
134 |
4174 |
&& fm->isQuantifierActive(q) |
135 |
8376 |
&& alreadyProc.find(q) == alreadyProc.end(); |
136 |
2101 |
if (doProcess) |
137 |
|
{ |
138 |
1719 |
if (process(q, fullEffort, r == 0)) |
139 |
|
{ |
140 |
|
// don't need to mark this if we are not stratifying |
141 |
1044 |
if (!options::fullSaturateStratify()) |
142 |
|
{ |
143 |
516 |
alreadyProc[q] = true; |
144 |
|
} |
145 |
|
// added lemma |
146 |
1044 |
addedLemmas++; |
147 |
|
} |
148 |
1719 |
if (d_qstate.isInConflict()) |
149 |
|
{ |
150 |
|
break; |
151 |
|
} |
152 |
|
} |
153 |
|
} |
154 |
534 |
if (d_qstate.isInConflict() |
155 |
267 |
|| (addedLemmas > 0 && options::fullSaturateStratify())) |
156 |
|
{ |
157 |
|
// we break if we are in conflict, or if we added any lemma at this |
158 |
|
// effort level and we stratify effort levels. |
159 |
11 |
break; |
160 |
|
} |
161 |
|
} |
162 |
|
} |
163 |
139 |
if (Trace.isOn("fs-engine")) |
164 |
|
{ |
165 |
|
Trace("fs-engine") << "Added lemmas = " << addedLemmas << std::endl; |
166 |
|
double clSet2 = double(clock()) / double(CLOCKS_PER_SEC); |
167 |
|
Trace("fs-engine") << "Finished full saturation engine, time = " |
168 |
|
<< (clSet2 - clSet) << std::endl; |
169 |
|
} |
170 |
139 |
if (d_fullSaturateLimit > 0) |
171 |
|
{ |
172 |
|
d_fullSaturateLimit--; |
173 |
|
} |
174 |
|
} |
175 |
|
|
176 |
1719 |
bool InstStrategyEnum::process(Node quantifier, bool fullEffort, bool isRd) |
177 |
|
{ |
178 |
|
// ignore if constant true (rare case of non-standard quantifier whose body |
179 |
|
// is rewritten to true) |
180 |
1719 |
if (quantifier[1].isConst() && quantifier[1].getConst<bool>()) |
181 |
|
{ |
182 |
|
return false; |
183 |
|
} |
184 |
|
|
185 |
|
TermTupleEnumeratorEnv ttec; |
186 |
1719 |
ttec.d_fullEffort = fullEffort; |
187 |
1719 |
ttec.d_increaseSum = options::fullSaturateSum(); |
188 |
|
// make the enumerator, which is either relevant domain or term database |
189 |
|
// based on the flag isRd. |
190 |
|
std::unique_ptr<TermTupleEnumeratorInterface> enumerator( |
191 |
3082 |
isRd ? mkTermTupleEnumeratorRd(quantifier, &ttec, d_rd) |
192 |
2075 |
: mkTermTupleEnumerator( |
193 |
5157 |
quantifier, &ttec, d_qstate, d_treg.getTermDatabase())); |
194 |
3438 |
std::vector<Node> terms; |
195 |
3438 |
std::vector<bool> failMask; |
196 |
1719 |
Instantiate* ie = d_qim.getInstantiate(); |
197 |
5835 |
for (enumerator->init(); enumerator->hasNext();) |
198 |
|
{ |
199 |
5160 |
if (d_qstate.isInConflict()) |
200 |
|
{ |
201 |
|
// could be conflicting for an internal reason |
202 |
|
return false; |
203 |
|
} |
204 |
5160 |
enumerator->next(terms); |
205 |
|
// try instantiation |
206 |
5160 |
failMask.clear(); |
207 |
|
/* if (ie->addInstantiation(quantifier, terms)) */ |
208 |
5160 |
if (ie->addInstantiationExpFail( |
209 |
|
quantifier, terms, failMask, InferenceId::QUANTIFIERS_INST_ENUM)) |
210 |
|
{ |
211 |
1044 |
Trace("inst-alg-rd") << "Success!" << std::endl; |
212 |
1044 |
return true; |
213 |
|
} |
214 |
|
else |
215 |
|
{ |
216 |
4116 |
enumerator->failureReason(failMask); |
217 |
|
} |
218 |
|
} |
219 |
675 |
return false; |
220 |
|
// TODO : term enumerator instantiation? |
221 |
|
} |
222 |
|
|
223 |
|
} // namespace quantifiers |
224 |
|
} // namespace theory |
225 |
31137 |
} // namespace cvc5 |