mirror of
https://github.com/Z3Prover/z3
synced 2026-03-07 13:54:53 +00:00
Add nseq_basic unit tests for theory_nseq solver
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
This commit is contained in:
parent
9a9083384f
commit
02db14c8c4
3 changed files with 205 additions and 0 deletions
|
|
@ -129,6 +129,7 @@ add_executable(test-z3
|
|||
simplifier.cpp
|
||||
sls_test.cpp
|
||||
sls_seq_plugin.cpp
|
||||
nseq_basic.cpp
|
||||
small_object_allocator.cpp
|
||||
smt2print_parse.cpp
|
||||
smt_context.cpp
|
||||
|
|
|
|||
|
|
@ -284,6 +284,7 @@ int main(int argc, char ** argv) {
|
|||
TST(sls_test);
|
||||
TST(scoped_vector);
|
||||
TST(sls_seq_plugin);
|
||||
TST(nseq_basic);
|
||||
TST(ho_matcher);
|
||||
TST(finite_set);
|
||||
TST(finite_set_rewriter);
|
||||
|
|
|
|||
203
src/test/nseq_basic.cpp
Normal file
203
src/test/nseq_basic.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
/*++
|
||||
Copyright (c) 2025 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
nseq_basic.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Basic unit tests for the Nielsen-based string theory solver (theory_nseq).
|
||||
Tests that theory_nseq can be selected via smt.string_solver=nseq and
|
||||
correctly handles basic string constraints.
|
||||
|
||||
Author:
|
||||
|
||||
Clemens Eisenhofer
|
||||
Nikolaj Bjorner (nbjorner) 2025-2-28
|
||||
|
||||
--*/
|
||||
|
||||
#include "api/z3.h"
|
||||
#include <iostream>
|
||||
#include "util/util.h"
|
||||
|
||||
// Helper: create a Z3 context with string_solver set to nseq
|
||||
static Z3_context mk_nseq_ctx() {
|
||||
Z3_global_param_set("smt.string_solver", "nseq");
|
||||
Z3_config cfg = Z3_mk_config();
|
||||
Z3_context ctx = Z3_mk_context(cfg);
|
||||
Z3_del_config(cfg);
|
||||
Z3_global_param_reset_all();
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// Test 1: Simple string constant equality (sat)
|
||||
static void test_nseq_simple_sat() {
|
||||
Z3_context ctx = mk_nseq_ctx();
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
|
||||
Z3_sort str_sort = Z3_mk_string_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), str_sort);
|
||||
Z3_ast hello = Z3_mk_string(ctx, "hello");
|
||||
Z3_ast eq = Z3_mk_eq(ctx, x, hello);
|
||||
Z3_solver_assert(ctx, s, eq);
|
||||
Z3_lbool r = Z3_solver_check(ctx, s);
|
||||
ENSURE(r == Z3_L_TRUE);
|
||||
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
// Test 2: Simple string constant disequality (unsat)
|
||||
static void test_nseq_simple_unsat() {
|
||||
Z3_context ctx = mk_nseq_ctx();
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
|
||||
Z3_sort str_sort = Z3_mk_string_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), str_sort);
|
||||
Z3_ast hello = Z3_mk_string(ctx, "hello");
|
||||
Z3_ast world = Z3_mk_string(ctx, "world");
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, x, hello));
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, x, world));
|
||||
Z3_lbool r = Z3_solver_check(ctx, s);
|
||||
ENSURE(r == Z3_L_FALSE);
|
||||
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
// Test 3: String concatenation (sat)
|
||||
static void test_nseq_concat_sat() {
|
||||
Z3_context ctx = mk_nseq_ctx();
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
|
||||
Z3_sort str_sort = Z3_mk_string_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), str_sort);
|
||||
Z3_ast y = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "y"), str_sort);
|
||||
Z3_ast hello = Z3_mk_string(ctx, "hello");
|
||||
Z3_ast args[2] = { x, y };
|
||||
Z3_ast xy = Z3_mk_seq_concat(ctx, 2, args);
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, xy, hello));
|
||||
Z3_lbool r = Z3_solver_check(ctx, s);
|
||||
ENSURE(r == Z3_L_TRUE);
|
||||
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
// Test 4: Prefix constraint (sat)
|
||||
static void test_nseq_prefix_sat() {
|
||||
Z3_context ctx = mk_nseq_ctx();
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
|
||||
Z3_sort str_sort = Z3_mk_string_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), str_sort);
|
||||
Z3_ast pre = Z3_mk_string(ctx, "hel");
|
||||
// prefix("hel", x)
|
||||
Z3_ast prefix_cond = Z3_mk_seq_prefix(ctx, pre, x);
|
||||
Z3_sort int_sort = Z3_mk_int_sort(ctx);
|
||||
Z3_ast five = Z3_mk_int(ctx, 5, int_sort);
|
||||
Z3_ast len_x = Z3_mk_seq_length(ctx, x);
|
||||
Z3_solver_assert(ctx, s, prefix_cond);
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, len_x, five));
|
||||
Z3_lbool r = Z3_solver_check(ctx, s);
|
||||
ENSURE(r == Z3_L_TRUE);
|
||||
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
// Test 5: Empty string equality (sat)
|
||||
static void test_nseq_empty_sat() {
|
||||
Z3_context ctx = mk_nseq_ctx();
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
|
||||
Z3_sort str_sort = Z3_mk_string_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), str_sort);
|
||||
Z3_ast empty = Z3_mk_string(ctx, "");
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, x, empty));
|
||||
Z3_lbool r = Z3_solver_check(ctx, s);
|
||||
ENSURE(r == Z3_L_TRUE);
|
||||
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
// Test 6: Basic regex membership (sat)
|
||||
static void test_nseq_regex_sat() {
|
||||
Z3_context ctx = mk_nseq_ctx();
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
|
||||
Z3_sort str_sort = Z3_mk_string_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), str_sort);
|
||||
// x = "abab" ∧ x ∈ (ab)*
|
||||
Z3_ast abab = Z3_mk_string(ctx, "abab");
|
||||
Z3_ast ab_re = Z3_mk_seq_to_re(ctx, Z3_mk_string(ctx, "ab"));
|
||||
Z3_ast star_re = Z3_mk_re_star(ctx, ab_re);
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, x, abab));
|
||||
Z3_solver_assert(ctx, s, Z3_mk_seq_in_re(ctx, x, star_re));
|
||||
Z3_lbool r = Z3_solver_check(ctx, s);
|
||||
ENSURE(r == Z3_L_TRUE);
|
||||
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
// Test 7: Basic regex membership (unsat)
|
||||
static void test_nseq_regex_unsat() {
|
||||
Z3_context ctx = mk_nseq_ctx();
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
|
||||
Z3_sort str_sort = Z3_mk_string_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), str_sort);
|
||||
// x = "abc" ∧ x ∈ (ab)* → unsat ("abc" is not in (ab)*)
|
||||
Z3_ast abc = Z3_mk_string(ctx, "abc");
|
||||
Z3_ast ab_re = Z3_mk_seq_to_re(ctx, Z3_mk_string(ctx, "ab"));
|
||||
Z3_ast star_re = Z3_mk_re_star(ctx, ab_re);
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, x, abc));
|
||||
Z3_solver_assert(ctx, s, Z3_mk_seq_in_re(ctx, x, star_re));
|
||||
Z3_lbool r = Z3_solver_check(ctx, s);
|
||||
ENSURE(r == Z3_L_FALSE);
|
||||
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
// Test 8: Length constraint (sat)
|
||||
static void test_nseq_length_sat() {
|
||||
Z3_context ctx = mk_nseq_ctx();
|
||||
Z3_solver s = Z3_mk_solver(ctx);
|
||||
Z3_solver_inc_ref(ctx, s);
|
||||
|
||||
Z3_sort str_sort = Z3_mk_string_sort(ctx);
|
||||
Z3_sort int_sort = Z3_mk_int_sort(ctx);
|
||||
Z3_ast x = Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, "x"), str_sort);
|
||||
Z3_ast len_x = Z3_mk_seq_length(ctx, x);
|
||||
Z3_ast three = Z3_mk_int(ctx, 3, int_sort);
|
||||
Z3_solver_assert(ctx, s, Z3_mk_eq(ctx, len_x, three));
|
||||
Z3_lbool r = Z3_solver_check(ctx, s);
|
||||
ENSURE(r == Z3_L_TRUE);
|
||||
|
||||
Z3_solver_dec_ref(ctx, s);
|
||||
Z3_del_context(ctx);
|
||||
}
|
||||
|
||||
void tst_nseq_basic() {
|
||||
test_nseq_simple_sat();
|
||||
test_nseq_simple_unsat();
|
||||
test_nseq_concat_sat();
|
||||
test_nseq_prefix_sat();
|
||||
test_nseq_empty_sat();
|
||||
test_nseq_regex_sat();
|
||||
test_nseq_regex_unsat();
|
||||
test_nseq_length_sat();
|
||||
std::cout << "nseq_basic: all tests passed\n";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue