3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-06-22 00:20:27 +00:00

Merge branch 'master' into c3

This commit is contained in:
CEisenhofer 2026-06-03 17:33:26 +02:00
commit 043c6c0ad1
259 changed files with 18907 additions and 3725 deletions

View file

@ -89,6 +89,7 @@ add_executable(test-z3
memory.cpp
model2expr.cpp
model_based_opt.cpp
mod_factor.cpp
model_evaluator.cpp
model_retrieval.cpp
monomial_bounds.cpp
@ -116,6 +117,7 @@ add_executable(test-z3
prime_generator.cpp
proof_checker.cpp
qe_arith.cpp
mbp_qel.cpp
quant_elim.cpp
quant_solve.cpp
random.cpp
@ -151,6 +153,7 @@ add_executable(test-z3
theory_dl.cpp
theory_pb.cpp
timeout.cpp
tptp.cpp
total_order.cpp
totalizer.cpp
trigo.cpp
@ -169,12 +172,11 @@ add_executable(test-z3
z3_add_install_tactic_rule(${z3_test_deps})
z3_add_memory_initializer_rule(${z3_test_deps})
z3_add_gparams_register_modules_rule(${z3_test_deps})
target_compile_definitions(test-z3 PRIVATE ${Z3_COMPONENT_CXX_DEFINES})
target_compile_definitions(test-z3 PRIVATE
${Z3_COMPONENT_CXX_DEFINES}
)
target_compile_options(test-z3 PRIVATE ${Z3_COMPONENT_CXX_FLAGS})
target_link_libraries(test-z3 PRIVATE ${Z3_DEPENDENT_LIBS})
target_include_directories(test-z3 PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS})
z3_append_linker_flag_list_to_target(test-z3 ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
z3_add_component_dependencies_to_target(test-z3 ${z3_test_expanded_deps})

View file

@ -104,6 +104,48 @@ void test_algebraic_comparison() {
VERIFY(!am.eq(a, b)); // 2 != 3
}
void test_algebraic_comparison_edge_case() {
std::cout << "test_algebraic_comparison edge case\n";
// Let p1 = 1073741837 x^2 - 576460758745874510 x - 16106127555
// Let p2 = p1 * (1073741837 x^2 - 576460759819616347 x -16106127555)
// = 1152921532524134569 x^4 - 1237940069261339757601884309 x^3
// + 332307006992839334837849081482577900 x^2 + 18569101038920096364028264635 x
// + 259407344817930278025
// Compare a = root(p1, 1) in (-8, 0) and b = root(p2, 2) in (-15/2^29, -7/2^28)
// The two numbers are different (a < b), but very close, and both are roots of p2
reslimit rl;
unsynch_mpq_manager qm;
anum_manager am(rl, qm);
manager m(rl, qm);
polynomial_ref x(m);
x = m.mk_polynomial(m.mk_var());
rational a0, a1, a2;
a0 = 161061;
a0 = (a0 * 100000) + 27555;
a1 = 576460758;
a1 = (a1 * 1000000000) + 745874510;
a2 = 10737;
a2 = (a2 * 100000) + 41837;
rational b1;
b1 = 576460759;
b1 = (b1 * 1000000000) + 819616347;
polynomial_ref p1(m);
polynomial_ref p2(m);
p1 = ((a2*x*x) - (a1*x)) - a0;
p2 = p1 * (((a2*x*x) - (b1*x)) - a0);
scoped_anum a(am), b(am);
am.mk_root(p1, 1, a);
am.mk_root(p2, 2, b);
VERIFY(!am.eq(a, b));
}
void test_algebraic_degree() {
std::cout << "test_algebraic_degree\n";
@ -158,6 +200,7 @@ void test_algebraic_numbers() {
test_algebraic_basic_operations();
test_algebraic_arithmetic();
test_algebraic_comparison();
test_algebraic_comparison_edge_case();
test_algebraic_degree();
test_algebraic_signs();
}

View file

@ -248,6 +248,7 @@ void test_max_reg() {
Z3_optimize_dec_ref(ctx, opt);
}
#if 0
// Approach 3: Weighted sum method (Python loop over weights)
int weights[][2] = {{1, 4}, {2, 3}, {1, 1}, {3, 2}, {4, 1}};
for (auto& w : weights) {
@ -271,9 +272,10 @@ void test_max_reg() {
}
Z3_optimize_dec_ref(ctx, opt);
}
#endif
std::cout << "BNH: " << num_sat << "/7 optimizations returned sat" << std::endl;
ENSURE(num_sat == 7);
std::cout << "BNH: " << num_sat << "/2 optimizations returned sat" << std::endl;
ENSURE(num_sat == 2);
Z3_del_context(ctx);
std::cout << "BNH optimization test done" << std::endl;
}

View file

@ -64,5 +64,31 @@ void tst_api_datalog() {
Z3_fixedpoint_dec_ref(ctx, fp);
}
// Regression test for Spacer model construction on ADT CHCs
{
char const* chc =
"(set-logic HORN)\n"
"(set-option :fp.engine spacer)\n"
"(set-option :fp.spacer.random_seed 51)\n"
"(set-option :timeout 2000)\n"
"(declare-datatypes ((L 0)) (((cons (hd Int) (tl L)) (nil))))\n"
"(declare-fun reva (L L L) Bool)\n"
"(assert (forall ((a L)) (reva nil a a)))\n"
"(assert (forall ((x L) (acc L) (r L) (h Int))\n"
" (=> (reva x (cons h acc) r)\n"
" (reva (cons h x) acc r))))\n"
"(assert (forall ((B L) (C L) (D L) (E L) (F L))\n"
" (=> (and (reva B C D)\n"
" (reva D nil E)\n"
" (reva C B F)\n"
" (not (= E F)))\n"
" false)))\n"
"(check-sat)\n";
Z3_string response = Z3_eval_smtlib2_string(ctx, chc);
ENSURE(response != nullptr);
ENSURE(Z3_get_error_code(ctx) == Z3_OK);
}
Z3_del_context(ctx);
}
}

View file

@ -23,10 +23,13 @@ static void test_table(mk_table_fn mk_table) {
sig.push_back(8);
sig.push_back(4);
smt_params params;
params_ref fp_params;
gparams::set("fp.engine", "datalog");
// fp_params.set_sym("fp.engine", symbol("datalog"));
ast_manager ast_m;
reg_decl_plugins(ast_m);
datalog::register_engine re;
datalog::context ctx(ast_m, re, params);
datalog::context ctx(ast_m, re, params, fp_params);
datalog::relation_manager & m = ctx.get_rel_context()->get_rmanager();
m.register_plugin(alloc(datalog::bitvector_table_plugin, m));
@ -48,13 +51,10 @@ static void test_table(mk_table_fn mk_table) {
table.add_fact(row2);
table.display(std::cout);
datalog::table_base::iterator it = table.begin();
datalog::table_base::iterator end = table.end();
for (; it != end; ++it) {
it->get_fact(row);
for (unsigned j = 0; j < row.size(); ++j) {
std::cout << row[j] << " ";
}
for (auto &r : table) {
r.get_fact(row);
for (auto v : row)
std::cout << v << " ";
std::cout << "\n";
}

View file

@ -4,6 +4,7 @@ Copyright (c) 2015 Microsoft Corporation
--*/
#include "util/gparams.h"
#include "muz/base/dl_util.h"
using namespace datalog;
@ -49,6 +50,7 @@ void dl_util_cycle_from_permutation() {
}
void tst_dl_util() {
gparams::set("fp.engine", "datalog");
dl_util_two_array_sort();
dl_util_cycle_from_permutation();
}

View file

@ -436,7 +436,7 @@ public:
//sub:{xxx \ {1x0, 0x1}}
//result:{100}
for (unsigned i = 0; i < 1000; ++i) {
for (unsigned i = 0; i < 100; ++i) {
udoc d1, d2;
mk_rand_udoc(3, 3, d1);
mk_rand_udoc(3, 3, d2);
@ -453,7 +453,7 @@ public:
void test_intersect() {
expr_ref fml1(m), fml2(m), fml3(m);
for (unsigned i = 0; i < 10000; ++i) {
for (unsigned i = 0; i < 100; ++i) {
udoc d1, d2;
mk_rand_udoc(3, 3, d1);
mk_rand_udoc(3, 3, d2);

View file

@ -60,6 +60,43 @@ static void test_fp_to_real_denormal() {
true);
}
// Regression test for soundness bug in to_fp (from real) with symbolic real interval.
// When the rounding mode is RTZ and the real variable is constrained to an interval
// that includes the exact rational value of a float, Z3 should return SAT.
// This was broken because mk_to_real computed 2^(1/|exp|) instead of 1/(2^|exp|)
// for floats with negative exponents, causing a conflict in the NRA solver.
static void test_to_fp_from_real_interval() {
// The interval (-4127125/16777216, -16508499/67108864] contains -16508499/67108864
// which is the exact rational value of fp #b1 #b01111100 #b11110111110011001010011.
// to_fp(RTZ, r) for r in this closed interval must equal that float.
run_fp_test(
"(set-logic QF_FPLRA)\n"
"(declare-const x Float32)\n"
"(assert (= x (fp #b1 #b01111100 #b11110111110011001010011)))\n"
"(declare-const r Real)\n"
"(assert (and (> r (- (/ 4127125.0 16777216.0))) (<= r (- (/ 16508499.0 67108864.0)))))\n"
"(declare-const w Float32)\n"
"(assert (= w ((_ to_fp 8 24) RTZ r)))\n"
"(assert (= x w))\n"
"(check-sat)\n",
true);
}
static void test_recfun_defined_function_soundness() {
run_fp_test(
"(set-option :model_validate true)\n"
"(declare-fun fixedAdd () Int)\n"
"(declare-fun variableAdd () Int)\n"
"(define-fun-rec $$add$$ ((a Int) (b Int)) Int\n"
" (ite (= 0 b) 2 (- a (+ 0 (- fixedAdd b)))))\n"
"(assert (= fixedAdd (* 9 fixedAdd)))\n"
"(assert (= 1 ($$add$$ 1 3)))\n"
"(check-sat)\n",
false);
}
void tst_fpa() {
test_fp_to_real_denormal();
test_to_fp_from_real_interval();
test_recfun_defined_function_soundness();
}

View file

@ -1971,28 +1971,28 @@ void test_lp_local(int argn, char **argv) {
if (args_parser.option_is_used("-nla_blfmz_mf")) {
#ifdef Z3DEBUG
nla::test_basic_lemma_for_mon_zero_from_monomial_to_factors();
// nla::test_basic_lemma_for_mon_zero_from_monomial_to_factors();
#endif
return finalize(0);
}
if (args_parser.option_is_used("-nla_blfmz_fm")) {
#ifdef Z3DEBUG
nla::test_basic_lemma_for_mon_zero_from_factors_to_monomial();
//nla::test_basic_lemma_for_mon_zero_from_factors_to_monomial();
#endif
return finalize(0);
}
if (args_parser.option_is_used("-nla_blnt_mf")) {
#ifdef Z3DEBUG
nla::test_basic_lemma_for_mon_neutral_from_monomial_to_factors();
// nla::test_basic_lemma_for_mon_neutral_from_monomial_to_factors();
#endif
return finalize(0);
}
if (args_parser.option_is_used("-nla_blnt_fm")) {
#ifdef Z3DEBUG
nla::test_basic_lemma_for_mon_neutral_from_factors_to_monomial();
// nla::test_basic_lemma_for_mon_neutral_from_factors_to_monomial();
#endif
return finalize(0);
}

View file

@ -150,7 +150,7 @@ void create_abcde(solver & nla,
nla.add_monic(lp_be, vec.size(), vec.begin());
}
#if 0
void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() {
std::cout << "test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0\n";
enable_trace("nla_solver");
@ -222,6 +222,7 @@ void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_0() {
}
#endif
void s_set_column_value_test(lp::lar_solver&s, lpvar j, const rational & v) {
s.set_column_value_test(j, lp::impq(v));
@ -231,6 +232,7 @@ void s_set_column_value_test(lp::lar_solver&s, lpvar j, const lp::impq & v) {
s.set_column_value_test(j, v);
}
#if 0
void test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1() {
std::cout << "test_basic_lemma_for_mon_neutral_from_factors_to_monomial_1\n";
TRACE(nla_solver,);
@ -367,6 +369,7 @@ void test_basic_lemma_for_mon_zero_from_factors_to_monomial() {
VERIFY(found0 && found1);
}
void test_basic_lemma_for_mon_zero_from_monomial_to_factors() {
std::cout << "test_basic_lemma_for_mon_zero_from_monomial_to_factors\n";
enable_trace("nla_solver");
@ -420,6 +423,7 @@ void test_basic_lemma_for_mon_zero_from_monomial_to_factors() {
}
void test_basic_lemma_for_mon_neutral_from_monomial_to_factors() {
std::cout << "test_basic_lemma_for_mon_neutral_from_monomial_to_factors\n";
enable_trace("nla_solver");
@ -489,6 +493,7 @@ void test_basic_lemma_for_mon_neutral_from_monomial_to_factors() {
VERIFY(found0 && found1);
}
#endif
void test_horner() {
enable_trace("nla_solver");

View file

@ -154,6 +154,7 @@
X(hilbert_basis) \
X(heap_trie) \
X(karr) \
X(mod_factor) \
X(no_overflow) \
X(datalog_parser) \
X_ARGV(datalog_parser_file) \
@ -162,6 +163,7 @@
X(rcf) \
X(polynorm) \
X(qe_arith) \
X(mbp_qel) \
X(expr_substitution) \
X(sorting_network) \
X(theory_pb) \
@ -539,7 +541,7 @@ int main(int argc, char ** argv) {
}
#ifndef __EMSCRIPTEN__
if (num_jobs > 0)
if (num_jobs > 0 && (test_all || requested_tests.size() > 1))
return run_parallel(argv[0], test_all, num_jobs, extra_args, requested_tests);
#endif

250
src/test/mbp_qel.cpp Normal file
View file

@ -0,0 +1,250 @@
/*++
Copyright (c) 2025 Microsoft Corporation
Module Name:
mbp_qel.cpp
Abstract:
Unit tests for model-based projection with QEL (term-graph based)
Author:
Hari Govind V K (hgvk94) 2025-05-25
--*/
#include "qe/qe_mbp.h"
#include "ast/reg_decl_plugins.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/arith_decl_plugin.h"
#include "ast/ast_pp.h"
#include "smt/smt_context.h"
#include "params/smt_params.h"
#include <iostream>
// Test that MBP with QEL does not return false for a satisfiable formula
// involving datatype accessors applied past the end of a list.
//
// Formula: (and ((_ is cons) x) ((_ is nil) (tl x)) (= nil (tl (tl x))) (< 8 n))
// Project: x
// Expected: result should imply n >= 9 (and model should satisfy it)
// Bug: QEL was returning false because rm_accessor unconditionally
// assumed (tl x) has constructor cons when eliminating (tl (tl x)),
// contradicting the ((_ is nil) (tl x)) literal.
static void test_dt_accessor_past_end() {
std::cout << "test_dt_accessor_past_end\n";
ast_manager m;
reg_decl_plugins(m);
datatype_util dt(m);
arith_util a(m);
// Create list datatype: (declare-datatypes ((L 0)) (((cons (hd Int) (tl L)) (nil))))
sort_ref int_sort(a.mk_int(), m);
func_decl_ref cons(m), is_cons(m), head(m), tail(m), nil(m), is_nil(m);
sort_ref L = dt.mk_list_datatype(int_sort, symbol("L"),
cons, is_cons, head, tail, nil, is_nil);
// Declare variables
app_ref x(m.mk_const("x", L), m);
app_ref n(m.mk_const("n", int_sort), m);
// Build formula: (and ((_ is cons) x) ((_ is nil) (tl x)) (= nil (tl (tl x))) (< 8 n))
expr_ref tl_x(m.mk_app(tail, x.get()), m);
expr_ref tl_tl_x(m.mk_app(tail, tl_x.get()), m);
expr_ref nil_val(m.mk_const(nil), m);
expr_ref is_cons_x(m.mk_app(is_cons, x.get()), m);
expr_ref is_nil_tl_x(m.mk_app(is_nil, tl_x.get()), m);
expr_ref eq_nil_tl_tl_x(m.mk_eq(nil_val, tl_tl_x), m);
expr_ref lt_8_n(a.mk_lt(a.mk_int(8), n), m);
expr_ref_vector conjs(m);
conjs.push_back(is_cons_x).push_back(is_nil_tl_x).push_back(eq_nil_tl_tl_x).push_back(lt_8_n);
expr_ref fml(m.mk_and(conjs), m);
std::cout << " formula:\n " << mk_pp(fml, m, 5) << "\n";
// Get a model
smt_params params;
params.m_model = true;
model_ref mdl;
{
smt::context ctx(m, params);
ctx.assert_expr(fml);
lbool result = ctx.check();
VERIFY(result == l_true);
ctx.get_model(mdl);
}
std::cout << " model: x = " << mk_pp((*mdl)(x), m)
<< ", n = " << mk_pp((*mdl)(n), m) << "\n";
// Call MBP with QEL enabled
app_ref_vector vars(m);
vars.push_back(x);
params_ref p;
p.set_bool("qsat_use_qel", true);
qe::mbproj mbp(m, p);
expr_ref projected(fml, m);
mbp.spacer(vars, *mdl.get(), projected);
std::cout << " projected (qel=true):\n " << mk_pp(projected, m, 5) << "\n";
// The result must not be false
VERIFY(!m.is_false(projected));
// The model should satisfy the projected formula
VERIFY(mdl->is_true(projected));
// x should have been eliminated
VERIFY(vars.empty());
std::cout << " PASS\n\n";
}
// Same test but with a deeper list structure:
// x is a 2-element list with a past-end accessor constraint
// Formula: (and ((_ is cons) x) ((_ is cons) (tl x)) ((_ is nil) (tl (tl x)))
// (= nil (tl (tl (tl x)))) (< 8 n))
static void test_dt_accessor_past_end_depth2() {
std::cout << "test_dt_accessor_past_end_depth2\n";
ast_manager m;
reg_decl_plugins(m);
datatype_util dt(m);
arith_util a(m);
sort_ref int_sort(a.mk_int(), m);
func_decl_ref cons(m), is_cons(m), head(m), tail(m), nil(m), is_nil(m);
sort_ref L = dt.mk_list_datatype(int_sort, symbol("L"),
cons, is_cons, head, tail, nil, is_nil);
app_ref x(m.mk_const("x", L), m);
app_ref n(m.mk_const("n", int_sort), m);
// Build: (and (is-cons x) (is-cons (tl x)) (is-nil (tl (tl x)))
// (= nil (tl (tl (tl x)))) (< 8 n))
expr_ref tl_x(m.mk_app(tail, x.get()), m);
expr_ref tl_tl_x(m.mk_app(tail, tl_x.get()), m);
expr_ref tl_tl_tl_x(m.mk_app(tail, tl_tl_x.get()), m);
expr_ref nil_val(m.mk_const(nil), m);
expr_ref is_cons_x(m.mk_app(is_cons, x.get()), m);
expr_ref is_cons_tl_x(m.mk_app(is_cons, tl_x.get()), m);
expr_ref is_nil_tl_tl_x(m.mk_app(is_nil, tl_tl_x.get()), m);
expr_ref eq_nil_tl3(m.mk_eq(nil_val, tl_tl_tl_x), m);
expr_ref lt_8_n(a.mk_lt(a.mk_int(8), n), m);
expr_ref_vector conjs(m);
conjs.push_back(is_cons_x).push_back(is_cons_tl_x).push_back(is_nil_tl_tl_x).push_back(eq_nil_tl3).push_back(lt_8_n);
expr_ref fml(m.mk_and(conjs), m);
std::cout << " formula:\n " << mk_pp(fml, m, 5) << "\n";
smt_params sparams;
sparams.m_model = true;
model_ref mdl;
{
smt::context ctx(m, sparams);
ctx.assert_expr(fml);
lbool result = ctx.check();
VERIFY(result == l_true);
ctx.get_model(mdl);
}
std::cout << " model: x = " << mk_pp((*mdl)(x), m)
<< ", n = " << mk_pp((*mdl)(n), m) << "\n";
app_ref_vector vars(m);
vars.push_back(x);
params_ref p;
p.set_bool("qsat_use_qel", true);
qe::mbproj mbp(m, p);
expr_ref projected(fml, m);
mbp.spacer(vars, *mdl.get(), projected);
std::cout << " projected (qel=true):\n " << mk_pp(projected, m, 5) << "\n";
VERIFY(!m.is_false(projected));
VERIFY(mdl->is_true(projected));
VERIFY(vars.empty());
std::cout << " PASS\n\n";
}
// Test with multiple DT variables projected simultaneously
// Formula: (and (= nil (tl (tl (tl x)))) ((_ is nil) (tl (tl x)))
// ((_ is cons) y) ((_ is nil) (tl y)) (< 8 n))
// Project: x, y
static void test_dt_multiple_vars() {
std::cout << "test_dt_multiple_vars\n";
ast_manager m;
reg_decl_plugins(m);
datatype_util dt(m);
arith_util a(m);
sort_ref int_sort(a.mk_int(), m);
func_decl_ref cons(m), is_cons(m), head(m), tail(m), nil(m), is_nil(m);
sort_ref L = dt.mk_list_datatype(int_sort, symbol("L"),
cons, is_cons, head, tail, nil, is_nil);
app_ref x(m.mk_const("x", L), m);
app_ref y(m.mk_const("y", L), m);
app_ref n(m.mk_const("n", int_sort), m);
expr_ref tl_x(m.mk_app(tail, x.get()), m);
expr_ref tl_tl_x(m.mk_app(tail, tl_x.get()), m);
expr_ref tl_tl_tl_x(m.mk_app(tail, tl_tl_x.get()), m);
expr_ref tl_y(m.mk_app(tail, y.get()), m);
expr_ref nil_val(m.mk_const(nil), m);
expr_ref eq_nil_tl3x(m.mk_eq(nil_val, tl_tl_tl_x), m);
expr_ref is_nil_tl2x(m.mk_app(is_nil, tl_tl_x.get()), m);
expr_ref is_cons_y(m.mk_app(is_cons, y.get()), m);
expr_ref is_nil_tl_y(m.mk_app(is_nil, tl_y.get()), m);
expr_ref lt_8_n(a.mk_lt(a.mk_int(8), n), m);
expr_ref_vector conjs(m);
conjs.push_back(eq_nil_tl3x).push_back(is_nil_tl2x).push_back(is_cons_y).push_back(is_nil_tl_y).push_back(lt_8_n);
expr_ref fml(m.mk_and(conjs), m);
std::cout << " formula:\n " << mk_pp(fml, m, 5) << "\n";
smt_params sparams;
sparams.m_model = true;
model_ref mdl;
{
smt::context ctx(m, sparams);
ctx.assert_expr(fml);
lbool result = ctx.check();
VERIFY(result == l_true);
ctx.get_model(mdl);
}
app_ref_vector vars(m);
vars.push_back(x);
vars.push_back(y);
params_ref p;
p.set_bool("qsat_use_qel", true);
qe::mbproj mbp(m, p);
expr_ref projected(fml, m);
mbp.spacer(vars, *mdl.get(), projected);
std::cout << " projected (qel=true):\n " << mk_pp(projected, m, 5) << "\n";
VERIFY(!m.is_false(projected));
VERIFY(mdl->is_true(projected));
std::cout << " PASS\n\n";
}
void tst_mbp_qel() {
test_dt_accessor_past_end();
test_dt_accessor_past_end_depth2();
test_dt_multiple_vars();
}

91
src/test/mod_factor.cpp Normal file
View file

@ -0,0 +1,91 @@
/*++
Copyright (c) 2025 Microsoft Corporation
--*/
#include "api/z3.h"
#include "util/util.h"
#include <string>
// x mod 7 = 0 & (x*y) mod 7 != 0 should be unsat
// Exercises: mod internalization path (is_mod with numeric divisor)
static void test_mod_factor_mod_path() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_solver s = Z3_mk_solver_for_logic(ctx, Z3_mk_string_symbol(ctx, "QF_NIA"));
Z3_solver_inc_ref(ctx, s);
Z3_sort int_sort = Z3_mk_int_sort(ctx);
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), int_sort);
Z3_ast y = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "y"), int_sort);
Z3_ast seven = Z3_mk_int(ctx, 7, int_sort);
Z3_ast zero = Z3_mk_int(ctx, 0, int_sort);
Z3_ast xy_args[] = {x, y};
Z3_ast xy = Z3_mk_mul(ctx, 2, xy_args);
// assert mul term first so ensure_nla() fires before mod internalization
Z3_solver_assert(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, Z3_mk_mod(ctx, xy, seven), zero)));
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, Z3_mk_mod(ctx, x, seven), zero));
ENSURE(Z3_solver_check(ctx, s) == Z3_L_FALSE);
Z3_solver_dec_ref(ctx, s);
Z3_del_config(cfg);
Z3_del_context(ctx);
}
// (x mod 100) mod 7 = 0 => ((x mod 100) * y) mod 7 = 0
// Exercises: idiv internalization path (is_idiv + numeric divisor + bounded dividend)
// because (x mod 100) is recognized as bounded by is_bounded()
static void test_mod_factor_idiv_path() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_solver s = Z3_mk_solver_for_logic(ctx, Z3_mk_string_symbol(ctx, "QF_NIA"));
Z3_solver_inc_ref(ctx, s);
Z3_sort int_sort = Z3_mk_int_sort(ctx);
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), int_sort);
Z3_ast y = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "y"), int_sort);
Z3_ast seven = Z3_mk_int(ctx, 7, int_sort);
Z3_ast zero = Z3_mk_int(ctx, 0, int_sort);
Z3_ast hundred = Z3_mk_int(ctx, 100, int_sort);
// xm = x mod 100 (bounded by is_bounded)
Z3_ast xm = Z3_mk_mod(ctx, x, hundred);
// (xm * y) — assert mul term first so ensure_nla() fires before mod internalization
Z3_ast xm_y_args[] = {xm, y};
Z3_ast xm_y = Z3_mk_mul(ctx, 2, xm_y_args);
Z3_ast xm_y_div = Z3_mk_div(ctx, xm_y, seven);
// assert (xm * y) mod 7 != 0
Z3_solver_assert(ctx, s, Z3_mk_not(ctx, Z3_mk_eq(ctx, Z3_mk_mod(ctx, xm_y, seven), zero)));
// use div to keep it alive
Z3_solver_assert(ctx, s, Z3_mk_ge(ctx, xm_y_div, zero));
// xm mod 7 = 0
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, Z3_mk_mod(ctx, xm, seven), zero));
ENSURE(Z3_solver_check(ctx, s) == Z3_L_FALSE);
Z3_solver_dec_ref(ctx, s);
Z3_del_config(cfg);
Z3_del_context(ctx);
}
static void test_const_array_store_chain_unsat() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
const char* script = R"(
(set-logic QF_ABV)
(declare-const x (_ BitVec 8))
(declare-const y (_ BitVec 8))
(define-fun A0 () (Array (_ BitVec 2) (_ BitVec 8)) ((as const (Array (_ BitVec 2) (_ BitVec 8))) x))
(define-fun A1 () (Array (_ BitVec 2) (_ BitVec 8)) ((as const (Array (_ BitVec 2) (_ BitVec 8))) y))
(declare-const i0 (_ BitVec 2))
(declare-const e0 (_ BitVec 8))
(declare-const i1 (_ BitVec 2))
(declare-const e1 (_ BitVec 8))
(assert (distinct x y))
(assert (= (store A0 i0 e0) (store A1 i1 e1)))
(check-sat)
)";
std::string resp = Z3_eval_smtlib2_string(ctx, script);
ENSURE(resp.find("unsat") != std::string::npos);
Z3_del_config(cfg);
Z3_del_context(ctx);
}
void tst_mod_factor() {
test_mod_factor_mod_path();
test_mod_factor_idiv_path();
test_const_array_store_chain_unsat();
}

View file

@ -207,13 +207,82 @@ void test_nla_intervals_fractional() {
VERIFY(true); // Placeholder
}
void test_fetch_normalized_term_column() {
std::cout << "test_fetch_normalized_term_column\n";
lp::lar_solver s;
// Create some variables
lpvar x = s.add_var(0, true); // j0
lpvar y = s.add_var(1, true); // j1
lpvar z = s.add_var(2, true); // j2
// Add a term t = 2*x + 3*y and register it
lp::lar_term t;
t.add_monomial(rational(2), x);
t.add_monomial(rational(3), y);
s.add_term(t.coeffs_as_vector(), UINT_MAX);
s.register_existing_terms();
// Now build the same term independently and look it up
lp::lar_term query;
query.add_monomial(rational(2), x);
query.add_monomial(rational(3), y);
lp::mpq a;
lp::lar_term norm_query = query.get_normalized_by_min_var(a);
std::pair<lp::mpq, lpvar> result;
bool found = s.fetch_normalized_term_column(norm_query, result);
VERIFY(found);
std::cout << " round-trip lookup: " << (found ? "PASS" : "FAIL") << "\n";
// Build query with variables added in reverse order
lp::lar_term query_rev;
query_rev.add_monomial(rational(3), y);
query_rev.add_monomial(rational(2), x);
lp::lar_term norm_rev = query_rev.get_normalized_by_min_var(a);
bool found_rev = s.fetch_normalized_term_column(norm_rev, result);
VERIFY(found_rev);
std::cout << " reverse-order lookup: " << (found_rev ? "PASS" : "FAIL") << "\n";
// Test a 3-variable term: x - y + 5*z
lp::lar_term t2;
t2.add_monomial(rational(1), x);
t2.add_monomial(rational(-1), y);
t2.add_monomial(rational(5), z);
s.add_term(t2.coeffs_as_vector(), UINT_MAX);
s.register_existing_terms();
lp::lar_term query2;
query2.add_monomial(rational(1), x);
query2.add_monomial(rational(-1), y);
query2.add_monomial(rational(5), z);
lp::lar_term norm2 = query2.get_normalized_by_min_var(a);
found = s.fetch_normalized_term_column(norm2, result);
VERIFY(found);
std::cout << " 3-variable term lookup: " << (found ? "PASS" : "FAIL") << "\n";
// Test that a non-registered term is NOT found
lp::lar_term query3;
query3.add_monomial(rational(7), x);
query3.add_monomial(rational(11), y);
lp::lar_term norm3 = query3.get_normalized_by_min_var(a);
bool found_missing = s.fetch_normalized_term_column(norm3, result);
VERIFY(!found_missing);
std::cout << " non-existent term not found: " << (!found_missing ? "PASS" : "FAIL") << "\n";
}
void test_nla_intervals() {
test_nla_intervals_basic();
test_nla_intervals_negative();
test_nla_intervals_negative();
test_nla_intervals_zero_crossing();
test_nla_intervals_power();
test_nla_intervals_mixed_signs();
test_nla_intervals_fractional();
test_fetch_normalized_term_column();
}
} // namespace nla

View file

@ -6,6 +6,7 @@ Copyright (c) 2015 Microsoft Corporation
#include "api/z3.h"
#include "api/z3_private.h"
#include <cstring>
#include <iostream>
#include "util/util.h"
#include "util/trace.h"
@ -211,6 +212,26 @@ static void test_array() {
Z3_del_context(ctx);
}
static void test_sat_smt_ufbv_predicate_model_validation() {
Z3_context ctx = Z3_mk_context(nullptr);
const char* result =
Z3_eval_smtlib2_string(ctx,
"(set-logic QF_UFBV)\n"
"(set-option :sat.smt true)\n"
"(set-option :model_validate true)\n"
"(declare-fun p ((_ BitVec 4)) Bool)\n"
"(declare-const x (_ BitVec 4))\n"
"(declare-const y (_ BitVec 4))\n"
"(assert (xor (p x) (p y)))\n"
"(assert (bvuge x (_ bv1 4)))\n"
"(assert (bvult y (_ bv1 4)))\n"
"(check-sat)\n"
"(get-model)\n");
ENSURE(std::strstr(result, "sat") != nullptr);
ENSURE(std::strstr(result, "invalid model") == nullptr);
Z3_del_context(ctx);
}
void tst_simplifier() {
test_array();
@ -218,4 +239,5 @@ void tst_simplifier() {
test_datatypes();
test_bool();
test_skolemize_bug();
test_sat_smt_ufbv_predicate_model_validation();
}

View file

@ -160,6 +160,39 @@ void test_repeated_eval() {
Z3_del_context(ctx);
}
void test_ho_curried_application() {
char const* spec =
"(set-logic HO_ALL)\n"
"(declare-fun transfer () (-> (-> Int Bool) (-> Int Bool)))\n"
"(assert (forall ((P (-> Int Bool))) (=> (P 0) ((transfer P) 0))))\n"
"(declare-fun top () (-> Int Bool))\n"
"(assert (forall ((x Int)) (top x)))\n"
"(assert (not ((transfer top) 0)))\n"
"(check-sat)\n";
Z3_context ctx = Z3_mk_context(nullptr);
Z3_set_error_handler(ctx, setError);
test_eval(ctx, spec, false);
Z3_del_context(ctx);
}
void test_ho_choice_expression() {
char const* spec =
"(set-logic HO_ALL)\n"
"(declare-sort U 0)\n"
"(declare-fun P () (-> U Bool))\n"
"(assert (exists ((x U)) (P x)))\n"
"(declare-fun witness () U)\n"
"(assert (= witness (choice ((x U)) (P x))))\n"
"(assert (not (P witness)))\n"
"(check-sat)\n";
Z3_context ctx = Z3_mk_context(nullptr);
Z3_set_error_handler(ctx, setError);
test_eval(ctx, spec, false);
Z3_del_context(ctx);
}
void test_name(Z3_string spec, Z3_string expected_name) {
Z3_context ctx = Z3_mk_context(nullptr);
Z3_set_error_handler(ctx, setError);
@ -289,6 +322,8 @@ void tst_smt2print_parse() {
// Test ?
test_repeated_eval();
test_ho_curried_application();
test_ho_choice_expression();
test_symbol_escape();

126
src/test/tptp.cpp Normal file
View file

@ -0,0 +1,126 @@
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#include "util/debug.h"
#include "util/error_codes.h"
#include "cmd_context/tptp_frontend.h"
struct tptp_case {
char const* name;
char const* input;
char const* expected_status;
};
static unsigned run_tptp(char const* input, std::string& out, std::string& err) {
std::streambuf* old_out = std::cout.rdbuf();
std::streambuf* old_err = std::cerr.rdbuf();
std::ostringstream out_buf;
std::ostringstream err_buf;
std::cout.rdbuf(out_buf.rdbuf());
std::cerr.rdbuf(err_buf.rdbuf());
unsigned code = read_tptp_string(input);
std::cout.rdbuf(old_out);
std::cerr.rdbuf(old_err);
out = out_buf.str();
err = err_buf.str();
return code;
}
static std::string run_tptp(char const* input) {
std::string out, err;
unsigned code = run_tptp(input, out, err);
ENSURE(code == 0);
return out;
}
extern bool g_display_statistics;
extern bool g_display_model;
void tst_tptp() {
g_display_statistics = false;
g_display_model = false;
std::vector<tptp_case> cases = {
{"agatha-butler",
R"(fof(ax1,axiom, lives(agatha)).
fof(ax2,axiom, lives(butler)).
fof(ax3,axiom, lives(charles)).
fof(ax4,axiom, ! [X] : (lives(X) => (X = agatha | X = butler | X = charles))).
fof(ax5,axiom, ! [X,Y] : (killed(X,Y) => hates(X,Y))).
fof(ax6,axiom, ! [X,Y] : (killed(X,Y) => ~ richer(X,Y))).
fof(ax7,axiom, ! [X] : (hates(agatha,X) => ~ hates(charles,X))).
fof(ax8,axiom, ! [X] : (X != butler => hates(agatha,X))).
fof(ax9,axiom, ! [X] : (~ richer(X,agatha) => hates(butler,X))).
fof(ax10,axiom, ! [X] : (hates(agatha,X) => hates(butler,X))).
fof(ax11,axiom, ! [X] : (? [Y] : ~ hates(X,Y))).
fof(ax12,axiom, agatha != butler).
fof(ax13,axiom, ? [X] : killed(X,agatha)).
fof(conj,conjecture, ~ killed(butler,agatha)).)",
"% SZS status Theorem"},
{"socrates-theorem",
R"(fof(a1,axiom, ! [X] : (human(X) => mortal(X))).
fof(a2,axiom, human(socrates)).
fof(c1,conjecture, mortal(socrates)).)",
"% SZS status Theorem"},
{"simple-sat",
R"(fof(a1,axiom, p(a)).)",
"% SZS status Satisfiable"},
{"fof-implicit-forall",
R"(fof(a1,axiom, p(X)).
fof(c1,conjecture, p(a)).)",
"% SZS status Theorem"},
{"cnf-implicit-forall",
R"(cnf(c1,axiom, p(X)).
cnf(c2,axiom, ~ p(a)).)",
"% SZS status Unsatisfiable"},
// {"fof-bare-constant-equality",
// R"(fof(a1,axiom, ! [X] : (X = a)).
//fof(c1,conjecture, b = a).)",
// "% SZS status Theorem"},
{"tff-negative-literal",
R"(tff(c1,conjecture, $less(-2,2)).)",
"% SZS status Theorem"},
{"tff-rational-literal",
R"(tff(c1,conjecture, $less(1/2,2/3)).)",
"% SZS status Theorem"},
{"tff-type-decl-arrow",
R"(tff(p_type,type, p: $int > $o ).
tff(a1,axiom, p(1)).
tff(c1,conjecture, p(1)).)",
"% SZS status Theorem"},
{"tff-typed-int-quantifier",
R"(tff(c1,conjecture, ? [X: $int] : $less(12,X)).)",
"% SZS status Theorem"},
{"tff-lesseq-built-in",
R"(tff(c1,conjecture, $lesseq(2,2)).)",
"% SZS status Theorem"},
{"tff-bare-integer-equality",
R"(tff(c1,conjecture, 31 != 12).)",
"% SZS status Theorem"},
{"tff-decimal-literal",
R"(tff(c1,conjecture, ~ $less(-3.25,-8.69)).)",
"% SZS status Theorem"},
{"tff-uminus-built-in",
R"(tff(c1,conjecture, $less($uminus(2),0)).)",
"% SZS status Theorem"},
{"tff-let-single-binding",
R"(tff(c1,conjecture, $let(a: $int, a := 3, $less(a,4))).)",
"% SZS status Theorem"},
{"tff-let-multiple-bindings",
R"(tff(c1,conjecture, $let([a: $int, b: $int], [a := 1, b := 2], $less($sum(a,b),4))).)",
"% SZS status Theorem"},
{"tff-let-nested",
R"(tff(c1,conjecture, $let(a: $int, a := 5, $let(b: $int, b := 3, $less(b,a)))).)",
"% SZS status Theorem"}
};
for (auto const& c : cases) {
std::string out = run_tptp(c.input);
std::cout << c.name << " status: " << c.expected_status << " out: " << out << "\n";
ENSURE(out.find(c.expected_status) != std::string::npos);
}
std::string out, err;
unsigned code = run_tptp("tff(c1,conjecture, $less(1/0,1)).", out, err);
ENSURE(code == ERR_PARSER);
ENSURE(err.find("denominator of rational literal cannot be zero") != std::string::npos);
}

View file

@ -6,7 +6,9 @@ Copyright (c) 2015 Microsoft Corporation
#include "muz/rel/udoc_relation.h"
#include "util/trace.h"
#include "util/gparams.h"
#include "util/vector.h"
#include "util/gparams.h"
#include "ast/ast.h"
#include "ast/ast_pp.h"
#include "ast/reg_decl_plugins.h"
@ -35,6 +37,7 @@ class udoc_tester {
struct init {
init(ast_manager& m) {
gparams::set("fp.engine", "datalog");
reg_decl_plugins(m);
}
};
@ -44,6 +47,7 @@ class udoc_tester {
bv_util bv;
expr_ref_vector m_vars;
smt_params m_smt_params;
params_ref m_fp_params;
datalog::register_engine m_reg;
datalog::context m_ctx;
datalog::rel_context rc;
@ -113,7 +117,7 @@ class udoc_tester {
public:
udoc_tester():
m_init(m), bv(m), m_vars(m), m_ctx(m, m_reg, m_smt_params), rc(m_ctx),
m_init(m), bv(m), m_vars(m), m_ctx(m, m_reg, m_smt_params, m_fp_params), rc(m_ctx),
p(dynamic_cast<udoc_plugin&>(*rc.get_rmanager().get_relation_plugin(symbol("doc")))),
cr(dynamic_cast<datalog::check_relation_plugin&>(*rc.get_rmanager().get_relation_plugin(symbol("check_relation"))))
{