1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Mathias Preiner, 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 dynamic quantifiers splitting. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/quantifiers/quant_split.h" |
17 |
|
|
18 |
|
#include "expr/dtype.h" |
19 |
|
#include "expr/dtype_cons.h" |
20 |
|
#include "options/quantifiers_options.h" |
21 |
|
#include "theory/datatypes/theory_datatypes_utils.h" |
22 |
|
#include "theory/quantifiers/first_order_model.h" |
23 |
|
#include "theory/quantifiers/term_database.h" |
24 |
|
|
25 |
|
using namespace cvc5::kind; |
26 |
|
|
27 |
|
namespace cvc5 { |
28 |
|
namespace theory { |
29 |
|
namespace quantifiers { |
30 |
|
|
31 |
5520 |
QuantDSplit::QuantDSplit(Env& env, |
32 |
|
QuantifiersState& qs, |
33 |
|
QuantifiersInferenceManager& qim, |
34 |
|
QuantifiersRegistry& qr, |
35 |
5520 |
TermRegistry& tr) |
36 |
5520 |
: QuantifiersModule(env, qs, qim, qr, tr), d_added_split(userContext()) |
37 |
|
{ |
38 |
5520 |
} |
39 |
|
|
40 |
11390 |
void QuantDSplit::checkOwnership(Node q) |
41 |
|
{ |
42 |
|
// If q is non-standard (marked as sygus, quantifier elimination, etc.), then |
43 |
|
// do no split it. |
44 |
22056 |
QAttributes qa; |
45 |
11390 |
QuantAttributes::computeQuantAttributes(q, qa); |
46 |
11390 |
if (!qa.isStandard()) |
47 |
|
{ |
48 |
724 |
return; |
49 |
|
} |
50 |
10666 |
bool takeOwnership = false; |
51 |
10666 |
bool doSplit = false; |
52 |
10666 |
QuantifiersBoundInference& qbi = d_qreg.getQuantifiersBoundInference(); |
53 |
10666 |
Trace("quant-dsplit-debug") << "Check split quantified formula : " << q << std::endl; |
54 |
34296 |
for( unsigned i=0; i<q[0].getNumChildren(); i++ ){ |
55 |
49072 |
TypeNode tn = q[0][i].getType(); |
56 |
25442 |
if( tn.isDatatype() ){ |
57 |
4627 |
bool isFinite = d_qstate.isFiniteType(tn); |
58 |
4627 |
const DType& dt = tn.getDType(); |
59 |
4627 |
if (dt.isRecursiveSingleton(tn)) |
60 |
|
{ |
61 |
|
Trace("quant-dsplit-debug") << "Datatype " << dt.getName() << " is recursive singleton." << std::endl; |
62 |
|
} |
63 |
|
else |
64 |
|
{ |
65 |
4627 |
if (options::quantDynamicSplit() == options::QuantDSplitMode::AGG) |
66 |
|
{ |
67 |
|
// split if it is a finite datatype |
68 |
|
doSplit = isFinite; |
69 |
|
} |
70 |
9254 |
else if (options::quantDynamicSplit() |
71 |
4627 |
== options::QuantDSplitMode::DEFAULT) |
72 |
|
{ |
73 |
4627 |
if (!qbi.isFiniteBound(q, q[0][i])) |
74 |
|
{ |
75 |
4492 |
if (isFinite) |
76 |
|
{ |
77 |
|
// split if goes from being unhandled -> handled by finite |
78 |
|
// instantiation. An example is datatypes with uninterpreted sort |
79 |
|
// fields which are "interpreted finite" but not "finite". |
80 |
902 |
doSplit = true; |
81 |
|
// we additionally take ownership of this formula, in other words, |
82 |
|
// we mark it reduced. |
83 |
902 |
takeOwnership = true; |
84 |
|
} |
85 |
3590 |
else if (dt.getNumConstructors() == 1 && !dt.isCodatatype()) |
86 |
|
{ |
87 |
|
// split if only one constructor |
88 |
910 |
doSplit = true; |
89 |
|
} |
90 |
|
} |
91 |
|
} |
92 |
4627 |
if (doSplit) |
93 |
|
{ |
94 |
|
// store the index to split |
95 |
1812 |
d_quant_to_reduce[q] = i; |
96 |
3624 |
Trace("quant-dsplit-debug") |
97 |
3624 |
<< "Split at index " << i << " based on datatype " << dt.getName() |
98 |
1812 |
<< std::endl; |
99 |
1812 |
break; |
100 |
|
} |
101 |
5630 |
Trace("quant-dsplit-debug") |
102 |
2815 |
<< "Do not split based on datatype " << dt.getName() << std::endl; |
103 |
|
} |
104 |
|
} |
105 |
|
} |
106 |
|
|
107 |
10666 |
if (takeOwnership) |
108 |
|
{ |
109 |
902 |
Trace("quant-dsplit-debug") << "Will take ownership." << std::endl; |
110 |
902 |
d_qreg.setOwner(q, this); |
111 |
|
} |
112 |
|
// Notice we may not take ownership in some cases, meaning that both the |
113 |
|
// original quantified formula and the split one are generated. This may |
114 |
|
// increase our ability to answer "unsat", since quantifier instantiation |
115 |
|
// heuristics may be more effective for one or the other (see issues #993 |
116 |
|
// and 3481). |
117 |
|
} |
118 |
|
|
119 |
|
/* whether this module needs to check this round */ |
120 |
47303 |
bool QuantDSplit::needsCheck( Theory::Effort e ) { |
121 |
47303 |
return e>=Theory::EFFORT_FULL && !d_quant_to_reduce.empty(); |
122 |
|
} |
123 |
|
|
124 |
205 |
bool QuantDSplit::checkCompleteFor( Node q ) { |
125 |
|
// true if we split q |
126 |
205 |
return d_added_split.find( q )!=d_added_split.end(); |
127 |
|
} |
128 |
|
|
129 |
|
/* Call during quantifier engine's check */ |
130 |
1602 |
void QuantDSplit::check(Theory::Effort e, QEffort quant_e) |
131 |
|
{ |
132 |
|
//add lemmas ASAP (they are a reduction) |
133 |
1602 |
if (quant_e != QEFFORT_CONFLICT) |
134 |
|
{ |
135 |
941 |
return; |
136 |
|
} |
137 |
661 |
Trace("quant-dsplit") << "QuantDSplit::check" << std::endl; |
138 |
661 |
NodeManager* nm = NodeManager::currentNM(); |
139 |
661 |
FirstOrderModel* m = d_treg.getModel(); |
140 |
1322 |
std::vector<Node> lemmas; |
141 |
28046 |
for (std::map<Node, int>::iterator it = d_quant_to_reduce.begin(); |
142 |
28046 |
it != d_quant_to_reduce.end(); |
143 |
|
++it) |
144 |
|
{ |
145 |
54770 |
Node q = it->first; |
146 |
27385 |
Trace("quant-dsplit") << "- Split quantifier " << q << std::endl; |
147 |
109515 |
if (m->isQuantifierAsserted(q) && m->isQuantifierActive(q) |
148 |
109515 |
&& d_added_split.find(q) == d_added_split.end()) |
149 |
|
{ |
150 |
1804 |
d_added_split.insert(q); |
151 |
3608 |
std::vector<Node> bvs; |
152 |
7535 |
for (unsigned i = 0, nvars = q[0].getNumChildren(); i < nvars; i++) |
153 |
|
{ |
154 |
5731 |
if (static_cast<int>(i) != it->second) |
155 |
|
{ |
156 |
3927 |
bvs.push_back(q[0][i]); |
157 |
|
} |
158 |
|
} |
159 |
3608 |
std::vector<Node> disj; |
160 |
1804 |
disj.push_back(q.negate()); |
161 |
3608 |
TNode svar = q[0][it->second]; |
162 |
3608 |
TypeNode tn = svar.getType(); |
163 |
1804 |
Assert(tn.isDatatype()); |
164 |
3608 |
std::vector<Node> cons; |
165 |
1804 |
const DType& dt = tn.getDType(); |
166 |
4273 |
for (unsigned j = 0, ncons = dt.getNumConstructors(); j < ncons; j++) |
167 |
|
{ |
168 |
4938 |
std::vector<Node> vars; |
169 |
4938 |
TypeNode dtjtn = dt[j].getSpecializedConstructorType(tn); |
170 |
2469 |
Assert(dtjtn.getNumChildren() == dt[j].getNumArgs() + 1); |
171 |
6063 |
for (unsigned k = 0, nargs = dt[j].getNumArgs(); k < nargs; k++) |
172 |
|
{ |
173 |
7188 |
TypeNode tns = dtjtn[k]; |
174 |
7188 |
Node v = nm->mkBoundVar(tns); |
175 |
3594 |
vars.push_back(v); |
176 |
|
} |
177 |
4938 |
std::vector<Node> bvs_cmb; |
178 |
2469 |
bvs_cmb.insert(bvs_cmb.end(), bvs.begin(), bvs.end()); |
179 |
2469 |
bvs_cmb.insert(bvs_cmb.end(), vars.begin(), vars.end()); |
180 |
4938 |
Node c = datatypes::utils::mkApplyCons(tn, dt, j, vars); |
181 |
4938 |
TNode ct = c; |
182 |
4938 |
Node body = q[1].substitute(svar, ct); |
183 |
2469 |
if (!bvs_cmb.empty()) |
184 |
|
{ |
185 |
4930 |
Node bvl = nm->mkNode(kind::BOUND_VAR_LIST, bvs_cmb); |
186 |
4930 |
std::vector<Node> children; |
187 |
2465 |
children.push_back(bvl); |
188 |
2465 |
children.push_back(body); |
189 |
2465 |
if (q.getNumChildren() == 3) |
190 |
|
{ |
191 |
1764 |
Node ipls = q[2].substitute(svar, ct); |
192 |
882 |
children.push_back(ipls); |
193 |
|
} |
194 |
2465 |
body = nm->mkNode(kind::FORALL, children); |
195 |
|
} |
196 |
2469 |
cons.push_back(body); |
197 |
|
} |
198 |
3608 |
Node conc = cons.size() == 1 ? cons[0] : nm->mkNode(kind::AND, cons); |
199 |
1804 |
disj.push_back(conc); |
200 |
1804 |
lemmas.push_back(disj.size() == 1 ? disj[0] : nm->mkNode(kind::OR, disj)); |
201 |
|
} |
202 |
|
} |
203 |
|
|
204 |
|
// add lemmas to quantifiers engine |
205 |
2465 |
for (const Node& lem : lemmas) |
206 |
|
{ |
207 |
1804 |
Trace("quant-dsplit") << "QuantDSplit lemma : " << lem << std::endl; |
208 |
1804 |
d_qim.addPendingLemma(lem, InferenceId::QUANTIFIERS_DSPLIT); |
209 |
|
} |
210 |
661 |
Trace("quant-dsplit") << "QuantDSplit::check finished" << std::endl; |
211 |
|
} |
212 |
|
|
213 |
|
} // namespace quantifiers |
214 |
|
} // namespace theory |
215 |
29574 |
} // namespace cvc5 |