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 |
5208 |
MonomialCheck::MonomialCheck(ExtState* data) : d_data(data) |
33 |
|
{ |
34 |
5208 |
d_order_points.push_back(d_data->d_neg_one); |
35 |
5208 |
d_order_points.push_back(d_data->d_zero); |
36 |
5208 |
d_order_points.push_back(d_data->d_one); |
37 |
5208 |
} |
38 |
|
|
39 |
3927 |
void MonomialCheck::init(const std::vector<Node>& xts) |
40 |
|
{ |
41 |
3927 |
d_ms_proc.clear(); |
42 |
3927 |
d_m_nconst_factor.clear(); |
43 |
|
|
44 |
33763 |
for (unsigned i = 0, xsize = xts.size(); i < xsize; i++) |
45 |
|
{ |
46 |
59672 |
Node a = xts[i]; |
47 |
29836 |
if (a.getKind() == Kind::NONLINEAR_MULT) |
48 |
|
{ |
49 |
21238 |
const std::vector<Node>& varList = d_data->d_mdb.getVariableList(a); |
50 |
62276 |
for (const Node& v : varList) |
51 |
|
{ |
52 |
82076 |
Node mvk = d_data->d_model.computeAbstractModelValue(v); |
53 |
41038 |
if (!mvk.isConst()) |
54 |
|
{ |
55 |
|
d_m_nconst_factor[a] = true; |
56 |
|
} |
57 |
|
} |
58 |
|
} |
59 |
|
} |
60 |
|
|
61 |
15708 |
for (unsigned j = 0; j < d_order_points.size(); j++) |
62 |
|
{ |
63 |
23562 |
Node c = d_order_points[j]; |
64 |
11781 |
d_data->d_model.computeConcreteModelValue(c); |
65 |
11781 |
d_data->d_model.computeAbstractModelValue(c); |
66 |
|
} |
67 |
3927 |
} |
68 |
|
|
69 |
3115 |
void MonomialCheck::checkSign() |
70 |
|
{ |
71 |
6230 |
std::map<Node, int> signs; |
72 |
3115 |
Trace("nl-ext") << "Get monomial sign lemmas..." << std::endl; |
73 |
20667 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
74 |
|
{ |
75 |
35104 |
Node a = d_data->d_ms[j]; |
76 |
17552 |
if (d_ms_proc.find(a) == d_ms_proc.end()) |
77 |
|
{ |
78 |
35104 |
std::vector<Node> exp; |
79 |
17552 |
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 |
17552 |
if (d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
86 |
|
{ |
87 |
17552 |
signs[a] = compareSign(a, a, 0, 1, exp); |
88 |
17552 |
if (signs[a] == 0) |
89 |
|
{ |
90 |
3500 |
d_ms_proc[a] = true; |
91 |
7000 |
Trace("nl-ext-debug") |
92 |
3500 |
<< "...mark " << a << " reduced since its value is 0." |
93 |
3500 |
<< 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 |
3115 |
} |
105 |
|
|
106 |
4403 |
void MonomialCheck::checkMagnitude(unsigned c) |
107 |
|
{ |
108 |
|
// ensure information is setup |
109 |
4403 |
if (c == 0) |
110 |
|
{ |
111 |
|
// sort by absolute values of abstract model values |
112 |
1986 |
assignOrderIds(d_data->d_ms_vars, d_order_vars, false, true); |
113 |
|
|
114 |
|
// sort individual variable lists |
115 |
1986 |
Trace("nl-ext-proc") << "Assign order var lists..." << std::endl; |
116 |
1986 |
d_data->d_mdb.sortVariablesByModel(d_data->d_ms, d_data->d_model); |
117 |
|
} |
118 |
|
|
119 |
4403 |
unsigned r = 1; |
120 |
8806 |
std::vector<SimpleTheoryLemma> lemmas; |
121 |
|
// if (x,y,L) in cmp_infers, then x > y inferred as conclusion of L |
122 |
|
// in lemmas |
123 |
8806 |
std::map<int, std::map<Node, std::map<Node, Node> > > cmp_infers; |
124 |
8806 |
Trace("nl-ext") << "Get monomial comparison lemmas (order=" << r |
125 |
4403 |
<< ", compare=" << c << ")..." << std::endl; |
126 |
30535 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
127 |
|
{ |
128 |
52264 |
Node a = d_data->d_ms[j]; |
129 |
52264 |
if (d_ms_proc.find(a) == d_ms_proc.end() |
130 |
26132 |
&& d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
131 |
|
{ |
132 |
23073 |
if (c == 0) |
133 |
|
{ |
134 |
|
// compare magnitude against 1 |
135 |
20308 |
std::vector<Node> exp; |
136 |
20308 |
NodeMultiset a_exp_proc; |
137 |
20308 |
NodeMultiset b_exp_proc; |
138 |
20308 |
compareMonomial(a, |
139 |
|
a, |
140 |
|
a_exp_proc, |
141 |
10154 |
d_data->d_one, |
142 |
10154 |
d_data->d_one, |
143 |
|
b_exp_proc, |
144 |
|
exp, |
145 |
|
lemmas, |
146 |
|
cmp_infers); |
147 |
|
} |
148 |
|
else |
149 |
|
{ |
150 |
12919 |
const NodeMultiset& mea = d_data->d_mdb.getMonomialExponentMap(a); |
151 |
12919 |
if (c == 1) |
152 |
|
{ |
153 |
|
// could compare not just against containing variables? |
154 |
|
// compare magnitude against variables |
155 |
71478 |
for (unsigned k = 0; k < d_data->d_ms_vars.size(); k++) |
156 |
|
{ |
157 |
127572 |
Node v = d_data->d_ms_vars[k]; |
158 |
127572 |
Node mvcv = d_data->d_model.computeConcreteModelValue(v); |
159 |
63786 |
if (mvcv.isConst()) |
160 |
|
{ |
161 |
126960 |
std::vector<Node> exp; |
162 |
126960 |
NodeMultiset a_exp_proc; |
163 |
126960 |
NodeMultiset b_exp_proc; |
164 |
63480 |
if (mea.find(v) != mea.end()) |
165 |
|
{ |
166 |
13948 |
a_exp_proc[v] = 1; |
167 |
13948 |
b_exp_proc[v] = 1; |
168 |
13948 |
setMonomialFactor(a, v, a_exp_proc); |
169 |
13948 |
setMonomialFactor(v, a, b_exp_proc); |
170 |
13948 |
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 |
42469 |
for (unsigned k = (j + 1); k < d_data->d_ms.size(); k++) |
187 |
|
{ |
188 |
74484 |
Node b = d_data->d_ms[k]; |
189 |
|
//(signs[a]==signs[b])==(r==0) |
190 |
74484 |
if (d_ms_proc.find(b) == d_ms_proc.end() |
191 |
37242 |
&& d_m_nconst_factor.find(b) == d_m_nconst_factor.end()) |
192 |
|
{ |
193 |
34402 |
const NodeMultiset& meb = d_data->d_mdb.getMonomialExponentMap(b); |
194 |
|
|
195 |
68804 |
std::vector<Node> exp; |
196 |
|
// take common factors of monomials, set minimum of |
197 |
|
// common exponents as processed |
198 |
68804 |
NodeMultiset a_exp_proc; |
199 |
68804 |
NodeMultiset b_exp_proc; |
200 |
99581 |
for (NodeMultiset::const_iterator itmea2 = mea.begin(); |
201 |
99581 |
itmea2 != mea.end(); |
202 |
|
++itmea2) |
203 |
|
{ |
204 |
65179 |
NodeMultiset::const_iterator itmeb2 = meb.find(itmea2->first); |
205 |
65179 |
if (itmeb2 != meb.end()) |
206 |
|
{ |
207 |
17073 |
unsigned min_exp = itmea2->second > itmeb2->second |
208 |
32976 |
? itmeb2->second |
209 |
32976 |
: itmea2->second; |
210 |
17073 |
a_exp_proc[itmea2->first] = min_exp; |
211 |
17073 |
b_exp_proc[itmea2->first] = min_exp; |
212 |
34146 |
Trace("nl-ext-comp") << "Common exponent : " << itmea2->first |
213 |
17073 |
<< " : " << min_exp << std::endl; |
214 |
|
} |
215 |
|
} |
216 |
34402 |
if (!a_exp_proc.empty()) |
217 |
|
{ |
218 |
16793 |
setMonomialFactor(a, b, a_exp_proc); |
219 |
16793 |
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 |
34402 |
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 |
8806 |
Trace("nl-ext-comp") << "Compute redundancies for " << lemmas.size() |
240 |
4403 |
<< " lemmas." << std::endl; |
241 |
|
// naive |
242 |
8806 |
std::unordered_set<Node> r_lemmas; |
243 |
1306 |
for (std::map<int, std::map<Node, std::map<Node, Node> > >::iterator itb = |
244 |
4403 |
cmp_infers.begin(); |
245 |
5709 |
itb != cmp_infers.end(); |
246 |
|
++itb) |
247 |
|
{ |
248 |
2306 |
for (std::map<Node, std::map<Node, Node> >::iterator itc = |
249 |
1306 |
itb->second.begin(); |
250 |
3612 |
itc != itb->second.end(); |
251 |
|
++itc) |
252 |
|
{ |
253 |
5471 |
for (std::map<Node, Node>::iterator itc2 = itc->second.begin(); |
254 |
5471 |
itc2 != itc->second.end(); |
255 |
|
++itc2) |
256 |
|
{ |
257 |
6330 |
std::map<Node, bool> visited; |
258 |
9319 |
for (std::map<Node, Node>::iterator itc3 = itc->second.begin(); |
259 |
9319 |
itc3 != itc->second.end(); |
260 |
|
++itc3) |
261 |
|
{ |
262 |
6312 |
if (itc3->first != itc2->first) |
263 |
|
{ |
264 |
6276 |
std::vector<Node> exp; |
265 |
3217 |
if (cmp_holds(itc3->first, itc2->first, itb->second, exp, visited)) |
266 |
|
{ |
267 |
158 |
r_lemmas.insert(itc2->second); |
268 |
316 |
Trace("nl-ext-comp") |
269 |
158 |
<< "...inference of " << itc->first << " > " << itc2->first |
270 |
158 |
<< " was redundant." << std::endl; |
271 |
158 |
break; |
272 |
|
} |
273 |
|
} |
274 |
|
} |
275 |
|
} |
276 |
|
} |
277 |
|
} |
278 |
7568 |
for (unsigned i = 0; i < lemmas.size(); i++) |
279 |
|
{ |
280 |
3165 |
if (r_lemmas.find(lemmas[i].d_node) == r_lemmas.end()) |
281 |
|
{ |
282 |
3007 |
d_data->d_im.addPendingLemma(lemmas[i]); |
283 |
|
} |
284 |
|
} |
285 |
|
// could only take maximal lower/minimial lower bounds? |
286 |
4403 |
} |
287 |
|
|
288 |
|
// show a <> 0 by inequalities between variables in monomial a w.r.t 0 |
289 |
46549 |
int MonomialCheck::compareSign( |
290 |
|
Node oa, Node a, unsigned a_index, int status, std::vector<Node>& exp) |
291 |
|
{ |
292 |
93098 |
Trace("nl-ext-debug") << "Process " << a << " at index " << a_index |
293 |
46549 |
<< ", status is " << status << std::endl; |
294 |
46549 |
NodeManager* nm = NodeManager::currentNM(); |
295 |
93098 |
Node mvaoa = d_data->d_model.computeAbstractModelValue(oa); |
296 |
46549 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
297 |
46549 |
if (a_index == vla.size()) |
298 |
|
{ |
299 |
14052 |
if (mvaoa.getConst<Rational>().sgn() != status) |
300 |
|
{ |
301 |
|
Node lemma = |
302 |
2476 |
nm->mkAnd(exp).impNode(mkLit(oa, d_data->d_zero, status * 2)); |
303 |
1238 |
CDProof* proof = nullptr; |
304 |
1238 |
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 |
1238 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
312 |
|
} |
313 |
14052 |
return status; |
314 |
|
} |
315 |
32497 |
Assert(a_index < vla.size()); |
316 |
64994 |
Node av = vla[a_index]; |
317 |
32497 |
unsigned aexp = d_data->d_mdb.getExponent(a, av); |
318 |
|
// take current sign in model |
319 |
64994 |
Node mvaav = d_data->d_model.computeAbstractModelValue(av); |
320 |
32497 |
int sgn = mvaav.getConst<Rational>().sgn(); |
321 |
64994 |
Trace("nl-ext-debug") << "Process var " << av << "^" << aexp |
322 |
32497 |
<< ", model sign = " << sgn << std::endl; |
323 |
32497 |
if (sgn == 0) |
324 |
|
{ |
325 |
3500 |
if (mvaoa.getConst<Rational>().sgn() != 0) |
326 |
|
{ |
327 |
1582 |
Node prem = av.eqNode(d_data->d_zero); |
328 |
1582 |
Node conc = oa.eqNode(d_data->d_zero); |
329 |
1582 |
Node lemma = prem.impNode(conc); |
330 |
791 |
CDProof* proof = nullptr; |
331 |
791 |
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 |
791 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
338 |
|
} |
339 |
3500 |
return 0; |
340 |
|
} |
341 |
28997 |
if (aexp % 2 == 0) |
342 |
|
{ |
343 |
2952 |
exp.push_back(av.eqNode(d_data->d_zero).negate()); |
344 |
2952 |
return compareSign(oa, a, a_index + 1, status, exp); |
345 |
|
} |
346 |
26045 |
exp.push_back(nm->mkNode(sgn == 1 ? Kind::GT : Kind::LT, av, d_data->d_zero)); |
347 |
26045 |
return compareSign(oa, a, a_index + 1, status * sgn, exp); |
348 |
|
} |
349 |
|
|
350 |
58504 |
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 |
117008 |
Trace("nl-ext-comp-debug") |
362 |
58504 |
<< "Check |" << a << "| >= |" << b << "|" << std::endl; |
363 |
58504 |
unsigned pexp_size = exp.size(); |
364 |
58504 |
if (compareMonomial( |
365 |
|
oa, a, 0, a_exp_proc, ob, b, 0, b_exp_proc, 0, exp, lem, cmp_infers)) |
366 |
|
{ |
367 |
40607 |
return true; |
368 |
|
} |
369 |
17897 |
exp.resize(pexp_size); |
370 |
35794 |
Trace("nl-ext-comp-debug") |
371 |
17897 |
<< "Check |" << b << "| >= |" << a << "|" << std::endl; |
372 |
17897 |
if (compareMonomial( |
373 |
|
ob, b, 0, b_exp_proc, oa, a, 0, a_exp_proc, 0, exp, lem, cmp_infers)) |
374 |
|
{ |
375 |
11212 |
return true; |
376 |
|
} |
377 |
6685 |
return false; |
378 |
|
} |
379 |
|
|
380 |
|
// trying to show a ( >, = ) b by inequalities between variables in |
381 |
|
// monomials a,b |
382 |
305186 |
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 |
610372 |
Trace("nl-ext-comp-debug") |
397 |
305186 |
<< "compareMonomial " << oa << " and " << ob << ", indices = " << a_index |
398 |
305186 |
<< " " << b_index << std::endl; |
399 |
305186 |
Assert(status == 0 || status == 2); |
400 |
305186 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
401 |
305186 |
const std::vector<Node>& vlb = d_data->d_mdb.getVariableList(b); |
402 |
305186 |
if (a_index == vla.size() && b_index == vlb.size()) |
403 |
|
{ |
404 |
|
// finished, compare absolute value of abstract model values |
405 |
51819 |
int modelStatus = d_data->d_model.compare(oa, ob, false, true) * -2; |
406 |
103638 |
Trace("nl-ext-comp") << "...finished comparison with " << oa << " <" |
407 |
51819 |
<< status << "> " << ob |
408 |
51819 |
<< ", model status = " << modelStatus << std::endl; |
409 |
51819 |
if (status != modelStatus) |
410 |
|
{ |
411 |
6330 |
Trace("nl-ext-comp-infer") |
412 |
3165 |
<< "infer : " << oa << " <" << status << "> " << ob << std::endl; |
413 |
3165 |
if (status == 2) |
414 |
|
{ |
415 |
|
// must state that all variables are non-zero |
416 |
6825 |
for (unsigned j = 0; j < vla.size(); j++) |
417 |
|
{ |
418 |
4394 |
exp.push_back(vla[j].eqNode(d_data->d_zero).negate()); |
419 |
|
} |
420 |
|
} |
421 |
3165 |
NodeManager* nm = NodeManager::currentNM(); |
422 |
|
Node clem = nm->mkNode( |
423 |
6330 |
Kind::IMPLIES, nm->mkAnd(exp), mkLit(oa, ob, status, true)); |
424 |
3165 |
Trace("nl-ext-comp-lemma") << "comparison lemma : " << clem << std::endl; |
425 |
3165 |
lem.emplace_back( |
426 |
6330 |
InferenceId::ARITH_NL_COMPARISON, clem, LemmaProperty::NONE, nullptr); |
427 |
3165 |
cmp_infers[status][oa][ob] = clem; |
428 |
|
} |
429 |
51819 |
return true; |
430 |
|
} |
431 |
|
// get a/b variable information |
432 |
506734 |
Node av; |
433 |
253367 |
unsigned aexp = 0; |
434 |
253367 |
unsigned avo = 0; |
435 |
253367 |
if (a_index < vla.size()) |
436 |
|
{ |
437 |
217225 |
av = vla[a_index]; |
438 |
217225 |
unsigned aexpTotal = d_data->d_mdb.getExponent(a, av); |
439 |
217225 |
Assert(a_exp_proc[av] <= aexpTotal); |
440 |
217225 |
aexp = aexpTotal - a_exp_proc[av]; |
441 |
217225 |
if (aexp == 0) |
442 |
|
{ |
443 |
152826 |
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 |
76413 |
cmp_infers); |
455 |
|
} |
456 |
140812 |
Assert(d_order_vars.find(av) != d_order_vars.end()); |
457 |
140812 |
avo = d_order_vars[av]; |
458 |
|
} |
459 |
353908 |
Node bv; |
460 |
176954 |
unsigned bexp = 0; |
461 |
176954 |
unsigned bvo = 0; |
462 |
176954 |
if (b_index < vlb.size()) |
463 |
|
{ |
464 |
143564 |
bv = vlb[b_index]; |
465 |
143564 |
unsigned bexpTotal = d_data->d_mdb.getExponent(b, bv); |
466 |
143564 |
Assert(b_exp_proc[bv] <= bexpTotal); |
467 |
143564 |
bexp = bexpTotal - b_exp_proc[bv]; |
468 |
143564 |
if (bexp == 0) |
469 |
|
{ |
470 |
146484 |
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 |
73242 |
cmp_infers); |
482 |
|
} |
483 |
70322 |
Assert(d_order_vars.find(bv) != d_order_vars.end()); |
484 |
70322 |
bvo = d_order_vars[bv]; |
485 |
|
} |
486 |
|
// get "one" information |
487 |
103712 |
Assert(d_order_vars.find(d_data->d_one) != d_order_vars.end()); |
488 |
103712 |
unsigned ovo = d_order_vars[d_data->d_one]; |
489 |
207424 |
Trace("nl-ext-comp-debug") << "....vars : " << av << "^" << aexp << " " << bv |
490 |
103712 |
<< "^" << bexp << std::endl; |
491 |
|
|
492 |
|
//--- cases |
493 |
103712 |
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 |
99843 |
else if (bv.isNull()) |
518 |
|
{ |
519 |
33390 |
if (avo >= ovo) |
520 |
|
{ |
521 |
30590 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
522 |
|
// can multiply a by >=1 |
523 |
30590 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
524 |
61180 |
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 |
30590 |
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 |
66453 |
Assert(!av.isNull() && !bv.isNull()); |
542 |
66453 |
if (avo >= bvo) |
543 |
|
{ |
544 |
45436 |
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 |
44940 |
unsigned min_exp = aexp > bexp ? bexp : aexp; |
563 |
44940 |
a_exp_proc[av] += min_exp; |
564 |
44940 |
b_exp_proc[bv] += min_exp; |
565 |
89880 |
Trace("nl-ext-comp-debug") << "...take leading " << min_exp << " from " |
566 |
44940 |
<< av << " and " << bv << std::endl; |
567 |
44940 |
exp.push_back(mkLit(av, bv, avo == bvo ? 0 : 2, true)); |
568 |
89880 |
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 |
44940 |
cmp_infers); |
580 |
44940 |
a_exp_proc[av] -= min_exp; |
581 |
44940 |
b_exp_proc[bv] -= min_exp; |
582 |
44940 |
return ret; |
583 |
|
} |
584 |
21017 |
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 |
41474 |
Trace("nl-ext-comp-debug") |
603 |
20737 |
<< "...failure, leading |b|>|a|>1 component." << std::endl; |
604 |
20737 |
return false; |
605 |
|
} |
606 |
|
|
607 |
4075 |
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 |
4075 |
if (x == y) |
614 |
|
{ |
615 |
158 |
return true; |
616 |
|
} |
617 |
3917 |
else if (visited.find(x) != visited.end()) |
618 |
|
{ |
619 |
620 |
return false; |
620 |
|
} |
621 |
3297 |
visited[x] = true; |
622 |
3297 |
std::map<Node, std::map<Node, Node> >::iterator it = cmp_infers.find(x); |
623 |
3297 |
if (it != cmp_infers.end()) |
624 |
|
{ |
625 |
1277 |
for (std::map<Node, Node>::iterator itc = it->second.begin(); |
626 |
1277 |
itc != it->second.end(); |
627 |
|
++itc) |
628 |
|
{ |
629 |
858 |
exp.push_back(itc->second); |
630 |
858 |
if (cmp_holds(itc->first, y, cmp_infers, exp, visited)) |
631 |
|
{ |
632 |
168 |
return true; |
633 |
|
} |
634 |
690 |
exp.pop_back(); |
635 |
|
} |
636 |
|
} |
637 |
3129 |
return false; |
638 |
|
} |
639 |
|
|
640 |
1986 |
void MonomialCheck::assignOrderIds(std::vector<Node>& vars, |
641 |
|
NodeMultiset& order, |
642 |
|
bool isConcrete, |
643 |
|
bool isAbsolute) |
644 |
|
{ |
645 |
1986 |
SortNlModel smv; |
646 |
1986 |
smv.d_nlm = &d_data->d_model; |
647 |
1986 |
smv.d_isConcrete = isConcrete; |
648 |
1986 |
smv.d_isAbsolute = isAbsolute; |
649 |
1986 |
smv.d_reverse_order = false; |
650 |
1986 |
std::sort(vars.begin(), vars.end(), smv); |
651 |
|
|
652 |
1986 |
order.clear(); |
653 |
|
// assign ordering id's |
654 |
1986 |
unsigned counter = 0; |
655 |
1986 |
unsigned order_index = isConcrete ? 0 : 1; |
656 |
3972 |
Node prev; |
657 |
11446 |
for (unsigned j = 0; j < vars.size(); j++) |
658 |
|
{ |
659 |
18920 |
Node x = vars[j]; |
660 |
18920 |
Node v = d_data->d_model.computeModelValue(x, isConcrete); |
661 |
9460 |
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 |
9460 |
Trace("nl-ext-mvo") << " order " << x << " : " << v << std::endl; |
669 |
9460 |
if (v != prev) |
670 |
|
{ |
671 |
|
// builtin points |
672 |
|
bool success; |
673 |
10075 |
do |
674 |
|
{ |
675 |
10075 |
success = false; |
676 |
10075 |
if (order_index < d_order_points.size()) |
677 |
|
{ |
678 |
4459 |
Node vv = d_data->d_model.computeModelValue( |
679 |
8918 |
d_order_points[order_index], isConcrete); |
680 |
4459 |
if (d_data->d_model.compareValue(v, vv, isAbsolute) <= 0) |
681 |
|
{ |
682 |
3323 |
counter++; |
683 |
6646 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
684 |
3323 |
<< "] = " << counter << std::endl; |
685 |
3323 |
order[d_order_points[order_index]] = counter; |
686 |
3323 |
prev = vv; |
687 |
3323 |
order_index++; |
688 |
3323 |
success = true; |
689 |
|
} |
690 |
|
} |
691 |
|
} while (success); |
692 |
|
} |
693 |
9460 |
if (prev.isNull() || d_data->d_model.compareValue(v, prev, isAbsolute) != 0) |
694 |
|
{ |
695 |
4447 |
counter++; |
696 |
|
} |
697 |
9460 |
Trace("nl-ext-mvo") << "O[" << x << "] = " << counter << std::endl; |
698 |
9460 |
order[x] = counter; |
699 |
9460 |
prev = v; |
700 |
|
} |
701 |
3284 |
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 |
1986 |
} |
710 |
84047 |
Node MonomialCheck::mkLit(Node a, Node b, int status, bool isAbsolute) const |
711 |
|
{ |
712 |
84047 |
if (status == 0) |
713 |
|
{ |
714 |
19342 |
Node a_eq_b = a.eqNode(b); |
715 |
9671 |
if (!isAbsolute) |
716 |
|
{ |
717 |
|
return a_eq_b; |
718 |
|
} |
719 |
19342 |
Node negate_b = NodeManager::currentNM()->mkNode(Kind::UMINUS, b); |
720 |
9671 |
return a_eq_b.orNode(a.eqNode(negate_b)); |
721 |
|
} |
722 |
74376 |
else if (status < 0) |
723 |
|
{ |
724 |
514 |
return mkLit(b, a, -status); |
725 |
|
} |
726 |
73862 |
Assert(status == 1 || status == 2); |
727 |
73862 |
NodeManager* nm = NodeManager::currentNM(); |
728 |
73862 |
Kind greater_op = status == 1 ? Kind::GEQ : Kind::GT; |
729 |
73862 |
if (!isAbsolute) |
730 |
|
{ |
731 |
1238 |
return nm->mkNode(greater_op, a, b); |
732 |
|
} |
733 |
|
// return nm->mkNode( greater_op, mkAbs( a ), mkAbs( b ) ); |
734 |
145248 |
Node a_is_nonnegative = nm->mkNode(Kind::GEQ, a, d_data->d_zero); |
735 |
145248 |
Node b_is_nonnegative = nm->mkNode(Kind::GEQ, b, d_data->d_zero); |
736 |
145248 |
Node negate_a = nm->mkNode(Kind::UMINUS, a); |
737 |
145248 |
Node negate_b = nm->mkNode(Kind::UMINUS, b); |
738 |
|
return a_is_nonnegative.iteNode( |
739 |
145248 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, a, b), |
740 |
145248 |
nm->mkNode(greater_op, a, negate_b)), |
741 |
145248 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, negate_a, b), |
742 |
217872 |
nm->mkNode(greater_op, negate_a, negate_b))); |
743 |
|
} |
744 |
|
|
745 |
61482 |
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 |
61482 |
std::map<Node, Node>& mono_diff_a = d_data->d_mono_diff[a]; |
751 |
61482 |
if (mono_diff_a.find(b) == mono_diff_a.end()) |
752 |
|
{ |
753 |
13924 |
Trace("nl-ext-mono-factor") |
754 |
6962 |
<< "Set monomial factor for " << a << "/" << b << std::endl; |
755 |
6962 |
mono_diff_a[b] = d_data->d_mdb.mkMonomialRemFactor(a, common); |
756 |
|
} |
757 |
61482 |
} |
758 |
|
|
759 |
|
} // namespace nl |
760 |
|
} // namespace arith |
761 |
|
} // namespace theory |
762 |
29499 |
} // namespace cvc5 |