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