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