mirror of
https://github.com/Z3Prover/z3
synced 2025-04-08 18:31:49 +00:00
307 lines
9.7 KiB
C++
307 lines
9.7 KiB
C++
/*++
|
|
Copyright (c) 2012 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nlsat.cpp
|
|
|
|
Abstract:
|
|
|
|
nlsat procedure
|
|
|
|
Author:
|
|
|
|
Leonardo (leonardo) 2012-01-09
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
#include"nlsat_assignment.h"
|
|
#include"nlsat_interval_set.h"
|
|
#include"nlsat_evaluator.h"
|
|
#include"nlsat_solver.h"
|
|
#include"util.h"
|
|
|
|
nlsat::interval_set_ref tst_interval(nlsat::interval_set_ref const & s1,
|
|
nlsat::interval_set_ref const & s2,
|
|
unsigned expected_num_intervals,
|
|
bool check_num_intervals = true) {
|
|
nlsat::interval_set_manager & ism = s1.m();
|
|
nlsat::interval_set_ref r(ism);
|
|
std::cout << "------------------\n";
|
|
std::cout << "s1: " << s1 << "\n";
|
|
std::cout << "s2: " << s2 << "\n";
|
|
r = ism.mk_union(s1, s2);
|
|
std::cout << "union(s1, s2): " << r << std::endl;
|
|
SASSERT(!check_num_intervals || ism.num_intervals(r) == expected_num_intervals);
|
|
SASSERT(ism.subset(s1, r));
|
|
SASSERT(ism.subset(s2, r));
|
|
if (ism.set_eq(s1, s2)) {
|
|
SASSERT(ism.set_eq(s1, r));
|
|
SASSERT(ism.set_eq(s2, r));
|
|
}
|
|
else {
|
|
SASSERT(ism.subset(s1, s2) || !ism.subset(r, s2));
|
|
SASSERT(ism.subset(s2, s1) || !ism.subset(r, s1));
|
|
}
|
|
nlsat::interval_set_ref r2(ism);
|
|
r2 = ism.mk_union(s2, s1);
|
|
SASSERT(ism.set_eq(r, r2));
|
|
anum zero;
|
|
nlsat::interval_set_ref full(ism);
|
|
nlsat::literal dummy(131, false);
|
|
full = ism.mk(true, true, zero, true, true, zero, dummy);
|
|
SASSERT(ism.set_eq(r, full) == ism.is_full(r));
|
|
return r;
|
|
}
|
|
|
|
static void tst3() {
|
|
enable_trace("nlsat_interval");
|
|
unsynch_mpq_manager qm;
|
|
anum_manager am(qm);
|
|
small_object_allocator allocator;
|
|
nlsat::interval_set_manager ism(am, allocator);
|
|
|
|
scoped_anum sqrt2(am), m_sqrt2(am), two(am), m_two(am), three(am), one(am), zero(am);
|
|
am.set(two, 2);
|
|
am.set(m_two, -2);
|
|
am.set(one, 1);
|
|
am.root(two, 2, sqrt2);
|
|
am.set(m_sqrt2, sqrt2);
|
|
am.neg(m_sqrt2);
|
|
am.set(three, 3);
|
|
|
|
nlsat::literal p1(1, false);
|
|
nlsat::literal p2(2, false);
|
|
nlsat::literal p3(3, false);
|
|
nlsat::literal p4(4, false);
|
|
nlsat::literal np2(2, true);
|
|
|
|
nlsat::interval_set_ref s1(ism), s2(ism), s3(ism), s4(ism);
|
|
s1 = ism.mk_empty();
|
|
std::cout << "s1: " << s1 << "\n";
|
|
s2 = ism.mk(true, true, zero, false, false, sqrt2, np2);
|
|
std::cout << "s2: " << s2 << "\n";
|
|
s3 = ism.mk(false, false, zero, false, false, two, p1);
|
|
std::cout << "s3: " << s3 << "\n";
|
|
s4 = ism.mk_union(s2, s3);
|
|
std::cout << "s4: " << s4 << "\n";
|
|
|
|
// Case
|
|
// s1: [ ... ]
|
|
// s2: [ ... ]
|
|
s1 = ism.mk(false, false, zero, false, false, two, p1);
|
|
s2 = ism.mk(false, false, zero, false, false, two, p2);
|
|
tst_interval(s1, s2, 1);
|
|
|
|
// Case
|
|
// s1: [ ... ]
|
|
// s2: [ ... ]
|
|
s1 = ism.mk(false, false, zero, false, false, two, p1);
|
|
s2 = ism.mk(false, false, m_sqrt2, false, false, one, p2);
|
|
s3 = ism.mk_union(s1, s2);
|
|
tst_interval(s1, s2, 2);
|
|
|
|
// Case
|
|
// s1: [ ... ]
|
|
// s2: [ ... ]
|
|
s1 = ism.mk(false, false, m_sqrt2, false, false, one, p1);
|
|
s2 = ism.mk(false, false, zero, false, false, two, p2);
|
|
tst_interval(s1, s2, 2);
|
|
|
|
// Case
|
|
// s1: [ ... ]
|
|
// s2: [ ... ]
|
|
s1 = ism.mk(false, false, m_sqrt2, false, false, one, p1);
|
|
s2 = ism.mk(false, false, two, false, false, three, p2);
|
|
tst_interval(s1, s2, 2);
|
|
|
|
// Case
|
|
// s1: [ ... ]
|
|
// s2: [ ... ]
|
|
s1 = ism.mk(false, false, m_sqrt2, false, false, three, p1);
|
|
s2 = ism.mk(false, false, zero, false, false, two, p2);
|
|
tst_interval(s1, s2, 1);
|
|
|
|
// Case
|
|
// s1: [ ... ]
|
|
// s2: [ ... ] [ ... ]
|
|
s1 = ism.mk(false, false, m_two, false, false, two, p1);
|
|
s2 = ism.mk(false, false, m_sqrt2, false, false, zero, p2);
|
|
s3 = ism.mk(false, false, one, false, false, three, p2);
|
|
s2 = ism.mk_union(s2, s3);
|
|
tst_interval(s1, s2, 2);
|
|
|
|
// Case
|
|
// s1: [ ... ]
|
|
// s2: [ ... ]
|
|
s1 = ism.mk(false, false, m_two, false, false, two, p1);
|
|
s2 = ism.mk(false, false, two, false, false, three, p2);
|
|
tst_interval(s1, s2, 2);
|
|
s2 = ism.mk(true, false, two, false, false, three, p2);
|
|
tst_interval(s1, s2, 2);
|
|
s2 = ism.mk(true, false, two, false, false, three, p1);
|
|
tst_interval(s1, s2, 1);
|
|
s1 = ism.mk(false, false, m_two, true, false, two, p1);
|
|
tst_interval(s1, s2, 2);
|
|
s1 = ism.mk(false, false, two, false, false, two, p1);
|
|
s2 = ism.mk(false, false, two, false, false, three, p2);
|
|
tst_interval(s1, s2, 1);
|
|
|
|
// Case
|
|
// s1: [ ... ] [ ... ]
|
|
// s2: [ .. ] [ ... ] [ ... ]
|
|
s1 = ism.mk(false, false, m_two, false, false, zero, p1);
|
|
s3 = ism.mk(false, false, one, false, false, three, p1);
|
|
s1 = ism.mk_union(s1, s3);
|
|
s2 = ism.mk(true, true, zero, false, false, m_sqrt2, p2);
|
|
tst_interval(s1, s2, 3);
|
|
s3 = ism.mk(false, false, one, false, false, sqrt2, p2);
|
|
s2 = ism.mk_union(s2, s3);
|
|
s3 = ism.mk(false, false, two, true, true, zero, p2);
|
|
s2 = ism.mk_union(s2, s3);
|
|
tst_interval(s1, s2, 4);
|
|
|
|
// Case
|
|
s1 = ism.mk(true, true, zero, false, false, one, p1);
|
|
s2 = ism.mk(true, false, one, true, true, zero, p2);
|
|
tst_interval(s1, s2, 2);
|
|
s2 = ism.mk(true, false, one, false, false, two, p2);
|
|
s3 = ism.mk(false, false, two, true, true, zero, p1);
|
|
s2 = ism.mk_union(s2, s3);
|
|
tst_interval(s1, s2, 3);
|
|
}
|
|
|
|
static nlsat::interval_set_ref mk_random(nlsat::interval_set_manager & ism, anum_manager & am, int range, int space, int tries, bool minus_inf, bool plus_inf,
|
|
nlsat::literal lit) {
|
|
static random_gen gen;
|
|
SASSERT(range > 0);
|
|
SASSERT(space > 0);
|
|
nlsat::interval_set_ref r(ism), curr(ism);
|
|
scoped_anum lower(am);
|
|
scoped_anum upper(am);
|
|
int prev = -range + (gen() % (space*4));
|
|
|
|
if (gen() % 3 == 0 && minus_inf) {
|
|
int next = prev + (gen() % space);
|
|
bool open = gen() % 2 == 0;
|
|
am.set(upper, next);
|
|
r = ism.mk(true, true, lower, open, false, upper, lit);
|
|
prev = next;
|
|
}
|
|
|
|
for (int i = 0; i < tries; i++) {
|
|
int l = prev + (gen() % space);
|
|
int u = l + (gen() % space);
|
|
bool lower_open = gen() % 2 == 0;
|
|
bool upper_open = gen() % 2 == 0;
|
|
if ((lower_open || upper_open) && l == u)
|
|
u++;
|
|
am.set(lower, l);
|
|
am.set(upper, u);
|
|
curr = ism.mk(lower_open, false, lower, upper_open, false, upper, lit);
|
|
r = ism.mk_union(r, curr);
|
|
prev = u;
|
|
}
|
|
|
|
if (gen() % 3 == 0 && plus_inf) {
|
|
int next = prev + (gen() % space);
|
|
bool open = gen() % 2 == 0;
|
|
am.set(lower, next);
|
|
curr = ism.mk(open, false, lower, true, true, upper, lit);
|
|
r = ism.mk_union(r, curr);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static void check_subset_result(nlsat::interval_set_ref const & s1,
|
|
nlsat::interval_set_ref const & s2,
|
|
nlsat::interval_set_ref const & r,
|
|
nlsat::literal l1,
|
|
nlsat::literal l2) {
|
|
nlsat::interval_set_manager ism(s1.m());
|
|
nlsat::interval_set_ref tmp(ism);
|
|
unsigned num = ism.num_intervals(r);
|
|
nlsat::literal_vector lits;
|
|
ism.get_justifications(r, lits);
|
|
SASSERT(lits.size() <= 2);
|
|
for (unsigned i = 0; i < num; i++) {
|
|
tmp = ism.get_interval(r, i);
|
|
ism.get_justifications(tmp, lits);
|
|
SASSERT(lits.size() == 1);
|
|
if (lits[0] == l1) {
|
|
SASSERT(ism.subset(tmp, s1));
|
|
}
|
|
else {
|
|
SASSERT(lits[0] == l2);
|
|
SASSERT(ism.subset(tmp, s2));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void tst4() {
|
|
enable_trace("nlsat_interval");
|
|
unsynch_mpq_manager qm;
|
|
anum_manager am(qm);
|
|
small_object_allocator allocator;
|
|
nlsat::interval_set_manager ism(am, allocator);
|
|
nlsat::interval_set_ref s1(ism), s2(ism), r(ism);
|
|
|
|
nlsat::literal l1(1, false);
|
|
nlsat::literal l2(2, false);
|
|
|
|
for (unsigned i = 0; i < 100; i++) {
|
|
s1 = mk_random(ism, am, 20, 3, 10, true, true, l1);
|
|
s2 = mk_random(ism, am, 20, 3, 10, true, true, l2);
|
|
r = tst_interval(s1, s2, 0, false);
|
|
check_subset_result(s1, s2, r, l1, l2);
|
|
}
|
|
|
|
for (unsigned i = 0; i < 100; i++) {
|
|
s1 = mk_random(ism, am, 200, 100, 20, true, true, l1);
|
|
s2 = mk_random(ism, am, 200, 100, 20, true, true, l2);
|
|
r = tst_interval(s1, s2, 0, false);
|
|
check_subset_result(s1, s2, r, l1, l2);
|
|
}
|
|
}
|
|
|
|
static void tst5() {
|
|
params_ref ps;
|
|
nlsat::solver s(ps);
|
|
unsynch_mpq_manager & qm = s.qm();
|
|
anum_manager & am = s.am();
|
|
nlsat::pmanager & pm = s.pm();
|
|
nlsat::assignment as(am);
|
|
small_object_allocator allocator;
|
|
nlsat::interval_set_manager ism(am, allocator);
|
|
nlsat::evaluator ev(as, pm, allocator);
|
|
nlsat::var x0, x1;
|
|
x0 = pm.mk_var();
|
|
x1 = pm.mk_var();
|
|
polynomial_ref p(pm);
|
|
polynomial_ref _x0(pm), _x1(pm);
|
|
_x0 = pm.mk_polynomial(x0);
|
|
_x1 = pm.mk_polynomial(x1);
|
|
p = (_x0^2) + (_x1^2) - 2;
|
|
nlsat::poly * _p[1] = { p.get() };
|
|
bool is_even[1] = { false };
|
|
nlsat::bool_var b = s.mk_ineq_atom(nlsat::atom::GT, 1, _p, is_even);
|
|
nlsat::atom * a = s.bool_var2atom(b);
|
|
SASSERT(a != 0);
|
|
nlsat::interval_set_ref i(ism);
|
|
scoped_anum zero(am);
|
|
am.set(zero, 0);
|
|
as.set(0, zero);
|
|
i = ev.infeasible_intervals(a, true);
|
|
std::cout << "1) " << i << "\n";
|
|
as.set(1, zero);
|
|
i = ev.infeasible_intervals(a, true);
|
|
std::cout << "2) " << i << "\n";
|
|
}
|
|
|
|
void tst_nlsat() {
|
|
tst5();
|
|
tst4();
|
|
tst3();
|
|
}
|