1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Gereon Kremer, Tim King |
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 |
|
* Check for some monomial lemmas. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/arith/nl/ext/monomial_check.h" |
17 |
|
|
18 |
|
#include "expr/node.h" |
19 |
|
#include "proof/proof.h" |
20 |
|
#include "theory/arith/arith_msum.h" |
21 |
|
#include "theory/arith/inference_manager.h" |
22 |
|
#include "theory/arith/nl/ext/ext_state.h" |
23 |
|
#include "theory/arith/nl/nl_lemma_utils.h" |
24 |
|
#include "theory/arith/nl/nl_model.h" |
25 |
|
#include "util/rational.h" |
26 |
|
|
27 |
|
namespace cvc5 { |
28 |
|
namespace theory { |
29 |
|
namespace arith { |
30 |
|
namespace nl { |
31 |
|
|
32 |
5195 |
MonomialCheck::MonomialCheck(ExtState* data) : d_data(data) |
33 |
|
{ |
34 |
5195 |
d_order_points.push_back(d_data->d_neg_one); |
35 |
5195 |
d_order_points.push_back(d_data->d_zero); |
36 |
5195 |
d_order_points.push_back(d_data->d_one); |
37 |
5195 |
} |
38 |
|
|
39 |
3990 |
void MonomialCheck::init(const std::vector<Node>& xts) |
40 |
|
{ |
41 |
3990 |
d_ms_proc.clear(); |
42 |
3990 |
d_m_nconst_factor.clear(); |
43 |
|
|
44 |
35044 |
for (unsigned i = 0, xsize = xts.size(); i < xsize; i++) |
45 |
|
{ |
46 |
62108 |
Node a = xts[i]; |
47 |
31054 |
if (a.getKind() == Kind::NONLINEAR_MULT) |
48 |
|
{ |
49 |
22456 |
const std::vector<Node>& varList = d_data->d_mdb.getVariableList(a); |
50 |
65927 |
for (const Node& v : varList) |
51 |
|
{ |
52 |
86942 |
Node mvk = d_data->d_model.computeAbstractModelValue(v); |
53 |
43471 |
if (!mvk.isConst()) |
54 |
|
{ |
55 |
|
d_m_nconst_factor[a] = true; |
56 |
|
} |
57 |
|
} |
58 |
|
} |
59 |
|
} |
60 |
|
|
61 |
15960 |
for (unsigned j = 0; j < d_order_points.size(); j++) |
62 |
|
{ |
63 |
23940 |
Node c = d_order_points[j]; |
64 |
11970 |
d_data->d_model.computeConcreteModelValue(c); |
65 |
11970 |
d_data->d_model.computeAbstractModelValue(c); |
66 |
|
} |
67 |
3990 |
} |
68 |
|
|
69 |
3161 |
void MonomialCheck::checkSign() |
70 |
|
{ |
71 |
6322 |
std::map<Node, int> signs; |
72 |
3161 |
Trace("nl-ext") << "Get monomial sign lemmas..." << std::endl; |
73 |
21590 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
74 |
|
{ |
75 |
36858 |
Node a = d_data->d_ms[j]; |
76 |
18429 |
if (d_ms_proc.find(a) == d_ms_proc.end()) |
77 |
|
{ |
78 |
36858 |
std::vector<Node> exp; |
79 |
18429 |
if (Trace.isOn("nl-ext-debug")) |
80 |
|
{ |
81 |
|
Node cmva = d_data->d_model.computeConcreteModelValue(a); |
82 |
|
Trace("nl-ext-debug") |
83 |
|
<< " process " << a << ", mv=" << cmva << "..." << std::endl; |
84 |
|
} |
85 |
18429 |
if (d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
86 |
|
{ |
87 |
18429 |
signs[a] = compareSign(a, a, 0, 1, exp); |
88 |
18429 |
if (signs[a] == 0) |
89 |
|
{ |
90 |
3689 |
d_ms_proc[a] = true; |
91 |
7378 |
Trace("nl-ext-debug") |
92 |
3689 |
<< "...mark " << a << " reduced since its value is 0." |
93 |
3689 |
<< std::endl; |
94 |
|
} |
95 |
|
} |
96 |
|
else |
97 |
|
{ |
98 |
|
Trace("nl-ext-debug") |
99 |
|
<< "...can't conclude sign lemma for " << a |
100 |
|
<< " since model value of a factor is non-constant." << std::endl; |
101 |
|
} |
102 |
|
} |
103 |
|
} |
104 |
3161 |
} |
105 |
|
|
106 |
4434 |
void MonomialCheck::checkMagnitude(unsigned c) |
107 |
|
{ |
108 |
|
// ensure information is setup |
109 |
4434 |
if (c == 0) |
110 |
|
{ |
111 |
|
// sort by absolute values of abstract model values |
112 |
2005 |
assignOrderIds(d_data->d_ms_vars, d_order_vars, false, true); |
113 |
|
|
114 |
|
// sort individual variable lists |
115 |
2005 |
Trace("nl-ext-proc") << "Assign order var lists..." << std::endl; |
116 |
2005 |
d_data->d_mdb.sortVariablesByModel(d_data->d_ms, d_data->d_model); |
117 |
|
} |
118 |
|
|
119 |
4434 |
unsigned r = 1; |
120 |
8868 |
std::vector<SimpleTheoryLemma> lemmas; |
121 |
|
// if (x,y,L) in cmp_infers, then x > y inferred as conclusion of L |
122 |
|
// in lemmas |
123 |
8868 |
std::map<int, std::map<Node, std::map<Node, Node> > > cmp_infers; |
124 |
8868 |
Trace("nl-ext") << "Get monomial comparison lemmas (order=" << r |
125 |
4434 |
<< ", compare=" << c << ")..." << std::endl; |
126 |
31256 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
127 |
|
{ |
128 |
53644 |
Node a = d_data->d_ms[j]; |
129 |
53644 |
if (d_ms_proc.find(a) == d_ms_proc.end() |
130 |
26822 |
&& d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
131 |
|
{ |
132 |
23654 |
if (c == 0) |
133 |
|
{ |
134 |
|
// compare magnitude against 1 |
135 |
21006 |
std::vector<Node> exp; |
136 |
21006 |
NodeMultiset a_exp_proc; |
137 |
21006 |
NodeMultiset b_exp_proc; |
138 |
21006 |
compareMonomial(a, |
139 |
|
a, |
140 |
|
a_exp_proc, |
141 |
10503 |
d_data->d_one, |
142 |
10503 |
d_data->d_one, |
143 |
|
b_exp_proc, |
144 |
|
exp, |
145 |
|
lemmas, |
146 |
|
cmp_infers); |
147 |
|
} |
148 |
|
else |
149 |
|
{ |
150 |
13151 |
const NodeMultiset& mea = d_data->d_mdb.getMonomialExponentMap(a); |
151 |
13151 |
if (c == 1) |
152 |
|
{ |
153 |
|
// could compare not just against containing variables? |
154 |
|
// compare magnitude against variables |
155 |
79621 |
for (unsigned k = 0; k < d_data->d_ms_vars.size(); k++) |
156 |
|
{ |
157 |
143492 |
Node v = d_data->d_ms_vars[k]; |
158 |
143492 |
Node mvcv = d_data->d_model.computeConcreteModelValue(v); |
159 |
71746 |
if (mvcv.isConst()) |
160 |
|
{ |
161 |
142880 |
std::vector<Node> exp; |
162 |
142880 |
NodeMultiset a_exp_proc; |
163 |
142880 |
NodeMultiset b_exp_proc; |
164 |
71440 |
if (mea.find(v) != mea.end()) |
165 |
|
{ |
166 |
14315 |
a_exp_proc[v] = 1; |
167 |
14315 |
b_exp_proc[v] = 1; |
168 |
14315 |
setMonomialFactor(a, v, a_exp_proc); |
169 |
14315 |
setMonomialFactor(v, a, b_exp_proc); |
170 |
14315 |
compareMonomial(a, |
171 |
|
a, |
172 |
|
a_exp_proc, |
173 |
|
v, |
174 |
|
v, |
175 |
|
b_exp_proc, |
176 |
|
exp, |
177 |
|
lemmas, |
178 |
|
cmp_infers); |
179 |
|
} |
180 |
|
} |
181 |
|
} |
182 |
|
} |
183 |
|
else |
184 |
|
{ |
185 |
|
// compare magnitude against other non-linear monomials |
186 |
43034 |
for (unsigned k = (j + 1); k < d_data->d_ms.size(); k++) |
187 |
|
{ |
188 |
75516 |
Node b = d_data->d_ms[k]; |
189 |
|
//(signs[a]==signs[b])==(r==0) |
190 |
75516 |
if (d_ms_proc.find(b) == d_ms_proc.end() |
191 |
37758 |
&& d_m_nconst_factor.find(b) == d_m_nconst_factor.end()) |
192 |
|
{ |
193 |
34795 |
const NodeMultiset& meb = d_data->d_mdb.getMonomialExponentMap(b); |
194 |
|
|
195 |
69590 |
std::vector<Node> exp; |
196 |
|
// take common factors of monomials, set minimum of |
197 |
|
// common exponents as processed |
198 |
69590 |
NodeMultiset a_exp_proc; |
199 |
69590 |
NodeMultiset b_exp_proc; |
200 |
100759 |
for (NodeMultiset::const_iterator itmea2 = mea.begin(); |
201 |
100759 |
itmea2 != mea.end(); |
202 |
|
++itmea2) |
203 |
|
{ |
204 |
65964 |
NodeMultiset::const_iterator itmeb2 = meb.find(itmea2->first); |
205 |
65964 |
if (itmeb2 != meb.end()) |
206 |
|
{ |
207 |
17072 |
unsigned min_exp = itmea2->second > itmeb2->second |
208 |
32973 |
? itmeb2->second |
209 |
32973 |
: itmea2->second; |
210 |
17072 |
a_exp_proc[itmea2->first] = min_exp; |
211 |
17072 |
b_exp_proc[itmea2->first] = min_exp; |
212 |
34144 |
Trace("nl-ext-comp") << "Common exponent : " << itmea2->first |
213 |
17072 |
<< " : " << min_exp << std::endl; |
214 |
|
} |
215 |
|
} |
216 |
34795 |
if (!a_exp_proc.empty()) |
217 |
|
{ |
218 |
16792 |
setMonomialFactor(a, b, a_exp_proc); |
219 |
16792 |
setMonomialFactor(b, a, b_exp_proc); |
220 |
|
} |
221 |
|
/* |
222 |
|
if( !a_exp_proc.empty() ){ |
223 |
|
//reduction based on common exponents a > 0 => ( a * b |
224 |
|
<> a * c <=> b <> c ), a < 0 => ( a * b <> a * c <=> b |
225 |
|
!<> c ) ? }else{ compareMonomial( a, a, a_exp_proc, b, |
226 |
|
b, b_exp_proc, exp, lemmas ); |
227 |
|
} |
228 |
|
*/ |
229 |
34795 |
compareMonomial( |
230 |
|
a, a, a_exp_proc, b, b, b_exp_proc, exp, lemmas, cmp_infers); |
231 |
|
} |
232 |
|
} |
233 |
|
} |
234 |
|
} |
235 |
|
} |
236 |
|
} |
237 |
|
// remove redundant lemmas, e.g. if a > b, b > c, a > c were |
238 |
|
// inferred, discard lemma with conclusion a > c |
239 |
8868 |
Trace("nl-ext-comp") << "Compute redundancies for " << lemmas.size() |
240 |
4434 |
<< " lemmas." << std::endl; |
241 |
|
// naive |
242 |
8868 |
std::unordered_set<Node> r_lemmas; |
243 |
1326 |
for (std::map<int, std::map<Node, std::map<Node, Node> > >::iterator itb = |
244 |
4434 |
cmp_infers.begin(); |
245 |
5760 |
itb != cmp_infers.end(); |
246 |
|
++itb) |
247 |
|
{ |
248 |
2396 |
for (std::map<Node, std::map<Node, Node> >::iterator itc = |
249 |
1326 |
itb->second.begin(); |
250 |
3722 |
itc != itb->second.end(); |
251 |
|
++itc) |
252 |
|
{ |
253 |
5668 |
for (std::map<Node, Node>::iterator itc2 = itc->second.begin(); |
254 |
5668 |
itc2 != itc->second.end(); |
255 |
|
++itc2) |
256 |
|
{ |
257 |
6544 |
std::map<Node, bool> visited; |
258 |
9558 |
for (std::map<Node, Node>::iterator itc3 = itc->second.begin(); |
259 |
9558 |
itc3 != itc->second.end(); |
260 |
|
++itc3) |
261 |
|
{ |
262 |
6454 |
if (itc3->first != itc2->first) |
263 |
|
{ |
264 |
6350 |
std::vector<Node> exp; |
265 |
3259 |
if (cmp_holds(itc3->first, itc2->first, itb->second, exp, visited)) |
266 |
|
{ |
267 |
168 |
r_lemmas.insert(itc2->second); |
268 |
336 |
Trace("nl-ext-comp") |
269 |
168 |
<< "...inference of " << itc->first << " > " << itc2->first |
270 |
168 |
<< " was redundant." << std::endl; |
271 |
168 |
break; |
272 |
|
} |
273 |
|
} |
274 |
|
} |
275 |
|
} |
276 |
|
} |
277 |
|
} |
278 |
7706 |
for (unsigned i = 0; i < lemmas.size(); i++) |
279 |
|
{ |
280 |
3272 |
if (r_lemmas.find(lemmas[i].d_node) == r_lemmas.end()) |
281 |
|
{ |
282 |
3104 |
d_data->d_im.addPendingLemma(lemmas[i]); |
283 |
|
} |
284 |
|
} |
285 |
|
// could only take maximal lower/minimial lower bounds? |
286 |
4434 |
} |
287 |
|
|
288 |
|
// show a <> 0 by inequalities between variables in monomial a w.r.t 0 |
289 |
48916 |
int MonomialCheck::compareSign( |
290 |
|
Node oa, Node a, unsigned a_index, int status, std::vector<Node>& exp) |
291 |
|
{ |
292 |
97832 |
Trace("nl-ext-debug") << "Process " << a << " at index " << a_index |
293 |
48916 |
<< ", status is " << status << std::endl; |
294 |
48916 |
NodeManager* nm = NodeManager::currentNM(); |
295 |
97832 |
Node mvaoa = d_data->d_model.computeAbstractModelValue(oa); |
296 |
48916 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
297 |
48916 |
if (a_index == vla.size()) |
298 |
|
{ |
299 |
14740 |
if (mvaoa.getConst<Rational>().sgn() != status) |
300 |
|
{ |
301 |
|
Node lemma = |
302 |
2576 |
nm->mkAnd(exp).impNode(mkLit(oa, d_data->d_zero, status * 2)); |
303 |
1288 |
CDProof* proof = nullptr; |
304 |
1288 |
if (d_data->isProofEnabled()) |
305 |
|
{ |
306 |
231 |
proof = d_data->getProof(); |
307 |
462 |
std::vector<Node> args = exp; |
308 |
231 |
args.emplace_back(oa); |
309 |
231 |
proof->addStep(lemma, PfRule::ARITH_MULT_SIGN, {}, args); |
310 |
|
} |
311 |
1288 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
312 |
|
} |
313 |
14740 |
return status; |
314 |
|
} |
315 |
34176 |
Assert(a_index < vla.size()); |
316 |
68352 |
Node av = vla[a_index]; |
317 |
34176 |
unsigned aexp = d_data->d_mdb.getExponent(a, av); |
318 |
|
// take current sign in model |
319 |
68352 |
Node mvaav = d_data->d_model.computeAbstractModelValue(av); |
320 |
34176 |
int sgn = mvaav.getConst<Rational>().sgn(); |
321 |
68352 |
Trace("nl-ext-debug") << "Process var " << av << "^" << aexp |
322 |
34176 |
<< ", model sign = " << sgn << std::endl; |
323 |
34176 |
if (sgn == 0) |
324 |
|
{ |
325 |
3689 |
if (mvaoa.getConst<Rational>().sgn() != 0) |
326 |
|
{ |
327 |
1668 |
Node prem = av.eqNode(d_data->d_zero); |
328 |
1668 |
Node conc = oa.eqNode(d_data->d_zero); |
329 |
1668 |
Node lemma = prem.impNode(conc); |
330 |
834 |
CDProof* proof = nullptr; |
331 |
834 |
if (d_data->isProofEnabled()) |
332 |
|
{ |
333 |
129 |
proof = d_data->getProof(); |
334 |
129 |
proof->addStep(conc, PfRule::MACRO_SR_PRED_INTRO, {prem}, {conc}); |
335 |
129 |
proof->addStep(lemma, PfRule::SCOPE, {conc}, {prem}); |
336 |
|
} |
337 |
834 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
338 |
|
} |
339 |
3689 |
return 0; |
340 |
|
} |
341 |
30487 |
if (aexp % 2 == 0) |
342 |
|
{ |
343 |
2954 |
exp.push_back(av.eqNode(d_data->d_zero).negate()); |
344 |
2954 |
return compareSign(oa, a, a_index + 1, status, exp); |
345 |
|
} |
346 |
27533 |
exp.push_back(nm->mkNode(sgn == 1 ? Kind::GT : Kind::LT, av, d_data->d_zero)); |
347 |
27533 |
return compareSign(oa, a, a_index + 1, status * sgn, exp); |
348 |
|
} |
349 |
|
|
350 |
59613 |
bool MonomialCheck::compareMonomial( |
351 |
|
Node oa, |
352 |
|
Node a, |
353 |
|
NodeMultiset& a_exp_proc, |
354 |
|
Node ob, |
355 |
|
Node b, |
356 |
|
NodeMultiset& b_exp_proc, |
357 |
|
std::vector<Node>& exp, |
358 |
|
std::vector<SimpleTheoryLemma>& lem, |
359 |
|
std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers) |
360 |
|
{ |
361 |
119226 |
Trace("nl-ext-comp-debug") |
362 |
59613 |
<< "Check |" << a << "| >= |" << b << "|" << std::endl; |
363 |
59613 |
unsigned pexp_size = exp.size(); |
364 |
59613 |
if (compareMonomial( |
365 |
|
oa, a, 0, a_exp_proc, ob, b, 0, b_exp_proc, 0, exp, lem, cmp_infers)) |
366 |
|
{ |
367 |
41642 |
return true; |
368 |
|
} |
369 |
17971 |
exp.resize(pexp_size); |
370 |
35942 |
Trace("nl-ext-comp-debug") |
371 |
17971 |
<< "Check |" << b << "| >= |" << a << "|" << std::endl; |
372 |
17971 |
if (compareMonomial( |
373 |
|
ob, b, 0, b_exp_proc, oa, a, 0, a_exp_proc, 0, exp, lem, cmp_infers)) |
374 |
|
{ |
375 |
11268 |
return true; |
376 |
|
} |
377 |
6703 |
return false; |
378 |
|
} |
379 |
|
|
380 |
|
// trying to show a ( >, = ) b by inequalities between variables in |
381 |
|
// monomials a,b |
382 |
310578 |
bool MonomialCheck::compareMonomial( |
383 |
|
Node oa, |
384 |
|
Node a, |
385 |
|
unsigned a_index, |
386 |
|
NodeMultiset& a_exp_proc, |
387 |
|
Node ob, |
388 |
|
Node b, |
389 |
|
unsigned b_index, |
390 |
|
NodeMultiset& b_exp_proc, |
391 |
|
int status, |
392 |
|
std::vector<Node>& exp, |
393 |
|
std::vector<SimpleTheoryLemma>& lem, |
394 |
|
std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers) |
395 |
|
{ |
396 |
621156 |
Trace("nl-ext-comp-debug") |
397 |
310578 |
<< "compareMonomial " << oa << " and " << ob << ", indices = " << a_index |
398 |
310578 |
<< " " << b_index << std::endl; |
399 |
310578 |
Assert(status == 0 || status == 2); |
400 |
310578 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
401 |
310578 |
const std::vector<Node>& vlb = d_data->d_mdb.getVariableList(b); |
402 |
310578 |
if (a_index == vla.size() && b_index == vlb.size()) |
403 |
|
{ |
404 |
|
// finished, compare absolute value of abstract model values |
405 |
52910 |
int modelStatus = d_data->d_model.compare(oa, ob, false, true) * -2; |
406 |
105820 |
Trace("nl-ext-comp") << "...finished comparison with " << oa << " <" |
407 |
52910 |
<< status << "> " << ob |
408 |
52910 |
<< ", model status = " << modelStatus << std::endl; |
409 |
52910 |
if (status != modelStatus) |
410 |
|
{ |
411 |
6544 |
Trace("nl-ext-comp-infer") |
412 |
3272 |
<< "infer : " << oa << " <" << status << "> " << ob << std::endl; |
413 |
3272 |
if (status == 2) |
414 |
|
{ |
415 |
|
// must state that all variables are non-zero |
416 |
6996 |
for (unsigned j = 0; j < vla.size(); j++) |
417 |
|
{ |
418 |
4509 |
exp.push_back(vla[j].eqNode(d_data->d_zero).negate()); |
419 |
|
} |
420 |
|
} |
421 |
3272 |
NodeManager* nm = NodeManager::currentNM(); |
422 |
|
Node clem = nm->mkNode( |
423 |
6544 |
Kind::IMPLIES, nm->mkAnd(exp), mkLit(oa, ob, status, true)); |
424 |
3272 |
Trace("nl-ext-comp-lemma") << "comparison lemma : " << clem << std::endl; |
425 |
3272 |
lem.emplace_back( |
426 |
6544 |
InferenceId::ARITH_NL_COMPARISON, clem, LemmaProperty::NONE, nullptr); |
427 |
3272 |
cmp_infers[status][oa][ob] = clem; |
428 |
|
} |
429 |
52910 |
return true; |
430 |
|
} |
431 |
|
// get a/b variable information |
432 |
515336 |
Node av; |
433 |
257668 |
unsigned aexp = 0; |
434 |
257668 |
unsigned avo = 0; |
435 |
257668 |
if (a_index < vla.size()) |
436 |
|
{ |
437 |
221151 |
av = vla[a_index]; |
438 |
221151 |
unsigned aexpTotal = d_data->d_mdb.getExponent(a, av); |
439 |
221151 |
Assert(a_exp_proc[av] <= aexpTotal); |
440 |
221151 |
aexp = aexpTotal - a_exp_proc[av]; |
441 |
221151 |
if (aexp == 0) |
442 |
|
{ |
443 |
155164 |
return compareMonomial(oa, |
444 |
|
a, |
445 |
|
a_index + 1, |
446 |
|
a_exp_proc, |
447 |
|
ob, |
448 |
|
b, |
449 |
|
b_index, |
450 |
|
b_exp_proc, |
451 |
|
status, |
452 |
|
exp, |
453 |
|
lem, |
454 |
77582 |
cmp_infers); |
455 |
|
} |
456 |
143569 |
Assert(d_order_vars.find(av) != d_order_vars.end()); |
457 |
143569 |
avo = d_order_vars[av]; |
458 |
|
} |
459 |
360172 |
Node bv; |
460 |
180086 |
unsigned bexp = 0; |
461 |
180086 |
unsigned bvo = 0; |
462 |
180086 |
if (b_index < vlb.size()) |
463 |
|
{ |
464 |
145629 |
bv = vlb[b_index]; |
465 |
145629 |
unsigned bexpTotal = d_data->d_mdb.getExponent(b, bv); |
466 |
145629 |
Assert(b_exp_proc[bv] <= bexpTotal); |
467 |
145629 |
bexp = bexpTotal - b_exp_proc[bv]; |
468 |
145629 |
if (bexp == 0) |
469 |
|
{ |
470 |
148824 |
return compareMonomial(oa, |
471 |
|
a, |
472 |
|
a_index, |
473 |
|
a_exp_proc, |
474 |
|
ob, |
475 |
|
b, |
476 |
|
b_index + 1, |
477 |
|
b_exp_proc, |
478 |
|
status, |
479 |
|
exp, |
480 |
|
lem, |
481 |
74412 |
cmp_infers); |
482 |
|
} |
483 |
71217 |
Assert(d_order_vars.find(bv) != d_order_vars.end()); |
484 |
71217 |
bvo = d_order_vars[bv]; |
485 |
|
} |
486 |
|
// get "one" information |
487 |
105674 |
Assert(d_order_vars.find(d_data->d_one) != d_order_vars.end()); |
488 |
105674 |
unsigned ovo = d_order_vars[d_data->d_one]; |
489 |
211348 |
Trace("nl-ext-comp-debug") << "....vars : " << av << "^" << aexp << " " << bv |
490 |
105674 |
<< "^" << bexp << std::endl; |
491 |
|
|
492 |
|
//--- cases |
493 |
105674 |
if (av.isNull()) |
494 |
|
{ |
495 |
3869 |
if (bvo <= ovo) |
496 |
|
{ |
497 |
2824 |
Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl; |
498 |
|
// can multiply b by <=1 |
499 |
2824 |
exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true)); |
500 |
5648 |
return compareMonomial(oa, |
501 |
|
a, |
502 |
|
a_index, |
503 |
|
a_exp_proc, |
504 |
|
ob, |
505 |
|
b, |
506 |
|
b_index + 1, |
507 |
|
b_exp_proc, |
508 |
|
bvo == ovo ? status : 2, |
509 |
|
exp, |
510 |
|
lem, |
511 |
2824 |
cmp_infers); |
512 |
|
} |
513 |
2090 |
Trace("nl-ext-comp-debug") |
514 |
1045 |
<< "...failure, unmatched |b|>1 component." << std::endl; |
515 |
1045 |
return false; |
516 |
|
} |
517 |
101805 |
else if (bv.isNull()) |
518 |
|
{ |
519 |
34457 |
if (avo >= ovo) |
520 |
|
{ |
521 |
31657 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
522 |
|
// can multiply a by >=1 |
523 |
31657 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
524 |
63314 |
return compareMonomial(oa, |
525 |
|
a, |
526 |
|
a_index + 1, |
527 |
|
a_exp_proc, |
528 |
|
ob, |
529 |
|
b, |
530 |
|
b_index, |
531 |
|
b_exp_proc, |
532 |
|
avo == ovo ? status : 2, |
533 |
|
exp, |
534 |
|
lem, |
535 |
31657 |
cmp_infers); |
536 |
|
} |
537 |
5600 |
Trace("nl-ext-comp-debug") |
538 |
2800 |
<< "...failure, unmatched |a|<1 component." << std::endl; |
539 |
2800 |
return false; |
540 |
|
} |
541 |
67348 |
Assert(!av.isNull() && !bv.isNull()); |
542 |
67348 |
if (avo >= bvo) |
543 |
|
{ |
544 |
46239 |
if (bvo < ovo && avo >= ovo) |
545 |
|
{ |
546 |
496 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
547 |
|
// do avo>=1 instead |
548 |
496 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
549 |
992 |
return compareMonomial(oa, |
550 |
|
a, |
551 |
|
a_index + 1, |
552 |
|
a_exp_proc, |
553 |
|
ob, |
554 |
|
b, |
555 |
|
b_index, |
556 |
|
b_exp_proc, |
557 |
|
avo == ovo ? status : 2, |
558 |
|
exp, |
559 |
|
lem, |
560 |
496 |
cmp_infers); |
561 |
|
} |
562 |
45743 |
unsigned min_exp = aexp > bexp ? bexp : aexp; |
563 |
45743 |
a_exp_proc[av] += min_exp; |
564 |
45743 |
b_exp_proc[bv] += min_exp; |
565 |
91486 |
Trace("nl-ext-comp-debug") << "...take leading " << min_exp << " from " |
566 |
45743 |
<< av << " and " << bv << std::endl; |
567 |
45743 |
exp.push_back(mkLit(av, bv, avo == bvo ? 0 : 2, true)); |
568 |
91486 |
bool ret = compareMonomial(oa, |
569 |
|
a, |
570 |
|
a_index, |
571 |
|
a_exp_proc, |
572 |
|
ob, |
573 |
|
b, |
574 |
|
b_index, |
575 |
|
b_exp_proc, |
576 |
|
avo == bvo ? status : 2, |
577 |
|
exp, |
578 |
|
lem, |
579 |
45743 |
cmp_infers); |
580 |
45743 |
a_exp_proc[av] -= min_exp; |
581 |
45743 |
b_exp_proc[bv] -= min_exp; |
582 |
45743 |
return ret; |
583 |
|
} |
584 |
21109 |
if (bvo <= ovo) |
585 |
|
{ |
586 |
280 |
Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl; |
587 |
|
// try multiply b <= 1 |
588 |
280 |
exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true)); |
589 |
560 |
return compareMonomial(oa, |
590 |
|
a, |
591 |
|
a_index, |
592 |
|
a_exp_proc, |
593 |
|
ob, |
594 |
|
b, |
595 |
|
b_index + 1, |
596 |
|
b_exp_proc, |
597 |
|
bvo == ovo ? status : 2, |
598 |
|
exp, |
599 |
|
lem, |
600 |
280 |
cmp_infers); |
601 |
|
} |
602 |
41658 |
Trace("nl-ext-comp-debug") |
603 |
20829 |
<< "...failure, leading |b|>|a|>1 component." << std::endl; |
604 |
20829 |
return false; |
605 |
|
} |
606 |
|
|
607 |
4144 |
bool MonomialCheck::cmp_holds(Node x, |
608 |
|
Node y, |
609 |
|
std::map<Node, std::map<Node, Node> >& cmp_infers, |
610 |
|
std::vector<Node>& exp, |
611 |
|
std::map<Node, bool>& visited) |
612 |
|
{ |
613 |
4144 |
if (x == y) |
614 |
|
{ |
615 |
168 |
return true; |
616 |
|
} |
617 |
3976 |
else if (visited.find(x) != visited.end()) |
618 |
|
{ |
619 |
634 |
return false; |
620 |
|
} |
621 |
3342 |
visited[x] = true; |
622 |
3342 |
std::map<Node, std::map<Node, Node> >::iterator it = cmp_infers.find(x); |
623 |
3342 |
if (it != cmp_infers.end()) |
624 |
|
{ |
625 |
1313 |
for (std::map<Node, Node>::iterator itc = it->second.begin(); |
626 |
1313 |
itc != it->second.end(); |
627 |
|
++itc) |
628 |
|
{ |
629 |
885 |
exp.push_back(itc->second); |
630 |
885 |
if (cmp_holds(itc->first, y, cmp_infers, exp, visited)) |
631 |
|
{ |
632 |
179 |
return true; |
633 |
|
} |
634 |
706 |
exp.pop_back(); |
635 |
|
} |
636 |
|
} |
637 |
3163 |
return false; |
638 |
|
} |
639 |
|
|
640 |
2005 |
void MonomialCheck::assignOrderIds(std::vector<Node>& vars, |
641 |
|
NodeMultiset& order, |
642 |
|
bool isConcrete, |
643 |
|
bool isAbsolute) |
644 |
|
{ |
645 |
2005 |
SortNlModel smv; |
646 |
2005 |
smv.d_nlm = &d_data->d_model; |
647 |
2005 |
smv.d_isConcrete = isConcrete; |
648 |
2005 |
smv.d_isAbsolute = isAbsolute; |
649 |
2005 |
smv.d_reverse_order = false; |
650 |
2005 |
std::sort(vars.begin(), vars.end(), smv); |
651 |
|
|
652 |
2005 |
order.clear(); |
653 |
|
// assign ordering id's |
654 |
2005 |
unsigned counter = 0; |
655 |
2005 |
unsigned order_index = isConcrete ? 0 : 1; |
656 |
4010 |
Node prev; |
657 |
12298 |
for (unsigned j = 0; j < vars.size(); j++) |
658 |
|
{ |
659 |
20586 |
Node x = vars[j]; |
660 |
20586 |
Node v = d_data->d_model.computeModelValue(x, isConcrete); |
661 |
10293 |
if (!v.isConst()) |
662 |
|
{ |
663 |
|
Trace("nl-ext-mvo") << "..do not assign order to " << x << " : " << v |
664 |
|
<< std::endl; |
665 |
|
// don't assign for non-constant values (transcendental function apps) |
666 |
|
break; |
667 |
|
} |
668 |
10293 |
Trace("nl-ext-mvo") << " order " << x << " : " << v << std::endl; |
669 |
10293 |
if (v != prev) |
670 |
|
{ |
671 |
|
// builtin points |
672 |
|
bool success; |
673 |
10303 |
do |
674 |
|
{ |
675 |
10303 |
success = false; |
676 |
10303 |
if (order_index < d_order_points.size()) |
677 |
|
{ |
678 |
4515 |
Node vv = d_data->d_model.computeModelValue( |
679 |
9030 |
d_order_points[order_index], isConcrete); |
680 |
4515 |
if (d_data->d_model.compareValue(v, vv, isAbsolute) <= 0) |
681 |
|
{ |
682 |
3361 |
counter++; |
683 |
6722 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
684 |
3361 |
<< "] = " << counter << std::endl; |
685 |
3361 |
order[d_order_points[order_index]] = counter; |
686 |
3361 |
prev = vv; |
687 |
3361 |
order_index++; |
688 |
3361 |
success = true; |
689 |
|
} |
690 |
|
} |
691 |
|
} while (success); |
692 |
|
} |
693 |
10293 |
if (prev.isNull() || d_data->d_model.compareValue(v, prev, isAbsolute) != 0) |
694 |
|
{ |
695 |
4520 |
counter++; |
696 |
|
} |
697 |
10293 |
Trace("nl-ext-mvo") << "O[" << x << "] = " << counter << std::endl; |
698 |
10293 |
order[x] = counter; |
699 |
10293 |
prev = v; |
700 |
|
} |
701 |
3303 |
while (order_index < d_order_points.size()) |
702 |
|
{ |
703 |
649 |
counter++; |
704 |
1298 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
705 |
649 |
<< "] = " << counter << std::endl; |
706 |
649 |
order[d_order_points[order_index]] = counter; |
707 |
649 |
order_index++; |
708 |
|
} |
709 |
2005 |
} |
710 |
86097 |
Node MonomialCheck::mkLit(Node a, Node b, int status, bool isAbsolute) const |
711 |
|
{ |
712 |
86097 |
if (status == 0) |
713 |
|
{ |
714 |
20938 |
Node a_eq_b = a.eqNode(b); |
715 |
10469 |
if (!isAbsolute) |
716 |
|
{ |
717 |
|
return a_eq_b; |
718 |
|
} |
719 |
20938 |
Node negate_b = NodeManager::currentNM()->mkNode(Kind::UMINUS, b); |
720 |
10469 |
return a_eq_b.orNode(a.eqNode(negate_b)); |
721 |
|
} |
722 |
75628 |
else if (status < 0) |
723 |
|
{ |
724 |
537 |
return mkLit(b, a, -status); |
725 |
|
} |
726 |
75091 |
Assert(status == 1 || status == 2); |
727 |
75091 |
NodeManager* nm = NodeManager::currentNM(); |
728 |
75091 |
Kind greater_op = status == 1 ? Kind::GEQ : Kind::GT; |
729 |
75091 |
if (!isAbsolute) |
730 |
|
{ |
731 |
1288 |
return nm->mkNode(greater_op, a, b); |
732 |
|
} |
733 |
|
// return nm->mkNode( greater_op, mkAbs( a ), mkAbs( b ) ); |
734 |
147606 |
Node a_is_nonnegative = nm->mkNode(Kind::GEQ, a, d_data->d_zero); |
735 |
147606 |
Node b_is_nonnegative = nm->mkNode(Kind::GEQ, b, d_data->d_zero); |
736 |
147606 |
Node negate_a = nm->mkNode(Kind::UMINUS, a); |
737 |
147606 |
Node negate_b = nm->mkNode(Kind::UMINUS, b); |
738 |
|
return a_is_nonnegative.iteNode( |
739 |
147606 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, a, b), |
740 |
147606 |
nm->mkNode(greater_op, a, negate_b)), |
741 |
147606 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, negate_a, b), |
742 |
221409 |
nm->mkNode(greater_op, negate_a, negate_b))); |
743 |
|
} |
744 |
|
|
745 |
62214 |
void MonomialCheck::setMonomialFactor(Node a, |
746 |
|
Node b, |
747 |
|
const NodeMultiset& common) |
748 |
|
{ |
749 |
|
// Could not tell if this was being inserted intentionally or not. |
750 |
62214 |
std::map<Node, Node>& mono_diff_a = d_data->d_mono_diff[a]; |
751 |
62214 |
if (mono_diff_a.find(b) == mono_diff_a.end()) |
752 |
|
{ |
753 |
14100 |
Trace("nl-ext-mono-factor") |
754 |
7050 |
<< "Set monomial factor for " << a << "/" << b << std::endl; |
755 |
7050 |
mono_diff_a[b] = d_data->d_mdb.mkMonomialRemFactor(a, common); |
756 |
|
} |
757 |
62214 |
} |
758 |
|
|
759 |
|
} // namespace nl |
760 |
|
} // namespace arith |
761 |
|
} // namespace theory |
762 |
29511 |
} // namespace cvc5 |