3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 09:05:31 +00:00

Add (updated and general) solve_for functionality for arithmetic, add congruence_explain to API to retrieve explanation for why two terms are congruent Tweak handling of smt.qi.max_instantations

Add API solve_for(vars).
It takes a list of variables and returns a triangular solved form for the variables.
Currently for arithmetic. The solved form is a list with elements of the form (var, term, guard).
Variables solved in the tail of the list do not occur before in the list.
For example it can return a solution [(x, z, True), (y, x + z, True)] because first x was solved to be z,
then y was solved to be x + z which is the same as 2z.

Add congruent_explain that retuns an explanation for congruent terms.
Terms congruent in the final state after calling SimpleSolver().check() can be queried for
an explanation, i.e., a list of literals that collectively entail the equality under congruence closure.
The literals are asserted in the final state of search.

Adjust smt_context cancellation for the smt.qi.max_instantiations parameter.
It gets checked when qi-queue elements are consumed.
Prior it was checked on insertion time, which didn't allow for processing as many
instantations as there were in the queue. Moreover, it would not cancel the solver.
So it would keep adding instantations to the queue when it was full / depleted the
configuration limit.
This commit is contained in:
Nikolaj Bjorner 2024-12-19 23:26:42 +01:00
parent e4ab2944fe
commit 87f7a20e14
31 changed files with 428 additions and 117 deletions

View file

@ -967,20 +967,41 @@ extern "C" {
Z3_CATCH_RETURN(nullptr);
}
Z3_ast Z3_API Z3_solver_solve_for(Z3_context c, Z3_solver s, Z3_ast a) {
Z3_ast Z3_API Z3_solver_congruence_explain(Z3_context c, Z3_solver s, Z3_ast a, Z3_ast b) {
Z3_TRY;
LOG_Z3_solver_solve_for(c, s, a);
LOG_Z3_solver_congruence_explain(c, s, a, b);
RESET_ERROR_CODE();
init_solver(c, s);
ast_manager& m = mk_c(c)->m();
expr_ref term(m);
if (!to_solver_ref(s)->solve_for(to_expr(a), term))
term = to_expr(a);
mk_c(c)->save_ast_trail(term.get());
RETURN_Z3(of_expr(term.get()));
auto exp = to_solver_ref(s)->congruence_explain(to_expr(a), to_expr(b));
mk_c(c)->save_ast_trail(exp.get());
RETURN_Z3(of_expr(exp));
Z3_CATCH_RETURN(nullptr);
}
void Z3_API Z3_solver_solve_for(Z3_context c, Z3_solver s, Z3_ast_vector vars, Z3_ast_vector terms, Z3_ast_vector guards) {
Z3_TRY;
LOG_Z3_solver_solve_for(c, s, vars, terms, guards);
RESET_ERROR_CODE();
init_solver(c, s);
ast_manager& m = mk_c(c)->m();
auto& _vars = to_ast_vector_ref(vars);
auto& _terms = to_ast_vector_ref(terms);
auto& _guards = to_ast_vector_ref(guards);
vector<solver::solution> solutions;
for (auto t : _vars)
solutions.push_back({ to_expr(t), expr_ref(m), expr_ref(m) });
to_solver_ref(s)->solve_for(solutions);
_vars.reset();
_terms.reset();
_guards.reset();
for (solver::solution const& s : solutions) {
_vars.push_back(s.var);
_terms.push_back(s.term);
_guards.push_back(s.guard);
}
Z3_CATCH;
}
class api_context_obj : public user_propagator::context_obj {
api::context* c;
public:

View file

@ -7336,26 +7336,44 @@ class Solver(Z3PPObject):
return self.cube_vs
def root(self, t):
t = _py2expr(t, self.ctx)
"""Retrieve congruence closure root of the term t relative to the current search state
The function primarily works for SimpleSolver. Terms and variables that are
eliminated during pre-processing are not visible to the congruence closure.
"""
t = _py2expr(t, self.ctx)
return _to_expr_ref(Z3_solver_congruence_root(self.ctx.ref(), self.solver, t.ast), self.ctx)
def next(self, t):
t = _py2expr(t, self.ctx)
"""Retrieve congruence closure sibling of the term t relative to the current search state
The function primarily works for SimpleSolver. Terms and variables that are
eliminated during pre-processing are not visible to the congruence closure.
"""
t = _py2expr(t, self.ctx)
return _to_expr_ref(Z3_solver_congruence_next(self.ctx.ref(), self.solver, t.ast), self.ctx)
def solve_for(self, t):
t = _py2expr(t, self.ctx)
def explain_congruent(self, a, b):
"""Explain congruence of a and b relative to the current search state"""
a = _py2expr(a, self.ctx)
b = _py2expr(b, self.ctx)
return _to_expr_ref(Z3_solver_congruence_explain(self.ctx.ref(), self.solver, a.ast, b.ast), self.ctx)
def solve_for1(self, t):
"""Retrieve a solution for t relative to linear equations maintained in the current state.
The function primarily works for SimpleSolver and when there is a solution using linear arithmetic."""
return _to_expr_ref(Z3_solver_solve_for(self.ctx.ref(), self.solver, t.ast), self.ctx)
t = _py2expr(t, self.ctx)
return _to_expr_ref(Z3_solver_solve_for1(self.ctx.ref(), self.solver, t.ast), self.ctx)
def solve_for(self, ts):
"""Retrieve a solution for t relative to linear equations maintained in the current state."""
vars = AstVector(ctx=self.ctx);
terms = AstVector(ctx=self.ctx);
guards = AstVector(ctx=self.ctx);
for t in ts:
t = _py2expr(t, self.ctx)
vars.push(t)
Z3_solver_solve_for(self.ctx.ref(), self.solver, vars.vector, terms.vector, guards.vector)
return [(vars[i], terms[i], guards[i]) for i in range(len(vars))]
def proof(self):
"""Return a proof for the last `check()`. Proof construction must be enabled."""

View file

@ -7076,14 +7076,23 @@ extern "C" {
*/
Z3_ast Z3_API Z3_solver_congruence_next(Z3_context c, Z3_solver s, Z3_ast a);
/**
\brief retrieve explanation for congruence.
\pre root(a) = root(b)
def_API('Z3_solver_congruence_explain', AST, (_in(CONTEXT), _in(SOLVER), _in(AST), _in(AST)))
*/
Z3_ast Z3_API Z3_solver_congruence_explain(Z3_context c, Z3_solver s, Z3_ast a, Z3_ast b);
/**
\brief retrieve a 'solution' for \c t as defined by equalities in maintained by solvers.
At this point, only linear solution are supported.
\brief retrieve a 'solution' for \c variables as defined by equalities in maintained by solvers.
At this point, only linear solution are supported.
The solution to \c variables may be presented in triangular form, such that
variables used in solutions themselves have solutions.
def_API('Z3_solver_solve_for', AST, (_in(CONTEXT), _in(SOLVER), _in(AST)))
def_API('Z3_solver_solve_for', VOID, (_in(CONTEXT), _in(SOLVER), _in(AST_VECTOR), _in(AST_VECTOR), _in(AST_VECTOR)))
*/
Z3_ast Z3_API Z3_solver_solve_for(Z3_context c, Z3_solver s, Z3_ast t);
void Z3_API Z3_solver_solve_for(Z3_context c, Z3_solver s, Z3_ast_vector variables, Z3_ast_vector terms, Z3_ast_vector guards);
/**
\brief register a callback to that retrieves assumed, inferred and deleted clauses during search.