mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
tangent lemma
Signed-off-by: Lev <levnach@hotmail.com>
This commit is contained in:
parent
c814b1b17e
commit
dcbb119aaf
1 changed files with 92 additions and 28 deletions
|
@ -28,9 +28,27 @@
|
|||
namespace nla {
|
||||
|
||||
typedef lp::lconstraint_kind llc;
|
||||
struct point {
|
||||
rational x;
|
||||
rational y;
|
||||
point(const rational& a, const rational& b): x(a), y(b) {}
|
||||
point() {}
|
||||
point& operator*=(rational a) {
|
||||
x *= a;
|
||||
y *= a;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
point operator+(const point& a, const point& b) {
|
||||
return point(a.x + b.x, a.y + b.y);
|
||||
}
|
||||
|
||||
point operator-(const point& a, const point& b) {
|
||||
return point(a.x - b.x, a.y - b.y);
|
||||
}
|
||||
|
||||
struct solver::imp {
|
||||
|
||||
struct bfc {
|
||||
lpvar m_x, m_y;
|
||||
bfc() {}
|
||||
|
@ -273,13 +291,13 @@ struct solver::imp {
|
|||
return out;
|
||||
}
|
||||
|
||||
std::ostream& print_tang_corner(const rational &a, const rational &b, std::ostream& out) const {
|
||||
out << "(" << a << ", " << b << ")";
|
||||
std::ostream& print_point(const point &a, std::ostream& out) const {
|
||||
out << "(" << a.x << ", " << a.y << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& print_tangent_domain(const rational &a, const rational &b, const rational &c, const rational &d, std::ostream& out) const {
|
||||
out << "("; print_tang_corner(a, b, out); out << ", "; print_tang_corner(c, d, out); out << ")";
|
||||
std::ostream& print_tangent_domain(const point &a, const point &b, std::ostream& out) const {
|
||||
out << "("; print_point(a, out); out << ", "; print_point(b, out); out << ")";
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -1866,37 +1884,83 @@ struct solver::imp {
|
|||
}
|
||||
|
||||
void tangent_lemma_bf(const bfc& bf, lpvar j, const rational& sign){
|
||||
rational a, b, c, d;
|
||||
bool below = vvr(j) * sign < vvr(bf.m_x) * vvr(bf.m_y);
|
||||
get_tang_domain(a, b, c, d, bf, below);
|
||||
TRACE("nla_solver", tout << "below = " << below << ", tang domain = "; print_tangent_domain(a, b, c, d, tout); tout << std::endl;);
|
||||
point a, b;
|
||||
point xy (vvr(bf.m_x), vvr(bf.m_y));
|
||||
rational correct_mult_val = xy.x * xy.y;
|
||||
rational val = vvr(j) * sign;
|
||||
bool below = val < correct_mult_val;
|
||||
TRACE("nla_solver", tout << "below = " << below << std::endl;);
|
||||
get_tang_points(a, b, below, val, xy);
|
||||
TRACE("nla_solver", tout << "tang domain = "; print_tangent_domain(a, b, tout); tout << std::endl;);
|
||||
SASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
void get_initial_tang_domain(rational &a, rational &b, rational &c, rational &d, const bfc& bf, bool below) const {
|
||||
rational x = vvr(bf.m_x);
|
||||
rational y = vvr(bf.m_y);
|
||||
if (below){
|
||||
a = x - rational(1);
|
||||
b = y + rational(1);
|
||||
c = x + rational(1);
|
||||
d = y - rational(1);
|
||||
// There are two planes tangent to surface z = xy at points a and b
|
||||
// One can show that these planes still create a cut
|
||||
void get_initial_tang_points(point &a, point &b, const point& xy,
|
||||
bool below) const {
|
||||
const rational& x = xy.x;
|
||||
const rational& y = xy.y;
|
||||
if (!below){
|
||||
a = point(x - rational(1), y + rational(1));
|
||||
b = point(x + rational(1), y - rational(1));
|
||||
}
|
||||
else {
|
||||
a = x - rational(1);
|
||||
b = y - rational(1);
|
||||
c = x + rational(1);
|
||||
d = y + rational(1);
|
||||
a = point(x - rational(1), y - rational(1));
|
||||
b = point(x + rational(1), y + rational(1));
|
||||
}
|
||||
}
|
||||
|
||||
void extend_tang_domain(rational &a, rational &b, rational &c, rational &d, const bfc& bf, bool below) const {
|
||||
void push_tang_point(point &a, const point& xy, bool below, const rational& correct_val, const rational& val) const {
|
||||
SASSERT(correct_val == xy.x * xy.y);
|
||||
int steps = 10;
|
||||
point del = a - xy;
|
||||
while (steps--) {
|
||||
del *= rational(2);
|
||||
point na = xy + del;
|
||||
TRACE("nla_solver", tout << "del = "; print_point(del, tout); tout << std::endl;);
|
||||
if (!plane_is_correct_cut(na, xy, correct_val, val, below)) {
|
||||
TRACE("nla_solver", tout << "exit";tout << std::endl;);
|
||||
return;
|
||||
}
|
||||
a = na;
|
||||
}
|
||||
}
|
||||
|
||||
void get_tang_domain(rational &a, rational &b, rational &c, rational &d, const bfc& bf, bool below) const {
|
||||
get_initial_tang_domain(a, b, c, d, bf, below);
|
||||
extend_tang_domain(a, b, c, d, bf, below);
|
||||
void push_tang_points(point &a, point &b, const point& xy, bool below, const rational& correct_val, const rational& val) const {
|
||||
push_tang_point(a, xy, below, correct_val, val);
|
||||
push_tang_point(b, xy, below, correct_val, val);
|
||||
}
|
||||
|
||||
rational tang_plane(const point& a, const point& x) const {
|
||||
return a.x * x.y + a.y * x.x - a.x * a.y;
|
||||
}
|
||||
|
||||
bool plane_is_correct_cut(const point& plane,
|
||||
const point& xy,
|
||||
const rational & correct_val,
|
||||
const rational & val,
|
||||
bool below) const {
|
||||
SASSERT(correct_val == xy.x * xy.y);
|
||||
if (below && val > correct_val) return false;
|
||||
rational sign = below? rational(1) : rational(-1);
|
||||
rational px = tang_plane(plane, xy);
|
||||
return ((correct_val - px)*sign).is_pos() && !((px - val)*sign).is_neg();
|
||||
|
||||
}
|
||||
|
||||
// "below" means that the val is below the surface xy
|
||||
void get_tang_points(point &a, point &b, bool below, const rational& val,
|
||||
const point& xy) const {
|
||||
get_initial_tang_points(a, b, xy, below);
|
||||
auto correct_val = xy.x * xy.y;
|
||||
TRACE("nla_solver", tout << "xy = "; print_point(xy, tout); tout << ", correct val = " << xy.x * xy.y;
|
||||
tout << "\ntang points:"; print_tangent_domain(a, b, tout);tout << std::endl;);
|
||||
TRACE("nla_solver", tout << "tang_plane(a, xy) = " << tang_plane(a, xy) << " , val = " << val;
|
||||
tout << "\ntang_plane(b, xy) = " << tang_plane(b, xy); tout << std::endl;);
|
||||
SASSERT(plane_is_correct_cut(a, xy, correct_val, val, below));
|
||||
SASSERT(plane_is_correct_cut(b, xy, correct_val, val, below));
|
||||
push_tang_points(a, b, xy, below, correct_val, val);
|
||||
TRACE("nla_solver", tout << "pushed a = "; print_point(a, tout); tout << "\npushed b = "; print_point(b, tout); tout << std::endl;);
|
||||
}
|
||||
|
||||
lbool check(vector<lp::explanation> & expl_vec, vector<lemma>& l_vec) {
|
||||
|
@ -2741,7 +2805,7 @@ void solver::test_tangent_lemma() {
|
|||
vec.push_back(lp_b);
|
||||
int mon_ab = nla.add_monomial(lp_ab, vec.size(), vec.begin());
|
||||
|
||||
s.set_column_value(lp_ab, nla.m_imp->mon_value_by_vars(mon_ab) + rational(1)); // greater by one than the correct value
|
||||
s.set_column_value(lp_ab, nla.m_imp->mon_value_by_vars(mon_ab) + rational(10)); // greater by ten than the correct value
|
||||
vector<lemma> lemma;
|
||||
vector<lp::explanation> exp;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue