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 "expr/proof.h" |
20 |
|
#include "theory/arith/arith_msum.h" |
21 |
|
#include "theory/arith/inference_manager.h" |
22 |
|
#include "theory/arith/nl/nl_model.h" |
23 |
|
#include "theory/arith/nl/nl_lemma_utils.h" |
24 |
|
#include "theory/arith/nl/ext/ext_state.h" |
25 |
|
|
26 |
|
namespace cvc5 { |
27 |
|
namespace theory { |
28 |
|
namespace arith { |
29 |
|
namespace nl { |
30 |
|
|
31 |
4914 |
MonomialCheck::MonomialCheck(ExtState* data) : d_data(data) |
32 |
|
{ |
33 |
4914 |
d_order_points.push_back(d_data->d_neg_one); |
34 |
4914 |
d_order_points.push_back(d_data->d_zero); |
35 |
4914 |
d_order_points.push_back(d_data->d_one); |
36 |
4914 |
} |
37 |
|
|
38 |
2829 |
void MonomialCheck::init(const std::vector<Node>& xts) |
39 |
|
{ |
40 |
2829 |
d_ms_proc.clear(); |
41 |
2829 |
d_m_nconst_factor.clear(); |
42 |
|
|
43 |
24354 |
for (unsigned i = 0, xsize = xts.size(); i < xsize; i++) |
44 |
|
{ |
45 |
43050 |
Node a = xts[i]; |
46 |
21525 |
if (a.getKind() == Kind::NONLINEAR_MULT) |
47 |
|
{ |
48 |
14887 |
const std::vector<Node>& varList = d_data->d_mdb.getVariableList(a); |
49 |
43641 |
for (const Node& v : varList) |
50 |
|
{ |
51 |
57508 |
Node mvk = d_data->d_model.computeAbstractModelValue(v); |
52 |
28754 |
if (!mvk.isConst()) |
53 |
|
{ |
54 |
|
d_m_nconst_factor[a] = true; |
55 |
|
} |
56 |
|
} |
57 |
|
} |
58 |
|
} |
59 |
|
|
60 |
11316 |
for (unsigned j = 0; j < d_order_points.size(); j++) |
61 |
|
{ |
62 |
16974 |
Node c = d_order_points[j]; |
63 |
8487 |
d_data->d_model.computeConcreteModelValue(c); |
64 |
8487 |
d_data->d_model.computeAbstractModelValue(c); |
65 |
|
} |
66 |
2829 |
} |
67 |
|
|
68 |
2436 |
void MonomialCheck::checkSign() |
69 |
|
{ |
70 |
4872 |
std::map<Node, int> signs; |
71 |
2436 |
Trace("nl-ext") << "Get monomial sign lemmas..." << std::endl; |
72 |
16291 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
73 |
|
{ |
74 |
27710 |
Node a = d_data->d_ms[j]; |
75 |
13855 |
if (d_ms_proc.find(a) == d_ms_proc.end()) |
76 |
|
{ |
77 |
27710 |
std::vector<Node> exp; |
78 |
13855 |
if (Trace.isOn("nl-ext-debug")) |
79 |
|
{ |
80 |
|
Node cmva = d_data->d_model.computeConcreteModelValue(a); |
81 |
|
Trace("nl-ext-debug") |
82 |
|
<< " process " << a << ", mv=" << cmva << "..." << std::endl; |
83 |
|
} |
84 |
13855 |
if (d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
85 |
|
{ |
86 |
13855 |
signs[a] = compareSign(a, a, 0, 1, exp); |
87 |
13855 |
if (signs[a] == 0) |
88 |
|
{ |
89 |
2145 |
d_ms_proc[a] = true; |
90 |
4290 |
Trace("nl-ext-debug") |
91 |
2145 |
<< "...mark " << a << " reduced since its value is 0." |
92 |
2145 |
<< std::endl; |
93 |
|
} |
94 |
|
} |
95 |
|
else |
96 |
|
{ |
97 |
|
Trace("nl-ext-debug") |
98 |
|
<< "...can't conclude sign lemma for " << a |
99 |
|
<< " since model value of a factor is non-constant." << std::endl; |
100 |
|
} |
101 |
|
} |
102 |
|
} |
103 |
2436 |
} |
104 |
|
|
105 |
3466 |
void MonomialCheck::checkMagnitude(unsigned c) |
106 |
|
{ |
107 |
|
// ensure information is setup |
108 |
3466 |
if (c == 0) |
109 |
|
{ |
110 |
|
// sort by absolute values of abstract model values |
111 |
1608 |
assignOrderIds(d_data->d_ms_vars, d_order_vars, false, true); |
112 |
|
|
113 |
|
// sort individual variable lists |
114 |
1608 |
Trace("nl-ext-proc") << "Assign order var lists..." << std::endl; |
115 |
1608 |
d_data->d_mdb.sortVariablesByModel(d_data->d_ms, d_data->d_model); |
116 |
|
} |
117 |
|
|
118 |
3466 |
unsigned r = 1; |
119 |
6932 |
std::vector<SimpleTheoryLemma> lemmas; |
120 |
|
// if (x,y,L) in cmp_infers, then x > y inferred as conclusion of L |
121 |
|
// in lemmas |
122 |
6932 |
std::map<int, std::map<Node, std::map<Node, Node> > > cmp_infers; |
123 |
6932 |
Trace("nl-ext") << "Get monomial comparison lemmas (order=" << r |
124 |
3466 |
<< ", compare=" << c << ")..." << std::endl; |
125 |
25425 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
126 |
|
{ |
127 |
43918 |
Node a = d_data->d_ms[j]; |
128 |
43918 |
if (d_ms_proc.find(a) == d_ms_proc.end() |
129 |
21959 |
&& d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
130 |
|
{ |
131 |
19895 |
if (c == 0) |
132 |
|
{ |
133 |
|
// compare magnitude against 1 |
134 |
17894 |
std::vector<Node> exp; |
135 |
17894 |
NodeMultiset a_exp_proc; |
136 |
17894 |
NodeMultiset b_exp_proc; |
137 |
17894 |
compareMonomial(a, |
138 |
|
a, |
139 |
|
a_exp_proc, |
140 |
8947 |
d_data->d_one, |
141 |
8947 |
d_data->d_one, |
142 |
|
b_exp_proc, |
143 |
|
exp, |
144 |
|
lemmas, |
145 |
|
cmp_infers); |
146 |
|
} |
147 |
|
else |
148 |
|
{ |
149 |
10948 |
const NodeMultiset& mea = d_data->d_mdb.getMonomialExponentMap(a); |
150 |
10948 |
if (c == 1) |
151 |
|
{ |
152 |
|
// could compare not just against containing variables? |
153 |
|
// compare magnitude against variables |
154 |
55112 |
for (unsigned k = 0; k < d_data->d_ms_vars.size(); k++) |
155 |
|
{ |
156 |
97284 |
Node v = d_data->d_ms_vars[k]; |
157 |
97284 |
Node mvcv = d_data->d_model.computeConcreteModelValue(v); |
158 |
48642 |
if (mvcv.isConst()) |
159 |
|
{ |
160 |
96828 |
std::vector<Node> exp; |
161 |
96828 |
NodeMultiset a_exp_proc; |
162 |
96828 |
NodeMultiset b_exp_proc; |
163 |
48414 |
if (mea.find(v) != mea.end()) |
164 |
|
{ |
165 |
11567 |
a_exp_proc[v] = 1; |
166 |
11567 |
b_exp_proc[v] = 1; |
167 |
11567 |
setMonomialFactor(a, v, a_exp_proc); |
168 |
11567 |
setMonomialFactor(v, a, b_exp_proc); |
169 |
11567 |
compareMonomial(a, |
170 |
|
a, |
171 |
|
a_exp_proc, |
172 |
|
v, |
173 |
|
v, |
174 |
|
b_exp_proc, |
175 |
|
exp, |
176 |
|
lemmas, |
177 |
|
cmp_infers); |
178 |
|
} |
179 |
|
} |
180 |
|
} |
181 |
|
} |
182 |
|
else |
183 |
|
{ |
184 |
|
// compare magnitude against other non-linear monomials |
185 |
34613 |
for (unsigned k = (j + 1); k < d_data->d_ms.size(); k++) |
186 |
|
{ |
187 |
60270 |
Node b = d_data->d_ms[k]; |
188 |
|
//(signs[a]==signs[b])==(r==0) |
189 |
60270 |
if (d_ms_proc.find(b) == d_ms_proc.end() |
190 |
30135 |
&& d_m_nconst_factor.find(b) == d_m_nconst_factor.end()) |
191 |
|
{ |
192 |
28516 |
const NodeMultiset& meb = d_data->d_mdb.getMonomialExponentMap(b); |
193 |
|
|
194 |
57032 |
std::vector<Node> exp; |
195 |
|
// take common factors of monomials, set minimum of |
196 |
|
// common exponents as processed |
197 |
57032 |
NodeMultiset a_exp_proc; |
198 |
57032 |
NodeMultiset b_exp_proc; |
199 |
81649 |
for (NodeMultiset::const_iterator itmea2 = mea.begin(); |
200 |
81649 |
itmea2 != mea.end(); |
201 |
|
++itmea2) |
202 |
|
{ |
203 |
53133 |
NodeMultiset::const_iterator itmeb2 = meb.find(itmea2->first); |
204 |
53133 |
if (itmeb2 != meb.end()) |
205 |
|
{ |
206 |
13999 |
unsigned min_exp = itmea2->second > itmeb2->second |
207 |
26700 |
? itmeb2->second |
208 |
26700 |
: itmea2->second; |
209 |
13999 |
a_exp_proc[itmea2->first] = min_exp; |
210 |
13999 |
b_exp_proc[itmea2->first] = min_exp; |
211 |
27998 |
Trace("nl-ext-comp") << "Common exponent : " << itmea2->first |
212 |
13999 |
<< " : " << min_exp << std::endl; |
213 |
|
} |
214 |
|
} |
215 |
28516 |
if (!a_exp_proc.empty()) |
216 |
|
{ |
217 |
13717 |
setMonomialFactor(a, b, a_exp_proc); |
218 |
13717 |
setMonomialFactor(b, a, b_exp_proc); |
219 |
|
} |
220 |
|
/* |
221 |
|
if( !a_exp_proc.empty() ){ |
222 |
|
//reduction based on common exponents a > 0 => ( a * b |
223 |
|
<> a * c <=> b <> c ), a < 0 => ( a * b <> a * c <=> b |
224 |
|
!<> c ) ? }else{ compareMonomial( a, a, a_exp_proc, b, |
225 |
|
b, b_exp_proc, exp, lemmas ); |
226 |
|
} |
227 |
|
*/ |
228 |
28516 |
compareMonomial( |
229 |
|
a, a, a_exp_proc, b, b, b_exp_proc, exp, lemmas, cmp_infers); |
230 |
|
} |
231 |
|
} |
232 |
|
} |
233 |
|
} |
234 |
|
} |
235 |
|
} |
236 |
|
// remove redundant lemmas, e.g. if a > b, b > c, a > c were |
237 |
|
// inferred, discard lemma with conclusion a > c |
238 |
6932 |
Trace("nl-ext-comp") << "Compute redundancies for " << lemmas.size() |
239 |
3466 |
<< " lemmas." << std::endl; |
240 |
|
// naive |
241 |
6932 |
std::unordered_set<Node> r_lemmas; |
242 |
1108 |
for (std::map<int, std::map<Node, std::map<Node, Node> > >::iterator itb = |
243 |
3466 |
cmp_infers.begin(); |
244 |
4574 |
itb != cmp_infers.end(); |
245 |
|
++itb) |
246 |
|
{ |
247 |
1975 |
for (std::map<Node, std::map<Node, Node> >::iterator itc = |
248 |
1108 |
itb->second.begin(); |
249 |
3083 |
itc != itb->second.end(); |
250 |
|
++itc) |
251 |
|
{ |
252 |
4956 |
for (std::map<Node, Node>::iterator itc2 = itc->second.begin(); |
253 |
4956 |
itc2 != itc->second.end(); |
254 |
|
++itc2) |
255 |
|
{ |
256 |
5962 |
std::map<Node, bool> visited; |
257 |
9527 |
for (std::map<Node, Node>::iterator itc3 = itc->second.begin(); |
258 |
9527 |
itc3 != itc->second.end(); |
259 |
|
++itc3) |
260 |
|
{ |
261 |
6811 |
if (itc3->first != itc2->first) |
262 |
|
{ |
263 |
7651 |
std::vector<Node> exp; |
264 |
3958 |
if (cmp_holds(itc3->first, itc2->first, itb->second, exp, visited)) |
265 |
|
{ |
266 |
265 |
r_lemmas.insert(itc2->second); |
267 |
530 |
Trace("nl-ext-comp") |
268 |
265 |
<< "...inference of " << itc->first << " > " << itc2->first |
269 |
265 |
<< " was redundant." << std::endl; |
270 |
265 |
break; |
271 |
|
} |
272 |
|
} |
273 |
|
} |
274 |
|
} |
275 |
|
} |
276 |
|
} |
277 |
6447 |
for (unsigned i = 0; i < lemmas.size(); i++) |
278 |
|
{ |
279 |
2981 |
if (r_lemmas.find(lemmas[i].d_node) == r_lemmas.end()) |
280 |
|
{ |
281 |
2716 |
d_data->d_im.addPendingLemma(lemmas[i]); |
282 |
|
} |
283 |
|
} |
284 |
|
// could only take maximal lower/minimial lower bounds? |
285 |
3466 |
} |
286 |
|
|
287 |
|
// show a <> 0 by inequalities between variables in monomial a w.r.t 0 |
288 |
37532 |
int MonomialCheck::compareSign( |
289 |
|
Node oa, Node a, unsigned a_index, int status, std::vector<Node>& exp) |
290 |
|
{ |
291 |
75064 |
Trace("nl-ext-debug") << "Process " << a << " at index " << a_index |
292 |
37532 |
<< ", status is " << status << std::endl; |
293 |
37532 |
NodeManager* nm = NodeManager::currentNM(); |
294 |
75064 |
Node mvaoa = d_data->d_model.computeAbstractModelValue(oa); |
295 |
37532 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
296 |
37532 |
if (a_index == vla.size()) |
297 |
|
{ |
298 |
11710 |
if (mvaoa.getConst<Rational>().sgn() != status) |
299 |
|
{ |
300 |
|
Node lemma = |
301 |
1868 |
nm->mkAnd(exp).impNode(mkLit(oa, d_data->d_zero, status * 2)); |
302 |
934 |
CDProof* proof = nullptr; |
303 |
934 |
if (d_data->isProofEnabled()) |
304 |
|
{ |
305 |
180 |
proof = d_data->getProof(); |
306 |
360 |
std::vector<Node> args = exp; |
307 |
180 |
args.emplace_back(oa); |
308 |
180 |
proof->addStep(lemma, PfRule::ARITH_MULT_SIGN, {}, args); |
309 |
|
} |
310 |
934 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
311 |
|
} |
312 |
11710 |
return status; |
313 |
|
} |
314 |
25822 |
Assert(a_index < vla.size()); |
315 |
51644 |
Node av = vla[a_index]; |
316 |
25822 |
unsigned aexp = d_data->d_mdb.getExponent(a, av); |
317 |
|
// take current sign in model |
318 |
51644 |
Node mvaav = d_data->d_model.computeAbstractModelValue(av); |
319 |
25822 |
int sgn = mvaav.getConst<Rational>().sgn(); |
320 |
51644 |
Trace("nl-ext-debug") << "Process var " << av << "^" << aexp |
321 |
25822 |
<< ", model sign = " << sgn << std::endl; |
322 |
25822 |
if (sgn == 0) |
323 |
|
{ |
324 |
2145 |
if (mvaoa.getConst<Rational>().sgn() != 0) |
325 |
|
{ |
326 |
1050 |
Node prem = av.eqNode(d_data->d_zero); |
327 |
1050 |
Node conc = oa.eqNode(d_data->d_zero); |
328 |
1050 |
Node lemma = prem.impNode(conc); |
329 |
525 |
CDProof* proof = nullptr; |
330 |
525 |
if (d_data->isProofEnabled()) |
331 |
|
{ |
332 |
77 |
proof = d_data->getProof(); |
333 |
77 |
proof->addStep(conc, PfRule::MACRO_SR_PRED_INTRO, {prem}, {conc}); |
334 |
77 |
proof->addStep(lemma, PfRule::SCOPE, {conc}, {prem}); |
335 |
|
} |
336 |
525 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
337 |
|
} |
338 |
2145 |
return 0; |
339 |
|
} |
340 |
23677 |
if (aexp % 2 == 0) |
341 |
|
{ |
342 |
2657 |
exp.push_back(av.eqNode(d_data->d_zero).negate()); |
343 |
2657 |
return compareSign(oa, a, a_index + 1, status, exp); |
344 |
|
} |
345 |
21020 |
exp.push_back(nm->mkNode(sgn == 1 ? Kind::GT : Kind::LT, av, d_data->d_zero)); |
346 |
21020 |
return compareSign(oa, a, a_index + 1, status * sgn, exp); |
347 |
|
} |
348 |
|
|
349 |
49030 |
bool MonomialCheck::compareMonomial( |
350 |
|
Node oa, |
351 |
|
Node a, |
352 |
|
NodeMultiset& a_exp_proc, |
353 |
|
Node ob, |
354 |
|
Node b, |
355 |
|
NodeMultiset& b_exp_proc, |
356 |
|
std::vector<Node>& exp, |
357 |
|
std::vector<SimpleTheoryLemma>& lem, |
358 |
|
std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers) |
359 |
|
{ |
360 |
98060 |
Trace("nl-ext-comp-debug") |
361 |
49030 |
<< "Check |" << a << "| >= |" << b << "|" << std::endl; |
362 |
49030 |
unsigned pexp_size = exp.size(); |
363 |
49030 |
if (compareMonomial( |
364 |
|
oa, a, 0, a_exp_proc, ob, b, 0, b_exp_proc, 0, exp, lem, cmp_infers)) |
365 |
|
{ |
366 |
34590 |
return true; |
367 |
|
} |
368 |
14440 |
exp.resize(pexp_size); |
369 |
28880 |
Trace("nl-ext-comp-debug") |
370 |
14440 |
<< "Check |" << b << "| >= |" << a << "|" << std::endl; |
371 |
14440 |
if (compareMonomial( |
372 |
|
ob, b, 0, b_exp_proc, oa, a, 0, a_exp_proc, 0, exp, lem, cmp_infers)) |
373 |
|
{ |
374 |
8248 |
return true; |
375 |
|
} |
376 |
6192 |
return false; |
377 |
|
} |
378 |
|
|
379 |
|
// trying to show a ( >, = ) b by inequalities between variables in |
380 |
|
// monomials a,b |
381 |
249566 |
bool MonomialCheck::compareMonomial( |
382 |
|
Node oa, |
383 |
|
Node a, |
384 |
|
unsigned a_index, |
385 |
|
NodeMultiset& a_exp_proc, |
386 |
|
Node ob, |
387 |
|
Node b, |
388 |
|
unsigned b_index, |
389 |
|
NodeMultiset& b_exp_proc, |
390 |
|
int status, |
391 |
|
std::vector<Node>& exp, |
392 |
|
std::vector<SimpleTheoryLemma>& lem, |
393 |
|
std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers) |
394 |
|
{ |
395 |
499132 |
Trace("nl-ext-comp-debug") |
396 |
249566 |
<< "compareMonomial " << oa << " and " << ob << ", indices = " << a_index |
397 |
249566 |
<< " " << b_index << std::endl; |
398 |
249566 |
Assert(status == 0 || status == 2); |
399 |
249566 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
400 |
249566 |
const std::vector<Node>& vlb = d_data->d_mdb.getVariableList(b); |
401 |
249566 |
if (a_index == vla.size() && b_index == vlb.size()) |
402 |
|
{ |
403 |
|
// finished, compare absolute value of abstract model values |
404 |
42838 |
int modelStatus = d_data->d_model.compare(oa, ob, false, true) * -2; |
405 |
85676 |
Trace("nl-ext-comp") << "...finished comparison with " << oa << " <" |
406 |
42838 |
<< status << "> " << ob |
407 |
42838 |
<< ", model status = " << modelStatus << std::endl; |
408 |
42838 |
if (status != modelStatus) |
409 |
|
{ |
410 |
5962 |
Trace("nl-ext-comp-infer") |
411 |
2981 |
<< "infer : " << oa << " <" << status << "> " << ob << std::endl; |
412 |
2981 |
if (status == 2) |
413 |
|
{ |
414 |
|
// must state that all variables are non-zero |
415 |
6924 |
for (unsigned j = 0; j < vla.size(); j++) |
416 |
|
{ |
417 |
4429 |
exp.push_back(vla[j].eqNode(d_data->d_zero).negate()); |
418 |
|
} |
419 |
|
} |
420 |
2981 |
NodeManager* nm = NodeManager::currentNM(); |
421 |
|
Node clem = nm->mkNode( |
422 |
5962 |
Kind::IMPLIES, nm->mkAnd(exp), mkLit(oa, ob, status, true)); |
423 |
2981 |
Trace("nl-ext-comp-lemma") << "comparison lemma : " << clem << std::endl; |
424 |
2981 |
lem.emplace_back( |
425 |
5962 |
InferenceId::ARITH_NL_COMPARISON, clem, LemmaProperty::NONE, nullptr); |
426 |
2981 |
cmp_infers[status][oa][ob] = clem; |
427 |
|
} |
428 |
42838 |
return true; |
429 |
|
} |
430 |
|
// get a/b variable information |
431 |
413456 |
Node av; |
432 |
206728 |
unsigned aexp = 0; |
433 |
206728 |
unsigned avo = 0; |
434 |
206728 |
if (a_index < vla.size()) |
435 |
|
{ |
436 |
177212 |
av = vla[a_index]; |
437 |
177212 |
unsigned aexpTotal = d_data->d_mdb.getExponent(a, av); |
438 |
177212 |
Assert(a_exp_proc[av] <= aexpTotal); |
439 |
177212 |
aexp = aexpTotal - a_exp_proc[av]; |
440 |
177212 |
if (aexp == 0) |
441 |
|
{ |
442 |
122544 |
return compareMonomial(oa, |
443 |
|
a, |
444 |
|
a_index + 1, |
445 |
|
a_exp_proc, |
446 |
|
ob, |
447 |
|
b, |
448 |
|
b_index, |
449 |
|
b_exp_proc, |
450 |
|
status, |
451 |
|
exp, |
452 |
|
lem, |
453 |
61272 |
cmp_infers); |
454 |
|
} |
455 |
115940 |
Assert(d_order_vars.find(av) != d_order_vars.end()); |
456 |
115940 |
avo = d_order_vars[av]; |
457 |
|
} |
458 |
290912 |
Node bv; |
459 |
145456 |
unsigned bexp = 0; |
460 |
145456 |
unsigned bvo = 0; |
461 |
145456 |
if (b_index < vlb.size()) |
462 |
|
{ |
463 |
116469 |
bv = vlb[b_index]; |
464 |
116469 |
unsigned bexpTotal = d_data->d_mdb.getExponent(b, bv); |
465 |
116469 |
Assert(b_exp_proc[bv] <= bexpTotal); |
466 |
116469 |
bexp = bexpTotal - b_exp_proc[bv]; |
467 |
116469 |
if (bexp == 0) |
468 |
|
{ |
469 |
118038 |
return compareMonomial(oa, |
470 |
|
a, |
471 |
|
a_index, |
472 |
|
a_exp_proc, |
473 |
|
ob, |
474 |
|
b, |
475 |
|
b_index + 1, |
476 |
|
b_exp_proc, |
477 |
|
status, |
478 |
|
exp, |
479 |
|
lem, |
480 |
59019 |
cmp_infers); |
481 |
|
} |
482 |
57450 |
Assert(d_order_vars.find(bv) != d_order_vars.end()); |
483 |
57450 |
bvo = d_order_vars[bv]; |
484 |
|
} |
485 |
|
// get "one" information |
486 |
86437 |
Assert(d_order_vars.find(d_data->d_one) != d_order_vars.end()); |
487 |
86437 |
unsigned ovo = d_order_vars[d_data->d_one]; |
488 |
172874 |
Trace("nl-ext-comp-debug") << "....vars : " << av << "^" << aexp << " " << bv |
489 |
86437 |
<< "^" << bexp << std::endl; |
490 |
|
|
491 |
|
//--- cases |
492 |
86437 |
if (av.isNull()) |
493 |
|
{ |
494 |
3488 |
if (bvo <= ovo) |
495 |
|
{ |
496 |
2019 |
Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl; |
497 |
|
// can multiply b by <=1 |
498 |
2019 |
exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true)); |
499 |
4038 |
return compareMonomial(oa, |
500 |
|
a, |
501 |
|
a_index, |
502 |
|
a_exp_proc, |
503 |
|
ob, |
504 |
|
b, |
505 |
|
b_index + 1, |
506 |
|
b_exp_proc, |
507 |
|
bvo == ovo ? status : 2, |
508 |
|
exp, |
509 |
|
lem, |
510 |
2019 |
cmp_infers); |
511 |
|
} |
512 |
2938 |
Trace("nl-ext-comp-debug") |
513 |
1469 |
<< "...failure, unmatched |b|>1 component." << std::endl; |
514 |
1469 |
return false; |
515 |
|
} |
516 |
82949 |
else if (bv.isNull()) |
517 |
|
{ |
518 |
28987 |
if (avo >= ovo) |
519 |
|
{ |
520 |
26672 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
521 |
|
// can multiply a by >=1 |
522 |
26672 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
523 |
53344 |
return compareMonomial(oa, |
524 |
|
a, |
525 |
|
a_index + 1, |
526 |
|
a_exp_proc, |
527 |
|
ob, |
528 |
|
b, |
529 |
|
b_index, |
530 |
|
b_exp_proc, |
531 |
|
avo == ovo ? status : 2, |
532 |
|
exp, |
533 |
|
lem, |
534 |
26672 |
cmp_infers); |
535 |
|
} |
536 |
4630 |
Trace("nl-ext-comp-debug") |
537 |
2315 |
<< "...failure, unmatched |a|<1 component." << std::endl; |
538 |
2315 |
return false; |
539 |
|
} |
540 |
53962 |
Assert(!av.isNull() && !bv.isNull()); |
541 |
53962 |
if (avo >= bvo) |
542 |
|
{ |
543 |
37006 |
if (bvo < ovo && avo >= ovo) |
544 |
|
{ |
545 |
272 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
546 |
|
// do avo>=1 instead |
547 |
272 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
548 |
544 |
return compareMonomial(oa, |
549 |
|
a, |
550 |
|
a_index + 1, |
551 |
|
a_exp_proc, |
552 |
|
ob, |
553 |
|
b, |
554 |
|
b_index, |
555 |
|
b_exp_proc, |
556 |
|
avo == ovo ? status : 2, |
557 |
|
exp, |
558 |
|
lem, |
559 |
272 |
cmp_infers); |
560 |
|
} |
561 |
36734 |
unsigned min_exp = aexp > bexp ? bexp : aexp; |
562 |
36734 |
a_exp_proc[av] += min_exp; |
563 |
36734 |
b_exp_proc[bv] += min_exp; |
564 |
73468 |
Trace("nl-ext-comp-debug") << "...take leading " << min_exp << " from " |
565 |
36734 |
<< av << " and " << bv << std::endl; |
566 |
36734 |
exp.push_back(mkLit(av, bv, avo == bvo ? 0 : 2, true)); |
567 |
73468 |
bool ret = compareMonomial(oa, |
568 |
|
a, |
569 |
|
a_index, |
570 |
|
a_exp_proc, |
571 |
|
ob, |
572 |
|
b, |
573 |
|
b_index, |
574 |
|
b_exp_proc, |
575 |
|
avo == bvo ? status : 2, |
576 |
|
exp, |
577 |
|
lem, |
578 |
36734 |
cmp_infers); |
579 |
36734 |
a_exp_proc[av] -= min_exp; |
580 |
36734 |
b_exp_proc[bv] -= min_exp; |
581 |
36734 |
return ret; |
582 |
|
} |
583 |
16956 |
if (bvo <= ovo) |
584 |
|
{ |
585 |
108 |
Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl; |
586 |
|
// try multiply b <= 1 |
587 |
108 |
exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true)); |
588 |
216 |
return compareMonomial(oa, |
589 |
|
a, |
590 |
|
a_index, |
591 |
|
a_exp_proc, |
592 |
|
ob, |
593 |
|
b, |
594 |
|
b_index + 1, |
595 |
|
b_exp_proc, |
596 |
|
bvo == ovo ? status : 2, |
597 |
|
exp, |
598 |
|
lem, |
599 |
108 |
cmp_infers); |
600 |
|
} |
601 |
33696 |
Trace("nl-ext-comp-debug") |
602 |
16848 |
<< "...failure, leading |b|>|a|>1 component." << std::endl; |
603 |
16848 |
return false; |
604 |
|
} |
605 |
|
|
606 |
5772 |
bool MonomialCheck::cmp_holds(Node x, |
607 |
|
Node y, |
608 |
|
std::map<Node, std::map<Node, Node> >& cmp_infers, |
609 |
|
std::vector<Node>& exp, |
610 |
|
std::map<Node, bool>& visited) |
611 |
|
{ |
612 |
5772 |
if (x == y) |
613 |
|
{ |
614 |
265 |
return true; |
615 |
|
} |
616 |
5507 |
else if (visited.find(x) != visited.end()) |
617 |
|
{ |
618 |
1312 |
return false; |
619 |
|
} |
620 |
4195 |
visited[x] = true; |
621 |
4195 |
std::map<Node, std::map<Node, Node> >::iterator it = cmp_infers.find(x); |
622 |
4195 |
if (it != cmp_infers.end()) |
623 |
|
{ |
624 |
2514 |
for (std::map<Node, Node>::iterator itc = it->second.begin(); |
625 |
2514 |
itc != it->second.end(); |
626 |
|
++itc) |
627 |
|
{ |
628 |
1814 |
exp.push_back(itc->second); |
629 |
1814 |
if (cmp_holds(itc->first, y, cmp_infers, exp, visited)) |
630 |
|
{ |
631 |
277 |
return true; |
632 |
|
} |
633 |
1537 |
exp.pop_back(); |
634 |
|
} |
635 |
|
} |
636 |
3918 |
return false; |
637 |
|
} |
638 |
|
|
639 |
1608 |
void MonomialCheck::assignOrderIds(std::vector<Node>& vars, |
640 |
|
NodeMultiset& order, |
641 |
|
bool isConcrete, |
642 |
|
bool isAbsolute) |
643 |
|
{ |
644 |
1608 |
SortNlModel smv; |
645 |
1608 |
smv.d_nlm = &d_data->d_model; |
646 |
1608 |
smv.d_isConcrete = isConcrete; |
647 |
1608 |
smv.d_isAbsolute = isAbsolute; |
648 |
1608 |
smv.d_reverse_order = false; |
649 |
1608 |
std::sort(vars.begin(), vars.end(), smv); |
650 |
|
|
651 |
1608 |
order.clear(); |
652 |
|
// assign ordering id's |
653 |
1608 |
unsigned counter = 0; |
654 |
1608 |
unsigned order_index = isConcrete ? 0 : 1; |
655 |
3216 |
Node prev; |
656 |
9532 |
for (unsigned j = 0; j < vars.size(); j++) |
657 |
|
{ |
658 |
15848 |
Node x = vars[j]; |
659 |
15848 |
Node v = d_data->d_model.computeModelValue(x, isConcrete); |
660 |
7924 |
if (!v.isConst()) |
661 |
|
{ |
662 |
|
Trace("nl-ext-mvo") << "..do not assign order to " << x << " : " << v |
663 |
|
<< std::endl; |
664 |
|
// don't assign for non-constant values (transcendental function apps) |
665 |
|
break; |
666 |
|
} |
667 |
7924 |
Trace("nl-ext-mvo") << " order " << x << " : " << v << std::endl; |
668 |
7924 |
if (v != prev) |
669 |
|
{ |
670 |
|
// builtin points |
671 |
|
bool success; |
672 |
8527 |
do |
673 |
|
{ |
674 |
8527 |
success = false; |
675 |
8527 |
if (order_index < d_order_points.size()) |
676 |
|
{ |
677 |
3819 |
Node vv = d_data->d_model.computeModelValue( |
678 |
7638 |
d_order_points[order_index], isConcrete); |
679 |
3819 |
if (d_data->d_model.compareValue(v, vv, isAbsolute) <= 0) |
680 |
|
{ |
681 |
2879 |
counter++; |
682 |
5758 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
683 |
2879 |
<< "] = " << counter << std::endl; |
684 |
2879 |
order[d_order_points[order_index]] = counter; |
685 |
2879 |
prev = vv; |
686 |
2879 |
order_index++; |
687 |
2879 |
success = true; |
688 |
|
} |
689 |
|
} |
690 |
|
} while (success); |
691 |
|
} |
692 |
7924 |
if (prev.isNull() || d_data->d_model.compareValue(v, prev, isAbsolute) != 0) |
693 |
|
{ |
694 |
3864 |
counter++; |
695 |
|
} |
696 |
7924 |
Trace("nl-ext-mvo") << "O[" << x << "] = " << counter << std::endl; |
697 |
7924 |
order[x] = counter; |
698 |
7924 |
prev = v; |
699 |
|
} |
700 |
2282 |
while (order_index < d_order_points.size()) |
701 |
|
{ |
702 |
337 |
counter++; |
703 |
674 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
704 |
337 |
<< "] = " << counter << std::endl; |
705 |
337 |
order[d_order_points[order_index]] = counter; |
706 |
337 |
order_index++; |
707 |
|
} |
708 |
1608 |
} |
709 |
70123 |
Node MonomialCheck::mkLit(Node a, Node b, int status, bool isAbsolute) const |
710 |
|
{ |
711 |
70123 |
if (status == 0) |
712 |
|
{ |
713 |
13160 |
Node a_eq_b = a.eqNode(b); |
714 |
6580 |
if (!isAbsolute) |
715 |
|
{ |
716 |
|
return a_eq_b; |
717 |
|
} |
718 |
13160 |
Node negate_b = NodeManager::currentNM()->mkNode(Kind::UMINUS, b); |
719 |
6580 |
return a_eq_b.orNode(a.eqNode(negate_b)); |
720 |
|
} |
721 |
63543 |
else if (status < 0) |
722 |
|
{ |
723 |
403 |
return mkLit(b, a, -status); |
724 |
|
} |
725 |
63140 |
Assert(status == 1 || status == 2); |
726 |
63140 |
NodeManager* nm = NodeManager::currentNM(); |
727 |
63140 |
Kind greater_op = status == 1 ? Kind::GEQ : Kind::GT; |
728 |
63140 |
if (!isAbsolute) |
729 |
|
{ |
730 |
934 |
return nm->mkNode(greater_op, a, b); |
731 |
|
} |
732 |
|
// return nm->mkNode( greater_op, mkAbs( a ), mkAbs( b ) ); |
733 |
124412 |
Node a_is_nonnegative = nm->mkNode(Kind::GEQ, a, d_data->d_zero); |
734 |
124412 |
Node b_is_nonnegative = nm->mkNode(Kind::GEQ, b, d_data->d_zero); |
735 |
124412 |
Node negate_a = nm->mkNode(Kind::UMINUS, a); |
736 |
124412 |
Node negate_b = nm->mkNode(Kind::UMINUS, b); |
737 |
|
return a_is_nonnegative.iteNode( |
738 |
124412 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, a, b), |
739 |
124412 |
nm->mkNode(greater_op, a, negate_b)), |
740 |
124412 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, negate_a, b), |
741 |
186618 |
nm->mkNode(greater_op, negate_a, negate_b))); |
742 |
|
} |
743 |
|
|
744 |
50568 |
void MonomialCheck::setMonomialFactor(Node a, |
745 |
|
Node b, |
746 |
|
const NodeMultiset& common) |
747 |
|
{ |
748 |
|
// Could not tell if this was being inserted intentionally or not. |
749 |
50568 |
std::map<Node, Node>& mono_diff_a = d_data->d_mono_diff[a]; |
750 |
50568 |
if (mono_diff_a.find(b) == mono_diff_a.end()) |
751 |
|
{ |
752 |
12300 |
Trace("nl-ext-mono-factor") |
753 |
6150 |
<< "Set monomial factor for " << a << "/" << b << std::endl; |
754 |
6150 |
mono_diff_a[b] = d_data->d_mdb.mkMonomialRemFactor(a, common); |
755 |
|
} |
756 |
50568 |
} |
757 |
|
|
758 |
|
} // namespace nl |
759 |
|
} // namespace arith |
760 |
|
} // namespace theory |
761 |
28191 |
} // namespace cvc5 |