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 |
5134 |
MonomialCheck::MonomialCheck(ExtState* data) : d_data(data) |
33 |
|
{ |
34 |
5134 |
d_order_points.push_back(d_data->d_neg_one); |
35 |
5134 |
d_order_points.push_back(d_data->d_zero); |
36 |
5134 |
d_order_points.push_back(d_data->d_one); |
37 |
5134 |
} |
38 |
|
|
39 |
2803 |
void MonomialCheck::init(const std::vector<Node>& xts) |
40 |
|
{ |
41 |
2803 |
d_ms_proc.clear(); |
42 |
2803 |
d_m_nconst_factor.clear(); |
43 |
|
|
44 |
23041 |
for (unsigned i = 0, xsize = xts.size(); i < xsize; i++) |
45 |
|
{ |
46 |
40476 |
Node a = xts[i]; |
47 |
20238 |
if (a.getKind() == Kind::NONLINEAR_MULT) |
48 |
|
{ |
49 |
13504 |
const std::vector<Node>& varList = d_data->d_mdb.getVariableList(a); |
50 |
39927 |
for (const Node& v : varList) |
51 |
|
{ |
52 |
52846 |
Node mvk = d_data->d_model.computeAbstractModelValue(v); |
53 |
26423 |
if (!mvk.isConst()) |
54 |
|
{ |
55 |
|
d_m_nconst_factor[a] = true; |
56 |
|
} |
57 |
|
} |
58 |
|
} |
59 |
|
} |
60 |
|
|
61 |
11212 |
for (unsigned j = 0; j < d_order_points.size(); j++) |
62 |
|
{ |
63 |
16818 |
Node c = d_order_points[j]; |
64 |
8409 |
d_data->d_model.computeConcreteModelValue(c); |
65 |
8409 |
d_data->d_model.computeAbstractModelValue(c); |
66 |
|
} |
67 |
2803 |
} |
68 |
|
|
69 |
2390 |
void MonomialCheck::checkSign() |
70 |
|
{ |
71 |
4780 |
std::map<Node, int> signs; |
72 |
2390 |
Trace("nl-ext") << "Get monomial sign lemmas..." << std::endl; |
73 |
14862 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
74 |
|
{ |
75 |
24944 |
Node a = d_data->d_ms[j]; |
76 |
12472 |
if (d_ms_proc.find(a) == d_ms_proc.end()) |
77 |
|
{ |
78 |
24944 |
std::vector<Node> exp; |
79 |
12472 |
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 |
12472 |
if (d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
86 |
|
{ |
87 |
12472 |
signs[a] = compareSign(a, a, 0, 1, exp); |
88 |
12472 |
if (signs[a] == 0) |
89 |
|
{ |
90 |
1920 |
d_ms_proc[a] = true; |
91 |
3840 |
Trace("nl-ext-debug") |
92 |
1920 |
<< "...mark " << a << " reduced since its value is 0." |
93 |
1920 |
<< 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 |
2390 |
} |
105 |
|
|
106 |
3321 |
void MonomialCheck::checkMagnitude(unsigned c) |
107 |
|
{ |
108 |
|
// ensure information is setup |
109 |
3321 |
if (c == 0) |
110 |
|
{ |
111 |
|
// sort by absolute values of abstract model values |
112 |
1542 |
assignOrderIds(d_data->d_ms_vars, d_order_vars, false, true); |
113 |
|
|
114 |
|
// sort individual variable lists |
115 |
1542 |
Trace("nl-ext-proc") << "Assign order var lists..." << std::endl; |
116 |
1542 |
d_data->d_mdb.sortVariablesByModel(d_data->d_ms, d_data->d_model); |
117 |
|
} |
118 |
|
|
119 |
3321 |
unsigned r = 1; |
120 |
6642 |
std::vector<SimpleTheoryLemma> lemmas; |
121 |
|
// if (x,y,L) in cmp_infers, then x > y inferred as conclusion of L |
122 |
|
// in lemmas |
123 |
6642 |
std::map<int, std::map<Node, std::map<Node, Node> > > cmp_infers; |
124 |
6642 |
Trace("nl-ext") << "Get monomial comparison lemmas (order=" << r |
125 |
3321 |
<< ", compare=" << c << ")..." << std::endl; |
126 |
22385 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
127 |
|
{ |
128 |
38128 |
Node a = d_data->d_ms[j]; |
129 |
38128 |
if (d_ms_proc.find(a) == d_ms_proc.end() |
130 |
19064 |
&& d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
131 |
|
{ |
132 |
17283 |
if (c == 0) |
133 |
|
{ |
134 |
|
// compare magnitude against 1 |
135 |
15728 |
std::vector<Node> exp; |
136 |
15728 |
NodeMultiset a_exp_proc; |
137 |
15728 |
NodeMultiset b_exp_proc; |
138 |
15728 |
compareMonomial(a, |
139 |
|
a, |
140 |
|
a_exp_proc, |
141 |
7864 |
d_data->d_one, |
142 |
7864 |
d_data->d_one, |
143 |
|
b_exp_proc, |
144 |
|
exp, |
145 |
|
lemmas, |
146 |
|
cmp_infers); |
147 |
|
} |
148 |
|
else |
149 |
|
{ |
150 |
9419 |
const NodeMultiset& mea = d_data->d_mdb.getMonomialExponentMap(a); |
151 |
9419 |
if (c == 1) |
152 |
|
{ |
153 |
|
// could compare not just against containing variables? |
154 |
|
// compare magnitude against variables |
155 |
45126 |
for (unsigned k = 0; k < d_data->d_ms_vars.size(); k++) |
156 |
|
{ |
157 |
79066 |
Node v = d_data->d_ms_vars[k]; |
158 |
79066 |
Node mvcv = d_data->d_model.computeConcreteModelValue(v); |
159 |
39533 |
if (mvcv.isConst()) |
160 |
|
{ |
161 |
78610 |
std::vector<Node> exp; |
162 |
78610 |
NodeMultiset a_exp_proc; |
163 |
78610 |
NodeMultiset b_exp_proc; |
164 |
39305 |
if (mea.find(v) != mea.end()) |
165 |
|
{ |
166 |
10046 |
a_exp_proc[v] = 1; |
167 |
10046 |
b_exp_proc[v] = 1; |
168 |
10046 |
setMonomialFactor(a, v, a_exp_proc); |
169 |
10046 |
setMonomialFactor(v, a, b_exp_proc); |
170 |
10046 |
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 |
29615 |
for (unsigned k = (j + 1); k < d_data->d_ms.size(); k++) |
187 |
|
{ |
188 |
51578 |
Node b = d_data->d_ms[k]; |
189 |
|
//(signs[a]==signs[b])==(r==0) |
190 |
51578 |
if (d_ms_proc.find(b) == d_ms_proc.end() |
191 |
25789 |
&& d_m_nconst_factor.find(b) == d_m_nconst_factor.end()) |
192 |
|
{ |
193 |
24360 |
const NodeMultiset& meb = d_data->d_mdb.getMonomialExponentMap(b); |
194 |
|
|
195 |
48720 |
std::vector<Node> exp; |
196 |
|
// take common factors of monomials, set minimum of |
197 |
|
// common exponents as processed |
198 |
48720 |
NodeMultiset a_exp_proc; |
199 |
48720 |
NodeMultiset b_exp_proc; |
200 |
70048 |
for (NodeMultiset::const_iterator itmea2 = mea.begin(); |
201 |
70048 |
itmea2 != mea.end(); |
202 |
|
++itmea2) |
203 |
|
{ |
204 |
45688 |
NodeMultiset::const_iterator itmeb2 = meb.find(itmea2->first); |
205 |
45688 |
if (itmeb2 != meb.end()) |
206 |
|
{ |
207 |
12053 |
unsigned min_exp = itmea2->second > itmeb2->second |
208 |
23196 |
? itmeb2->second |
209 |
23196 |
: itmea2->second; |
210 |
12053 |
a_exp_proc[itmea2->first] = min_exp; |
211 |
12053 |
b_exp_proc[itmea2->first] = min_exp; |
212 |
24106 |
Trace("nl-ext-comp") << "Common exponent : " << itmea2->first |
213 |
12053 |
<< " : " << min_exp << std::endl; |
214 |
|
} |
215 |
|
} |
216 |
24360 |
if (!a_exp_proc.empty()) |
217 |
|
{ |
218 |
11729 |
setMonomialFactor(a, b, a_exp_proc); |
219 |
11729 |
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 |
24360 |
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 |
6642 |
Trace("nl-ext-comp") << "Compute redundancies for " << lemmas.size() |
240 |
3321 |
<< " lemmas." << std::endl; |
241 |
|
// naive |
242 |
6642 |
std::unordered_set<Node> r_lemmas; |
243 |
1043 |
for (std::map<int, std::map<Node, std::map<Node, Node> > >::iterator itb = |
244 |
3321 |
cmp_infers.begin(); |
245 |
4364 |
itb != cmp_infers.end(); |
246 |
|
++itb) |
247 |
|
{ |
248 |
1861 |
for (std::map<Node, std::map<Node, Node> >::iterator itc = |
249 |
1043 |
itb->second.begin(); |
250 |
2904 |
itc != itb->second.end(); |
251 |
|
++itc) |
252 |
|
{ |
253 |
4646 |
for (std::map<Node, Node>::iterator itc2 = itc->second.begin(); |
254 |
4646 |
itc2 != itc->second.end(); |
255 |
|
++itc2) |
256 |
|
{ |
257 |
5570 |
std::map<Node, bool> visited; |
258 |
8681 |
for (std::map<Node, Node>::iterator itc3 = itc->second.begin(); |
259 |
8681 |
itc3 != itc->second.end(); |
260 |
|
++itc3) |
261 |
|
{ |
262 |
6101 |
if (itc3->first != itc2->first) |
263 |
|
{ |
264 |
6635 |
std::vector<Node> exp; |
265 |
3420 |
if (cmp_holds(itc3->first, itc2->first, itb->second, exp, visited)) |
266 |
|
{ |
267 |
205 |
r_lemmas.insert(itc2->second); |
268 |
410 |
Trace("nl-ext-comp") |
269 |
205 |
<< "...inference of " << itc->first << " > " << itc2->first |
270 |
205 |
<< " was redundant." << std::endl; |
271 |
205 |
break; |
272 |
|
} |
273 |
|
} |
274 |
|
} |
275 |
|
} |
276 |
|
} |
277 |
|
} |
278 |
6106 |
for (unsigned i = 0; i < lemmas.size(); i++) |
279 |
|
{ |
280 |
2785 |
if (r_lemmas.find(lemmas[i].d_node) == r_lemmas.end()) |
281 |
|
{ |
282 |
2580 |
d_data->d_im.addPendingLemma(lemmas[i]); |
283 |
|
} |
284 |
|
} |
285 |
|
// could only take maximal lower/minimial lower bounds? |
286 |
3321 |
} |
287 |
|
|
288 |
|
// show a <> 0 by inequalities between variables in monomial a w.r.t 0 |
289 |
34039 |
int MonomialCheck::compareSign( |
290 |
|
Node oa, Node a, unsigned a_index, int status, std::vector<Node>& exp) |
291 |
|
{ |
292 |
68078 |
Trace("nl-ext-debug") << "Process " << a << " at index " << a_index |
293 |
34039 |
<< ", status is " << status << std::endl; |
294 |
34039 |
NodeManager* nm = NodeManager::currentNM(); |
295 |
68078 |
Node mvaoa = d_data->d_model.computeAbstractModelValue(oa); |
296 |
34039 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
297 |
34039 |
if (a_index == vla.size()) |
298 |
|
{ |
299 |
10552 |
if (mvaoa.getConst<Rational>().sgn() != status) |
300 |
|
{ |
301 |
|
Node lemma = |
302 |
1872 |
nm->mkAnd(exp).impNode(mkLit(oa, d_data->d_zero, status * 2)); |
303 |
936 |
CDProof* proof = nullptr; |
304 |
936 |
if (d_data->isProofEnabled()) |
305 |
|
{ |
306 |
181 |
proof = d_data->getProof(); |
307 |
362 |
std::vector<Node> args = exp; |
308 |
181 |
args.emplace_back(oa); |
309 |
181 |
proof->addStep(lemma, PfRule::ARITH_MULT_SIGN, {}, args); |
310 |
|
} |
311 |
936 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
312 |
|
} |
313 |
10552 |
return status; |
314 |
|
} |
315 |
23487 |
Assert(a_index < vla.size()); |
316 |
46974 |
Node av = vla[a_index]; |
317 |
23487 |
unsigned aexp = d_data->d_mdb.getExponent(a, av); |
318 |
|
// take current sign in model |
319 |
46974 |
Node mvaav = d_data->d_model.computeAbstractModelValue(av); |
320 |
23487 |
int sgn = mvaav.getConst<Rational>().sgn(); |
321 |
46974 |
Trace("nl-ext-debug") << "Process var " << av << "^" << aexp |
322 |
23487 |
<< ", model sign = " << sgn << std::endl; |
323 |
23487 |
if (sgn == 0) |
324 |
|
{ |
325 |
1920 |
if (mvaoa.getConst<Rational>().sgn() != 0) |
326 |
|
{ |
327 |
1032 |
Node prem = av.eqNode(d_data->d_zero); |
328 |
1032 |
Node conc = oa.eqNode(d_data->d_zero); |
329 |
1032 |
Node lemma = prem.impNode(conc); |
330 |
516 |
CDProof* proof = nullptr; |
331 |
516 |
if (d_data->isProofEnabled()) |
332 |
|
{ |
333 |
80 |
proof = d_data->getProof(); |
334 |
80 |
proof->addStep(conc, PfRule::MACRO_SR_PRED_INTRO, {prem}, {conc}); |
335 |
80 |
proof->addStep(lemma, PfRule::SCOPE, {conc}, {prem}); |
336 |
|
} |
337 |
516 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
338 |
|
} |
339 |
1920 |
return 0; |
340 |
|
} |
341 |
21567 |
if (aexp % 2 == 0) |
342 |
|
{ |
343 |
2337 |
exp.push_back(av.eqNode(d_data->d_zero).negate()); |
344 |
2337 |
return compareSign(oa, a, a_index + 1, status, exp); |
345 |
|
} |
346 |
19230 |
exp.push_back(nm->mkNode(sgn == 1 ? Kind::GT : Kind::LT, av, d_data->d_zero)); |
347 |
19230 |
return compareSign(oa, a, a_index + 1, status * sgn, exp); |
348 |
|
} |
349 |
|
|
350 |
42270 |
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 |
84540 |
Trace("nl-ext-comp-debug") |
362 |
42270 |
<< "Check |" << a << "| >= |" << b << "|" << std::endl; |
363 |
42270 |
unsigned pexp_size = exp.size(); |
364 |
42270 |
if (compareMonomial( |
365 |
|
oa, a, 0, a_exp_proc, ob, b, 0, b_exp_proc, 0, exp, lem, cmp_infers)) |
366 |
|
{ |
367 |
30094 |
return true; |
368 |
|
} |
369 |
12176 |
exp.resize(pexp_size); |
370 |
24352 |
Trace("nl-ext-comp-debug") |
371 |
12176 |
<< "Check |" << b << "| >= |" << a << "|" << std::endl; |
372 |
12176 |
if (compareMonomial( |
373 |
|
ob, b, 0, b_exp_proc, oa, a, 0, a_exp_proc, 0, exp, lem, cmp_infers)) |
374 |
|
{ |
375 |
7117 |
return true; |
376 |
|
} |
377 |
5059 |
return false; |
378 |
|
} |
379 |
|
|
380 |
|
// trying to show a ( >, = ) b by inequalities between variables in |
381 |
|
// monomials a,b |
382 |
215590 |
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 |
431180 |
Trace("nl-ext-comp-debug") |
397 |
215590 |
<< "compareMonomial " << oa << " and " << ob << ", indices = " << a_index |
398 |
215590 |
<< " " << b_index << std::endl; |
399 |
215590 |
Assert(status == 0 || status == 2); |
400 |
215590 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
401 |
215590 |
const std::vector<Node>& vlb = d_data->d_mdb.getVariableList(b); |
402 |
215590 |
if (a_index == vla.size() && b_index == vlb.size()) |
403 |
|
{ |
404 |
|
// finished, compare absolute value of abstract model values |
405 |
37211 |
int modelStatus = d_data->d_model.compare(oa, ob, false, true) * -2; |
406 |
74422 |
Trace("nl-ext-comp") << "...finished comparison with " << oa << " <" |
407 |
37211 |
<< status << "> " << ob |
408 |
37211 |
<< ", model status = " << modelStatus << std::endl; |
409 |
37211 |
if (status != modelStatus) |
410 |
|
{ |
411 |
5570 |
Trace("nl-ext-comp-infer") |
412 |
2785 |
<< "infer : " << oa << " <" << status << "> " << ob << std::endl; |
413 |
2785 |
if (status == 2) |
414 |
|
{ |
415 |
|
// must state that all variables are non-zero |
416 |
6439 |
for (unsigned j = 0; j < vla.size(); j++) |
417 |
|
{ |
418 |
4148 |
exp.push_back(vla[j].eqNode(d_data->d_zero).negate()); |
419 |
|
} |
420 |
|
} |
421 |
2785 |
NodeManager* nm = NodeManager::currentNM(); |
422 |
|
Node clem = nm->mkNode( |
423 |
5570 |
Kind::IMPLIES, nm->mkAnd(exp), mkLit(oa, ob, status, true)); |
424 |
2785 |
Trace("nl-ext-comp-lemma") << "comparison lemma : " << clem << std::endl; |
425 |
2785 |
lem.emplace_back( |
426 |
5570 |
InferenceId::ARITH_NL_COMPARISON, clem, LemmaProperty::NONE, nullptr); |
427 |
2785 |
cmp_infers[status][oa][ob] = clem; |
428 |
|
} |
429 |
37211 |
return true; |
430 |
|
} |
431 |
|
// get a/b variable information |
432 |
356758 |
Node av; |
433 |
178379 |
unsigned aexp = 0; |
434 |
178379 |
unsigned avo = 0; |
435 |
178379 |
if (a_index < vla.size()) |
436 |
|
{ |
437 |
152465 |
av = vla[a_index]; |
438 |
152465 |
unsigned aexpTotal = d_data->d_mdb.getExponent(a, av); |
439 |
152465 |
Assert(a_exp_proc[av] <= aexpTotal); |
440 |
152465 |
aexp = aexpTotal - a_exp_proc[av]; |
441 |
152465 |
if (aexp == 0) |
442 |
|
{ |
443 |
106052 |
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 |
53026 |
cmp_infers); |
455 |
|
} |
456 |
99439 |
Assert(d_order_vars.find(av) != d_order_vars.end()); |
457 |
99439 |
avo = d_order_vars[av]; |
458 |
|
} |
459 |
250706 |
Node bv; |
460 |
125353 |
unsigned bexp = 0; |
461 |
125353 |
unsigned bvo = 0; |
462 |
125353 |
if (b_index < vlb.size()) |
463 |
|
{ |
464 |
100134 |
bv = vlb[b_index]; |
465 |
100134 |
unsigned bexpTotal = d_data->d_mdb.getExponent(b, bv); |
466 |
100134 |
Assert(b_exp_proc[bv] <= bexpTotal); |
467 |
100134 |
bexp = bexpTotal - b_exp_proc[bv]; |
468 |
100134 |
if (bexp == 0) |
469 |
|
{ |
470 |
102126 |
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 |
51063 |
cmp_infers); |
482 |
|
} |
483 |
49071 |
Assert(d_order_vars.find(bv) != d_order_vars.end()); |
484 |
49071 |
bvo = d_order_vars[bv]; |
485 |
|
} |
486 |
|
// get "one" information |
487 |
74290 |
Assert(d_order_vars.find(d_data->d_one) != d_order_vars.end()); |
488 |
74290 |
unsigned ovo = d_order_vars[d_data->d_one]; |
489 |
148580 |
Trace("nl-ext-comp-debug") << "....vars : " << av << "^" << aexp << " " << bv |
490 |
74290 |
<< "^" << bexp << std::endl; |
491 |
|
|
492 |
|
//--- cases |
493 |
74290 |
if (av.isNull()) |
494 |
|
{ |
495 |
2994 |
if (bvo <= ovo) |
496 |
|
{ |
497 |
2064 |
Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl; |
498 |
|
// can multiply b by <=1 |
499 |
2064 |
exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true)); |
500 |
4128 |
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 |
2064 |
cmp_infers); |
512 |
|
} |
513 |
1860 |
Trace("nl-ext-comp-debug") |
514 |
930 |
<< "...failure, unmatched |b|>1 component." << std::endl; |
515 |
930 |
return false; |
516 |
|
} |
517 |
71296 |
else if (bv.isNull()) |
518 |
|
{ |
519 |
25219 |
if (avo >= ovo) |
520 |
|
{ |
521 |
22878 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
522 |
|
// can multiply a by >=1 |
523 |
22878 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
524 |
45756 |
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 |
22878 |
cmp_infers); |
536 |
|
} |
537 |
4682 |
Trace("nl-ext-comp-debug") |
538 |
2341 |
<< "...failure, unmatched |a|<1 component." << std::endl; |
539 |
2341 |
return false; |
540 |
|
} |
541 |
46077 |
Assert(!av.isNull() && !bv.isNull()); |
542 |
46077 |
if (avo >= bvo) |
543 |
|
{ |
544 |
32019 |
if (bvo < ovo && avo >= ovo) |
545 |
|
{ |
546 |
324 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
547 |
|
// do avo>=1 instead |
548 |
324 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
549 |
648 |
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 |
324 |
cmp_infers); |
561 |
|
} |
562 |
31695 |
unsigned min_exp = aexp > bexp ? bexp : aexp; |
563 |
31695 |
a_exp_proc[av] += min_exp; |
564 |
31695 |
b_exp_proc[bv] += min_exp; |
565 |
63390 |
Trace("nl-ext-comp-debug") << "...take leading " << min_exp << " from " |
566 |
31695 |
<< av << " and " << bv << std::endl; |
567 |
31695 |
exp.push_back(mkLit(av, bv, avo == bvo ? 0 : 2, true)); |
568 |
63390 |
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 |
31695 |
cmp_infers); |
580 |
31695 |
a_exp_proc[av] -= min_exp; |
581 |
31695 |
b_exp_proc[bv] -= min_exp; |
582 |
31695 |
return ret; |
583 |
|
} |
584 |
14058 |
if (bvo <= ovo) |
585 |
|
{ |
586 |
94 |
Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl; |
587 |
|
// try multiply b <= 1 |
588 |
94 |
exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true)); |
589 |
188 |
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 |
94 |
cmp_infers); |
601 |
|
} |
602 |
27928 |
Trace("nl-ext-comp-debug") |
603 |
13964 |
<< "...failure, leading |b|>|a|>1 component." << std::endl; |
604 |
13964 |
return false; |
605 |
|
} |
606 |
|
|
607 |
4780 |
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 |
4780 |
if (x == y) |
614 |
|
{ |
615 |
205 |
return true; |
616 |
|
} |
617 |
4575 |
else if (visited.find(x) != visited.end()) |
618 |
|
{ |
619 |
1008 |
return false; |
620 |
|
} |
621 |
3567 |
visited[x] = true; |
622 |
3567 |
std::map<Node, std::map<Node, Node> >::iterator it = cmp_infers.find(x); |
623 |
3567 |
if (it != cmp_infers.end()) |
624 |
|
{ |
625 |
1890 |
for (std::map<Node, Node>::iterator itc = it->second.begin(); |
626 |
1890 |
itc != it->second.end(); |
627 |
|
++itc) |
628 |
|
{ |
629 |
1360 |
exp.push_back(itc->second); |
630 |
1360 |
if (cmp_holds(itc->first, y, cmp_infers, exp, visited)) |
631 |
|
{ |
632 |
217 |
return true; |
633 |
|
} |
634 |
1143 |
exp.pop_back(); |
635 |
|
} |
636 |
|
} |
637 |
3350 |
return false; |
638 |
|
} |
639 |
|
|
640 |
1542 |
void MonomialCheck::assignOrderIds(std::vector<Node>& vars, |
641 |
|
NodeMultiset& order, |
642 |
|
bool isConcrete, |
643 |
|
bool isAbsolute) |
644 |
|
{ |
645 |
1542 |
SortNlModel smv; |
646 |
1542 |
smv.d_nlm = &d_data->d_model; |
647 |
1542 |
smv.d_isConcrete = isConcrete; |
648 |
1542 |
smv.d_isAbsolute = isAbsolute; |
649 |
1542 |
smv.d_reverse_order = false; |
650 |
1542 |
std::sort(vars.begin(), vars.end(), smv); |
651 |
|
|
652 |
1542 |
order.clear(); |
653 |
|
// assign ordering id's |
654 |
1542 |
unsigned counter = 0; |
655 |
1542 |
unsigned order_index = isConcrete ? 0 : 1; |
656 |
3084 |
Node prev; |
657 |
8577 |
for (unsigned j = 0; j < vars.size(); j++) |
658 |
|
{ |
659 |
14070 |
Node x = vars[j]; |
660 |
14070 |
Node v = d_data->d_model.computeModelValue(x, isConcrete); |
661 |
7035 |
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 |
7035 |
Trace("nl-ext-mvo") << " order " << x << " : " << v << std::endl; |
669 |
7035 |
if (v != prev) |
670 |
|
{ |
671 |
|
// builtin points |
672 |
|
bool success; |
673 |
7783 |
do |
674 |
|
{ |
675 |
7783 |
success = false; |
676 |
7783 |
if (order_index < d_order_points.size()) |
677 |
|
{ |
678 |
3565 |
Node vv = d_data->d_model.computeModelValue( |
679 |
7130 |
d_order_points[order_index], isConcrete); |
680 |
3565 |
if (d_data->d_model.compareValue(v, vv, isAbsolute) <= 0) |
681 |
|
{ |
682 |
2720 |
counter++; |
683 |
5440 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
684 |
2720 |
<< "] = " << counter << std::endl; |
685 |
2720 |
order[d_order_points[order_index]] = counter; |
686 |
2720 |
prev = vv; |
687 |
2720 |
order_index++; |
688 |
2720 |
success = true; |
689 |
|
} |
690 |
|
} |
691 |
|
} while (success); |
692 |
|
} |
693 |
7035 |
if (prev.isNull() || d_data->d_model.compareValue(v, prev, isAbsolute) != 0) |
694 |
|
{ |
695 |
3450 |
counter++; |
696 |
|
} |
697 |
7035 |
Trace("nl-ext-mvo") << "O[" << x << "] = " << counter << std::endl; |
698 |
7035 |
order[x] = counter; |
699 |
7035 |
prev = v; |
700 |
|
} |
701 |
2270 |
while (order_index < d_order_points.size()) |
702 |
|
{ |
703 |
364 |
counter++; |
704 |
728 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
705 |
364 |
<< "] = " << counter << std::endl; |
706 |
364 |
order[d_order_points[order_index]] = counter; |
707 |
364 |
order_index++; |
708 |
|
} |
709 |
1542 |
} |
710 |
61190 |
Node MonomialCheck::mkLit(Node a, Node b, int status, bool isAbsolute) const |
711 |
|
{ |
712 |
61190 |
if (status == 0) |
713 |
|
{ |
714 |
12060 |
Node a_eq_b = a.eqNode(b); |
715 |
6030 |
if (!isAbsolute) |
716 |
|
{ |
717 |
|
return a_eq_b; |
718 |
|
} |
719 |
12060 |
Node negate_b = NodeManager::currentNM()->mkNode(Kind::UMINUS, b); |
720 |
6030 |
return a_eq_b.orNode(a.eqNode(negate_b)); |
721 |
|
} |
722 |
55160 |
else if (status < 0) |
723 |
|
{ |
724 |
414 |
return mkLit(b, a, -status); |
725 |
|
} |
726 |
54746 |
Assert(status == 1 || status == 2); |
727 |
54746 |
NodeManager* nm = NodeManager::currentNM(); |
728 |
54746 |
Kind greater_op = status == 1 ? Kind::GEQ : Kind::GT; |
729 |
54746 |
if (!isAbsolute) |
730 |
|
{ |
731 |
936 |
return nm->mkNode(greater_op, a, b); |
732 |
|
} |
733 |
|
// return nm->mkNode( greater_op, mkAbs( a ), mkAbs( b ) ); |
734 |
107620 |
Node a_is_nonnegative = nm->mkNode(Kind::GEQ, a, d_data->d_zero); |
735 |
107620 |
Node b_is_nonnegative = nm->mkNode(Kind::GEQ, b, d_data->d_zero); |
736 |
107620 |
Node negate_a = nm->mkNode(Kind::UMINUS, a); |
737 |
107620 |
Node negate_b = nm->mkNode(Kind::UMINUS, b); |
738 |
|
return a_is_nonnegative.iteNode( |
739 |
107620 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, a, b), |
740 |
107620 |
nm->mkNode(greater_op, a, negate_b)), |
741 |
107620 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, negate_a, b), |
742 |
161430 |
nm->mkNode(greater_op, negate_a, negate_b))); |
743 |
|
} |
744 |
|
|
745 |
43550 |
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 |
43550 |
std::map<Node, Node>& mono_diff_a = d_data->d_mono_diff[a]; |
751 |
43550 |
if (mono_diff_a.find(b) == mono_diff_a.end()) |
752 |
|
{ |
753 |
11108 |
Trace("nl-ext-mono-factor") |
754 |
5554 |
<< "Set monomial factor for " << a << "/" << b << std::endl; |
755 |
5554 |
mono_diff_a[b] = d_data->d_mdb.mkMonomialRemFactor(a, common); |
756 |
|
} |
757 |
43550 |
} |
758 |
|
|
759 |
|
} // namespace nl |
760 |
|
} // namespace arith |
761 |
|
} // namespace theory |
762 |
29280 |
} // namespace cvc5 |