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 |
9696 |
MonomialCheck::MonomialCheck(Env& env, ExtState* data) |
33 |
9696 |
: EnvObj(env), d_data(data) |
34 |
|
{ |
35 |
9696 |
d_order_points.push_back(d_data->d_neg_one); |
36 |
9696 |
d_order_points.push_back(d_data->d_zero); |
37 |
9696 |
d_order_points.push_back(d_data->d_one); |
38 |
9696 |
} |
39 |
|
|
40 |
4364 |
void MonomialCheck::init(const std::vector<Node>& xts) |
41 |
|
{ |
42 |
4364 |
d_ms_proc.clear(); |
43 |
4364 |
d_m_nconst_factor.clear(); |
44 |
|
|
45 |
38804 |
for (unsigned i = 0, xsize = xts.size(); i < xsize; i++) |
46 |
|
{ |
47 |
68880 |
Node a = xts[i]; |
48 |
34440 |
if (a.getKind() == Kind::NONLINEAR_MULT) |
49 |
|
{ |
50 |
25862 |
const std::vector<Node>& varList = d_data->d_mdb.getVariableList(a); |
51 |
75598 |
for (const Node& v : varList) |
52 |
|
{ |
53 |
99472 |
Node mvk = d_data->d_model.computeAbstractModelValue(v); |
54 |
49736 |
if (!mvk.isConst()) |
55 |
|
{ |
56 |
|
d_m_nconst_factor[a] = true; |
57 |
|
} |
58 |
|
} |
59 |
|
} |
60 |
|
} |
61 |
|
|
62 |
17456 |
for (unsigned j = 0; j < d_order_points.size(); j++) |
63 |
|
{ |
64 |
26184 |
Node c = d_order_points[j]; |
65 |
13092 |
d_data->d_model.computeConcreteModelValue(c); |
66 |
13092 |
d_data->d_model.computeAbstractModelValue(c); |
67 |
|
} |
68 |
4364 |
} |
69 |
|
|
70 |
3486 |
void MonomialCheck::checkSign() |
71 |
|
{ |
72 |
6972 |
std::map<Node, int> signs; |
73 |
3486 |
Trace("nl-ext") << "Get monomial sign lemmas..." << std::endl; |
74 |
25366 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
75 |
|
{ |
76 |
43760 |
Node a = d_data->d_ms[j]; |
77 |
21880 |
if (d_ms_proc.find(a) == d_ms_proc.end()) |
78 |
|
{ |
79 |
43760 |
std::vector<Node> exp; |
80 |
21880 |
if (Trace.isOn("nl-ext-debug")) |
81 |
|
{ |
82 |
|
Node cmva = d_data->d_model.computeConcreteModelValue(a); |
83 |
|
Trace("nl-ext-debug") |
84 |
|
<< " process " << a << ", mv=" << cmva << "..." << std::endl; |
85 |
|
} |
86 |
21880 |
if (d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
87 |
|
{ |
88 |
21880 |
signs[a] = compareSign(a, a, 0, 1, exp); |
89 |
21880 |
if (signs[a] == 0) |
90 |
|
{ |
91 |
4293 |
d_ms_proc[a] = true; |
92 |
8586 |
Trace("nl-ext-debug") |
93 |
4293 |
<< "...mark " << a << " reduced since its value is 0." |
94 |
4293 |
<< std::endl; |
95 |
|
} |
96 |
|
} |
97 |
|
else |
98 |
|
{ |
99 |
|
Trace("nl-ext-debug") |
100 |
|
<< "...can't conclude sign lemma for " << a |
101 |
|
<< " since model value of a factor is non-constant." << std::endl; |
102 |
|
} |
103 |
|
} |
104 |
|
} |
105 |
3486 |
} |
106 |
|
|
107 |
4707 |
void MonomialCheck::checkMagnitude(unsigned c) |
108 |
|
{ |
109 |
|
// ensure information is setup |
110 |
4707 |
if (c == 0) |
111 |
|
{ |
112 |
|
// sort by absolute values of abstract model values |
113 |
2170 |
assignOrderIds(d_data->d_ms_vars, d_order_vars, false, true); |
114 |
|
|
115 |
|
// sort individual variable lists |
116 |
2170 |
Trace("nl-ext-proc") << "Assign order var lists..." << std::endl; |
117 |
2170 |
d_data->d_mdb.sortVariablesByModel(d_data->d_ms, d_data->d_model); |
118 |
|
} |
119 |
|
|
120 |
4707 |
unsigned r = 1; |
121 |
9414 |
std::vector<SimpleTheoryLemma> lemmas; |
122 |
|
// if (x,y,L) in cmp_infers, then x > y inferred as conclusion of L |
123 |
|
// in lemmas |
124 |
9414 |
std::map<int, std::map<Node, std::map<Node, Node> > > cmp_infers; |
125 |
9414 |
Trace("nl-ext") << "Get monomial comparison lemmas (order=" << r |
126 |
4707 |
<< ", compare=" << c << ")..." << std::endl; |
127 |
38108 |
for (unsigned j = 0; j < d_data->d_ms.size(); j++) |
128 |
|
{ |
129 |
66802 |
Node a = d_data->d_ms[j]; |
130 |
66802 |
if (d_ms_proc.find(a) == d_ms_proc.end() |
131 |
33401 |
&& d_m_nconst_factor.find(a) == d_m_nconst_factor.end()) |
132 |
|
{ |
133 |
29543 |
if (c == 0) |
134 |
|
{ |
135 |
|
// compare magnitude against 1 |
136 |
25494 |
std::vector<Node> exp; |
137 |
25494 |
NodeMultiset a_exp_proc; |
138 |
25494 |
NodeMultiset b_exp_proc; |
139 |
25494 |
compareMonomial(a, |
140 |
|
a, |
141 |
|
a_exp_proc, |
142 |
12747 |
d_data->d_one, |
143 |
12747 |
d_data->d_one, |
144 |
|
b_exp_proc, |
145 |
|
exp, |
146 |
|
lemmas, |
147 |
|
cmp_infers); |
148 |
|
} |
149 |
|
else |
150 |
|
{ |
151 |
16796 |
const NodeMultiset& mea = d_data->d_mdb.getMonomialExponentMap(a); |
152 |
16796 |
if (c == 1) |
153 |
|
{ |
154 |
|
// could compare not just against containing variables? |
155 |
|
// compare magnitude against variables |
156 |
98361 |
for (unsigned k = 0; k < d_data->d_ms_vars.size(); k++) |
157 |
|
{ |
158 |
177190 |
Node v = d_data->d_ms_vars[k]; |
159 |
177190 |
Node mvcv = d_data->d_model.computeConcreteModelValue(v); |
160 |
88595 |
if (mvcv.isConst()) |
161 |
|
{ |
162 |
176578 |
std::vector<Node> exp; |
163 |
176578 |
NodeMultiset a_exp_proc; |
164 |
176578 |
NodeMultiset b_exp_proc; |
165 |
88289 |
if (mea.find(v) != mea.end()) |
166 |
|
{ |
167 |
17763 |
a_exp_proc[v] = 1; |
168 |
17763 |
b_exp_proc[v] = 1; |
169 |
17763 |
setMonomialFactor(a, v, a_exp_proc); |
170 |
17763 |
setMonomialFactor(v, a, b_exp_proc); |
171 |
17763 |
compareMonomial(a, |
172 |
|
a, |
173 |
|
a_exp_proc, |
174 |
|
v, |
175 |
|
v, |
176 |
|
b_exp_proc, |
177 |
|
exp, |
178 |
|
lemmas, |
179 |
|
cmp_infers); |
180 |
|
} |
181 |
|
} |
182 |
|
} |
183 |
|
} |
184 |
|
else |
185 |
|
{ |
186 |
|
// compare magnitude against other non-linear monomials |
187 |
95430 |
for (unsigned k = (j + 1); k < d_data->d_ms.size(); k++) |
188 |
|
{ |
189 |
176800 |
Node b = d_data->d_ms[k]; |
190 |
|
//(signs[a]==signs[b])==(r==0) |
191 |
176800 |
if (d_ms_proc.find(b) == d_ms_proc.end() |
192 |
88400 |
&& d_m_nconst_factor.find(b) == d_m_nconst_factor.end()) |
193 |
|
{ |
194 |
83497 |
const NodeMultiset& meb = d_data->d_mdb.getMonomialExponentMap(b); |
195 |
|
|
196 |
166994 |
std::vector<Node> exp; |
197 |
|
// take common factors of monomials, set minimum of |
198 |
|
// common exponents as processed |
199 |
166994 |
NodeMultiset a_exp_proc; |
200 |
166994 |
NodeMultiset b_exp_proc; |
201 |
242877 |
for (NodeMultiset::const_iterator itmea2 = mea.begin(); |
202 |
242877 |
itmea2 != mea.end(); |
203 |
|
++itmea2) |
204 |
|
{ |
205 |
159380 |
NodeMultiset::const_iterator itmeb2 = meb.find(itmea2->first); |
206 |
159380 |
if (itmeb2 != meb.end()) |
207 |
|
{ |
208 |
30597 |
unsigned min_exp = itmea2->second > itmeb2->second |
209 |
59470 |
? itmeb2->second |
210 |
59470 |
: itmea2->second; |
211 |
30597 |
a_exp_proc[itmea2->first] = min_exp; |
212 |
30597 |
b_exp_proc[itmea2->first] = min_exp; |
213 |
61194 |
Trace("nl-ext-comp") << "Common exponent : " << itmea2->first |
214 |
30597 |
<< " : " << min_exp << std::endl; |
215 |
|
} |
216 |
|
} |
217 |
83497 |
if (!a_exp_proc.empty()) |
218 |
|
{ |
219 |
30469 |
setMonomialFactor(a, b, a_exp_proc); |
220 |
30469 |
setMonomialFactor(b, a, b_exp_proc); |
221 |
|
} |
222 |
|
/* |
223 |
|
if( !a_exp_proc.empty() ){ |
224 |
|
//reduction based on common exponents a > 0 => ( a * b |
225 |
|
<> a * c <=> b <> c ), a < 0 => ( a * b <> a * c <=> b |
226 |
|
!<> c ) ? }else{ compareMonomial( a, a, a_exp_proc, b, |
227 |
|
b, b_exp_proc, exp, lemmas ); |
228 |
|
} |
229 |
|
*/ |
230 |
83497 |
compareMonomial( |
231 |
|
a, a, a_exp_proc, b, b, b_exp_proc, exp, lemmas, cmp_infers); |
232 |
|
} |
233 |
|
} |
234 |
|
} |
235 |
|
} |
236 |
|
} |
237 |
|
} |
238 |
|
// remove redundant lemmas, e.g. if a > b, b > c, a > c were |
239 |
|
// inferred, discard lemma with conclusion a > c |
240 |
9414 |
Trace("nl-ext-comp") << "Compute redundancies for " << lemmas.size() |
241 |
4707 |
<< " lemmas." << std::endl; |
242 |
|
// naive |
243 |
9414 |
std::unordered_set<Node> r_lemmas; |
244 |
1383 |
for (std::map<int, std::map<Node, std::map<Node, Node> > >::iterator itb = |
245 |
4707 |
cmp_infers.begin(); |
246 |
6090 |
itb != cmp_infers.end(); |
247 |
|
++itb) |
248 |
|
{ |
249 |
2492 |
for (std::map<Node, std::map<Node, Node> >::iterator itc = |
250 |
1383 |
itb->second.begin(); |
251 |
3875 |
itc != itb->second.end(); |
252 |
|
++itc) |
253 |
|
{ |
254 |
5895 |
for (std::map<Node, Node>::iterator itc2 = itc->second.begin(); |
255 |
5895 |
itc2 != itc->second.end(); |
256 |
|
++itc2) |
257 |
|
{ |
258 |
6806 |
std::map<Node, bool> visited; |
259 |
10228 |
for (std::map<Node, Node>::iterator itc3 = itc->second.begin(); |
260 |
10228 |
itc3 != itc->second.end(); |
261 |
|
++itc3) |
262 |
|
{ |
263 |
6983 |
if (itc3->first != itc2->first) |
264 |
|
{ |
265 |
7172 |
std::vector<Node> exp; |
266 |
3665 |
if (cmp_holds(itc3->first, itc2->first, itb->second, exp, visited)) |
267 |
|
{ |
268 |
158 |
r_lemmas.insert(itc2->second); |
269 |
316 |
Trace("nl-ext-comp") |
270 |
158 |
<< "...inference of " << itc->first << " > " << itc2->first |
271 |
158 |
<< " was redundant." << std::endl; |
272 |
158 |
break; |
273 |
|
} |
274 |
|
} |
275 |
|
} |
276 |
|
} |
277 |
|
} |
278 |
|
} |
279 |
8110 |
for (unsigned i = 0; i < lemmas.size(); i++) |
280 |
|
{ |
281 |
3403 |
if (r_lemmas.find(lemmas[i].d_node) == r_lemmas.end()) |
282 |
|
{ |
283 |
3245 |
d_data->d_im.addPendingLemma(lemmas[i]); |
284 |
|
} |
285 |
|
} |
286 |
|
// could only take maximal lower/minimial lower bounds? |
287 |
4707 |
} |
288 |
|
|
289 |
|
// show a <> 0 by inequalities between variables in monomial a w.r.t 0 |
290 |
58053 |
int MonomialCheck::compareSign( |
291 |
|
Node oa, Node a, unsigned a_index, int status, std::vector<Node>& exp) |
292 |
|
{ |
293 |
116106 |
Trace("nl-ext-debug") << "Process " << a << " at index " << a_index |
294 |
58053 |
<< ", status is " << status << std::endl; |
295 |
58053 |
NodeManager* nm = NodeManager::currentNM(); |
296 |
116106 |
Node mvaoa = d_data->d_model.computeAbstractModelValue(oa); |
297 |
58053 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
298 |
58053 |
if (a_index == vla.size()) |
299 |
|
{ |
300 |
17587 |
if (mvaoa.getConst<Rational>().sgn() != status) |
301 |
|
{ |
302 |
|
Node lemma = |
303 |
2970 |
nm->mkAnd(exp).impNode(mkLit(oa, d_data->d_zero, status * 2)); |
304 |
1485 |
CDProof* proof = nullptr; |
305 |
1485 |
if (d_data->isProofEnabled()) |
306 |
|
{ |
307 |
269 |
proof = d_data->getProof(); |
308 |
538 |
std::vector<Node> args = exp; |
309 |
269 |
args.emplace_back(oa); |
310 |
269 |
proof->addStep(lemma, PfRule::ARITH_MULT_SIGN, {}, args); |
311 |
|
} |
312 |
1485 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
313 |
|
} |
314 |
17587 |
return status; |
315 |
|
} |
316 |
40466 |
Assert(a_index < vla.size()); |
317 |
80932 |
Node av = vla[a_index]; |
318 |
40466 |
unsigned aexp = d_data->d_mdb.getExponent(a, av); |
319 |
|
// take current sign in model |
320 |
80932 |
Node mvaav = d_data->d_model.computeAbstractModelValue(av); |
321 |
40466 |
int sgn = mvaav.getConst<Rational>().sgn(); |
322 |
80932 |
Trace("nl-ext-debug") << "Process var " << av << "^" << aexp |
323 |
40466 |
<< ", model sign = " << sgn << std::endl; |
324 |
40466 |
if (sgn == 0) |
325 |
|
{ |
326 |
4293 |
if (mvaoa.getConst<Rational>().sgn() != 0) |
327 |
|
{ |
328 |
2050 |
Node prem = av.eqNode(d_data->d_zero); |
329 |
2050 |
Node conc = oa.eqNode(d_data->d_zero); |
330 |
2050 |
Node lemma = prem.impNode(conc); |
331 |
1025 |
CDProof* proof = nullptr; |
332 |
1025 |
if (d_data->isProofEnabled()) |
333 |
|
{ |
334 |
149 |
proof = d_data->getProof(); |
335 |
149 |
proof->addStep(conc, PfRule::MACRO_SR_PRED_INTRO, {prem}, {conc}); |
336 |
149 |
proof->addStep(lemma, PfRule::SCOPE, {conc}, {prem}); |
337 |
|
} |
338 |
1025 |
d_data->d_im.addPendingLemma(lemma, InferenceId::ARITH_NL_SIGN, proof); |
339 |
|
} |
340 |
4293 |
return 0; |
341 |
|
} |
342 |
36173 |
if (aexp % 2 == 0) |
343 |
|
{ |
344 |
3167 |
exp.push_back(av.eqNode(d_data->d_zero).negate()); |
345 |
3167 |
return compareSign(oa, a, a_index + 1, status, exp); |
346 |
|
} |
347 |
33006 |
exp.push_back(nm->mkNode(sgn == 1 ? Kind::GT : Kind::LT, av, d_data->d_zero)); |
348 |
33006 |
return compareSign(oa, a, a_index + 1, status * sgn, exp); |
349 |
|
} |
350 |
|
|
351 |
114007 |
bool MonomialCheck::compareMonomial( |
352 |
|
Node oa, |
353 |
|
Node a, |
354 |
|
NodeMultiset& a_exp_proc, |
355 |
|
Node ob, |
356 |
|
Node b, |
357 |
|
NodeMultiset& b_exp_proc, |
358 |
|
std::vector<Node>& exp, |
359 |
|
std::vector<SimpleTheoryLemma>& lem, |
360 |
|
std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers) |
361 |
|
{ |
362 |
228014 |
Trace("nl-ext-comp-debug") |
363 |
114007 |
<< "Check |" << a << "| >= |" << b << "|" << std::endl; |
364 |
114007 |
unsigned pexp_size = exp.size(); |
365 |
114007 |
if (compareMonomial( |
366 |
|
oa, a, 0, a_exp_proc, ob, b, 0, b_exp_proc, 0, exp, lem, cmp_infers)) |
367 |
|
{ |
368 |
82007 |
return true; |
369 |
|
} |
370 |
32000 |
exp.resize(pexp_size); |
371 |
64000 |
Trace("nl-ext-comp-debug") |
372 |
32000 |
<< "Check |" << b << "| >= |" << a << "|" << std::endl; |
373 |
32000 |
if (compareMonomial( |
374 |
|
ob, b, 0, b_exp_proc, oa, a, 0, a_exp_proc, 0, exp, lem, cmp_infers)) |
375 |
|
{ |
376 |
17045 |
return true; |
377 |
|
} |
378 |
14955 |
return false; |
379 |
|
} |
380 |
|
|
381 |
|
// trying to show a ( >, = ) b by inequalities between variables in |
382 |
|
// monomials a,b |
383 |
637138 |
bool MonomialCheck::compareMonomial( |
384 |
|
Node oa, |
385 |
|
Node a, |
386 |
|
unsigned a_index, |
387 |
|
NodeMultiset& a_exp_proc, |
388 |
|
Node ob, |
389 |
|
Node b, |
390 |
|
unsigned b_index, |
391 |
|
NodeMultiset& b_exp_proc, |
392 |
|
int status, |
393 |
|
std::vector<Node>& exp, |
394 |
|
std::vector<SimpleTheoryLemma>& lem, |
395 |
|
std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers) |
396 |
|
{ |
397 |
1274276 |
Trace("nl-ext-comp-debug") |
398 |
637138 |
<< "compareMonomial " << oa << " and " << ob << ", indices = " << a_index |
399 |
637138 |
<< " " << b_index << std::endl; |
400 |
637138 |
Assert(status == 0 || status == 2); |
401 |
637138 |
const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a); |
402 |
637138 |
const std::vector<Node>& vlb = d_data->d_mdb.getVariableList(b); |
403 |
637138 |
if (a_index == vla.size() && b_index == vlb.size()) |
404 |
|
{ |
405 |
|
// finished, compare absolute value of abstract model values |
406 |
99052 |
int modelStatus = d_data->d_model.compare(oa, ob, false, true) * 2; |
407 |
198104 |
Trace("nl-ext-comp") << "...finished comparison with " << oa << " <" |
408 |
99052 |
<< status << "> " << ob |
409 |
99052 |
<< ", model status = " << modelStatus << std::endl; |
410 |
99052 |
if (status != modelStatus) |
411 |
|
{ |
412 |
6806 |
Trace("nl-ext-comp-infer") |
413 |
3403 |
<< "infer : " << oa << " <" << status << "> " << ob << std::endl; |
414 |
3403 |
if (status == 2) |
415 |
|
{ |
416 |
|
// must state that all variables are non-zero |
417 |
7421 |
for (unsigned j = 0; j < vla.size(); j++) |
418 |
|
{ |
419 |
4789 |
exp.push_back(vla[j].eqNode(d_data->d_zero).negate()); |
420 |
|
} |
421 |
|
} |
422 |
3403 |
NodeManager* nm = NodeManager::currentNM(); |
423 |
|
Node clem = nm->mkNode( |
424 |
6806 |
Kind::IMPLIES, nm->mkAnd(exp), mkLit(oa, ob, status, true)); |
425 |
3403 |
Trace("nl-ext-comp-lemma") << "comparison lemma : " << clem << std::endl; |
426 |
3403 |
lem.emplace_back( |
427 |
6806 |
InferenceId::ARITH_NL_COMPARISON, clem, LemmaProperty::NONE, nullptr); |
428 |
3403 |
cmp_infers[status][oa][ob] = clem; |
429 |
|
} |
430 |
99052 |
return true; |
431 |
|
} |
432 |
|
// get a/b variable information |
433 |
1076172 |
Node av; |
434 |
538086 |
unsigned aexp = 0; |
435 |
538086 |
unsigned avo = 0; |
436 |
538086 |
if (a_index < vla.size()) |
437 |
|
{ |
438 |
457620 |
av = vla[a_index]; |
439 |
457620 |
unsigned aexpTotal = d_data->d_mdb.getExponent(a, av); |
440 |
457620 |
Assert(a_exp_proc[av] <= aexpTotal); |
441 |
457620 |
aexp = aexpTotal - a_exp_proc[av]; |
442 |
457620 |
if (aexp == 0) |
443 |
|
{ |
444 |
337096 |
return compareMonomial(oa, |
445 |
|
a, |
446 |
|
a_index + 1, |
447 |
|
a_exp_proc, |
448 |
|
ob, |
449 |
|
b, |
450 |
|
b_index, |
451 |
|
b_exp_proc, |
452 |
|
status, |
453 |
|
exp, |
454 |
|
lem, |
455 |
168548 |
cmp_infers); |
456 |
|
} |
457 |
289072 |
Assert(d_order_vars.find(av) != d_order_vars.end()); |
458 |
289072 |
avo = d_order_vars[av]; |
459 |
|
} |
460 |
739076 |
Node bv; |
461 |
369538 |
unsigned bexp = 0; |
462 |
369538 |
unsigned bvo = 0; |
463 |
369538 |
if (b_index < vlb.size()) |
464 |
|
{ |
465 |
328184 |
bv = vlb[b_index]; |
466 |
328184 |
unsigned bexpTotal = d_data->d_mdb.getExponent(b, bv); |
467 |
328184 |
Assert(b_exp_proc[bv] <= bexpTotal); |
468 |
328184 |
bexp = bexpTotal - b_exp_proc[bv]; |
469 |
328184 |
if (bexp == 0) |
470 |
|
{ |
471 |
318258 |
return compareMonomial(oa, |
472 |
|
a, |
473 |
|
a_index, |
474 |
|
a_exp_proc, |
475 |
|
ob, |
476 |
|
b, |
477 |
|
b_index + 1, |
478 |
|
b_exp_proc, |
479 |
|
status, |
480 |
|
exp, |
481 |
|
lem, |
482 |
159129 |
cmp_infers); |
483 |
|
} |
484 |
169055 |
Assert(d_order_vars.find(bv) != d_order_vars.end()); |
485 |
169055 |
bvo = d_order_vars[bv]; |
486 |
|
} |
487 |
|
// get "one" information |
488 |
210409 |
Assert(d_order_vars.find(d_data->d_one) != d_order_vars.end()); |
489 |
210409 |
unsigned ovo = d_order_vars[d_data->d_one]; |
490 |
420818 |
Trace("nl-ext-comp-debug") << "....vars : " << av << "^" << aexp << " " << bv |
491 |
210409 |
<< "^" << bexp << std::endl; |
492 |
|
|
493 |
|
//--- cases |
494 |
210409 |
if (av.isNull()) |
495 |
|
{ |
496 |
2231 |
if (bvo <= ovo) |
497 |
|
{ |
498 |
1838 |
Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl; |
499 |
|
// can multiply b by <=1 |
500 |
1838 |
exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true)); |
501 |
3676 |
return compareMonomial(oa, |
502 |
|
a, |
503 |
|
a_index, |
504 |
|
a_exp_proc, |
505 |
|
ob, |
506 |
|
b, |
507 |
|
b_index + 1, |
508 |
|
b_exp_proc, |
509 |
|
bvo == ovo ? status : 2, |
510 |
|
exp, |
511 |
|
lem, |
512 |
1838 |
cmp_infers); |
513 |
|
} |
514 |
786 |
Trace("nl-ext-comp-debug") |
515 |
393 |
<< "...failure, unmatched |b|>1 component." << std::endl; |
516 |
393 |
return false; |
517 |
|
} |
518 |
208178 |
else if (bv.isNull()) |
519 |
|
{ |
520 |
41354 |
if (avo >= ovo) |
521 |
|
{ |
522 |
39784 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
523 |
|
// can multiply a by >=1 |
524 |
39784 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
525 |
79568 |
return compareMonomial(oa, |
526 |
|
a, |
527 |
|
a_index + 1, |
528 |
|
a_exp_proc, |
529 |
|
ob, |
530 |
|
b, |
531 |
|
b_index, |
532 |
|
b_exp_proc, |
533 |
|
avo == ovo ? status : 2, |
534 |
|
exp, |
535 |
|
lem, |
536 |
39784 |
cmp_infers); |
537 |
|
} |
538 |
3140 |
Trace("nl-ext-comp-debug") |
539 |
1570 |
<< "...failure, unmatched |a|<1 component." << std::endl; |
540 |
1570 |
return false; |
541 |
|
} |
542 |
166824 |
Assert(!av.isNull() && !bv.isNull()); |
543 |
166824 |
if (avo >= bvo) |
544 |
|
{ |
545 |
121772 |
if (bvo < ovo && avo >= ovo) |
546 |
|
{ |
547 |
96 |
Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl; |
548 |
|
// do avo>=1 instead |
549 |
96 |
exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true)); |
550 |
192 |
return compareMonomial(oa, |
551 |
|
a, |
552 |
|
a_index + 1, |
553 |
|
a_exp_proc, |
554 |
|
ob, |
555 |
|
b, |
556 |
|
b_index, |
557 |
|
b_exp_proc, |
558 |
|
avo == ovo ? status : 2, |
559 |
|
exp, |
560 |
|
lem, |
561 |
96 |
cmp_infers); |
562 |
|
} |
563 |
121676 |
unsigned min_exp = aexp > bexp ? bexp : aexp; |
564 |
121676 |
a_exp_proc[av] += min_exp; |
565 |
121676 |
b_exp_proc[bv] += min_exp; |
566 |
243352 |
Trace("nl-ext-comp-debug") << "...take leading " << min_exp << " from " |
567 |
121676 |
<< av << " and " << bv << std::endl; |
568 |
121676 |
exp.push_back(mkLit(av, bv, avo == bvo ? 0 : 2, true)); |
569 |
243352 |
bool ret = compareMonomial(oa, |
570 |
|
a, |
571 |
|
a_index, |
572 |
|
a_exp_proc, |
573 |
|
ob, |
574 |
|
b, |
575 |
|
b_index, |
576 |
|
b_exp_proc, |
577 |
|
avo == bvo ? status : 2, |
578 |
|
exp, |
579 |
|
lem, |
580 |
121676 |
cmp_infers); |
581 |
121676 |
a_exp_proc[av] -= min_exp; |
582 |
121676 |
b_exp_proc[bv] -= min_exp; |
583 |
121676 |
return ret; |
584 |
|
} |
585 |
45052 |
if (bvo <= ovo) |
586 |
|
{ |
587 |
60 |
Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl; |
588 |
|
// try multiply b <= 1 |
589 |
60 |
exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true)); |
590 |
120 |
return compareMonomial(oa, |
591 |
|
a, |
592 |
|
a_index, |
593 |
|
a_exp_proc, |
594 |
|
ob, |
595 |
|
b, |
596 |
|
b_index + 1, |
597 |
|
b_exp_proc, |
598 |
|
bvo == ovo ? status : 2, |
599 |
|
exp, |
600 |
|
lem, |
601 |
60 |
cmp_infers); |
602 |
|
} |
603 |
89984 |
Trace("nl-ext-comp-debug") |
604 |
44992 |
<< "...failure, leading |b|>|a|>1 component." << std::endl; |
605 |
44992 |
return false; |
606 |
|
} |
607 |
|
|
608 |
4581 |
bool MonomialCheck::cmp_holds(Node x, |
609 |
|
Node y, |
610 |
|
std::map<Node, std::map<Node, Node> >& cmp_infers, |
611 |
|
std::vector<Node>& exp, |
612 |
|
std::map<Node, bool>& visited) |
613 |
|
{ |
614 |
4581 |
if (x == y) |
615 |
|
{ |
616 |
158 |
return true; |
617 |
|
} |
618 |
4423 |
else if (visited.find(x) != visited.end()) |
619 |
|
{ |
620 |
625 |
return false; |
621 |
|
} |
622 |
3798 |
visited[x] = true; |
623 |
3798 |
std::map<Node, std::map<Node, Node> >::iterator it = cmp_infers.find(x); |
624 |
3798 |
if (it != cmp_infers.end()) |
625 |
|
{ |
626 |
1262 |
for (std::map<Node, Node>::iterator itc = it->second.begin(); |
627 |
1262 |
itc != it->second.end(); |
628 |
|
++itc) |
629 |
|
{ |
630 |
916 |
exp.push_back(itc->second); |
631 |
916 |
if (cmp_holds(itc->first, y, cmp_infers, exp, visited)) |
632 |
|
{ |
633 |
192 |
return true; |
634 |
|
} |
635 |
724 |
exp.pop_back(); |
636 |
|
} |
637 |
|
} |
638 |
3606 |
return false; |
639 |
|
} |
640 |
|
|
641 |
2170 |
void MonomialCheck::assignOrderIds(std::vector<Node>& vars, |
642 |
|
NodeMultiset& order, |
643 |
|
bool isConcrete, |
644 |
|
bool isAbsolute) |
645 |
|
{ |
646 |
2170 |
SortNlModel smv; |
647 |
2170 |
smv.d_nlm = &d_data->d_model; |
648 |
2170 |
smv.d_isConcrete = isConcrete; |
649 |
2170 |
smv.d_isAbsolute = isAbsolute; |
650 |
2170 |
smv.d_reverse_order = false; |
651 |
2170 |
std::sort(vars.begin(), vars.end(), smv); |
652 |
|
|
653 |
2170 |
order.clear(); |
654 |
|
// assign ordering id's |
655 |
2170 |
unsigned counter = 0; |
656 |
2170 |
unsigned order_index = isConcrete ? 0 : 1; |
657 |
4340 |
Node prev; |
658 |
12815 |
for (unsigned j = 0; j < vars.size(); j++) |
659 |
|
{ |
660 |
21290 |
Node x = vars[j]; |
661 |
21290 |
Node v = d_data->d_model.computeModelValue(x, isConcrete); |
662 |
10645 |
if (!v.isConst()) |
663 |
|
{ |
664 |
|
Trace("nl-ext-mvo") << "..do not assign order to " << x << " : " << v |
665 |
|
<< std::endl; |
666 |
|
// don't assign for non-constant values (transcendental function apps) |
667 |
|
break; |
668 |
|
} |
669 |
10645 |
Trace("nl-ext-mvo") << " order " << x << " : " << v << std::endl; |
670 |
10645 |
if (v != prev) |
671 |
|
{ |
672 |
|
// builtin points |
673 |
|
bool success; |
674 |
11153 |
do |
675 |
|
{ |
676 |
11153 |
success = false; |
677 |
11153 |
if (order_index < d_order_points.size()) |
678 |
|
{ |
679 |
4830 |
Node vv = d_data->d_model.computeModelValue( |
680 |
9660 |
d_order_points[order_index], isConcrete); |
681 |
4830 |
if (d_data->d_model.compareValue(v, vv, isAbsolute) >= 0) |
682 |
|
{ |
683 |
3711 |
counter++; |
684 |
7422 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
685 |
3711 |
<< "] = " << counter << std::endl; |
686 |
3711 |
order[d_order_points[order_index]] = counter; |
687 |
3711 |
prev = vv; |
688 |
3711 |
order_index++; |
689 |
3711 |
success = true; |
690 |
|
} |
691 |
|
} |
692 |
|
} while (success); |
693 |
|
} |
694 |
10645 |
if (prev.isNull() || d_data->d_model.compareValue(v, prev, isAbsolute) != 0) |
695 |
|
{ |
696 |
4751 |
counter++; |
697 |
|
} |
698 |
10645 |
Trace("nl-ext-mvo") << "O[" << x << "] = " << counter << std::endl; |
699 |
10645 |
order[x] = counter; |
700 |
10645 |
prev = v; |
701 |
|
} |
702 |
3428 |
while (order_index < d_order_points.size()) |
703 |
|
{ |
704 |
629 |
counter++; |
705 |
1258 |
Trace("nl-ext-mvo") << "O[" << d_order_points[order_index] |
706 |
629 |
<< "] = " << counter << std::endl; |
707 |
629 |
order[d_order_points[order_index]] = counter; |
708 |
629 |
order_index++; |
709 |
|
} |
710 |
2170 |
} |
711 |
168962 |
Node MonomialCheck::mkLit(Node a, Node b, int status, bool isAbsolute) const |
712 |
|
{ |
713 |
168962 |
if (status == 0) |
714 |
|
{ |
715 |
60062 |
Node a_eq_b = a.eqNode(b); |
716 |
30031 |
if (!isAbsolute) |
717 |
|
{ |
718 |
|
return a_eq_b; |
719 |
|
} |
720 |
60062 |
Node negate_b = NodeManager::currentNM()->mkNode(Kind::UMINUS, b); |
721 |
30031 |
return a_eq_b.orNode(a.eqNode(negate_b)); |
722 |
|
} |
723 |
138931 |
else if (status < 0) |
724 |
|
{ |
725 |
620 |
return mkLit(b, a, -status); |
726 |
|
} |
727 |
138311 |
Assert(status == 1 || status == 2); |
728 |
138311 |
NodeManager* nm = NodeManager::currentNM(); |
729 |
138311 |
Kind greater_op = status == 1 ? Kind::GEQ : Kind::GT; |
730 |
138311 |
if (!isAbsolute) |
731 |
|
{ |
732 |
1485 |
return nm->mkNode(greater_op, a, b); |
733 |
|
} |
734 |
|
// return nm->mkNode( greater_op, mkAbs( a ), mkAbs( b ) ); |
735 |
273652 |
Node a_is_nonnegative = nm->mkNode(Kind::GEQ, a, d_data->d_zero); |
736 |
273652 |
Node b_is_nonnegative = nm->mkNode(Kind::GEQ, b, d_data->d_zero); |
737 |
273652 |
Node negate_a = nm->mkNode(Kind::UMINUS, a); |
738 |
273652 |
Node negate_b = nm->mkNode(Kind::UMINUS, b); |
739 |
|
return a_is_nonnegative.iteNode( |
740 |
273652 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, a, b), |
741 |
273652 |
nm->mkNode(greater_op, a, negate_b)), |
742 |
273652 |
b_is_nonnegative.iteNode(nm->mkNode(greater_op, negate_a, b), |
743 |
410478 |
nm->mkNode(greater_op, negate_a, negate_b))); |
744 |
|
} |
745 |
|
|
746 |
96464 |
void MonomialCheck::setMonomialFactor(Node a, |
747 |
|
Node b, |
748 |
|
const NodeMultiset& common) |
749 |
|
{ |
750 |
|
// Could not tell if this was being inserted intentionally or not. |
751 |
96464 |
std::map<Node, Node>& mono_diff_a = d_data->d_mono_diff[a]; |
752 |
96464 |
if (mono_diff_a.find(b) == mono_diff_a.end()) |
753 |
|
{ |
754 |
20940 |
Trace("nl-ext-mono-factor") |
755 |
10470 |
<< "Set monomial factor for " << a << "/" << b << std::endl; |
756 |
10470 |
mono_diff_a[b] = d_data->d_mdb.mkMonomialRemFactor(a, common); |
757 |
|
} |
758 |
96464 |
} |
759 |
|
|
760 |
|
} // namespace nl |
761 |
|
} // namespace arith |
762 |
|
} // namespace theory |
763 |
31137 |
} // namespace cvc5 |