- api_fpa.cpp: add RETURN_Z3(nullptr) after SET_ERROR_CODE in Z3_mk_fpa_sort to prevent fall-through to mk_float_sort with invalid params
- api_seq.cpp: add null check for str in Z3_mk_string; add null check for str when sz>0 in Z3_mk_lstring; add lo<=hi validation in Z3_mk_re_loop
- api_array.cpp: add explicit n==0 validation in Z3_mk_array_sort_n
- api_solver.cpp: rename local variable 'c' to avoid shadowing Z3_context param in Z3_solver_propagate_created/decide/on_binding; move init_solver call inside file-exists branches of Z3_solver_from_file
- api_ast.cpp: add null check for target in Z3_translate; add null check for _from/_to arrays when num_exprs>0 in Z3_substitute
- api_model.cpp: add CHECK_NON_NULL(m) in Z3_add_func_interp; add CHECK_NON_NULL(a) in Z3_model_get_const_interp; add null check for target in Z3_model_translate
- api_opt.cpp: add null check for weight string in Z3_optimize_assert_soft
- api_quant.cpp: add num_patterns==0 validation in Z3_mk_pattern
Co-authored-by: NikolajBjorner <3085284+NikolajBjorner@users.noreply.github.com>
The optimizer's simplification pass did not expand products of sums
into sum-of-monomials form. This caused mathematically equivalent
expressions like (5-x)^2 vs (x-5)^2 to simplify into different
internal forms, where the former produced nested multiplies
(+ 5.0 (* -1.0 x)) that led to harder purification constraints
and solver timeouts.
Enabling som=true in the first simplification tactic normalizes
polynomial objectives into canonical monomial form, making the
optimizer robust to operand ordering.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Same as test_bnh_optimize but constructs f1 and f2 with reversed
parameter order in mk_add, mk_mul, mk_sub calls. Exposes optimizer
sensitivity to expression structure.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
**Root cause**: `vector::resize(SZ s, Args args...)` in `src/util/vector.h` took `args` by value and used `std::forward<Args>(args)` in a loop. The first iteration moved from `args`, leaving all subsequent elements with a moved-from state (`rational{0/0}` instead of
`rational{0/1}`). This corrupted the coefficient vector in the pretty printer, causing a division-by-zero assertion when multiplying.
**Fix**: Changed `resize` to take `Args const& args` and copy-construct each element instead of forwarding/moving.
- Add ENSURE(result == Z3_L_TRUE) for each BNH optimization call and
ENSURE(num_sat == 7) at the end so CI catches regressions.
- Remove test_bnh_optimize() from tst_api() to avoid duplicate
execution under /a; keep standalone tst_bnh_opt() entry point.
- Fix Test 2 comment: it tests same-size backup, not backup-longer.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Relax restore_x() to handle backup/current size mismatches: when
backup is shorter (new columns added), call
move_non_basic_columns_to_bounds() to find a feasible solution.
- Fix 100x performance regression in nonlinear optimization: save LP
optimum before check_nla and return it as bound regardless of NLA
result, so opt_solver::check_bound() can validate via full re-solve
with accumulated NLA lemmas.
- Refactor theory_lra::maximize() into three helpers: max_with_lp(),
max_with_nl(), and max_result().
- Add mk_gt(theory_var, impq const&) overload for building blockers
from saved LP optimum values.
- Add BNH multi-objective optimization test (7/7 sat in <1s vs 1/7
in 30s before fix).
- Add restore_x test for backup size mismatch handling.
Fixes#8890
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>