3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2026-04-15 16:54:11 +00:00

Introduce new monomials in Horner when shared factors have bounded linear combinations

When solve-eqs eliminates a variable x (= a - b) that appears as a factor
in a nonlinear product x*y, the product splits into a*y - b*y. The NLA
solver then reasons about a*y and b*y independently, losing the tight
bounds that x had. This can cause severe performance degradation (e.g.,
timeout on a QF_UFNIA verification condition that solves in 3s without
solve-eqs).

The Horner module's cross-nested factoring already recovers the factored
form y*(a-b), and interval_from_term (fixed in the previous commit) finds
the LP column for (a-b) with its tight bounds. However, only Horner's
zero-exclusion check used this — the rest of the NLA solver (order lemmas,
tangent planes, bounds propagation) continued reasoning about the split
monomials independently.

This commit adds a new mechanism: when Horner discovers that a linear
sub-expression maps to a bounded LP column, it introduces a new monomial
pairing that column with the shared factor. For example, if y*(a-b) is
discovered and (a-b) maps to LP column j with bounds [L,U], we create a
new monomial m := y*j via add_mul_def and assert the equality
m = a*y - b*y via literals. This allows all NLA modules to generate
lemmas using j's tight bounds.

The feature is gated by smt.arith.nl.horner_max_new_monomials (default 2,
0 to disable). On the motivating benchmark, this changes
simplify+propagate-values+solve-eqs+smt from timeout (30s) to UNSAT in
~15s with no regressions on other configurations.

Files changed:
- horner.cpp: introduce_monomials_from_term_columns() and find_binary_monic()
- horner.h: m_introduced_monomials dedup set
- nla_intervals.cpp/h: m_term_columns to record interval_from_term discoveries
- smt_params_helper.pyg: arith.nl.horner_max_new_monomials parameter

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arie Gurfinkel 2026-04-07 22:00:10 -04:00
parent 70e88e56fa
commit 1eb83ca9d4
5 changed files with 124 additions and 2 deletions

View file

@ -292,6 +292,7 @@ bool intervals::interval_from_term(const nex& e, scoped_dep_interval& i) {
if (j + 1 == 0)
return false;
m_term_columns.push_back(j);
set_var_interval<wd>(j, i);
interval bi;
m_dep_intervals.mul<wd>(a, i, bi);