#include "api/z3.h"
#include "util/trace.h"
#include "util/debug.h"
static void test_ackermannize_bv_basic() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_del_config(cfg);
Z3_sort bv8 = Z3_mk_bv_sort(ctx, 8);
Z3_func_decl f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 1, &bv8, bv8);
Z3_ast a = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "a"), bv8);
Z3_ast b = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "b"), bv8);
Z3_ast fa = Z3_mk_app(ctx, f, 1, &a);
Z3_ast fb = Z3_mk_app(ctx, f, 1, &b);
Z3_ast eq_ab = Z3_mk_eq(ctx, a, b);
Z3_ast neq_fab = Z3_mk_not(ctx, Z3_mk_eq(ctx, fa, fb));
Z3_ast args[2] = { eq_ab, neq_fab };
Z3_ast formula = Z3_mk_and(ctx, 2, args);
Z3_goal g = Z3_mk_goal(ctx, true, false, false);
Z3_goal_inc_ref(ctx, g);
Z3_goal_assert(ctx, g, formula);
unsigned input_size = Z3_goal_size(ctx, g);
Z3_tactic t = Z3_mk_tactic(ctx, "ackermannize_bv");
Z3_tactic_inc_ref(ctx, t);
Z3_apply_result ar = Z3_tactic_apply(ctx, t, g);
Z3_apply_result_inc_ref(ctx, ar);
unsigned num_subgoals = Z3_apply_result_get_num_subgoals(ctx, ar);
ENSURE(num_subgoals == 1);
Z3_goal rg = Z3_apply_result_get_subgoal(ctx, ar, 0);
ENSURE(Z3_goal_size(ctx, rg) > input_size);
Z3_apply_result_dec_ref(ctx, ar);
Z3_tactic_dec_ref(ctx, t);
Z3_goal_dec_ref(ctx, g);
Z3_del_context(ctx);
}
static void test_ackermannize_bv_zero_limit() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_del_config(cfg);
Z3_sort bv8 = Z3_mk_bv_sort(ctx, 8);
Z3_func_decl f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 1, &bv8, bv8);
Z3_ast a = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "a"), bv8);
Z3_ast b = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "b"), bv8);
Z3_ast fa = Z3_mk_app(ctx, f, 1, &a);
Z3_ast fb = Z3_mk_app(ctx, f, 1, &b);
Z3_ast eq_fab = Z3_mk_eq(ctx, fa, fb);
Z3_goal g = Z3_mk_goal(ctx, false, false, false);
Z3_goal_inc_ref(ctx, g);
Z3_goal_assert(ctx, g, eq_fab);
unsigned input_size = Z3_goal_size(ctx, g);
Z3_params p = Z3_mk_params(ctx);
Z3_params_inc_ref(ctx, p);
Z3_params_set_uint(ctx, p, Z3_mk_string_symbol(ctx, "div0_ackermann_limit"), 0);
Z3_tactic t = Z3_mk_tactic(ctx, "ackermannize_bv");
Z3_tactic_inc_ref(ctx, t);
Z3_apply_result ar = Z3_tactic_apply_ex(ctx, t, g, p);
Z3_apply_result_inc_ref(ctx, ar);
unsigned num_subgoals = Z3_apply_result_get_num_subgoals(ctx, ar);
ENSURE(num_subgoals == 1);
Z3_goal rg = Z3_apply_result_get_subgoal(ctx, ar, 0);
ENSURE(Z3_goal_size(ctx, rg) == input_size);
Z3_apply_result_dec_ref(ctx, ar);
Z3_params_dec_ref(ctx, p);
Z3_tactic_dec_ref(ctx, t);
Z3_goal_dec_ref(ctx, g);
Z3_del_context(ctx);
}
static void test_ackr_bound_probe() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_del_config(cfg);
Z3_sort bv8 = Z3_mk_bv_sort(ctx, 8);
Z3_func_decl f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 1, &bv8, bv8);
Z3_ast a = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "a"), bv8);
Z3_ast b = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "b"), bv8);
Z3_ast fa = Z3_mk_app(ctx, f, 1, &a);
Z3_ast fb = Z3_mk_app(ctx, f, 1, &b);
Z3_ast eq_fab = Z3_mk_eq(ctx, fa, fb);
Z3_goal g = Z3_mk_goal(ctx, false, false, false);
Z3_goal_inc_ref(ctx, g);
Z3_goal_assert(ctx, g, eq_fab);
Z3_probe pr = Z3_mk_probe(ctx, "ackr-bound-probe");
Z3_probe_inc_ref(ctx, pr);
double bound = Z3_probe_apply(ctx, pr, g);
ENSURE(bound >= 1.0);
Z3_probe_dec_ref(ctx, pr);
Z3_goal_dec_ref(ctx, g);
Z3_del_context(ctx);
}
[[maybe_unused]] static void test_ackermannize_bv_model() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_del_config(cfg);
Z3_sort bv8 = Z3_mk_bv_sort(ctx, 8);
Z3_func_decl f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 1, &bv8, bv8);
Z3_ast a = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "a"), bv8);
Z3_ast b = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "b"), bv8);
Z3_ast fa = Z3_mk_app(ctx, f, 1, &a);
Z3_ast fb = Z3_mk_app(ctx, f, 1, &b);
Z3_ast formula = Z3_mk_not(ctx, Z3_mk_eq(ctx, fa, fb));
Z3_goal g = Z3_mk_goal(ctx, true, false, false);
Z3_goal_inc_ref(ctx, g);
Z3_goal_assert(ctx, g, formula);
Z3_tactic t = Z3_mk_tactic(ctx, "ackermannize_bv");
Z3_tactic_inc_ref(ctx, t);
Z3_apply_result ar = Z3_tactic_apply(ctx, t, g);
Z3_apply_result_inc_ref(ctx, ar);
ENSURE(Z3_apply_result_get_num_subgoals(ctx, ar) == 1);
Z3_goal rg = Z3_apply_result_get_subgoal(ctx, ar, 0);
Z3_model empty_m = Z3_mk_model(ctx);
Z3_model_inc_ref(ctx, empty_m);
Z3_model converted = Z3_goal_convert_model(ctx, rg, empty_m);
if (converted) Z3_model_inc_ref(ctx, converted);
if (converted) Z3_model_dec_ref(ctx, converted);
Z3_model_dec_ref(ctx, empty_m);
Z3_apply_result_dec_ref(ctx, ar);
Z3_tactic_dec_ref(ctx, t);
Z3_goal_dec_ref(ctx, g);
Z3_del_context(ctx);
}
static void test_ackermannize_bv_multiple_assertions() {
Z3_config cfg = Z3_mk_config();
Z3_context ctx = Z3_mk_context(cfg);
Z3_del_config(cfg);
Z3_sort bv8 = Z3_mk_bv_sort(ctx, 8);
Z3_func_decl f = Z3_mk_func_decl(ctx, Z3_mk_string_symbol(ctx, "f"), 1, &bv8, bv8);
Z3_ast a = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "a"), bv8);
Z3_ast b = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "b"), bv8);
Z3_ast c = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "c"), bv8);
Z3_ast fa = Z3_mk_app(ctx, f, 1, &a);
Z3_ast fb = Z3_mk_app(ctx, f, 1, &b);
Z3_ast fc = Z3_mk_app(ctx, f, 1, &c);
Z3_ast f1 = Z3_mk_eq(ctx, fa, fb);
Z3_ast f2 = Z3_mk_eq(ctx, fb, fc);
Z3_ast f3 = Z3_mk_not(ctx, Z3_mk_eq(ctx, a, b));
Z3_goal g = Z3_mk_goal(ctx, false, false, false);
Z3_goal_inc_ref(ctx, g);
Z3_goal_assert(ctx, g, f1);
Z3_goal_assert(ctx, g, f2);
Z3_goal_assert(ctx, g, f3);
unsigned input_size = Z3_goal_size(ctx, g);
Z3_tactic t = Z3_mk_tactic(ctx, "ackermannize_bv");
Z3_tactic_inc_ref(ctx, t);
Z3_apply_result ar = Z3_tactic_apply(ctx, t, g);
Z3_apply_result_inc_ref(ctx, ar);
ENSURE(Z3_apply_result_get_num_subgoals(ctx, ar) == 1);
Z3_goal rg = Z3_apply_result_get_subgoal(ctx, ar, 0);
ENSURE(Z3_goal_size(ctx, rg) > input_size);
Z3_apply_result_dec_ref(ctx, ar);
Z3_tactic_dec_ref(ctx, t);
Z3_goal_dec_ref(ctx, g);
Z3_del_context(ctx);
}
void tst_ackermannize() {
test_ackermannize_bv_basic();
test_ackermannize_bv_zero_limit();
test_ackr_bound_probe();
test_ackermannize_bv_multiple_assertions();
}