3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-04-02 18:08:57 +00:00

updated tests

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2026-04-02 10:03:29 -07:00
parent 34cb0a17fc
commit b0a4a15c98
3 changed files with 106 additions and 86 deletions

View file

@ -20,15 +20,15 @@
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <crtdbg.h>
#include <signal.h>
static jmp_buf jmp_env;
static volatile int in_test = 0;
#ifdef _WIN32
#include <windows.h>
#include <crtdbg.h>
void abort_handler(int sig) {
(void)sig;
if (in_test) {
@ -50,13 +50,6 @@ void suppress_dialogs() {
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
signal(SIGABRT, abort_handler);
}
#else
void suppress_dialogs() {}
#endif
static int tests_run = 0;
static int tests_passed = 0;
static int tests_crashed = 0;
#define RUN_TEST(name) do { \
fprintf(stderr, "[TEST] Running %s\n", #name); \
@ -79,6 +72,40 @@ static int tests_crashed = 0;
} \
} while(0)
#else
void abort_handler(int sig) {
(void)sig;
if (in_test) {
in_test = 0;
signal(SIGABRT, abort_handler);
longjmp(jmp_env, 1);
}
}
void suppress_dialogs() { signal(SIGABRT, abort_handler); }
#define RUN_TEST(name) do { \
fprintf(stderr, "[TEST] Running %s\n", #name); \
tests_run++; \
in_test = 1; \
if (setjmp(jmp_env) == 0) { \
name(); \
in_test = 0; \
tests_passed++; \
fprintf(stderr, "[TEST] PASS %s\n", #name); \
} else { \
tests_crashed++; \
fprintf(stderr, "[TEST] ABORT %s (caught SIGABRT)\n", #name); \
} \
} while(0)
#endif
static int tests_run = 0;
static int tests_passed = 0;
static int tests_crashed = 0;
/* ===== Helpers ===== */
static Z3_sort mk_string_sort(Z3_context ctx) { return Z3_mk_string_sort(ctx); }
static Z3_ast mk_str(Z3_context ctx, const char* s) { return Z3_mk_string(ctx, s); }

View file

@ -4,15 +4,15 @@
#include <stdlib.h>
#include <setjmp.h>
#ifdef _WIN32
#include <windows.h>
#include <crtdbg.h>
#include <signal.h>
static jmp_buf jmp_env;
static volatile int in_test = 0;
#ifdef _WIN32
#include <windows.h>
#include <crtdbg.h>
void abort_handler(int sig) {
(void)sig;
if (in_test) {
@ -34,12 +34,6 @@ void suppress_dialogs() {
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
signal(SIGABRT, abort_handler);
}
#else
void suppress_dialogs() {}
#endif
static int tests_run = 0;
static int tests_passed = 0;
#define RUN_TEST(name) do { \
fprintf(stderr, "[TEST] Running %s\n", #name); \
@ -60,6 +54,38 @@ static int tests_passed = 0;
} \
} while(0)
#else
void abort_handler(int sig) {
(void)sig;
if (in_test) {
in_test = 0;
signal(SIGABRT, abort_handler);
longjmp(jmp_env, 1);
}
}
void suppress_dialogs() { signal(SIGABRT, abort_handler); }
#define RUN_TEST(name) do { \
fprintf(stderr, "[TEST] Running %s\n", #name); \
tests_run++; \
in_test = 1; \
if (setjmp(jmp_env) == 0) { \
name(); \
in_test = 0; \
tests_passed++; \
fprintf(stderr, "[TEST] PASS %s\n", #name); \
} else { \
fprintf(stderr, "[TEST] ABORT %s (caught SIGABRT)\n", #name); \
} \
} while(0)
#endif
static int tests_run = 0;
static int tests_passed = 0;
/* Helper to create string sort, variables, constants */
Z3_sort mk_string_sort(Z3_context ctx) { return Z3_mk_string_sort(ctx); }
Z3_ast mk_string_var(Z3_context ctx, const char* name) {

View file

@ -1125,80 +1125,41 @@ namespace seq {
}
}
// consume symbolic characters (s_unit tokens) via uniform derivative
// check. When all minterms of the regex produce the same Brzozowski
// derivative, the derivative is independent of the character value
// and we can deterministically consume the token. Forward direction
// only (matches ZIPT history tracking convention).
//
// Extended: when uniform derivative fails but the token has a char_range
// constraint (from apply_regex_var_split), check if the char_range is a
// subset of a single minterm's character class. If so, the derivative
// is deterministic for that token.
// Mirrors ZIPT StrMem.SimplifyCharRegex lines 96-117.
// consume symbolic characters via uniform derivatives
for (str_mem& mem : m_str_mem) {
SASSERT(mem.m_str && mem.m_regex);
if (mem.is_primitive())
continue;
while (mem.m_str && !mem.m_str->is_empty()) {
euf::snode* tok = mem.m_str->first();
if (!tok || !tok->is_unit())
// TODO: generalize this to work for reverse derivative as well.
euf::snode *tok = mem.m_str->first();
if (!tok || !tok->is_char_or_unit())
break;
//
// TODO -rewrite to use symbolic derivative and add back resulting derived regex.
//
seq_rewriter rw(m);
expr_ref d(rw.mk_derivative(mem.m_regex->get_expr()), m);
// compute minterms and check for uniform derivative
euf::snode_vector minterms;
sg.compute_minterms(mem.m_regex, minterms);
VERIFY(!minterms.empty());
// try char_range subset approach.
// If the symbolic char has a char_range constraint and that
// range is a subset of exactly one minterm's character class,
// we can deterministically take that minterm's derivative.
SASSERT(m_graph.m_parikh);
auto full = char_set::full(zstring::max_char());
char_set* cs;
dep_tracker dep;
if (m_char_ranges.contains(tok->id())) {
auto& ranges = m_char_ranges[tok->id()];
cs = &ranges.first;
dep = ranges.second;
}
else {
cs = &full;
dep = graph().dep_mgr().mk_empty();
// Extract the inner char expression from seq.unit(?inner)
expr *unit_expr = tok->arg(0)->get_expr(), *inner_char;
// substitute the inner char for the derivative variable in d
var_subst vs(m);
d = vs(d, inner_char);
th_rewriter thrw(m);
thrw(d);
auto next = sg.mk(d);
if (next->is_fail()) {
m_is_general_conflict = true;
set_conflict(backtrack_reason::regex, mem.m_dep);
return simplify_result::conflict;
}
if (!cs->is_empty()) {
euf::snode* matching_deriv = nullptr;
bool found = false;
for (euf::snode* mt : minterms) {
SASSERT(mt && mt->get_expr());
SASSERT(!mt->is_fail());
char_set mt_cs = m_graph.m_seq_regex->minterm_to_char_set(mt->get_expr());
if (cs->is_subset(mt_cs)) {
euf::snode* deriv = sg.brzozowski_deriv(mem.m_regex, mt);
if (!deriv) { found = false; break; }
if (deriv->is_fail()) {
m_is_general_conflict = true;
set_conflict(backtrack_reason::regex, graph().dep_mgr().mk_join(mem.m_dep, dep));
return simplify_result::conflict;
}
matching_deriv = deriv;
found = true;
break;
}
}
if (found && matching_deriv) {
mem.m_str = sg.drop_left(mem.m_str, 1);
mem.m_regex = matching_deriv;
mem.m_history = sg.mk_concat(mem.m_history, tok);
continue;
}
}
break;
mem.m_str = sg.drop_left(mem.m_str, 1);
mem.m_regex = next;
mem.m_history = sg.mk_concat(mem.m_history, tok);
}
}
@ -3140,12 +3101,13 @@ namespace seq {
}
return false;
}
bool nielsen_graph::apply_regex_unit_split(nielsen_node *node) {
for (str_mem const &mem : node->str_mems()) {
SASSERT(mem.m_str && mem.m_regex);
if (mem.is_primitive())
continue;
euf::snode *first = mem.m_str->first();
if (!first || !first->is_char_or_unit())
continue;
@ -3272,6 +3234,11 @@ namespace seq {
created = true;
}
// TODO: replace this with a version that just uses symbolic derivatives
// and not min-terms.
// It solves x -> unit(nth(x, 0)) ++ x
// Then the split_regex_unit can solve process the node further.
// Branch 2+: for each minterm m_i, x → ?c · x
// where ?c is a symbolic char constrained by the minterm
for (euf::snode* mt : minterms) {