mirror of
https://github.com/Z3Prover/z3
synced 2026-04-27 14:23:35 +00:00
first end-pass. Atomic
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
13f9fec339
commit
5aa3713d19
15 changed files with 6160 additions and 209 deletions
|
|
@ -7,7 +7,18 @@ Module Name:
|
|||
|
||||
Abstract:
|
||||
|
||||
Model generation from solved Nielsen graph.
|
||||
Model construction for the Nielsen-based string solver (theory_nseq).
|
||||
|
||||
After the Nielsen graph search returns sat, this module extracts
|
||||
variable-to-value assignments from the satisfying leaf node and
|
||||
builds model_value_proc callbacks for the SMT model generator.
|
||||
|
||||
The workflow is:
|
||||
1. init() — allocate seq_factory, register existing string literals,
|
||||
and extract variable assignments from the satisfying Nielsen node.
|
||||
2. mk_value(enode*) — return a model_value_proc that lazily builds
|
||||
the concrete value for a given enode.
|
||||
3. finalize() — clean up temporary state.
|
||||
|
||||
Author:
|
||||
|
||||
|
|
@ -16,57 +27,99 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "ast/ast.h"
|
||||
#include "ast/seq_decl_plugin.h"
|
||||
#include "util/zstring.h"
|
||||
#include "ast/rewriter/seq_rewriter.h"
|
||||
#include "ast/euf/euf_sgraph.h"
|
||||
#include "smt/smt_types.h"
|
||||
#include "smt/seq/seq_nielsen.h"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include "model/seq_factory.h"
|
||||
|
||||
class proto_model;
|
||||
|
||||
namespace smt {
|
||||
|
||||
class theory_nseq;
|
||||
class nseq_regex;
|
||||
class nseq_state;
|
||||
class model_value_proc;
|
||||
|
||||
class nseq_model {
|
||||
ast_manager& m;
|
||||
seq_util m_seq;
|
||||
euf::sgraph& m_sg;
|
||||
unsigned m_fresh_counter = 0;
|
||||
theory_nseq& m_th;
|
||||
ast_manager& m;
|
||||
seq_util& m_seq;
|
||||
seq_rewriter& m_rewriter;
|
||||
euf::sgraph& m_sg;
|
||||
nseq_regex& m_regex;
|
||||
|
||||
// factory for generating fresh string/regex values
|
||||
seq_factory* m_factory = nullptr;
|
||||
|
||||
// variable assignments extracted from the satisfying Nielsen node.
|
||||
// maps snode id -> expr* (concrete value)
|
||||
u_map<expr*> m_var_values;
|
||||
|
||||
// trail for GC protection of generated expressions
|
||||
expr_ref_vector m_trail;
|
||||
|
||||
// per-variable regex constraints: maps snode id -> intersected regex snode.
|
||||
// collected during init() from the state's str_mem list.
|
||||
u_map<euf::snode*> m_var_regex;
|
||||
|
||||
public:
|
||||
nseq_model(ast_manager& m, euf::sgraph& sg) : m(m), m_seq(m), m_sg(sg) {}
|
||||
nseq_model(theory_nseq& th, ast_manager& m, seq_util& seq,
|
||||
seq_rewriter& rw, euf::sgraph& sg, nseq_regex& regex);
|
||||
|
||||
// generate a fresh string value (used when a variable is unconstrained)
|
||||
expr_ref mk_fresh_value() {
|
||||
std::string name = "s!" + std::to_string(m_fresh_counter++);
|
||||
zstring zs(name.c_str());
|
||||
return expr_ref(m_seq.str.mk_string(zs), m);
|
||||
}
|
||||
// Phase 1: initialize model construction.
|
||||
// Allocates seq_factory, registers it with mg, collects
|
||||
// existing string literals, and extracts variable assignments
|
||||
// from the satisfying Nielsen leaf node.
|
||||
void init(model_generator& mg, seq::nielsen_graph& nielsen, nseq_state const& state);
|
||||
|
||||
// extract variable assignments from a satisfied leaf node
|
||||
// Returns true if all variables got a valid assignment
|
||||
bool extract_assignments(seq::nielsen_node* node,
|
||||
std::vector<std::pair<euf::snode*, expr*>>& assignment) {
|
||||
if (!node)
|
||||
return false;
|
||||
for (auto const& eq : node->str_eqs()) {
|
||||
if (!eq.m_lhs || !eq.m_rhs)
|
||||
continue;
|
||||
if (eq.m_lhs->is_var() && eq.m_rhs->get_expr()) {
|
||||
assignment.emplace_back(eq.m_lhs, eq.m_rhs->get_expr());
|
||||
}
|
||||
else if (eq.m_rhs->is_var() && eq.m_lhs->get_expr()) {
|
||||
assignment.emplace_back(eq.m_rhs, eq.m_lhs->get_expr());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Phase 2: build a model_value_proc for the given enode.
|
||||
// Returns nullptr if the enode is not a sequence/string sort.
|
||||
model_value_proc* mk_value(enode* n, model_generator& mg);
|
||||
|
||||
// validate that a regex membership constraint is satisfied by the assignment
|
||||
bool validate_regex(seq::str_mem const& mem,
|
||||
obj_map<euf::snode, expr*> const& assignment) {
|
||||
// stub: assume valid for now
|
||||
return true;
|
||||
}
|
||||
// Phase 3: clean up temporary model construction state.
|
||||
void finalize(model_generator& mg);
|
||||
|
||||
// Validate that model assignments satisfy all regex membership
|
||||
// constraints from the state. Checks positive and negative
|
||||
// memberships. Returns true if all constraints pass.
|
||||
bool validate_regex(nseq_state const& state, ::proto_model& mdl);
|
||||
|
||||
private:
|
||||
// extract variable assignments from a satisfying Nielsen node.
|
||||
// Walks str_eqs looking for x = value patterns and records them.
|
||||
void extract_assignments(seq::nielsen_node const* node);
|
||||
|
||||
// recursively substitute known variable assignments into an snode tree.
|
||||
// Returns a concrete Z3 expression.
|
||||
expr_ref snode_to_value(euf::snode* n);
|
||||
|
||||
// generate a concrete witness string for a regex.
|
||||
// Uses nullable check and first-char collection to build
|
||||
// a minimal satisfying string. depth bounds recursion.
|
||||
expr_ref generate_regex_witness(euf::snode* regex, unsigned depth = 0);
|
||||
|
||||
// register all string literals appearing in the constraint store
|
||||
// with the factory to avoid collisions with fresh values.
|
||||
void register_existing_values(seq::nielsen_graph& nielsen);
|
||||
|
||||
// look up or compute the value for an snode variable.
|
||||
// If no assignment exists, delegates to mk_fresh_value.
|
||||
expr* get_var_value(euf::snode* var);
|
||||
|
||||
// generate a fresh value for a variable, respecting regex
|
||||
// membership constraints. If the variable has associated
|
||||
// regex constraints (collected during init), generates a
|
||||
// witness satisfying the intersection; otherwise falls back
|
||||
// to a plain fresh value from the factory.
|
||||
expr* mk_fresh_value(euf::snode* var);
|
||||
|
||||
// collect per-variable regex constraints from the state.
|
||||
// For each positive str_mem, records the regex (or intersects
|
||||
// with existing) into m_var_regex keyed by the string snode id.
|
||||
void collect_var_regex_constraints(nseq_state const& state);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue