mirror of
https://github.com/Z3Prover/z3
synced 2026-06-23 00:50:29 +00:00
Lookahead for regex splits applied to membership constraints
Rewriting constraint/prefix/suffix with constant strings to regexes
This commit is contained in:
parent
f9f16550e0
commit
2dbefbcd56
7 changed files with 220 additions and 69 deletions
|
|
@ -33,6 +33,7 @@ Author:
|
|||
|
||||
#include "ast/seq_decl_plugin.h"
|
||||
#include "ast/rewriter/seq_subset.h"
|
||||
#include <functional>
|
||||
|
||||
class seq_rewriter;
|
||||
|
||||
|
|
@ -57,6 +58,11 @@ typedef vector<split_pair> split_set;
|
|||
// give up (return false) on complement / intersection instead.
|
||||
enum class split_mode { weak, strong };
|
||||
|
||||
// Optional lookahead oracle. Called for each candidate split <D, N> as it is
|
||||
// generated; returns true to keep it, false to prune it. An empty oracle (the
|
||||
// default) keeps everything, so sigma is unchanged. See seq_split::compute.
|
||||
typedef std::function<bool(expr* D, expr* N)> split_oracle;
|
||||
|
||||
class seq_split {
|
||||
seq_rewriter& m_rw; // for mk_re_append + manager / seq_util access
|
||||
seq_subset m_subset; // language-subset checks for subsumption
|
||||
|
|
@ -65,13 +71,18 @@ class seq_split {
|
|||
seq_util& seq() const;
|
||||
seq_util::rex& re() const;
|
||||
|
||||
// Push <d, n> onto `out`, unless `oracle` rejects it.
|
||||
void push(split_set& out, split_oracle const& oracle, expr* d, expr* n) const;
|
||||
|
||||
// S1 cap S2 = { <D1 cap D2, N1 cap N2> } dropping any pair with a bottom
|
||||
// component. Returns false on threshold overrun.
|
||||
bool intersect(split_set const& s1, split_set const& s2, split_set& result, unsigned threshold);
|
||||
// component (and any rejected by `oracle`). Returns false on threshold overrun.
|
||||
bool intersect(split_set const& s1, split_set const& s2, split_set& result,
|
||||
unsigned threshold, split_oracle const& oracle);
|
||||
|
||||
// De Morgan complement of a split-set: ~S = cap_{s in S} ~s with
|
||||
// ~<D,N> = { <~D, .*>, <.*, ~N> } and ~{} = { <.*, .*> }.
|
||||
bool complement(sort* seq_sort, split_set const& sp, split_set& result, unsigned threshold);
|
||||
bool complement(sort* seq_sort, split_set const& sp, split_set& result,
|
||||
unsigned threshold, split_oracle const& oracle);
|
||||
|
||||
// same-D / same-N merge: groups pairs that share a (syntactically identical)
|
||||
// left (resp. right) component and unions the other component.
|
||||
|
|
@ -84,7 +95,16 @@ public:
|
|||
// bounds the number of produced splits; an overrun, an unsupported regex
|
||||
// shape (bounded loop / ite), or a Boolean-closure case in weak mode makes
|
||||
// it return false ("give up").
|
||||
bool compute(expr* r, split_set& out, unsigned threshold, split_mode mode = split_mode::strong);
|
||||
//
|
||||
// `oracle` (optional) prunes non-viable splits *during* generation. It must
|
||||
// be sound to apply at every generation step: a candidate N can still gain a
|
||||
// prefix from a factor appended to its right later (concat/star), so the
|
||||
// oracle must use a "prefix-compatible" test (prune only when N can never
|
||||
// match the lookahead, even partially), NOT a strict "starts-with" test.
|
||||
// The complement body is computed WITHOUT the oracle (inverted orientation);
|
||||
// the oracle is re-applied to the complement's output fold.
|
||||
bool compute(expr* r, split_set& out, unsigned threshold,
|
||||
split_mode mode = split_mode::strong, split_oracle const& oracle = {});
|
||||
|
||||
// In-place simplification of a split-set: drop bottom components, apply the
|
||||
// same-D / same-N merge rules, and drop splits subsumed by another (using
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue