1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Gereon Kremer, Aina Niemetz |
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 |
|
* Implementation of NlExt proof checker. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "theory/arith/nl/ext/proof_checker.h" |
17 |
|
|
18 |
|
#include "expr/sequence.h" |
19 |
|
#include "theory/arith/arith_utilities.h" |
20 |
|
#include "theory/rewriter.h" |
21 |
|
|
22 |
|
using namespace cvc5::kind; |
23 |
|
|
24 |
|
namespace cvc5 { |
25 |
|
namespace theory { |
26 |
|
namespace arith { |
27 |
|
namespace nl { |
28 |
|
|
29 |
543 |
void ExtProofRuleChecker::registerTo(ProofChecker* pc) |
30 |
|
{ |
31 |
543 |
pc->registerChecker(PfRule::ARITH_MULT_SIGN, this); |
32 |
543 |
pc->registerChecker(PfRule::ARITH_MULT_TANGENT, this); |
33 |
543 |
} |
34 |
|
|
35 |
206 |
Node ExtProofRuleChecker::checkInternal(PfRule id, |
36 |
|
const std::vector<Node>& children, |
37 |
|
const std::vector<Node>& args) |
38 |
|
{ |
39 |
206 |
NodeManager* nm = NodeManager::currentNM(); |
40 |
412 |
auto zero = nm->mkConst<Rational>(0); |
41 |
412 |
auto one = nm->mkConst<Rational>(1); |
42 |
412 |
auto mone = nm->mkConst<Rational>(-1); |
43 |
412 |
auto pi = nm->mkNullaryOperator(nm->realType(), Kind::PI); |
44 |
412 |
auto mpi = nm->mkNode(Kind::MULT, mone, pi); |
45 |
206 |
Trace("nl-ext-checker") << "Checking " << id << std::endl; |
46 |
206 |
for (const auto& c : children) |
47 |
|
{ |
48 |
|
Trace("nl-ext-checker") << "\t" << c << std::endl; |
49 |
|
} |
50 |
206 |
if (id == PfRule::ARITH_MULT_SIGN) |
51 |
|
{ |
52 |
180 |
Assert(children.empty()); |
53 |
180 |
Assert(args.size() > 1); |
54 |
360 |
Node mon = args.back(); |
55 |
360 |
std::map<Node, int> exps; |
56 |
360 |
std::vector<Node> premise = args; |
57 |
180 |
premise.pop_back(); |
58 |
180 |
Assert(mon.getKind() == Kind::MULT |
59 |
|
|| mon.getKind() == Kind::NONLINEAR_MULT); |
60 |
658 |
for (const auto& v : mon) |
61 |
|
{ |
62 |
478 |
exps[v]++; |
63 |
|
} |
64 |
360 |
std::map<Node, int> signs; |
65 |
591 |
for (const auto& f : premise) |
66 |
|
{ |
67 |
442 |
if (f.getKind() == Kind::NOT) |
68 |
|
{ |
69 |
31 |
Assert(f[0].getKind() == Kind::EQUAL); |
70 |
31 |
Assert(f[0][1].isConst() && f[0][1].getConst<Rational>().isZero()); |
71 |
31 |
Assert(signs.find(f[0][0]) == signs.end()); |
72 |
31 |
signs.emplace(f[0][0], 0); |
73 |
31 |
continue; |
74 |
|
} |
75 |
380 |
Assert(f.getKind() == Kind::LT || f.getKind() == Kind::GT); |
76 |
380 |
Assert(f[1].isConst() && f[1].getConst<Rational>().isZero()); |
77 |
380 |
Assert(signs.find(f[0]) == signs.end()); |
78 |
380 |
signs.emplace(f[0], f.getKind() == Kind::LT ? -1 : 1); |
79 |
|
} |
80 |
180 |
int sign = 0; |
81 |
591 |
for (const auto& ve : exps) |
82 |
|
{ |
83 |
411 |
auto sit = signs.find(ve.first); |
84 |
411 |
Assert(sit != signs.end()); |
85 |
411 |
if (ve.second % 2 == 0) |
86 |
|
{ |
87 |
31 |
Assert(sit->second == 0); |
88 |
31 |
if (sign == 0) |
89 |
|
{ |
90 |
26 |
sign = 1; |
91 |
|
} |
92 |
|
} |
93 |
|
else |
94 |
|
{ |
95 |
380 |
Assert(sit->second != 0); |
96 |
380 |
if (sign == 0) |
97 |
|
{ |
98 |
154 |
sign = sit->second; |
99 |
|
} |
100 |
|
else |
101 |
|
{ |
102 |
226 |
sign *= sit->second; |
103 |
|
} |
104 |
|
} |
105 |
|
} |
106 |
180 |
switch (sign) |
107 |
|
{ |
108 |
74 |
case -1: |
109 |
|
return nm->mkNode( |
110 |
74 |
Kind::IMPLIES, nm->mkAnd(premise), nm->mkNode(Kind::GT, zero, mon)); |
111 |
|
case 0: |
112 |
|
return nm->mkNode(Kind::IMPLIES, |
113 |
|
nm->mkAnd(premise), |
114 |
|
nm->mkNode(Kind::DISTINCT, mon, zero)); |
115 |
106 |
case 1: |
116 |
|
return nm->mkNode( |
117 |
106 |
Kind::IMPLIES, nm->mkAnd(premise), nm->mkNode(Kind::GT, mon, zero)); |
118 |
|
default: Assert(false); return Node(); |
119 |
|
} |
120 |
|
} |
121 |
26 |
else if (id == PfRule::ARITH_MULT_TANGENT) |
122 |
|
{ |
123 |
26 |
Assert(children.empty()); |
124 |
26 |
Assert(args.size() == 6); |
125 |
26 |
Assert(args[0].getType().isReal()); |
126 |
26 |
Assert(args[1].getType().isReal()); |
127 |
26 |
Assert(args[2].getType().isReal()); |
128 |
26 |
Assert(args[3].getType().isReal()); |
129 |
26 |
Assert(args[4].getType().isReal()); |
130 |
26 |
Assert(args[5].isConst() && args[5].getKind() == Kind::CONST_RATIONAL |
131 |
|
&& args[5].getConst<Rational>().isIntegral()); |
132 |
52 |
Node t = args[0]; |
133 |
52 |
Node x = args[1]; |
134 |
52 |
Node y = args[2]; |
135 |
52 |
Node a = args[3]; |
136 |
52 |
Node b = args[4]; |
137 |
26 |
int sgn = args[5].getConst<Rational>().getNumerator().sgn(); |
138 |
26 |
Assert(sgn == -1 || sgn == 1); |
139 |
|
Node tplane = nm->mkNode(Kind::MINUS, |
140 |
104 |
nm->mkNode(Kind::PLUS, |
141 |
52 |
nm->mkNode(Kind::MULT, b, x), |
142 |
52 |
nm->mkNode(Kind::MULT, a, y)), |
143 |
104 |
nm->mkNode(Kind::MULT, a, b)); |
144 |
|
return nm->mkNode( |
145 |
|
Kind::EQUAL, |
146 |
52 |
nm->mkNode(sgn == -1 ? Kind::LEQ : Kind::GEQ, t, tplane), |
147 |
104 |
nm->mkNode( |
148 |
|
Kind::OR, |
149 |
104 |
nm->mkNode(Kind::AND, |
150 |
52 |
nm->mkNode(Kind::LEQ, x, a), |
151 |
52 |
nm->mkNode(sgn == -1 ? Kind::GEQ : Kind::LEQ, y, b)), |
152 |
104 |
nm->mkNode(Kind::AND, |
153 |
52 |
nm->mkNode(Kind::GEQ, x, a), |
154 |
130 |
nm->mkNode(sgn == -1 ? Kind::LEQ : Kind::GEQ, y, b)))); |
155 |
|
} |
156 |
|
return Node::null(); |
157 |
|
} |
158 |
|
|
159 |
|
} // namespace nl |
160 |
|
} // namespace arith |
161 |
|
} // namespace theory |
162 |
28191 |
} // namespace cvc5 |